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