@peektravel/app-utilities 0.2.9 → 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 +682 -676
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +5 -0
- package/dist/index.d.ts +5 -0
- package/dist/index.js +682 -676
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
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-
|
|
212
|
-
var
|
|
213
|
-
var
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
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
|
-
|
|
350
|
-
|
|
351
|
-
|
|
238
|
+
`;
|
|
239
|
+
var bookingGuestsFields = `
|
|
240
|
+
bookingGuests {
|
|
241
|
+
${guestFields}
|
|
352
242
|
}
|
|
353
|
-
|
|
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
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
name
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
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
|
-
|
|
431
|
-
|
|
432
|
-
|
|
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
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
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
|
-
|
|
451
|
-
|
|
452
|
-
|
|
330
|
+
questionAnswers {
|
|
331
|
+
answer
|
|
332
|
+
questionText
|
|
333
|
+
questionLocationSnapshot {
|
|
334
|
+
latitude
|
|
335
|
+
longitude
|
|
336
|
+
}
|
|
453
337
|
}
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
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
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
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
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
}
|
|
493
|
-
|
|
494
|
-
}
|
|
495
|
-
|
|
496
|
-
|
|
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
|
-
|
|
514
|
-
|
|
515
|
-
|
|
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
|
-
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
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
|
-
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
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
|
-
|
|
581
|
-
|
|
582
|
-
|
|
583
|
-
|
|
447
|
+
`;
|
|
448
|
+
var UPDATE_BOOKING_CHECKIN_MUTATION = `
|
|
449
|
+
mutation Account($input: UpdateBookingCheckInInput!) {
|
|
450
|
+
updateBookingCheckIn(input: $input) {
|
|
451
|
+
booking { checkinStatus }
|
|
452
|
+
}
|
|
584
453
|
}
|
|
585
|
-
|
|
586
|
-
|
|
587
|
-
|
|
588
|
-
|
|
589
|
-
|
|
590
|
-
}
|
|
591
|
-
|
|
592
|
-
|
|
593
|
-
|
|
594
|
-
|
|
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
|
-
|
|
603
|
-
|
|
604
|
-
|
|
605
|
-
|
|
606
|
-
|
|
607
|
-
|
|
608
|
-
|
|
609
|
-
|
|
610
|
-
|
|
611
|
-
var
|
|
612
|
-
|
|
613
|
-
|
|
614
|
-
|
|
615
|
-
|
|
616
|
-
|
|
617
|
-
|
|
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
|
|
634
|
-
|
|
635
|
-
${
|
|
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
|
-
|
|
638
|
-
|
|
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
|
|
642
|
-
|
|
643
|
-
|
|
644
|
-
|
|
645
|
-
|
|
646
|
-
|
|
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
|
-
|
|
654
|
-
|
|
655
|
-
|
|
656
|
-
|
|
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
|
-
|
|
659
|
-
|
|
660
|
-
|
|
661
|
-
|
|
662
|
-
|
|
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
|
-
|
|
666
|
-
|
|
667
|
-
returnStatus
|
|
668
|
-
fulfillmentStatusOverride {
|
|
669
|
-
status
|
|
555
|
+
if (params.email) {
|
|
556
|
+
filter.primaryGuestEmail = params.email;
|
|
670
557
|
}
|
|
671
|
-
|
|
672
|
-
|
|
673
|
-
legacyId
|
|
558
|
+
if (params.searchString && params.searchString.length > 0) {
|
|
559
|
+
filter.searchString = params.searchString;
|
|
674
560
|
}
|
|
675
|
-
|
|
676
|
-
|
|
677
|
-
|
|
678
|
-
|
|
679
|
-
|
|
680
|
-
|
|
681
|
-
|
|
682
|
-
|
|
683
|
-
|
|
684
|
-
|
|
685
|
-
|
|
686
|
-
|
|
687
|
-
|
|
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
|
-
|
|
691
|
-
|
|
692
|
-
|
|
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
|
-
|
|
697
|
-
|
|
698
|
-
|
|
699
|
-
|
|
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
|
-
|
|
703
|
-
|
|
704
|
-
|
|
705
|
-
|
|
706
|
-
|
|
707
|
-
|
|
708
|
-
|
|
709
|
-
|
|
710
|
-
|
|
711
|
-
|
|
712
|
-
|
|
713
|
-
|
|
714
|
-
|
|
715
|
-
|
|
716
|
-
|
|
717
|
-
|
|
718
|
-
|
|
719
|
-
|
|
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
|
-
|
|
725
|
-
|
|
726
|
-
|
|
727
|
-
|
|
728
|
-
|
|
729
|
-
|
|
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
|
-
|
|
733
|
-
|
|
734
|
-
|
|
735
|
-
|
|
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
|
-
|
|
739
|
-
|
|
740
|
-
|
|
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
|
-
|
|
756
|
-
|
|
757
|
-
|
|
758
|
-
|
|
759
|
-
|
|
760
|
-
|
|
761
|
-
|
|
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
|
-
|
|
774
|
-
const
|
|
775
|
-
const
|
|
776
|
-
|
|
777
|
-
|
|
778
|
-
|
|
779
|
-
|
|
780
|
-
|
|
781
|
-
|
|
782
|
-
|
|
783
|
-
|
|
784
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
818
|
-
|
|
819
|
-
|
|
820
|
-
|
|
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
|
-
|
|
836
|
-
|
|
837
|
-
|
|
838
|
-
|
|
839
|
-
}
|
|
840
|
-
|
|
841
|
-
|
|
842
|
-
|
|
843
|
-
|
|
844
|
-
|
|
845
|
-
|
|
846
|
-
|
|
847
|
-
|
|
848
|
-
|
|
849
|
-
|
|
850
|
-
|
|
851
|
-
|
|
852
|
-
|
|
853
|
-
|
|
854
|
-
|
|
855
|
-
|
|
856
|
-
|
|
857
|
-
|
|
858
|
-
|
|
859
|
-
|
|
860
|
-
|
|
861
|
-
|
|
862
|
-
|
|
863
|
-
|
|
864
|
-
|
|
865
|
-
|
|
866
|
-
|
|
867
|
-
|
|
868
|
-
|
|
869
|
-
|
|
870
|
-
|
|
871
|
-
|
|
872
|
-
|
|
873
|
-
|
|
874
|
-
|
|
875
|
-
|
|
876
|
-
|
|
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
|
-
|
|
916
|
-
|
|
917
|
-
|
|
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
|
-
|
|
933
|
-
|
|
934
|
-
|
|
935
|
-
|
|
936
|
-
|
|
937
|
-
|
|
938
|
-
|
|
939
|
-
|
|
940
|
-
|
|
941
|
-
|
|
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
|
-
|
|
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
|