@peektravel/app-utilities 0.2.7 → 0.2.10

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/index.js CHANGED
@@ -186,759 +186,765 @@ var ACTIVITY_PRODUCT_TYPE = "ACTIVITY";
186
186
  var RENTAL_PRODUCT_TYPE = "RENTAL";
187
187
  var ADD_ON_PRODUCT_TYPE = "ADD-ON";
188
188
 
189
- // src/internal/bookings/booking-converter.ts
190
- var UNKNOWN = "unknown";
191
- var SOURCE_SOURCE_MAP = {
192
- APP_REGISTRY: "app",
193
- BOOKING_IMPORTER_FUTURE: "importer",
194
- BOOKING_IMPORTER_HISTORIC: "importer",
195
- EXPEDIA: "expedia",
196
- GROUPON: "groupon",
197
- GYG: "getyourguide",
198
- HOOK: "internal",
199
- INTERNAL_TOOLS: "internal",
200
- IOS_PP: "ios",
201
- OCTO: "octo",
202
- PDC: "peekcom",
203
- PEEK_PLUS: "peekcom",
204
- PP: "backend",
205
- RWG: "rwg",
206
- SELF_SERVE: "internal",
207
- SYSTEM: "internal",
208
- VIATOR: "viator",
209
- WIDGET: "website",
210
- YELP: "yelp"
211
- };
212
- var SOURCE_DESC_MAP = {
213
- APP_REGISTRY: "App Store App",
214
- BOOKING_IMPORTER_FUTURE: "Booking Importer",
215
- BOOKING_IMPORTER_HISTORIC: "Booking Importer",
216
- EXPEDIA: "Expedia",
217
- GROUPON: "Groupon",
218
- GYG: "GetYourGuide",
219
- HOOK: "Internal",
220
- INTERNAL_TOOLS: "Internal",
221
- IOS_PP: "Peek Pro: iOS App",
222
- OCTO: "OCTO",
223
- PDC: "Peek.com",
224
- PEEK_PLUS: "Peek.com",
225
- PP: "Peek Pro: Backend",
226
- RWG: "Reserve with Google",
227
- SELF_SERVE: "Internal",
228
- SYSTEM: "Internal",
229
- VIATOR: "Viator",
230
- WIDGET: "Website Booking Flow",
231
- YELP: "Yelp"
232
- };
233
- function fromBookingNode(node, includeGuests = false, includePriceBreakdown = false) {
234
- const data = node ?? {};
235
- const ticketQuantities = data.ticketQuantities ?? [];
236
- const app = data.order?.initialQuote?.source?.actor?.app ?? null;
237
- const sourceDetails = data.order?.initialQuote?.source?.actor?.name ?? null;
238
- const customQuestionAnswers = (data.questionAnswers ?? []).map(
239
- (answer) => {
240
- const base = {
241
- question: answer.questionText,
242
- answer: answer.answer
243
- };
244
- const location = answer.questionLocationSnapshot;
245
- if (location && location.latitude && location.longitude) {
246
- base.latitude = location.latitude;
247
- base.longitude = location.longitude;
189
+ // src/internal/bookings/booking-queries.ts
190
+ var SEARCH_BY_PURCHASE_DATE = "purchaseDate";
191
+ var SEARCH_BY_ACTIVITY_DATE = "activityDate";
192
+ function normalizeBookingId(bookingId) {
193
+ return bookingId.toLowerCase().replace(/-/g, "_");
194
+ }
195
+ var guestFields = `
196
+ id
197
+ name
198
+ country
199
+ dateOfBirth
200
+ email
201
+ isGdpr
202
+ isParticipant
203
+ optinSms
204
+ optinMarketing
205
+ phone
206
+ postalCode
207
+ fieldResponses {
208
+ id
209
+ text
210
+ fieldLocation {
211
+ field {
212
+ name
248
213
  }
249
- return base;
250
214
  }
251
- );
252
- const customGuestQuestionAnswers = Array.isArray(data.tickets) ? data.tickets.flatMap(
253
- (ticket) => Array.isArray(ticket?.questionAnswers) ? ticket.questionAnswers.filter((qa) => qa && qa.answer !== void 0 && qa.questionText !== void 0).map((qa) => ({ question: qa.questionText, answer: qa.answer })) : []
254
- ) : [];
255
- return {
256
- bookingId: data.id || "",
257
- displayId: data.displayId || "",
258
- source: sourceFromApp(app),
259
- sourceApp: app || UNKNOWN,
260
- sourceDescription: sourceDescriptionFromApp(app),
261
- sourceDetails,
262
- customerName: data.primaryGuest?.name || "",
263
- customerEmail: data.primaryGuest?.email || null,
264
- customerPhone: data.primaryGuest?.phone || null,
265
- productId: data.activitySnapshot?.id || UNKNOWN,
266
- productName: data.activitySnapshot?.name || UNKNOWN,
267
- isRentalProduct: data.activitySnapshot?.type === "RENTAL",
268
- timeslotId: data.timeSnapshot?.legacyId || null,
269
- totalTickets: ticketQuantity(ticketQuantities),
270
- ticketDescription: formatTickets(ticketQuantities),
271
- tickets: ticketsToTicketArray(ticketQuantities, includePriceBreakdown),
272
- isCanceled: data.reservationStatus === "CANCELED",
273
- isNoShow: data.fulfillmentStatusOverride?.status === "NO_SHOW",
274
- isCheckedIn: data.checkinStatus !== "NONE",
275
- isReturned: data.returnStatus !== "NONE",
276
- purchasedAt: data.purchasedAt || null,
277
- purchasedAtUtc: data.purchasedAtUtc || null,
278
- startsAt: data.startsAt || null,
279
- startsAtUtc: data.startsAtUtc || null,
280
- endsAt: data.endsAt || null,
281
- endsAtUtc: data.endsAtUtc || null,
282
- durationMin: durationInMin(data.startsAt || null, data.endsAt || null),
283
- availabilityTimeId: data.availabilityTimeId || null,
284
- portalUrl: data.bookingPortalUrl || null,
285
- notes: data.operatorNotes || "",
286
- valueDisplay: data.value?.total?.formatted || "",
287
- valueAmount: data.value?.total?.amount || "",
288
- outstandingBalanceAmount: data.balance?.total?.amount || "",
289
- outstandingBalanceDisplay: data.balance?.total?.formatted || "",
290
- promoCodes: data.order?.promoCodes?.map((promo) => promo.code) ?? [],
291
- tips: (data.tips ?? []).map((tip) => ({
292
- display: tip.price?.formatted || "",
293
- amount: tip.price?.amount || ""
294
- })),
295
- customQuestionAnswers,
296
- customGuestQuestionAnswers,
297
- resources: (data.resourcePoolAssignments ?? []).map((resource) => ({
298
- quantity: resource.quantity || 0,
299
- name: resource.resourcePool?.name || "",
300
- shortName: resource.resourcePool?.shortName || ""
301
- })),
302
- resourcePoolAssignments: mapResourcePoolAssignments(data.resourcePoolAssignments),
303
- resellerId: data.order?.channelSnapshot?.id || null,
304
- resellerName: resellerNameFromChannelSnapshot(data.order?.channelSnapshot),
305
- orderId: data.order?.id || "",
306
- convenienceFee: includePriceBreakdown ? mapPrice(data.value?.convenienceFee) : void 0,
307
- deposit: includePriceBreakdown ? mapPrice(data.value?.deposit) : void 0,
308
- discount: includePriceBreakdown ? mapPrice(data.value?.discount) : void 0,
309
- discountedPrice: includePriceBreakdown ? mapPrice(data.value?.discountedPrice) : void 0,
310
- fees: includePriceBreakdown ? mapPrice(data.value?.fees) : void 0,
311
- flatPartnerFee: includePriceBreakdown ? mapPrice(data.value?.flatPartnerFee) : void 0,
312
- price: includePriceBreakdown ? mapPrice(data.value?.price) : void 0,
313
- retailPrice: includePriceBreakdown ? mapPrice(data.value?.retailPrice) : void 0,
314
- taxes: includePriceBreakdown ? mapPrice(data.value?.taxes) : void 0,
315
- tipsBreakdown: includePriceBreakdown ? mapPrice(data.value?.tips) : void 0,
316
- guests: includeGuests ? convertGuests(data) : void 0
317
- };
318
- }
319
- function convertGuests(data) {
320
- const bookingGuestsNodes = Array.isArray(data.bookingGuests) ? data.bookingGuests : [];
321
- const primaryGuestNode = data.primaryGuest;
322
- const primaryId = primaryGuestNode?.id;
323
- const guests = [];
324
- for (const guestNode of bookingGuestsNodes) {
325
- guests.push(mapGuestNode(guestNode, primaryId ? guestNode.id === primaryId : false));
326
215
  }
327
- const hasPrimaryInGuests = primaryId ? bookingGuestsNodes.some((guest) => guest.id === primaryId) : false;
328
- if (!hasPrimaryInGuests && primaryGuestNode?.id) {
329
- guests.push(mapGuestNode(primaryGuestNode, true));
216
+ `;
217
+ var bookingGuestsFields = `
218
+ bookingGuests {
219
+ ${guestFields}
330
220
  }
331
- return guests;
332
- }
333
- function mapGuestNode(guestNode, isPrimary) {
334
- const fieldResponses = Array.isArray(guestNode.fieldResponses) ? guestNode.fieldResponses : [];
335
- const metadata = fieldResponses.map((response) => ({
336
- id: response.id,
337
- name: response.fieldLocation?.field?.name ?? "",
338
- value: response.text ?? ""
339
- }));
340
- return {
341
- id: guestNode.id,
342
- name: guestNode.name ?? null,
343
- country: guestNode.country ?? null,
344
- dateOfBirth: guestNode.dateOfBirth ? new Date(guestNode.dateOfBirth) : null,
345
- phone: guestNode.phone ?? null,
346
- email: guestNode.email ?? null,
347
- isGdpr: Boolean(guestNode.isGdpr),
348
- isParticipant: Boolean(guestNode.isParticipant),
349
- isPrimary,
350
- optinSms: Boolean(guestNode.optinSms),
351
- optinMarketing: Boolean(guestNode.optinMarketing),
352
- postalCode: guestNode.postalCode ?? null,
353
- metadata
354
- };
355
- }
356
- function sourceFromApp(app) {
357
- if (!app) return UNKNOWN;
358
- return SOURCE_SOURCE_MAP[app] ?? UNKNOWN;
359
- }
360
- function sourceDescriptionFromApp(app) {
361
- if (!app) return UNKNOWN;
362
- return SOURCE_DESC_MAP[app] ?? UNKNOWN;
363
- }
364
- function resellerNameFromChannelSnapshot(channelSnapshot) {
365
- if (!channelSnapshot) return null;
366
- let out = channelSnapshot.name ?? "";
367
- if (channelSnapshot.agent?.name) {
368
- out += " - " + channelSnapshot.agent.name;
221
+ primaryGuest {
222
+ ${guestFields}
369
223
  }
370
- return out;
371
- }
372
- function ticketsToTicketArray(ticketQuantities, includePriceBreakdown) {
373
- if (!ticketQuantities || ticketQuantities.length === 0) return [];
374
- return ticketQuantities.map((ticket) => ({
375
- name: ticket.resourceOptionSnapshot?.name || "Unknown",
376
- quantity: ticket.quantity || 0,
377
- ticketId: ticket.resourceOptionSnapshot?.id || "unknown",
378
- listPrice: includePriceBreakdown ? mapPrice(ticket.value?.price) : void 0,
379
- totalValue: includePriceBreakdown ? mapPrice(ticket.value?.total) : void 0
380
- }));
381
- }
382
- function durationInMin(startsAt, endsAt) {
383
- if (!startsAt || !endsAt) return 0;
384
- const duration = new Date(endsAt).getTime() - new Date(startsAt).getTime();
385
- return Math.floor(duration / 1e3 / 60);
386
- }
387
- function ticketQuantity(ticketQuantities) {
388
- if (!ticketQuantities || ticketQuantities.length === 0) return 0;
389
- return ticketQuantities.reduce((acc, ticket) => acc + (ticket.quantity || 0), 0);
390
- }
391
- function formatTickets(ticketQuantities) {
392
- if (!ticketQuantities || ticketQuantities.length === 0) return "";
393
- return ticketQuantities.map((ticket) => `${ticket.quantity || 0}x ${ticket.resourceOptionSnapshot?.name || "Unknown"}`).join(", ");
394
- }
395
- function mapResourcePoolAssignments(poolAssignments) {
396
- if (!poolAssignments || poolAssignments.length === 0) return [];
397
- return poolAssignments.flatMap(
398
- (pool) => (pool.resourceAssignments ?? []).map((assignment) => ({
399
- id: assignment.resource?.id || "",
400
- name: assignment.resource?.name || ""
401
- }))
402
- );
403
- }
404
- function mapPrice(priceData) {
405
- if (!priceData || !priceData.amount && !priceData.formatted) {
406
- return void 0;
224
+ `;
225
+ var bookingQueryFields = `
226
+ displayId
227
+ id
228
+ primaryGuest {
229
+ name
230
+ email
231
+ phone
232
+ optinMarketing
233
+ optinSms
234
+ isGdpr
235
+ postalCode
407
236
  }
408
- return {
409
- amount: priceData.amount || "0",
410
- display: priceData.formatted || ""
411
- };
412
- }
413
-
414
- // src/internal/bookings/booking-guest-converter.ts
415
- function fromBookingGuestsResponse(response) {
416
- const firstEdge = (response?.sales?.edges ?? [])[0];
417
- if (!firstEdge) {
418
- return [];
237
+ activitySnapshot {
238
+ type
239
+ name
240
+ id
419
241
  }
420
- const bookingNode = firstEdge.node;
421
- const primaryGuestNode = bookingNode.primaryGuest;
422
- const bookingGuestsNodes = Array.isArray(bookingNode.bookingGuests) ? bookingNode.bookingGuests : [];
423
- const primaryId = primaryGuestNode?.id;
424
- const guests = [];
425
- for (const guestNode of bookingGuestsNodes) {
426
- guests.push(mapGuestNode(guestNode, primaryId ? guestNode.id === primaryId : false));
242
+ ticketQuantities {
243
+ quantity
244
+ resourceOptionSnapshot {
245
+ name
246
+ id
247
+ }
248
+ }
249
+ reservationStatus
250
+ checkinStatus
251
+ returnStatus
252
+ fulfillmentStatusOverride {
253
+ status
254
+ }
255
+ timeSnapshot {
256
+ id
257
+ legacyId
258
+ }
259
+ purchasedAt
260
+ purchasedAtUtc
261
+ startsAt
262
+ startsAtUtc
263
+ endsAt
264
+ endsAtUtc
265
+ availabilityTimeId
266
+ bookingPortalUrl
267
+ operatorNotes
268
+ value {
269
+ total {
270
+ formatted
271
+ amount
272
+ }
273
+ }
274
+ balance {
275
+ total {
276
+ amount
277
+ formatted
278
+ }
279
+ }
280
+ tips {
281
+ price {
282
+ amount
283
+ formatted
284
+ }
285
+ }
286
+ order {
287
+ displayId
288
+ id
289
+ promoCodes {
290
+ code
291
+ }
292
+ channelSnapshot {
293
+ id
294
+ name
295
+ agent {
296
+ name
297
+ }
298
+ }
299
+ initialQuote {
300
+ source {
301
+ actor {
302
+ app
303
+ name
304
+ }
305
+ }
306
+ }
427
307
  }
428
- const hasPrimaryInGuests = primaryId ? bookingGuestsNodes.some((guest) => guest.id === primaryId) : false;
429
- if (!hasPrimaryInGuests && primaryGuestNode) {
430
- guests.push(mapGuestNode(primaryGuestNode, true));
308
+ questionAnswers {
309
+ answer
310
+ questionText
311
+ questionLocationSnapshot {
312
+ latitude
313
+ longitude
314
+ }
431
315
  }
432
- return guests;
433
- }
434
-
435
- // src/internal/bookings/payments-on-file-converter.ts
436
- function fromPaymentsOnFileResponse(response, bookingId) {
437
- const firstEdge = (response?.sales?.edges ?? [])[0];
438
- if (!firstEdge) {
439
- return null;
316
+ tickets {
317
+ questionAnswers {
318
+ answer
319
+ questionText
320
+ }
440
321
  }
441
- const order = firstEdge.node.order;
442
- const orderId = order?.id ?? "";
443
- const rawPaymentSources = order?.paymentSources ?? [];
444
- const rawPayments = order?.payments ?? [];
445
- const paymentsBySourceId = /* @__PURE__ */ new Map();
446
- for (const payment of rawPayments) {
447
- const sourceId = payment.paymentSource?.id;
448
- if (!sourceId) continue;
449
- const mapped = {
450
- id: payment.id,
451
- paidAt: dateOnly(payment.appliedAt),
452
- currentAmount: payment.currentAmount,
453
- refundableAmount: payment.refundableAmount
454
- };
455
- const existing = paymentsBySourceId.get(sourceId);
456
- if (existing) {
457
- existing.push(mapped);
458
- } else {
459
- paymentsBySourceId.set(sourceId, [mapped]);
322
+ resourcePoolAssignments {
323
+ quantity
324
+ resourcePool {
325
+ name
326
+ shortName
327
+ resources {
328
+ name
329
+ }
330
+ }
331
+ resourceAssignments {
332
+ resource {
333
+ id
334
+ name
335
+ }
460
336
  }
461
337
  }
462
- const paymentsOnFile = rawPaymentSources.map((source) => {
463
- const payments = paymentsBySourceId.get(source.id);
464
- return {
465
- description: source.description,
466
- id: source.id,
467
- type: source.type,
468
- ...payments ? { payments } : {}
469
- };
470
- });
471
- return { bookingId, orderId, paymentsOnFile };
472
- }
473
- function dateOnly(iso) {
474
- return iso.split("T")[0] ?? iso;
338
+ `;
339
+ var PRICE_BREAKDOWN_FIELDS = `
340
+ convenienceFee { amount formatted }
341
+ deposit { amount formatted }
342
+ discount { amount formatted }
343
+ discountedPrice { amount formatted }
344
+ fees { amount formatted }
345
+ flatPartnerFee { amount formatted }
346
+ price { amount formatted }
347
+ retailPrice { amount formatted }
348
+ taxes { amount formatted }
349
+ tips { amount formatted }
350
+ `;
351
+ var TICKET_VALUE_FIELDS = `
352
+ value {
353
+ price { amount formatted }
354
+ total { amount formatted }
355
+ }
356
+ `;
357
+ function buildBookingsListingQuery(includeGuests, includePriceBreakdown) {
358
+ const guestsSection = includeGuests ? bookingGuestsFields : "";
359
+ const fields = includePriceBreakdown ? bookingQueryFields.replace("value {", `value { ${PRICE_BREAKDOWN_FIELDS}`).replace("ticketQuantities {", `ticketQuantities { ${TICKET_VALUE_FIELDS}`) : bookingQueryFields;
360
+ return `
361
+ query Sales($after: String, $first: Int, $filter: SalesFilter!, $orderBy: SalesOrdering) {
362
+ sales(after: $after, first: $first, filter: $filter, orderBy: $orderBy) {
363
+ pageInfo { endCursor hasNextPage }
364
+ edges {
365
+ node {
366
+ ... on Booking {
367
+ ${fields}
368
+ ${guestsSection}
369
+ }
370
+ }
371
+ }
372
+ }
373
+ }
374
+ `;
475
375
  }
476
-
477
- // src/internal/bookings/addon-queries.ts
478
- var RESERVATION_STATUS_CONFIRMED = "CONFIRMED";
479
- var ADDON_OPTION_STATUS_CANCELED = "CANCELED";
480
- var SALES_ADDONS_PAGE_SIZE = 100;
481
- var SALES_ADDONS_QUERY = `
376
+ var BOOKING_GUESTS_QUERY = `
482
377
  query Sales($after: String, $first: Int, $filter: SalesFilter!, $orderBy: SalesOrdering) {
483
378
  sales(after: $after, first: $first, filter: $filter, orderBy: $orderBy) {
484
379
  pageInfo { endCursor hasNextPage }
485
380
  edges {
486
381
  node {
487
- order { id displayId }
488
382
  ... on Booking {
489
383
  displayId
490
384
  id
491
- refid
492
- reservationStatus
493
- items {
385
+ ${bookingGuestsFields}
386
+ }
387
+ }
388
+ }
389
+ }
390
+ }
391
+ `;
392
+ var BOOKING_PAYMENTS_ON_FILE_QUERY = `
393
+ query Sales($after: String, $first: Int, $filter: SalesFilter!, $orderBy: SalesOrdering) {
394
+ sales(after: $after, first: $first, filter: $filter, orderBy: $orderBy) {
395
+ pageInfo { endCursor hasNextPage }
396
+ edges {
397
+ node {
398
+ order {
399
+ payments {
494
400
  id
495
- refid
496
- value { total { amount currency formatted } }
497
- reservationStatus
498
- options {
499
- refid
500
- reservationStatus
501
- price { amount currency formatted }
502
- itemOptionSnapshot { id name }
503
- itemSnapshot { id name }
504
- }
401
+ paymentSource { id }
402
+ appliedAt
403
+ currentAmount { amount currency }
404
+ refundableAmount { amount currency }
505
405
  }
406
+ id
407
+ displayId
408
+ paymentSources { description type id }
409
+ }
410
+ ... on Booking {
411
+ displayId
412
+ id
506
413
  }
507
414
  }
508
415
  }
509
416
  }
510
417
  }
511
418
  `;
512
- function buildSalesAddonsVariables(searchString) {
513
- return {
514
- first: SALES_ADDONS_PAGE_SIZE,
515
- after: null,
516
- orderBy: { direction: "DESC", field: "STARTS_AT" },
517
- filter: { searchString }
518
- };
519
- }
520
-
521
- // src/internal/bookings/addon-converter.ts
522
- var ERROR_INCONSISTENT_ADDON_ITEM_ID = "Add-on group contains options with mismatched item IDs";
523
- function parseSaleNode(node) {
524
- const bookingId = node.id || "";
525
- const displayId = node.displayId || "";
526
- const orderId = node.order?.id || "";
527
- const bookingQuoteRefid = node.refid || "";
528
- const bookingQuoteReservationStatus = node.reservationStatus || "";
529
- const items = Array.isArray(node.items) ? node.items : [];
530
- return items.map((item) => {
531
- const options = Array.isArray(item.options) ? item.options : [];
532
- const addonItemOptions = options.map((opt) => ({
533
- itemId: opt.itemSnapshot?.id || "",
534
- optionId: opt.itemOptionSnapshot?.id || "",
535
- itemName: opt.itemSnapshot?.name || "",
536
- optionName: opt.itemOptionSnapshot?.name || "",
537
- optionRefid: opt.refid || "",
538
- optionReservationStatus: opt.reservationStatus || "",
539
- itemReservationStatus: item.reservationStatus || "",
540
- itemRefid: item.refid || ""
541
- }));
542
- return {
543
- bookingId,
544
- displayId,
545
- orderId,
546
- total: item.value?.total ?? null,
547
- bookingQuoteRefid,
548
- bookingQuoteReservationStatus,
549
- addonItemOptions
550
- };
551
- });
552
- }
553
- function toBookingAddon(item) {
554
- const options = item.addonItemOptions || [];
555
- if (options.length === 0) {
556
- return null;
419
+ var UPDATE_OPERATOR_NOTES_MUTATION = `
420
+ mutation Account($input: UpdateOperatorNotesForBookingInput!) {
421
+ updateOperatorNotesForBooking(input: $input) {
422
+ booking { operatorNotes }
423
+ }
557
424
  }
558
- const addonId = options[0].itemId;
559
- const addonName = options[0].itemName;
560
- if (options.some((opt) => opt.itemId !== addonId)) {
561
- throw new Error(ERROR_INCONSISTENT_ADDON_ITEM_ID);
425
+ `;
426
+ var UPDATE_BOOKING_CHECKIN_MUTATION = `
427
+ mutation Account($input: UpdateBookingCheckInInput!) {
428
+ updateBookingCheckIn(input: $input) {
429
+ booking { checkinStatus }
430
+ }
562
431
  }
563
- const grouped = /* @__PURE__ */ new Map();
564
- options.filter((opt) => opt.optionReservationStatus !== ADDON_OPTION_STATUS_CANCELED).forEach((opt) => {
565
- const existing = grouped.get(opt.optionId);
566
- if (existing) {
567
- existing.quantity += 1;
568
- } else {
569
- grouped.set(opt.optionId, {
570
- addonOptionId: opt.optionId,
571
- addonOptionName: opt.optionName,
572
- quantity: 1
573
- });
432
+ `;
433
+ var CANCEL_BOOKING_MUTATION = `
434
+ mutation Account($input: CancelBookingInput!) {
435
+ cancelBooking(input: $input) {
436
+ booking { id displayId reservationStatus }
437
+ }
438
+ }
439
+ `;
440
+ var APPLY_PAYMENT_TO_ORDER_MUTATION = `
441
+ mutation ApplyPaymentToOrder($input: ApplyPaymentToOrderInput!) {
442
+ applyPaymentToOrder(input: $input) {
443
+ transactionId
444
+ errors { code detail value }
445
+ }
446
+ }
447
+ `;
448
+ var APPLY_REFUND_TO_ORDER_MUTATION = `
449
+ mutation ApplyRefundToOrder($input: ApplyRefundToOrderInput!) {
450
+ applyRefundToOrder(input: $input) {
451
+ transactionId
452
+ errors { code detail value }
574
453
  }
575
- });
576
- const addonOptions = Array.from(grouped.values());
577
- if (addonOptions.length === 0) {
578
- return null;
579
454
  }
580
- return { addonId, addonName, total: item.total, addonOptions };
581
- }
582
-
583
- // src/internal/bookings/booking-queries.ts
584
- var SEARCH_BY_PURCHASE_DATE = "purchaseDate";
585
- var SEARCH_BY_ACTIVITY_DATE = "activityDate";
586
- function normalizeBookingId(bookingId) {
587
- return bookingId.toLowerCase().replace(/-/g, "_");
588
- }
589
- var guestFields = `
590
- id
591
- name
592
- country
593
- dateOfBirth
594
- email
595
- isGdpr
596
- isParticipant
597
- optinSms
598
- optinMarketing
599
- phone
600
- postalCode
601
- fieldResponses {
602
- id
603
- text
604
- fieldLocation {
605
- field {
606
- name
455
+ `;
456
+ var CREATE_INVOICE_LINK_MUTATION = `
457
+ mutation CreateInvoiceLink($input: CreateInvoiceLinkInput!) {
458
+ createInvoiceLink(input: $input) {
459
+ invoiceLink { status url }
460
+ errors { code detail value __typename }
461
+ }
462
+ }
463
+ `;
464
+ var CREATE_QUOTE_FROM_ORDER_MUTATION = `
465
+ mutation CreateQuoteFromOrder($input: CreateQuoteFromOrderInput!) {
466
+ createQuoteFromOrder(input: $input) {
467
+ errors { detail value code }
468
+ quote {
469
+ id
470
+ saleQuotes { refid reservationStatus }
607
471
  }
608
472
  }
609
473
  }
610
474
  `;
611
- var bookingGuestsFields = `
612
- bookingGuests {
613
- ${guestFields}
475
+ var UPDATE_QUOTE_V2_MUTATION = `
476
+ mutation UpdateQuoteV2($input: UpdateQuoteV2Input!) {
477
+ updateQuoteV2(input: $input) {
478
+ errors { detail value code }
479
+ quote { id }
480
+ }
614
481
  }
615
- primaryGuest {
616
- ${guestFields}
482
+ `;
483
+ var AMEND_ORDER_MUTATION = `
484
+ mutation AmendOrder($input: AmendOrderInput!) {
485
+ amendOrder(input: $input) {
486
+ errors { code detail value }
487
+ order { id }
488
+ }
617
489
  }
618
490
  `;
619
- var bookingQueryFields = `
620
- displayId
621
- id
622
- primaryGuest {
623
- name
624
- email
625
- phone
626
- optinMarketing
627
- optinSms
628
- isGdpr
629
- postalCode
491
+ var CREATE_QUOTE_V2_MUTATION = `
492
+ mutation CreateQuoteV2($input: CreateQuoteV2Input!) {
493
+ createQuoteV2(input: $input) {
494
+ errors { detail value code }
495
+ quote { id }
496
+ }
630
497
  }
631
- activitySnapshot {
632
- type
633
- name
634
- id
498
+ `;
499
+ var CREATE_ORDER_FROM_QUOTE_MUTATION = `
500
+ mutation CreateOrderFromQuote($input: CreateOrderFromQuoteInput!) {
501
+ createOrderFromQuote(input: $input) {
502
+ errors { code detail value }
503
+ order {
504
+ id
505
+ sales {
506
+ id
507
+ displayId
508
+ ... on Booking {
509
+ balance { total { amount currency formatted } }
510
+ }
511
+ }
512
+ }
513
+ }
635
514
  }
636
- ticketQuantities {
637
- quantity
638
- resourceOptionSnapshot {
639
- name
640
- id
515
+ `;
516
+ function buildBookingsVariables(params) {
517
+ const filter = {};
518
+ const bookingFilter = {};
519
+ if (params.bookingId) {
520
+ bookingFilter.ids = [normalizeBookingId(params.bookingId)];
521
+ } else if (params.timeslotId) {
522
+ bookingFilter.timeslotRefid = params.timeslotId;
523
+ } else {
524
+ if (params.searchBy === SEARCH_BY_ACTIVITY_DATE) {
525
+ bookingFilter.overlapsRange = `[${params.startDateTime},${params.endDateTime}]`;
526
+ } else if (params.searchBy === SEARCH_BY_PURCHASE_DATE) {
527
+ filter.purchasedAtRangeUtc = `[${params.startDateTime},${params.endDateTime}]`;
528
+ }
529
+ if (params.productId) {
530
+ bookingFilter.activityIds = [params.productId];
641
531
  }
642
532
  }
643
- reservationStatus
644
- checkinStatus
645
- returnStatus
646
- fulfillmentStatusOverride {
647
- status
533
+ if (params.email) {
534
+ filter.primaryGuestEmail = params.email;
648
535
  }
649
- timeSnapshot {
650
- id
651
- legacyId
536
+ if (params.searchString && params.searchString.length > 0) {
537
+ filter.searchString = params.searchString;
652
538
  }
653
- purchasedAt
654
- purchasedAtUtc
655
- startsAt
656
- startsAtUtc
657
- endsAt
658
- endsAtUtc
659
- availabilityTimeId
660
- bookingPortalUrl
661
- operatorNotes
662
- value {
663
- total {
664
- formatted
665
- amount
539
+ if (Object.keys(bookingFilter).length > 0) {
540
+ filter.bookingFilter = bookingFilter;
541
+ }
542
+ return {
543
+ first: params.pageSize,
544
+ after: params.after,
545
+ orderBy: { direction: "ASC", field: "STARTS_AT" },
546
+ filter
547
+ };
548
+ }
549
+
550
+ // src/internal/bookings/booking-converter.ts
551
+ var UNKNOWN = "unknown";
552
+ var PEEK_PRO_DEEP_LINK_BASE = "http://pro-app.peek.com/-/order";
553
+ var SOURCE_SOURCE_MAP = {
554
+ APP_REGISTRY: "app",
555
+ BOOKING_IMPORTER_FUTURE: "importer",
556
+ BOOKING_IMPORTER_HISTORIC: "importer",
557
+ EXPEDIA: "expedia",
558
+ GROUPON: "groupon",
559
+ GYG: "getyourguide",
560
+ HOOK: "internal",
561
+ INTERNAL_TOOLS: "internal",
562
+ IOS_PP: "ios",
563
+ OCTO: "octo",
564
+ PDC: "peekcom",
565
+ PEEK_PLUS: "peekcom",
566
+ PP: "backend",
567
+ RWG: "rwg",
568
+ SELF_SERVE: "internal",
569
+ SYSTEM: "internal",
570
+ VIATOR: "viator",
571
+ WIDGET: "website",
572
+ YELP: "yelp"
573
+ };
574
+ var SOURCE_DESC_MAP = {
575
+ APP_REGISTRY: "App Store App",
576
+ BOOKING_IMPORTER_FUTURE: "Booking Importer",
577
+ BOOKING_IMPORTER_HISTORIC: "Booking Importer",
578
+ EXPEDIA: "Expedia",
579
+ GROUPON: "Groupon",
580
+ GYG: "GetYourGuide",
581
+ HOOK: "Internal",
582
+ INTERNAL_TOOLS: "Internal",
583
+ IOS_PP: "Peek Pro: iOS App",
584
+ OCTO: "OCTO",
585
+ PDC: "Peek.com",
586
+ PEEK_PLUS: "Peek.com",
587
+ PP: "Peek Pro: Backend",
588
+ RWG: "Reserve with Google",
589
+ SELF_SERVE: "Internal",
590
+ SYSTEM: "Internal",
591
+ VIATOR: "Viator",
592
+ WIDGET: "Website Booking Flow",
593
+ YELP: "Yelp"
594
+ };
595
+ function fromBookingNode(node, includeGuests = false, includePriceBreakdown = false) {
596
+ const data = node ?? {};
597
+ const ticketQuantities = data.ticketQuantities ?? [];
598
+ const app = data.order?.initialQuote?.source?.actor?.app ?? null;
599
+ const sourceDetails = data.order?.initialQuote?.source?.actor?.name ?? null;
600
+ const customQuestionAnswers = (data.questionAnswers ?? []).map(
601
+ (answer) => {
602
+ const base = {
603
+ question: answer.questionText,
604
+ answer: answer.answer
605
+ };
606
+ const location = answer.questionLocationSnapshot;
607
+ if (location && location.latitude && location.longitude) {
608
+ base.latitude = location.latitude;
609
+ base.longitude = location.longitude;
610
+ }
611
+ return base;
666
612
  }
613
+ );
614
+ const customGuestQuestionAnswers = Array.isArray(data.tickets) ? data.tickets.flatMap(
615
+ (ticket) => Array.isArray(ticket?.questionAnswers) ? ticket.questionAnswers.filter((qa) => qa && qa.answer !== void 0 && qa.questionText !== void 0).map((qa) => ({ question: qa.questionText, answer: qa.answer })) : []
616
+ ) : [];
617
+ return {
618
+ bookingId: data.id || "",
619
+ displayId: data.displayId || "",
620
+ source: sourceFromApp(app),
621
+ sourceApp: app || UNKNOWN,
622
+ sourceDescription: sourceDescriptionFromApp(app),
623
+ sourceDetails,
624
+ customerName: data.primaryGuest?.name || "",
625
+ customerEmail: data.primaryGuest?.email || null,
626
+ customerPhone: data.primaryGuest?.phone || null,
627
+ productId: data.activitySnapshot?.id || UNKNOWN,
628
+ productName: data.activitySnapshot?.name || UNKNOWN,
629
+ isRentalProduct: data.activitySnapshot?.type === "RENTAL",
630
+ timeslotId: data.timeSnapshot?.legacyId || null,
631
+ totalTickets: ticketQuantity(ticketQuantities),
632
+ ticketDescription: formatTickets(ticketQuantities),
633
+ tickets: ticketsToTicketArray(ticketQuantities, includePriceBreakdown),
634
+ isCanceled: data.reservationStatus === "CANCELED",
635
+ isNoShow: data.fulfillmentStatusOverride?.status === "NO_SHOW",
636
+ isCheckedIn: data.checkinStatus !== "NONE",
637
+ isReturned: data.returnStatus !== "NONE",
638
+ purchasedAt: data.purchasedAt || null,
639
+ purchasedAtUtc: data.purchasedAtUtc || null,
640
+ startsAt: data.startsAt || null,
641
+ startsAtUtc: data.startsAtUtc || null,
642
+ endsAt: data.endsAt || null,
643
+ endsAtUtc: data.endsAtUtc || null,
644
+ durationMin: durationInMin(data.startsAt || null, data.endsAt || null),
645
+ availabilityTimeId: data.availabilityTimeId || null,
646
+ portalUrl: data.bookingPortalUrl || null,
647
+ notes: data.operatorNotes || "",
648
+ valueDisplay: data.value?.total?.formatted || "",
649
+ valueAmount: data.value?.total?.amount || "",
650
+ outstandingBalanceAmount: data.balance?.total?.amount || "",
651
+ outstandingBalanceDisplay: data.balance?.total?.formatted || "",
652
+ promoCodes: data.order?.promoCodes?.map((promo) => promo.code) ?? [],
653
+ tips: (data.tips ?? []).map((tip) => ({
654
+ display: tip.price?.formatted || "",
655
+ amount: tip.price?.amount || ""
656
+ })),
657
+ customQuestionAnswers,
658
+ customGuestQuestionAnswers,
659
+ resources: (data.resourcePoolAssignments ?? []).map((resource) => ({
660
+ quantity: resource.quantity || 0,
661
+ name: resource.resourcePool?.name || "",
662
+ shortName: resource.resourcePool?.shortName || ""
663
+ })),
664
+ resourcePoolAssignments: mapResourcePoolAssignments(data.resourcePoolAssignments),
665
+ resellerId: data.order?.channelSnapshot?.id || null,
666
+ resellerName: resellerNameFromChannelSnapshot(data.order?.channelSnapshot),
667
+ orderId: data.order?.id || "",
668
+ peekProBookingDeepLink: buildPeekProBookingDeepLink(data.order?.id, data.id),
669
+ convenienceFee: includePriceBreakdown ? mapPrice(data.value?.convenienceFee) : void 0,
670
+ deposit: includePriceBreakdown ? mapPrice(data.value?.deposit) : void 0,
671
+ discount: includePriceBreakdown ? mapPrice(data.value?.discount) : void 0,
672
+ discountedPrice: includePriceBreakdown ? mapPrice(data.value?.discountedPrice) : void 0,
673
+ fees: includePriceBreakdown ? mapPrice(data.value?.fees) : void 0,
674
+ flatPartnerFee: includePriceBreakdown ? mapPrice(data.value?.flatPartnerFee) : void 0,
675
+ price: includePriceBreakdown ? mapPrice(data.value?.price) : void 0,
676
+ retailPrice: includePriceBreakdown ? mapPrice(data.value?.retailPrice) : void 0,
677
+ taxes: includePriceBreakdown ? mapPrice(data.value?.taxes) : void 0,
678
+ tipsBreakdown: includePriceBreakdown ? mapPrice(data.value?.tips) : void 0,
679
+ guests: includeGuests ? convertGuests(data) : void 0
680
+ };
681
+ }
682
+ function convertGuests(data) {
683
+ const bookingGuestsNodes = Array.isArray(data.bookingGuests) ? data.bookingGuests : [];
684
+ const primaryGuestNode = data.primaryGuest;
685
+ const primaryId = primaryGuestNode?.id;
686
+ const guests = [];
687
+ for (const guestNode of bookingGuestsNodes) {
688
+ guests.push(mapGuestNode(guestNode, primaryId ? guestNode.id === primaryId : false));
667
689
  }
668
- balance {
669
- total {
670
- amount
671
- formatted
672
- }
690
+ const hasPrimaryInGuests = primaryId ? bookingGuestsNodes.some((guest) => guest.id === primaryId) : false;
691
+ if (!hasPrimaryInGuests && primaryGuestNode?.id) {
692
+ guests.push(mapGuestNode(primaryGuestNode, true));
673
693
  }
674
- tips {
675
- price {
676
- amount
677
- formatted
678
- }
694
+ return guests;
695
+ }
696
+ function mapGuestNode(guestNode, isPrimary) {
697
+ const fieldResponses = Array.isArray(guestNode.fieldResponses) ? guestNode.fieldResponses : [];
698
+ const metadata = fieldResponses.map((response) => ({
699
+ id: response.id,
700
+ name: response.fieldLocation?.field?.name ?? "",
701
+ value: response.text ?? ""
702
+ }));
703
+ return {
704
+ id: guestNode.id,
705
+ name: guestNode.name ?? null,
706
+ country: guestNode.country ?? null,
707
+ dateOfBirth: guestNode.dateOfBirth ? new Date(guestNode.dateOfBirth) : null,
708
+ phone: guestNode.phone ?? null,
709
+ email: guestNode.email ?? null,
710
+ isGdpr: Boolean(guestNode.isGdpr),
711
+ isParticipant: Boolean(guestNode.isParticipant),
712
+ isPrimary,
713
+ optinSms: Boolean(guestNode.optinSms),
714
+ optinMarketing: Boolean(guestNode.optinMarketing),
715
+ postalCode: guestNode.postalCode ?? null,
716
+ metadata
717
+ };
718
+ }
719
+ function buildPeekProBookingDeepLink(orderId, bookingId) {
720
+ if (!orderId || !bookingId) return "";
721
+ return `${PEEK_PRO_DEEP_LINK_BASE}%2F${normalizeBookingId(orderId)}%3FsaleId=${normalizeBookingId(bookingId)}`;
722
+ }
723
+ function sourceFromApp(app) {
724
+ if (!app) return UNKNOWN;
725
+ return SOURCE_SOURCE_MAP[app] ?? UNKNOWN;
726
+ }
727
+ function sourceDescriptionFromApp(app) {
728
+ if (!app) return UNKNOWN;
729
+ return SOURCE_DESC_MAP[app] ?? UNKNOWN;
730
+ }
731
+ function resellerNameFromChannelSnapshot(channelSnapshot) {
732
+ if (!channelSnapshot) return null;
733
+ let out = channelSnapshot.name ?? "";
734
+ if (channelSnapshot.agent?.name) {
735
+ out += " - " + channelSnapshot.agent.name;
679
736
  }
680
- order {
681
- displayId
682
- id
683
- promoCodes {
684
- code
685
- }
686
- channelSnapshot {
687
- id
688
- name
689
- agent {
690
- name
691
- }
692
- }
693
- initialQuote {
694
- source {
695
- actor {
696
- app
697
- name
698
- }
699
- }
700
- }
737
+ return out;
738
+ }
739
+ function ticketsToTicketArray(ticketQuantities, includePriceBreakdown) {
740
+ if (!ticketQuantities || ticketQuantities.length === 0) return [];
741
+ return ticketQuantities.map((ticket) => ({
742
+ name: ticket.resourceOptionSnapshot?.name || "Unknown",
743
+ quantity: ticket.quantity || 0,
744
+ ticketId: ticket.resourceOptionSnapshot?.id || "unknown",
745
+ listPrice: includePriceBreakdown ? mapPrice(ticket.value?.price) : void 0,
746
+ totalValue: includePriceBreakdown ? mapPrice(ticket.value?.total) : void 0
747
+ }));
748
+ }
749
+ function durationInMin(startsAt, endsAt) {
750
+ if (!startsAt || !endsAt) return 0;
751
+ const duration = new Date(endsAt).getTime() - new Date(startsAt).getTime();
752
+ return Math.floor(duration / 1e3 / 60);
753
+ }
754
+ function ticketQuantity(ticketQuantities) {
755
+ if (!ticketQuantities || ticketQuantities.length === 0) return 0;
756
+ return ticketQuantities.reduce((acc, ticket) => acc + (ticket.quantity || 0), 0);
757
+ }
758
+ function formatTickets(ticketQuantities) {
759
+ if (!ticketQuantities || ticketQuantities.length === 0) return "";
760
+ return ticketQuantities.map((ticket) => `${ticket.quantity || 0}x ${ticket.resourceOptionSnapshot?.name || "Unknown"}`).join(", ");
761
+ }
762
+ function mapResourcePoolAssignments(poolAssignments) {
763
+ if (!poolAssignments || poolAssignments.length === 0) return [];
764
+ return poolAssignments.flatMap(
765
+ (pool) => (pool.resourceAssignments ?? []).map((assignment) => ({
766
+ id: assignment.resource?.id || "",
767
+ name: assignment.resource?.name || ""
768
+ }))
769
+ );
770
+ }
771
+ function mapPrice(priceData) {
772
+ if (!priceData || !priceData.amount && !priceData.formatted) {
773
+ return void 0;
701
774
  }
702
- questionAnswers {
703
- answer
704
- questionText
705
- questionLocationSnapshot {
706
- latitude
707
- longitude
708
- }
775
+ return {
776
+ amount: priceData.amount || "0",
777
+ display: priceData.formatted || ""
778
+ };
779
+ }
780
+
781
+ // src/internal/bookings/booking-guest-converter.ts
782
+ function fromBookingGuestsResponse(response) {
783
+ const firstEdge = (response?.sales?.edges ?? [])[0];
784
+ if (!firstEdge) {
785
+ return [];
709
786
  }
710
- tickets {
711
- questionAnswers {
712
- answer
713
- questionText
714
- }
787
+ const bookingNode = firstEdge.node;
788
+ const primaryGuestNode = bookingNode.primaryGuest;
789
+ const bookingGuestsNodes = Array.isArray(bookingNode.bookingGuests) ? bookingNode.bookingGuests : [];
790
+ const primaryId = primaryGuestNode?.id;
791
+ const guests = [];
792
+ for (const guestNode of bookingGuestsNodes) {
793
+ guests.push(mapGuestNode(guestNode, primaryId ? guestNode.id === primaryId : false));
715
794
  }
716
- resourcePoolAssignments {
717
- quantity
718
- resourcePool {
719
- name
720
- shortName
721
- resources {
722
- name
723
- }
724
- }
725
- resourceAssignments {
726
- resource {
727
- id
728
- name
729
- }
730
- }
795
+ const hasPrimaryInGuests = primaryId ? bookingGuestsNodes.some((guest) => guest.id === primaryId) : false;
796
+ if (!hasPrimaryInGuests && primaryGuestNode) {
797
+ guests.push(mapGuestNode(primaryGuestNode, true));
731
798
  }
732
- `;
733
- var PRICE_BREAKDOWN_FIELDS = `
734
- convenienceFee { amount formatted }
735
- deposit { amount formatted }
736
- discount { amount formatted }
737
- discountedPrice { amount formatted }
738
- fees { amount formatted }
739
- flatPartnerFee { amount formatted }
740
- price { amount formatted }
741
- retailPrice { amount formatted }
742
- taxes { amount formatted }
743
- tips { amount formatted }
744
- `;
745
- var TICKET_VALUE_FIELDS = `
746
- value {
747
- price { amount formatted }
748
- total { amount formatted }
799
+ return guests;
800
+ }
801
+
802
+ // src/internal/bookings/payments-on-file-converter.ts
803
+ function fromPaymentsOnFileResponse(response, bookingId) {
804
+ const firstEdge = (response?.sales?.edges ?? [])[0];
805
+ if (!firstEdge) {
806
+ return null;
749
807
  }
750
- `;
751
- function buildBookingsListingQuery(includeGuests, includePriceBreakdown) {
752
- const guestsSection = includeGuests ? bookingGuestsFields : "";
753
- const fields = includePriceBreakdown ? bookingQueryFields.replace("value {", `value { ${PRICE_BREAKDOWN_FIELDS}`).replace("ticketQuantities {", `ticketQuantities { ${TICKET_VALUE_FIELDS}`) : bookingQueryFields;
754
- return `
755
- query Sales($after: String, $first: Int, $filter: SalesFilter!, $orderBy: SalesOrdering) {
756
- sales(after: $after, first: $first, filter: $filter, orderBy: $orderBy) {
757
- pageInfo { endCursor hasNextPage }
758
- edges {
759
- node {
760
- ... on Booking {
761
- ${fields}
762
- ${guestsSection}
763
- }
764
- }
765
- }
766
- }
808
+ const order = firstEdge.node.order;
809
+ const orderId = order?.id ?? "";
810
+ const rawPaymentSources = order?.paymentSources ?? [];
811
+ const rawPayments = order?.payments ?? [];
812
+ const paymentsBySourceId = /* @__PURE__ */ new Map();
813
+ for (const payment of rawPayments) {
814
+ const sourceId = payment.paymentSource?.id;
815
+ if (!sourceId) continue;
816
+ const mapped = {
817
+ id: payment.id,
818
+ paidAt: dateOnly(payment.appliedAt),
819
+ currentAmount: payment.currentAmount,
820
+ refundableAmount: payment.refundableAmount
821
+ };
822
+ const existing = paymentsBySourceId.get(sourceId);
823
+ if (existing) {
824
+ existing.push(mapped);
825
+ } else {
826
+ paymentsBySourceId.set(sourceId, [mapped]);
767
827
  }
768
- `;
828
+ }
829
+ const paymentsOnFile = rawPaymentSources.map((source) => {
830
+ const payments = paymentsBySourceId.get(source.id);
831
+ return {
832
+ description: source.description,
833
+ id: source.id,
834
+ type: source.type,
835
+ ...payments ? { payments } : {}
836
+ };
837
+ });
838
+ return { bookingId, orderId, paymentsOnFile };
769
839
  }
770
- var BOOKING_GUESTS_QUERY = `
840
+ function dateOnly(iso) {
841
+ return iso.split("T")[0] ?? iso;
842
+ }
843
+
844
+ // src/internal/bookings/addon-queries.ts
845
+ var RESERVATION_STATUS_CONFIRMED = "CONFIRMED";
846
+ var ADDON_OPTION_STATUS_CANCELED = "CANCELED";
847
+ var SALES_ADDONS_PAGE_SIZE = 100;
848
+ var SALES_ADDONS_QUERY = `
771
849
  query Sales($after: String, $first: Int, $filter: SalesFilter!, $orderBy: SalesOrdering) {
772
850
  sales(after: $after, first: $first, filter: $filter, orderBy: $orderBy) {
773
851
  pageInfo { endCursor hasNextPage }
774
852
  edges {
775
853
  node {
854
+ order { id displayId }
776
855
  ... on Booking {
777
856
  displayId
778
857
  id
779
- ${bookingGuestsFields}
780
- }
781
- }
782
- }
783
- }
784
- }
785
- `;
786
- var BOOKING_PAYMENTS_ON_FILE_QUERY = `
787
- query Sales($after: String, $first: Int, $filter: SalesFilter!, $orderBy: SalesOrdering) {
788
- sales(after: $after, first: $first, filter: $filter, orderBy: $orderBy) {
789
- pageInfo { endCursor hasNextPage }
790
- edges {
791
- node {
792
- order {
793
- payments {
858
+ refid
859
+ reservationStatus
860
+ items {
794
861
  id
795
- paymentSource { id }
796
- appliedAt
797
- currentAmount { amount currency }
798
- refundableAmount { amount currency }
862
+ refid
863
+ value { total { amount currency formatted } }
864
+ reservationStatus
865
+ options {
866
+ refid
867
+ reservationStatus
868
+ price { amount currency formatted }
869
+ itemOptionSnapshot { id name }
870
+ itemSnapshot { id name }
871
+ }
799
872
  }
800
- id
801
- displayId
802
- paymentSources { description type id }
803
- }
804
- ... on Booking {
805
- displayId
806
- id
807
873
  }
808
874
  }
809
875
  }
810
876
  }
811
877
  }
812
878
  `;
813
- var UPDATE_OPERATOR_NOTES_MUTATION = `
814
- mutation Account($input: UpdateOperatorNotesForBookingInput!) {
815
- updateOperatorNotesForBooking(input: $input) {
816
- booking { operatorNotes }
817
- }
818
- }
819
- `;
820
- var UPDATE_BOOKING_CHECKIN_MUTATION = `
821
- mutation Account($input: UpdateBookingCheckInInput!) {
822
- updateBookingCheckIn(input: $input) {
823
- booking { checkinStatus }
824
- }
825
- }
826
- `;
827
- var CANCEL_BOOKING_MUTATION = `
828
- mutation Account($input: CancelBookingInput!) {
829
- cancelBooking(input: $input) {
830
- booking { id displayId reservationStatus }
831
- }
832
- }
833
- `;
834
- var APPLY_PAYMENT_TO_ORDER_MUTATION = `
835
- mutation ApplyPaymentToOrder($input: ApplyPaymentToOrderInput!) {
836
- applyPaymentToOrder(input: $input) {
837
- transactionId
838
- errors { code detail value }
839
- }
840
- }
841
- `;
842
- var APPLY_REFUND_TO_ORDER_MUTATION = `
843
- mutation ApplyRefundToOrder($input: ApplyRefundToOrderInput!) {
844
- applyRefundToOrder(input: $input) {
845
- transactionId
846
- errors { code detail value }
847
- }
848
- }
849
- `;
850
- var CREATE_INVOICE_LINK_MUTATION = `
851
- mutation CreateInvoiceLink($input: CreateInvoiceLinkInput!) {
852
- createInvoiceLink(input: $input) {
853
- invoiceLink { status url }
854
- errors { code detail value __typename }
855
- }
856
- }
857
- `;
858
- var CREATE_QUOTE_FROM_ORDER_MUTATION = `
859
- mutation CreateQuoteFromOrder($input: CreateQuoteFromOrderInput!) {
860
- createQuoteFromOrder(input: $input) {
861
- errors { detail value code }
862
- quote {
863
- id
864
- saleQuotes { refid reservationStatus }
865
- }
866
- }
867
- }
868
- `;
869
- var UPDATE_QUOTE_V2_MUTATION = `
870
- mutation UpdateQuoteV2($input: UpdateQuoteV2Input!) {
871
- updateQuoteV2(input: $input) {
872
- errors { detail value code }
873
- quote { id }
874
- }
875
- }
876
- `;
877
- var AMEND_ORDER_MUTATION = `
878
- mutation AmendOrder($input: AmendOrderInput!) {
879
- amendOrder(input: $input) {
880
- errors { code detail value }
881
- order { id }
882
- }
883
- }
884
- `;
885
- var CREATE_QUOTE_V2_MUTATION = `
886
- mutation CreateQuoteV2($input: CreateQuoteV2Input!) {
887
- createQuoteV2(input: $input) {
888
- errors { detail value code }
889
- quote { id }
890
- }
879
+ function buildSalesAddonsVariables(searchString) {
880
+ return {
881
+ first: SALES_ADDONS_PAGE_SIZE,
882
+ after: null,
883
+ orderBy: { direction: "DESC", field: "STARTS_AT" },
884
+ filter: { searchString }
885
+ };
886
+ }
887
+
888
+ // src/internal/bookings/addon-converter.ts
889
+ var ERROR_INCONSISTENT_ADDON_ITEM_ID = "Add-on group contains options with mismatched item IDs";
890
+ function parseSaleNode(node) {
891
+ const bookingId = node.id || "";
892
+ const displayId = node.displayId || "";
893
+ const orderId = node.order?.id || "";
894
+ const bookingQuoteRefid = node.refid || "";
895
+ const bookingQuoteReservationStatus = node.reservationStatus || "";
896
+ const items = Array.isArray(node.items) ? node.items : [];
897
+ return items.map((item) => {
898
+ const options = Array.isArray(item.options) ? item.options : [];
899
+ const addonItemOptions = options.map((opt) => ({
900
+ itemId: opt.itemSnapshot?.id || "",
901
+ optionId: opt.itemOptionSnapshot?.id || "",
902
+ itemName: opt.itemSnapshot?.name || "",
903
+ optionName: opt.itemOptionSnapshot?.name || "",
904
+ optionRefid: opt.refid || "",
905
+ optionReservationStatus: opt.reservationStatus || "",
906
+ itemReservationStatus: item.reservationStatus || "",
907
+ itemRefid: item.refid || ""
908
+ }));
909
+ return {
910
+ bookingId,
911
+ displayId,
912
+ orderId,
913
+ total: item.value?.total ?? null,
914
+ bookingQuoteRefid,
915
+ bookingQuoteReservationStatus,
916
+ addonItemOptions
917
+ };
918
+ });
919
+ }
920
+ function toBookingAddon(item) {
921
+ const options = item.addonItemOptions || [];
922
+ if (options.length === 0) {
923
+ return null;
891
924
  }
892
- `;
893
- var CREATE_ORDER_FROM_QUOTE_MUTATION = `
894
- mutation CreateOrderFromQuote($input: CreateOrderFromQuoteInput!) {
895
- createOrderFromQuote(input: $input) {
896
- errors { code detail value }
897
- order {
898
- id
899
- sales {
900
- id
901
- displayId
902
- ... on Booking {
903
- balance { total { amount currency formatted } }
904
- }
905
- }
906
- }
907
- }
925
+ const addonId = options[0].itemId;
926
+ const addonName = options[0].itemName;
927
+ if (options.some((opt) => opt.itemId !== addonId)) {
928
+ throw new Error(ERROR_INCONSISTENT_ADDON_ITEM_ID);
908
929
  }
909
- `;
910
- function buildBookingsVariables(params) {
911
- const filter = {};
912
- const bookingFilter = {};
913
- if (params.bookingId) {
914
- bookingFilter.ids = [normalizeBookingId(params.bookingId)];
915
- } else if (params.timeslotId) {
916
- bookingFilter.timeslotRefid = params.timeslotId;
917
- } else {
918
- if (params.searchBy === SEARCH_BY_ACTIVITY_DATE) {
919
- bookingFilter.overlapsRange = `[${params.startDateTime},${params.endDateTime}]`;
920
- } else if (params.searchBy === SEARCH_BY_PURCHASE_DATE) {
921
- filter.purchasedAtRangeUtc = `[${params.startDateTime},${params.endDateTime}]`;
922
- }
923
- if (params.productId) {
924
- bookingFilter.activityIds = [params.productId];
930
+ const grouped = /* @__PURE__ */ new Map();
931
+ options.filter((opt) => opt.optionReservationStatus !== ADDON_OPTION_STATUS_CANCELED).forEach((opt) => {
932
+ const existing = grouped.get(opt.optionId);
933
+ if (existing) {
934
+ existing.quantity += 1;
935
+ } else {
936
+ grouped.set(opt.optionId, {
937
+ addonOptionId: opt.optionId,
938
+ addonOptionName: opt.optionName,
939
+ quantity: 1
940
+ });
925
941
  }
942
+ });
943
+ const addonOptions = Array.from(grouped.values());
944
+ if (addonOptions.length === 0) {
945
+ return null;
926
946
  }
927
- if (params.email) {
928
- filter.primaryGuestEmail = params.email;
929
- }
930
- if (params.searchString && params.searchString.length > 0) {
931
- filter.searchString = params.searchString;
932
- }
933
- if (Object.keys(bookingFilter).length > 0) {
934
- filter.bookingFilter = bookingFilter;
935
- }
936
- return {
937
- first: params.pageSize,
938
- after: params.after,
939
- orderBy: { direction: "ASC", field: "STARTS_AT" },
940
- filter
941
- };
947
+ return { addonId, addonName, total: item.total, addonOptions };
942
948
  }
943
949
 
944
950
  // src/internal/bookings/booking-service.ts
@@ -2333,18 +2339,18 @@ function fromTimeslotNode(node, productId) {
2333
2339
  assignedResources: mapAssignedResources(node.inheritedResourceAllocations)
2334
2340
  };
2335
2341
  }
2342
+ var ACTIVE_ALLOCATION_STATUS = "ACTIVE";
2336
2343
  function mapAssignedResources(allocations) {
2337
2344
  if (!Array.isArray(allocations) || allocations.length === 0) {
2338
2345
  return [];
2339
2346
  }
2340
- return allocations.map((allocation) => {
2347
+ return allocations.filter((allocation) => allocation.status === ACTIVE_ALLOCATION_STATUS).map((allocation) => {
2341
2348
  const pool = allocation.resourcePool;
2342
2349
  return {
2343
2350
  name: pool?.name || "",
2344
2351
  capacity: pool?.capacity ?? 0,
2345
2352
  category: pool?.category || "",
2346
2353
  quantity: allocation.quantity ?? 0,
2347
- status: allocation.status || "",
2348
2354
  accountUserId: pool?.accountUser?.id ?? null
2349
2355
  };
2350
2356
  });