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