@session-services/web-elements 0.1.24 → 0.1.25

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.
@@ -1,8 +1,8 @@
1
1
  import { createClient } from "@session-services/sdk";
2
- import { createAnalytics, formatPrice } from "@session-services/sdk/analytics";
2
+ import { buildOrderChannel, createAnalytics, formatPrice, } from "@session-services/sdk/analytics";
3
3
  import { formatNaiveDateTime } from "@session-services/utils/naive-datetime";
4
- import { normalizeCouponCode } from "@session-services/utils/ticket-quote";
5
4
  import { isSectionSoldOut } from "@session-services/utils/ticket-availability";
5
+ import { normalizeCouponCode } from "@session-services/utils/ticket-quote";
6
6
  import { Host,
7
7
  // biome-ignore lint/correctness/noUnusedImports: h is required by Stencil JSX transform
8
8
  h, } from "@stencil/core";
@@ -330,9 +330,11 @@ export class SessionsTicketing {
330
330
  this.passcodeDenied = false;
331
331
  const response = await this.client.event.get({
332
332
  key: this.eventId,
333
+ couponCode: this.appliedCouponCode || undefined,
333
334
  passcode: this.activePasscode || undefined,
334
335
  });
335
336
  this.event = response.event;
337
+ this.pruneSelectedItems(response.event);
336
338
  this.trackLoadedEvent(response.event);
337
339
  await this.updatePreviewQuote();
338
340
  }
@@ -345,6 +347,15 @@ export class SessionsTicketing {
345
347
  this.loading = false;
346
348
  }
347
349
  }
350
+ pruneSelectedItems(event) {
351
+ const keys = new Set(event.admissions.map((admission) => selectionKey(admission.id, admission.sectionId ?? null)));
352
+ const selected = Array.from(this.selectedItems).filter(([key]) => keys.has(key));
353
+ if (selected.length === this.selectedItems.size)
354
+ return;
355
+ this.selectedItems = new Map(selected);
356
+ this.quote = null;
357
+ this.quoteError = null;
358
+ }
348
359
  trackLoadedEvent(event) {
349
360
  this.setupAnalytics(event);
350
361
  this.trackProductViewed(event);
@@ -631,6 +642,7 @@ export class SessionsTicketing {
631
642
  this.couponInput = "";
632
643
  const coupon = this.appliedCouponCode;
633
644
  this.appliedCouponCode = "";
645
+ await this.loadEventData();
634
646
  this.previewRequestId++;
635
647
  this.previewLoading = false;
636
648
  this.previewQuote = null;
@@ -639,8 +651,17 @@ export class SessionsTicketing {
639
651
  async applyCartCoupon(coupon) {
640
652
  this.requestId++;
641
653
  const currentId = this.requestId;
654
+ const previousCoupon = this.appliedCouponCode;
642
655
  try {
643
656
  this.quoteLoading = true;
657
+ this.appliedCouponCode = coupon;
658
+ await this.loadEventData();
659
+ if (currentId !== this.requestId)
660
+ return;
661
+ if (this.selectedItems.size === 0) {
662
+ await this.applyPreviewCoupon(coupon);
663
+ return;
664
+ }
644
665
  const response = await this.fetchCartQuote(coupon);
645
666
  if (currentId !== this.requestId)
646
667
  return;
@@ -650,6 +671,9 @@ export class SessionsTicketing {
650
671
  this.trackCouponApplied(coupon, response.quote);
651
672
  }
652
673
  catch (_err) {
674
+ if (currentId === this.requestId) {
675
+ this.appliedCouponCode = previousCoupon;
676
+ }
653
677
  this.handleCouponError(currentId);
654
678
  this.trackCouponDenied(coupon);
655
679
  }
@@ -660,6 +684,17 @@ export class SessionsTicketing {
660
684
  }
661
685
  }
662
686
  async applyPreviewCoupon(coupon) {
687
+ const previousCoupon = this.appliedCouponCode;
688
+ this.appliedCouponCode = coupon;
689
+ try {
690
+ await this.loadEventData();
691
+ }
692
+ catch (_err) {
693
+ this.appliedCouponCode = previousCoupon;
694
+ this.setCouponError();
695
+ this.trackCouponDenied(coupon);
696
+ return;
697
+ }
663
698
  const event = this.event;
664
699
  if (!event)
665
700
  return;
@@ -704,6 +739,14 @@ export class SessionsTicketing {
704
739
  const coupon = this.appliedCouponCode;
705
740
  try {
706
741
  this.quoteLoading = true;
742
+ this.appliedCouponCode = "";
743
+ await this.loadEventData();
744
+ if (this.selectedItems.size === 0) {
745
+ this.couponInput = "";
746
+ this.previewQuote = null;
747
+ this.trackCouponRemoved(coupon, null);
748
+ return;
749
+ }
707
750
  const response = await this.fetchCartQuote("");
708
751
  if (currentId !== this.requestId)
709
752
  return;
@@ -788,6 +831,7 @@ export class SessionsTicketing {
788
831
  items: this.getCheckoutItems(this.quote),
789
832
  couponCode: this.appliedCouponCode || undefined,
790
833
  returnUrl: this.returnUrl,
834
+ channel: buildOrderChannel("elements"),
791
835
  });
792
836
  this.handleCheckoutOrder(result.order);
793
837
  }
@@ -804,6 +848,14 @@ export class SessionsTicketing {
804
848
  products: this.getCheckoutProducts(),
805
849
  });
806
850
  }
851
+ trackExternalTicketClick(url, surface) {
852
+ this.trackEvent("Checkout Started", {
853
+ ticketing_mode: "external",
854
+ external_ticket_url: url,
855
+ external_ticket_domain: urlDomain(url),
856
+ cta_surface: surface,
857
+ });
858
+ }
807
859
  getCheckoutItems(quote) {
808
860
  return quote.items.map((item) => ({
809
861
  quantity: item.quantity,
@@ -947,7 +999,7 @@ export class SessionsTicketing {
947
999
  renderQuantityControls(admission, sectionId, disabled, maxQuantity) {
948
1000
  const key = selectionKey(admission.id, sectionId);
949
1001
  const quantity = this.selectedItems.get(key) || 0;
950
- return (h("div", { class: "quantity-controls" }, h("button", { type: "button", class: "quantity-btn decrease", onClick: () => this.handleQuantityDecrease(admission.id, sectionId), disabled: disabled || quantity === 0, "aria-label": "Decrease quantity" }, "\u2212"), h("input", { class: "quantity-value", type: "number", min: "0", max: maxQuantity, inputmode: "numeric", value: quantity, onInput: (e) => this.handleQuantityInput(admission.id, sectionId, e), disabled: disabled, "aria-label": `Quantity for ${admission.name}` }), h("button", { type: "button", class: "quantity-btn increase", onClick: () => this.handleQuantityIncrease(admission.id, sectionId), disabled: disabled || quantity >= maxQuantity, "aria-label": "Increase quantity" }, "+")));
1002
+ return (h("div", { class: "quantity-controls" }, h("button", { type: "button", class: "quantity-btn decrease", onClick: () => this.handleQuantityDecrease(admission.id, sectionId), disabled: disabled || quantity === 0, "aria-label": "Decrease quantity", "data-testid": "event-admission-decrement" }, "\u2212"), h("input", { class: "quantity-value", type: "number", min: "0", max: maxQuantity, inputmode: "numeric", value: quantity, onInput: (e) => this.handleQuantityInput(admission.id, sectionId, e), disabled: disabled, "aria-label": `Quantity for ${admission.name}`, "data-testid": "event-admission-quantity-input" }), h("button", { type: "button", class: "quantity-btn increase", onClick: () => this.handleQuantityIncrease(admission.id, sectionId), disabled: disabled || quantity >= maxQuantity, "aria-label": "Increase quantity", "data-testid": "event-admission-increment" }, "+")));
951
1003
  }
952
1004
  getMaxQuantity(admission, sectionId) {
953
1005
  if (!this.event)
@@ -1023,7 +1075,7 @@ export class SessionsTicketing {
1023
1075
  sectionSoldOut: isSectionSoldOut,
1024
1076
  });
1025
1077
  const sectionId = section?.id || null;
1026
- return (h("section", { class: this.getAdmissionClassName(state, section), key: selectionKey(admission.id, sectionId), tabindex: state.disabled ? -1 : 0, "aria-label": this.getAdmissionAriaLabel(admission, section, state) }, h("div", { class: "admission-content" }, h("div", { class: "admission-details" }, this.renderAdmissionHeader(admission), this.renderAdmissionBody(admission, event, sectionId, state, mode)))));
1078
+ return (h("section", { class: this.getAdmissionClassName(state, section), key: selectionKey(admission.id, sectionId), tabindex: state.disabled ? -1 : 0, "aria-label": this.getAdmissionAriaLabel(admission, section, state), "data-testid": "event-admission-card", "data-admission-id": admission.id, "data-admission-name": admission.name, "data-section-id": section?.id ?? "" }, h("div", { class: "admission-content" }, h("div", { class: "admission-details" }, this.renderAdmissionHeader(admission), this.renderAdmissionBody(admission, event, sectionId, state, mode)))));
1027
1079
  }
1028
1080
  getAdmissionClassName(state, section) {
1029
1081
  return `admission-card ${state.soldOut ? "sold-out" : ""} ${state.disabled && !state.soldOut ? "unavailable" : ""} ${section ? "" : "solo-admission"}`;
@@ -1149,7 +1201,7 @@ export class SessionsTicketing {
1149
1201
  return this.formatPriceValue(total);
1150
1202
  }
1151
1203
  renderCheckoutActions() {
1152
- return (h("div", { class: "checkout-actions" }, this.renderCouponPanel(), this.quoteError && h("div", { class: "error-message" }, this.quoteError), h("button", { type: "button", class: "checkout-btn", onClick: () => this.initiateCheckout(), disabled: this.isCheckoutDisabled(), "aria-label": this.quoteLoading ? "Updating" : undefined }, this.renderCheckoutButtonContent())));
1204
+ return (h("div", { class: "checkout-actions" }, this.renderCouponPanel(), this.quoteError && h("div", { class: "error-message" }, this.quoteError), h("button", { type: "button", class: "checkout-btn", onClick: () => this.initiateCheckout(), disabled: this.isCheckoutDisabled(), "aria-label": this.quoteLoading ? "Updating" : undefined, "data-testid": "event-checkout-cta-desktop" }, this.renderCheckoutButtonContent())));
1153
1205
  }
1154
1206
  renderStickyCheckout(state) {
1155
1207
  if (!this.stickyCheckout)
@@ -1164,7 +1216,7 @@ export class SessionsTicketing {
1164
1216
  if (!state.externalTicketUrl)
1165
1217
  return null;
1166
1218
  const domain = urlDomain(state.externalTicketUrl);
1167
- return (h("div", { class: "sticky-checkout-bar" }, h("a", { class: "external-ticket-button sticky-checkout-btn", href: state.externalTicketUrl, target: "_blank", rel: "noreferrer" }, h("span", { class: "external-ticket-label" }, "Get tickets"), h("span", { class: "external-ticket-domain" }, "via ", domain))));
1219
+ return (h("div", { class: "sticky-checkout-bar" }, h("a", { class: "external-ticket-button sticky-checkout-btn", href: state.externalTicketUrl, target: "_blank", rel: "noreferrer", onClick: () => this.trackExternalTicketClick(state.externalTicketUrl, "sticky") }, h("span", { class: "external-ticket-label" }, "Get tickets"), h("span", { class: "external-ticket-domain" }, "via ", domain))));
1168
1220
  }
1169
1221
  renderModal() {
1170
1222
  if (!this.openModalAdmissionId)
@@ -1179,7 +1231,13 @@ export class SessionsTicketing {
1179
1231
  renderTicketSections(event) {
1180
1232
  const state = getTicketingState(event);
1181
1233
  const mode = state.isDoorOnly ? "door" : "default";
1182
- const items = topLevelTicketItems(event.sections, visibleAdmissions(event, mode));
1234
+ const items = topLevelTicketItems(event.sections, visibleAdmissions(event, mode), {
1235
+ event,
1236
+ initialAdmissionPrices: this.activeInitialAdmissionPrices(),
1237
+ mode,
1238
+ previewQuote: this.previewQuote,
1239
+ quote: this.quote,
1240
+ });
1183
1241
  return (h("div", { class: "tickets-wrapper" }, this.renderDoorAlert(event, mode), h("h2", { class: "tickets-heading" }, state.ticketHeading), items.map((item) => this.renderTopLevelItem(item, event, mode))));
1184
1242
  }
1185
1243
  renderTopLevelItem(item, event, mode) {
@@ -1224,7 +1282,7 @@ export class SessionsTicketing {
1224
1282
  const domain = urlDomain(state.externalTicketUrl);
1225
1283
  if (!state.externalTicketUrl)
1226
1284
  return null;
1227
- return (h("div", { class: "tickets-wrapper" }, h("h2", { class: "tickets-heading" }, state.ticketHeading), h("div", { class: "external-ticket-panel" }, h("p", { class: "external-ticket-warning" }, "This event sells through an external ticketing site. Checkout, tickets, and support are handled there."), h("a", { class: "external-ticket-button inline-external-ticket-button", href: state.externalTicketUrl, target: "_blank", rel: "noreferrer" }, h("span", { class: "external-ticket-label" }, "Get tickets"), h("span", { class: "external-ticket-domain" }, "via ", domain)))));
1285
+ return (h("div", { class: "tickets-wrapper" }, h("h2", { class: "tickets-heading" }, state.ticketHeading), h("div", { class: "external-ticket-panel" }, h("p", { class: "external-ticket-warning" }, "This event sells through an external ticketing site. Checkout, tickets, and support are handled there."), h("a", { class: "external-ticket-button inline-external-ticket-button", href: state.externalTicketUrl, target: "_blank", rel: "noreferrer", onClick: () => this.trackExternalTicketClick(state.externalTicketUrl, "inline") }, h("span", { class: "external-ticket-label" }, "Get tickets"), h("span", { class: "external-ticket-domain" }, "via ", domain)))));
1228
1286
  }
1229
1287
  renderUnavailableState(state) {
1230
1288
  return (h("div", { class: "empty-ticketing-state" }, h("strong", null, "Tickets Unavailable"), h("span", null, state.isEnded
@@ -1393,7 +1451,7 @@ export class SessionsTicketing {
1393
1451
  "mutable": false,
1394
1452
  "complexType": {
1395
1453
  "original": "OrderQuote | string",
1396
- "resolved": "string | { items: { id: string; kind: \"ADMISSION\" | \"ADDON\"; quantity: number; price: { net: number; total: number; gross: number; base: number; booking: number; refunded: number; discount: number; currency: \"AUD\" | \"AED\" | \"ALL\" | \"AMD\" | \"ANG\" | \"AOA\" | \"ARS\" | \"AWG\" | \"AZN\" | \"BAM\" | \"BBD\" | \"BDT\" | \"BGN\" | \"BHD\" | \"BIF\" | \"BMD\" | \"BND\" | \"BOB\" | \"BRL\" | \"BSD\" | \"BTN\" | \"BWP\" | \"BZD\" | \"CAD\" | \"CHF\" | \"CLP\" | \"CNY\" | \"COP\" | \"CRC\" | \"CVE\" | \"CZK\" | \"DJF\" | \"DKK\" | \"DOP\" | \"DZD\" | \"EGP\" | \"ERN\" | \"ETB\" | \"EUR\" | \"FJD\" | \"FKP\" | \"GBP\" | \"GEL\" | \"GHS\" | \"GIP\" | \"GMD\" | \"GNF\" | \"GTQ\" | \"GYD\" | \"HKD\" | \"HNL\" | \"HUF\" | \"IDR\" | \"ILS\" | \"INR\" | \"ISK\" | \"JMD\" | \"JOD\" | \"JPY\" | \"KES\" | \"KGS\" | \"KHR\" | \"KMF\" | \"KRW\" | \"KWD\" | \"KYD\" | \"KZT\" | \"LAK\" | \"LBP\" | \"LKR\" | \"LRD\" | \"LSL\" | \"LYD\" | \"MAD\" | \"MDL\" | \"MGA\" | \"MKD\" | \"MNT\" | \"MOP\" | \"MUR\" | \"MVR\" | \"MWK\" | \"MXN\" | \"MYR\" | \"NAD\" | \"NGN\" | \"NIO\" | \"NOK\" | \"NPR\" | \"NZD\" | \"OMR\" | \"PAB\" | \"PEN\" | \"PGK\" | \"PHP\" | \"PKR\" | \"PLN\" | \"PYG\" | \"QAR\" | \"RON\" | \"RSD\" | \"RWF\" | \"SAR\" | \"SBD\" | \"SCR\" | \"SEK\" | \"SGD\" | \"SHP\" | \"SLE\" | \"SRD\" | \"SVC\" | \"SZL\" | \"THB\" | \"TJS\" | \"TMT\" | \"TND\" | \"TOP\" | \"TRY\" | \"TTD\" | \"TWD\" | \"TZS\" | \"UAH\" | \"UGX\" | \"USD\" | \"UYU\" | \"UZS\" | \"VND\" | \"VUV\" | \"WST\" | \"XAF\" | \"XCD\" | \"XOF\" | \"XPF\" | \"ZAR\" | \"ZMW\" | \"ZWL\"; }; admissionId?: string; sectionId?: string; admission?: { name: string; capacity: number; limit: number; order: number; entryStartsAt: string; entryEndsAt: string; saleStartsAt: string; saleEndsAt: string; saleEndsBehavior: \"SALE_ENDED\" | \"SOLD_OUT\" | \"DOOR\"; price: { base: number; booking: number; currency: \"AUD\" | \"AED\" | \"ALL\" | \"AMD\" | \"ANG\" | \"AOA\" | \"ARS\" | \"AWG\" | \"AZN\" | \"BAM\" | \"BBD\" | \"BDT\" | \"BGN\" | \"BHD\" | \"BIF\" | \"BMD\" | \"BND\" | \"BOB\" | \"BRL\" | \"BSD\" | \"BTN\" | \"BWP\" | \"BZD\" | \"CAD\" | \"CHF\" | \"CLP\" | \"CNY\" | \"COP\" | \"CRC\" | \"CVE\" | \"CZK\" | \"DJF\" | \"DKK\" | \"DOP\" | \"DZD\" | \"EGP\" | \"ERN\" | \"ETB\" | \"EUR\" | \"FJD\" | \"FKP\" | \"GBP\" | \"GEL\" | \"GHS\" | \"GIP\" | \"GMD\" | \"GNF\" | \"GTQ\" | \"GYD\" | \"HKD\" | \"HNL\" | \"HUF\" | \"IDR\" | \"ILS\" | \"INR\" | \"ISK\" | \"JMD\" | \"JOD\" | \"JPY\" | \"KES\" | \"KGS\" | \"KHR\" | \"KMF\" | \"KRW\" | \"KWD\" | \"KYD\" | \"KZT\" | \"LAK\" | \"LBP\" | \"LKR\" | \"LRD\" | \"LSL\" | \"LYD\" | \"MAD\" | \"MDL\" | \"MGA\" | \"MKD\" | \"MNT\" | \"MOP\" | \"MUR\" | \"MVR\" | \"MWK\" | \"MXN\" | \"MYR\" | \"NAD\" | \"NGN\" | \"NIO\" | \"NOK\" | \"NPR\" | \"NZD\" | \"OMR\" | \"PAB\" | \"PEN\" | \"PGK\" | \"PHP\" | \"PKR\" | \"PLN\" | \"PYG\" | \"QAR\" | \"RON\" | \"RSD\" | \"RWF\" | \"SAR\" | \"SBD\" | \"SCR\" | \"SEK\" | \"SGD\" | \"SHP\" | \"SLE\" | \"SRD\" | \"SVC\" | \"SZL\" | \"THB\" | \"TJS\" | \"TMT\" | \"TND\" | \"TOP\" | \"TRY\" | \"TTD\" | \"TWD\" | \"TZS\" | \"UAH\" | \"UGX\" | \"USD\" | \"UYU\" | \"UZS\" | \"VND\" | \"VUV\" | \"WST\" | \"XAF\" | \"XCD\" | \"XOF\" | \"XPF\" | \"ZAR\" | \"ZMW\" | \"ZWL\"; }; visibility: \"ALWAYS\" | \"STACKED\" | \"HIDDEN\"; teamId: string; promoterId: string; eventId: string; eventSlug: string; id?: string; subtitle?: string; description?: string; available?: number; sold?: number; reserved?: number; createdAt?: string; updatedAt?: string; passcode?: string; sectionId?: string; }; section?: { name: string; capacity: number; limit: number; order: number; location: { createdAt: string; updatedAt: string; name: string; address: string; country: string; latitude: number; longitude: number; timeZone: string; id?: string; googlePlaceId?: string; city?: string; state?: string; postcode?: string; types?: string[]; description?: string; image?: { src: string; alt: string; width: number; height: number; }; venueId?: string; }; teamId: string; promoterId: string; eventId: string; eventSlug: string; id?: string; createdAt?: string; updatedAt?: string; available?: number; sold?: number; reserved?: number; passcode?: string; }; }[]; price: { net: number; total: number; gross: number; base: number; booking: number; shipping: number; sms: number; refunded: number; discount: number; gateway: number; dispute: number; currency: \"AUD\" | \"AED\" | \"ALL\" | \"AMD\" | \"ANG\" | \"AOA\" | \"ARS\" | \"AWG\" | \"AZN\" | \"BAM\" | \"BBD\" | \"BDT\" | \"BGN\" | \"BHD\" | \"BIF\" | \"BMD\" | \"BND\" | \"BOB\" | \"BRL\" | \"BSD\" | \"BTN\" | \"BWP\" | \"BZD\" | \"CAD\" | \"CHF\" | \"CLP\" | \"CNY\" | \"COP\" | \"CRC\" | \"CVE\" | \"CZK\" | \"DJF\" | \"DKK\" | \"DOP\" | \"DZD\" | \"EGP\" | \"ERN\" | \"ETB\" | \"EUR\" | \"FJD\" | \"FKP\" | \"GBP\" | \"GEL\" | \"GHS\" | \"GIP\" | \"GMD\" | \"GNF\" | \"GTQ\" | \"GYD\" | \"HKD\" | \"HNL\" | \"HUF\" | \"IDR\" | \"ILS\" | \"INR\" | \"ISK\" | \"JMD\" | \"JOD\" | \"JPY\" | \"KES\" | \"KGS\" | \"KHR\" | \"KMF\" | \"KRW\" | \"KWD\" | \"KYD\" | \"KZT\" | \"LAK\" | \"LBP\" | \"LKR\" | \"LRD\" | \"LSL\" | \"LYD\" | \"MAD\" | \"MDL\" | \"MGA\" | \"MKD\" | \"MNT\" | \"MOP\" | \"MUR\" | \"MVR\" | \"MWK\" | \"MXN\" | \"MYR\" | \"NAD\" | \"NGN\" | \"NIO\" | \"NOK\" | \"NPR\" | \"NZD\" | \"OMR\" | \"PAB\" | \"PEN\" | \"PGK\" | \"PHP\" | \"PKR\" | \"PLN\" | \"PYG\" | \"QAR\" | \"RON\" | \"RSD\" | \"RWF\" | \"SAR\" | \"SBD\" | \"SCR\" | \"SEK\" | \"SGD\" | \"SHP\" | \"SLE\" | \"SRD\" | \"SVC\" | \"SZL\" | \"THB\" | \"TJS\" | \"TMT\" | \"TND\" | \"TOP\" | \"TRY\" | \"TTD\" | \"TWD\" | \"TZS\" | \"UAH\" | \"UGX\" | \"USD\" | \"UYU\" | \"UZS\" | \"VND\" | \"VUV\" | \"WST\" | \"XAF\" | \"XCD\" | \"XOF\" | \"XPF\" | \"ZAR\" | \"ZMW\" | \"ZWL\"; }; couponCode?: { name: string; active: boolean; couponId: string; teamId: string; id?: string; createdAt?: string; updatedAt?: string; uses?: number; }; }",
1454
+ "resolved": "string | { items: { id: string; kind: \"ADMISSION\" | \"ADDON\"; quantity: number; price: { net: number; total: number; gross: number; base: number; booking: number; refunded: number; discount: number; currency: \"AUD\" | \"AED\" | \"ALL\" | \"AMD\" | \"ANG\" | \"AOA\" | \"ARS\" | \"AWG\" | \"AZN\" | \"BAM\" | \"BBD\" | \"BDT\" | \"BGN\" | \"BHD\" | \"BIF\" | \"BMD\" | \"BND\" | \"BOB\" | \"BRL\" | \"BSD\" | \"BTN\" | \"BWP\" | \"BZD\" | \"CAD\" | \"CHF\" | \"CLP\" | \"CNY\" | \"COP\" | \"CRC\" | \"CVE\" | \"CZK\" | \"DJF\" | \"DKK\" | \"DOP\" | \"DZD\" | \"EGP\" | \"ERN\" | \"ETB\" | \"EUR\" | \"FJD\" | \"FKP\" | \"GBP\" | \"GEL\" | \"GHS\" | \"GIP\" | \"GMD\" | \"GNF\" | \"GTQ\" | \"GYD\" | \"HKD\" | \"HNL\" | \"HUF\" | \"IDR\" | \"ILS\" | \"INR\" | \"ISK\" | \"JMD\" | \"JOD\" | \"JPY\" | \"KES\" | \"KGS\" | \"KHR\" | \"KMF\" | \"KRW\" | \"KWD\" | \"KYD\" | \"KZT\" | \"LAK\" | \"LBP\" | \"LKR\" | \"LRD\" | \"LSL\" | \"LYD\" | \"MAD\" | \"MDL\" | \"MGA\" | \"MKD\" | \"MNT\" | \"MOP\" | \"MUR\" | \"MVR\" | \"MWK\" | \"MXN\" | \"MYR\" | \"NAD\" | \"NGN\" | \"NIO\" | \"NOK\" | \"NPR\" | \"NZD\" | \"OMR\" | \"PAB\" | \"PEN\" | \"PGK\" | \"PHP\" | \"PKR\" | \"PLN\" | \"PYG\" | \"QAR\" | \"RON\" | \"RSD\" | \"RWF\" | \"SAR\" | \"SBD\" | \"SCR\" | \"SEK\" | \"SGD\" | \"SHP\" | \"SLE\" | \"SRD\" | \"SVC\" | \"SZL\" | \"THB\" | \"TJS\" | \"TMT\" | \"TND\" | \"TOP\" | \"TRY\" | \"TTD\" | \"TWD\" | \"TZS\" | \"UAH\" | \"UGX\" | \"USD\" | \"UYU\" | \"UZS\" | \"VND\" | \"VUV\" | \"WST\" | \"XAF\" | \"XCD\" | \"XOF\" | \"XPF\" | \"ZAR\" | \"ZMW\" | \"ZWL\"; }; admissionId?: string; sectionId?: string; admission?: { name: string; capacity: number; limit: number; order: number; entryStartsAt: string; entryEndsAt: string; saleStartsAt: string; saleEndsAt: string; saleEndsBehavior: \"SALE_ENDED\" | \"SOLD_OUT\" | \"DOOR\"; price: { base: number; booking: number; currency: \"AUD\" | \"AED\" | \"ALL\" | \"AMD\" | \"ANG\" | \"AOA\" | \"ARS\" | \"AWG\" | \"AZN\" | \"BAM\" | \"BBD\" | \"BDT\" | \"BGN\" | \"BHD\" | \"BIF\" | \"BMD\" | \"BND\" | \"BOB\" | \"BRL\" | \"BSD\" | \"BTN\" | \"BWP\" | \"BZD\" | \"CAD\" | \"CHF\" | \"CLP\" | \"CNY\" | \"COP\" | \"CRC\" | \"CVE\" | \"CZK\" | \"DJF\" | \"DKK\" | \"DOP\" | \"DZD\" | \"EGP\" | \"ERN\" | \"ETB\" | \"EUR\" | \"FJD\" | \"FKP\" | \"GBP\" | \"GEL\" | \"GHS\" | \"GIP\" | \"GMD\" | \"GNF\" | \"GTQ\" | \"GYD\" | \"HKD\" | \"HNL\" | \"HUF\" | \"IDR\" | \"ILS\" | \"INR\" | \"ISK\" | \"JMD\" | \"JOD\" | \"JPY\" | \"KES\" | \"KGS\" | \"KHR\" | \"KMF\" | \"KRW\" | \"KWD\" | \"KYD\" | \"KZT\" | \"LAK\" | \"LBP\" | \"LKR\" | \"LRD\" | \"LSL\" | \"LYD\" | \"MAD\" | \"MDL\" | \"MGA\" | \"MKD\" | \"MNT\" | \"MOP\" | \"MUR\" | \"MVR\" | \"MWK\" | \"MXN\" | \"MYR\" | \"NAD\" | \"NGN\" | \"NIO\" | \"NOK\" | \"NPR\" | \"NZD\" | \"OMR\" | \"PAB\" | \"PEN\" | \"PGK\" | \"PHP\" | \"PKR\" | \"PLN\" | \"PYG\" | \"QAR\" | \"RON\" | \"RSD\" | \"RWF\" | \"SAR\" | \"SBD\" | \"SCR\" | \"SEK\" | \"SGD\" | \"SHP\" | \"SLE\" | \"SRD\" | \"SVC\" | \"SZL\" | \"THB\" | \"TJS\" | \"TMT\" | \"TND\" | \"TOP\" | \"TRY\" | \"TTD\" | \"TWD\" | \"TZS\" | \"UAH\" | \"UGX\" | \"USD\" | \"UYU\" | \"UZS\" | \"VND\" | \"VUV\" | \"WST\" | \"XAF\" | \"XCD\" | \"XOF\" | \"XPF\" | \"ZAR\" | \"ZMW\" | \"ZWL\"; }; visibility: \"ALWAYS\" | \"HIDDEN\"; teamId: string; promoterId: string; eventId: string; eventSlug: string; id?: string; subtitle?: string; description?: string; available?: number; sold?: number; reserved?: number; createdAt?: string; updatedAt?: string; sectionId?: string; }; section?: { name: string; capacity: number; limit: number; order: number; visibility: \"ALWAYS\" | \"HIDDEN\" | \"STACKED\"; location: { createdAt: string; updatedAt: string; name: string; address: string; country: string; latitude: number; longitude: number; timeZone: string; id?: string; googlePlaceId?: string; city?: string; state?: string; postcode?: string; types?: string[]; description?: string; image?: { src: string; alt: string; width: number; height: number; }; venueId?: string; }; teamId: string; promoterId: string; eventId: string; eventSlug: string; id?: string; createdAt?: string; updatedAt?: string; available?: number; sold?: number; reserved?: number; }; }[]; price: { net: number; total: number; gross: number; base: number; booking: number; shipping: number; sms: number; refunded: number; discount: number; gateway: number; dispute: number; currency: \"AUD\" | \"AED\" | \"ALL\" | \"AMD\" | \"ANG\" | \"AOA\" | \"ARS\" | \"AWG\" | \"AZN\" | \"BAM\" | \"BBD\" | \"BDT\" | \"BGN\" | \"BHD\" | \"BIF\" | \"BMD\" | \"BND\" | \"BOB\" | \"BRL\" | \"BSD\" | \"BTN\" | \"BWP\" | \"BZD\" | \"CAD\" | \"CHF\" | \"CLP\" | \"CNY\" | \"COP\" | \"CRC\" | \"CVE\" | \"CZK\" | \"DJF\" | \"DKK\" | \"DOP\" | \"DZD\" | \"EGP\" | \"ERN\" | \"ETB\" | \"EUR\" | \"FJD\" | \"FKP\" | \"GBP\" | \"GEL\" | \"GHS\" | \"GIP\" | \"GMD\" | \"GNF\" | \"GTQ\" | \"GYD\" | \"HKD\" | \"HNL\" | \"HUF\" | \"IDR\" | \"ILS\" | \"INR\" | \"ISK\" | \"JMD\" | \"JOD\" | \"JPY\" | \"KES\" | \"KGS\" | \"KHR\" | \"KMF\" | \"KRW\" | \"KWD\" | \"KYD\" | \"KZT\" | \"LAK\" | \"LBP\" | \"LKR\" | \"LRD\" | \"LSL\" | \"LYD\" | \"MAD\" | \"MDL\" | \"MGA\" | \"MKD\" | \"MNT\" | \"MOP\" | \"MUR\" | \"MVR\" | \"MWK\" | \"MXN\" | \"MYR\" | \"NAD\" | \"NGN\" | \"NIO\" | \"NOK\" | \"NPR\" | \"NZD\" | \"OMR\" | \"PAB\" | \"PEN\" | \"PGK\" | \"PHP\" | \"PKR\" | \"PLN\" | \"PYG\" | \"QAR\" | \"RON\" | \"RSD\" | \"RWF\" | \"SAR\" | \"SBD\" | \"SCR\" | \"SEK\" | \"SGD\" | \"SHP\" | \"SLE\" | \"SRD\" | \"SVC\" | \"SZL\" | \"THB\" | \"TJS\" | \"TMT\" | \"TND\" | \"TOP\" | \"TRY\" | \"TTD\" | \"TWD\" | \"TZS\" | \"UAH\" | \"UGX\" | \"USD\" | \"UYU\" | \"UZS\" | \"VND\" | \"VUV\" | \"WST\" | \"XAF\" | \"XCD\" | \"XOF\" | \"XPF\" | \"ZAR\" | \"ZMW\" | \"ZWL\"; }; couponCode?: { name: string; active: boolean; couponId: string; teamId: string; id?: string; createdAt?: string; updatedAt?: string; uses?: number; }; }",
1397
1455
  "references": {
1398
1456
  "OrderQuote": {
1399
1457
  "location": "import",
@@ -1565,7 +1623,7 @@ export class SessionsTicketing {
1565
1623
  },
1566
1624
  "complexType": {
1567
1625
  "original": "OrderQuote",
1568
- "resolved": "{ items: { id: string; kind: \"ADMISSION\" | \"ADDON\"; quantity: number; price: { net: number; total: number; gross: number; base: number; booking: number; refunded: number; discount: number; currency: \"AUD\" | \"AED\" | \"ALL\" | \"AMD\" | \"ANG\" | \"AOA\" | \"ARS\" | \"AWG\" | \"AZN\" | \"BAM\" | \"BBD\" | \"BDT\" | \"BGN\" | \"BHD\" | \"BIF\" | \"BMD\" | \"BND\" | \"BOB\" | \"BRL\" | \"BSD\" | \"BTN\" | \"BWP\" | \"BZD\" | \"CAD\" | \"CHF\" | \"CLP\" | \"CNY\" | \"COP\" | \"CRC\" | \"CVE\" | \"CZK\" | \"DJF\" | \"DKK\" | \"DOP\" | \"DZD\" | \"EGP\" | \"ERN\" | \"ETB\" | \"EUR\" | \"FJD\" | \"FKP\" | \"GBP\" | \"GEL\" | \"GHS\" | \"GIP\" | \"GMD\" | \"GNF\" | \"GTQ\" | \"GYD\" | \"HKD\" | \"HNL\" | \"HUF\" | \"IDR\" | \"ILS\" | \"INR\" | \"ISK\" | \"JMD\" | \"JOD\" | \"JPY\" | \"KES\" | \"KGS\" | \"KHR\" | \"KMF\" | \"KRW\" | \"KWD\" | \"KYD\" | \"KZT\" | \"LAK\" | \"LBP\" | \"LKR\" | \"LRD\" | \"LSL\" | \"LYD\" | \"MAD\" | \"MDL\" | \"MGA\" | \"MKD\" | \"MNT\" | \"MOP\" | \"MUR\" | \"MVR\" | \"MWK\" | \"MXN\" | \"MYR\" | \"NAD\" | \"NGN\" | \"NIO\" | \"NOK\" | \"NPR\" | \"NZD\" | \"OMR\" | \"PAB\" | \"PEN\" | \"PGK\" | \"PHP\" | \"PKR\" | \"PLN\" | \"PYG\" | \"QAR\" | \"RON\" | \"RSD\" | \"RWF\" | \"SAR\" | \"SBD\" | \"SCR\" | \"SEK\" | \"SGD\" | \"SHP\" | \"SLE\" | \"SRD\" | \"SVC\" | \"SZL\" | \"THB\" | \"TJS\" | \"TMT\" | \"TND\" | \"TOP\" | \"TRY\" | \"TTD\" | \"TWD\" | \"TZS\" | \"UAH\" | \"UGX\" | \"USD\" | \"UYU\" | \"UZS\" | \"VND\" | \"VUV\" | \"WST\" | \"XAF\" | \"XCD\" | \"XOF\" | \"XPF\" | \"ZAR\" | \"ZMW\" | \"ZWL\"; }; admissionId?: string; sectionId?: string; admission?: { name: string; capacity: number; limit: number; order: number; entryStartsAt: string; entryEndsAt: string; saleStartsAt: string; saleEndsAt: string; saleEndsBehavior: \"SALE_ENDED\" | \"SOLD_OUT\" | \"DOOR\"; price: { base: number; booking: number; currency: \"AUD\" | \"AED\" | \"ALL\" | \"AMD\" | \"ANG\" | \"AOA\" | \"ARS\" | \"AWG\" | \"AZN\" | \"BAM\" | \"BBD\" | \"BDT\" | \"BGN\" | \"BHD\" | \"BIF\" | \"BMD\" | \"BND\" | \"BOB\" | \"BRL\" | \"BSD\" | \"BTN\" | \"BWP\" | \"BZD\" | \"CAD\" | \"CHF\" | \"CLP\" | \"CNY\" | \"COP\" | \"CRC\" | \"CVE\" | \"CZK\" | \"DJF\" | \"DKK\" | \"DOP\" | \"DZD\" | \"EGP\" | \"ERN\" | \"ETB\" | \"EUR\" | \"FJD\" | \"FKP\" | \"GBP\" | \"GEL\" | \"GHS\" | \"GIP\" | \"GMD\" | \"GNF\" | \"GTQ\" | \"GYD\" | \"HKD\" | \"HNL\" | \"HUF\" | \"IDR\" | \"ILS\" | \"INR\" | \"ISK\" | \"JMD\" | \"JOD\" | \"JPY\" | \"KES\" | \"KGS\" | \"KHR\" | \"KMF\" | \"KRW\" | \"KWD\" | \"KYD\" | \"KZT\" | \"LAK\" | \"LBP\" | \"LKR\" | \"LRD\" | \"LSL\" | \"LYD\" | \"MAD\" | \"MDL\" | \"MGA\" | \"MKD\" | \"MNT\" | \"MOP\" | \"MUR\" | \"MVR\" | \"MWK\" | \"MXN\" | \"MYR\" | \"NAD\" | \"NGN\" | \"NIO\" | \"NOK\" | \"NPR\" | \"NZD\" | \"OMR\" | \"PAB\" | \"PEN\" | \"PGK\" | \"PHP\" | \"PKR\" | \"PLN\" | \"PYG\" | \"QAR\" | \"RON\" | \"RSD\" | \"RWF\" | \"SAR\" | \"SBD\" | \"SCR\" | \"SEK\" | \"SGD\" | \"SHP\" | \"SLE\" | \"SRD\" | \"SVC\" | \"SZL\" | \"THB\" | \"TJS\" | \"TMT\" | \"TND\" | \"TOP\" | \"TRY\" | \"TTD\" | \"TWD\" | \"TZS\" | \"UAH\" | \"UGX\" | \"USD\" | \"UYU\" | \"UZS\" | \"VND\" | \"VUV\" | \"WST\" | \"XAF\" | \"XCD\" | \"XOF\" | \"XPF\" | \"ZAR\" | \"ZMW\" | \"ZWL\"; }; visibility: \"ALWAYS\" | \"STACKED\" | \"HIDDEN\"; teamId: string; promoterId: string; eventId: string; eventSlug: string; id?: string; subtitle?: string; description?: string; available?: number; sold?: number; reserved?: number; createdAt?: string; updatedAt?: string; passcode?: string; sectionId?: string; }; section?: { name: string; capacity: number; limit: number; order: number; location: { createdAt: string; updatedAt: string; name: string; address: string; country: string; latitude: number; longitude: number; timeZone: string; id?: string; googlePlaceId?: string; city?: string; state?: string; postcode?: string; types?: string[]; description?: string; image?: { src: string; alt: string; width: number; height: number; }; venueId?: string; }; teamId: string; promoterId: string; eventId: string; eventSlug: string; id?: string; createdAt?: string; updatedAt?: string; available?: number; sold?: number; reserved?: number; passcode?: string; }; }[]; price: { net: number; total: number; gross: number; base: number; booking: number; shipping: number; sms: number; refunded: number; discount: number; gateway: number; dispute: number; currency: \"AUD\" | \"AED\" | \"ALL\" | \"AMD\" | \"ANG\" | \"AOA\" | \"ARS\" | \"AWG\" | \"AZN\" | \"BAM\" | \"BBD\" | \"BDT\" | \"BGN\" | \"BHD\" | \"BIF\" | \"BMD\" | \"BND\" | \"BOB\" | \"BRL\" | \"BSD\" | \"BTN\" | \"BWP\" | \"BZD\" | \"CAD\" | \"CHF\" | \"CLP\" | \"CNY\" | \"COP\" | \"CRC\" | \"CVE\" | \"CZK\" | \"DJF\" | \"DKK\" | \"DOP\" | \"DZD\" | \"EGP\" | \"ERN\" | \"ETB\" | \"EUR\" | \"FJD\" | \"FKP\" | \"GBP\" | \"GEL\" | \"GHS\" | \"GIP\" | \"GMD\" | \"GNF\" | \"GTQ\" | \"GYD\" | \"HKD\" | \"HNL\" | \"HUF\" | \"IDR\" | \"ILS\" | \"INR\" | \"ISK\" | \"JMD\" | \"JOD\" | \"JPY\" | \"KES\" | \"KGS\" | \"KHR\" | \"KMF\" | \"KRW\" | \"KWD\" | \"KYD\" | \"KZT\" | \"LAK\" | \"LBP\" | \"LKR\" | \"LRD\" | \"LSL\" | \"LYD\" | \"MAD\" | \"MDL\" | \"MGA\" | \"MKD\" | \"MNT\" | \"MOP\" | \"MUR\" | \"MVR\" | \"MWK\" | \"MXN\" | \"MYR\" | \"NAD\" | \"NGN\" | \"NIO\" | \"NOK\" | \"NPR\" | \"NZD\" | \"OMR\" | \"PAB\" | \"PEN\" | \"PGK\" | \"PHP\" | \"PKR\" | \"PLN\" | \"PYG\" | \"QAR\" | \"RON\" | \"RSD\" | \"RWF\" | \"SAR\" | \"SBD\" | \"SCR\" | \"SEK\" | \"SGD\" | \"SHP\" | \"SLE\" | \"SRD\" | \"SVC\" | \"SZL\" | \"THB\" | \"TJS\" | \"TMT\" | \"TND\" | \"TOP\" | \"TRY\" | \"TTD\" | \"TWD\" | \"TZS\" | \"UAH\" | \"UGX\" | \"USD\" | \"UYU\" | \"UZS\" | \"VND\" | \"VUV\" | \"WST\" | \"XAF\" | \"XCD\" | \"XOF\" | \"XPF\" | \"ZAR\" | \"ZMW\" | \"ZWL\"; }; couponCode?: { name: string; active: boolean; couponId: string; teamId: string; id?: string; createdAt?: string; updatedAt?: string; uses?: number; }; }",
1626
+ "resolved": "{ items: { id: string; kind: \"ADMISSION\" | \"ADDON\"; quantity: number; price: { net: number; total: number; gross: number; base: number; booking: number; refunded: number; discount: number; currency: \"AUD\" | \"AED\" | \"ALL\" | \"AMD\" | \"ANG\" | \"AOA\" | \"ARS\" | \"AWG\" | \"AZN\" | \"BAM\" | \"BBD\" | \"BDT\" | \"BGN\" | \"BHD\" | \"BIF\" | \"BMD\" | \"BND\" | \"BOB\" | \"BRL\" | \"BSD\" | \"BTN\" | \"BWP\" | \"BZD\" | \"CAD\" | \"CHF\" | \"CLP\" | \"CNY\" | \"COP\" | \"CRC\" | \"CVE\" | \"CZK\" | \"DJF\" | \"DKK\" | \"DOP\" | \"DZD\" | \"EGP\" | \"ERN\" | \"ETB\" | \"EUR\" | \"FJD\" | \"FKP\" | \"GBP\" | \"GEL\" | \"GHS\" | \"GIP\" | \"GMD\" | \"GNF\" | \"GTQ\" | \"GYD\" | \"HKD\" | \"HNL\" | \"HUF\" | \"IDR\" | \"ILS\" | \"INR\" | \"ISK\" | \"JMD\" | \"JOD\" | \"JPY\" | \"KES\" | \"KGS\" | \"KHR\" | \"KMF\" | \"KRW\" | \"KWD\" | \"KYD\" | \"KZT\" | \"LAK\" | \"LBP\" | \"LKR\" | \"LRD\" | \"LSL\" | \"LYD\" | \"MAD\" | \"MDL\" | \"MGA\" | \"MKD\" | \"MNT\" | \"MOP\" | \"MUR\" | \"MVR\" | \"MWK\" | \"MXN\" | \"MYR\" | \"NAD\" | \"NGN\" | \"NIO\" | \"NOK\" | \"NPR\" | \"NZD\" | \"OMR\" | \"PAB\" | \"PEN\" | \"PGK\" | \"PHP\" | \"PKR\" | \"PLN\" | \"PYG\" | \"QAR\" | \"RON\" | \"RSD\" | \"RWF\" | \"SAR\" | \"SBD\" | \"SCR\" | \"SEK\" | \"SGD\" | \"SHP\" | \"SLE\" | \"SRD\" | \"SVC\" | \"SZL\" | \"THB\" | \"TJS\" | \"TMT\" | \"TND\" | \"TOP\" | \"TRY\" | \"TTD\" | \"TWD\" | \"TZS\" | \"UAH\" | \"UGX\" | \"USD\" | \"UYU\" | \"UZS\" | \"VND\" | \"VUV\" | \"WST\" | \"XAF\" | \"XCD\" | \"XOF\" | \"XPF\" | \"ZAR\" | \"ZMW\" | \"ZWL\"; }; admissionId?: string; sectionId?: string; admission?: { name: string; capacity: number; limit: number; order: number; entryStartsAt: string; entryEndsAt: string; saleStartsAt: string; saleEndsAt: string; saleEndsBehavior: \"SALE_ENDED\" | \"SOLD_OUT\" | \"DOOR\"; price: { base: number; booking: number; currency: \"AUD\" | \"AED\" | \"ALL\" | \"AMD\" | \"ANG\" | \"AOA\" | \"ARS\" | \"AWG\" | \"AZN\" | \"BAM\" | \"BBD\" | \"BDT\" | \"BGN\" | \"BHD\" | \"BIF\" | \"BMD\" | \"BND\" | \"BOB\" | \"BRL\" | \"BSD\" | \"BTN\" | \"BWP\" | \"BZD\" | \"CAD\" | \"CHF\" | \"CLP\" | \"CNY\" | \"COP\" | \"CRC\" | \"CVE\" | \"CZK\" | \"DJF\" | \"DKK\" | \"DOP\" | \"DZD\" | \"EGP\" | \"ERN\" | \"ETB\" | \"EUR\" | \"FJD\" | \"FKP\" | \"GBP\" | \"GEL\" | \"GHS\" | \"GIP\" | \"GMD\" | \"GNF\" | \"GTQ\" | \"GYD\" | \"HKD\" | \"HNL\" | \"HUF\" | \"IDR\" | \"ILS\" | \"INR\" | \"ISK\" | \"JMD\" | \"JOD\" | \"JPY\" | \"KES\" | \"KGS\" | \"KHR\" | \"KMF\" | \"KRW\" | \"KWD\" | \"KYD\" | \"KZT\" | \"LAK\" | \"LBP\" | \"LKR\" | \"LRD\" | \"LSL\" | \"LYD\" | \"MAD\" | \"MDL\" | \"MGA\" | \"MKD\" | \"MNT\" | \"MOP\" | \"MUR\" | \"MVR\" | \"MWK\" | \"MXN\" | \"MYR\" | \"NAD\" | \"NGN\" | \"NIO\" | \"NOK\" | \"NPR\" | \"NZD\" | \"OMR\" | \"PAB\" | \"PEN\" | \"PGK\" | \"PHP\" | \"PKR\" | \"PLN\" | \"PYG\" | \"QAR\" | \"RON\" | \"RSD\" | \"RWF\" | \"SAR\" | \"SBD\" | \"SCR\" | \"SEK\" | \"SGD\" | \"SHP\" | \"SLE\" | \"SRD\" | \"SVC\" | \"SZL\" | \"THB\" | \"TJS\" | \"TMT\" | \"TND\" | \"TOP\" | \"TRY\" | \"TTD\" | \"TWD\" | \"TZS\" | \"UAH\" | \"UGX\" | \"USD\" | \"UYU\" | \"UZS\" | \"VND\" | \"VUV\" | \"WST\" | \"XAF\" | \"XCD\" | \"XOF\" | \"XPF\" | \"ZAR\" | \"ZMW\" | \"ZWL\"; }; visibility: \"ALWAYS\" | \"HIDDEN\"; teamId: string; promoterId: string; eventId: string; eventSlug: string; id?: string; subtitle?: string; description?: string; available?: number; sold?: number; reserved?: number; createdAt?: string; updatedAt?: string; sectionId?: string; }; section?: { name: string; capacity: number; limit: number; order: number; visibility: \"ALWAYS\" | \"HIDDEN\" | \"STACKED\"; location: { createdAt: string; updatedAt: string; name: string; address: string; country: string; latitude: number; longitude: number; timeZone: string; id?: string; googlePlaceId?: string; city?: string; state?: string; postcode?: string; types?: string[]; description?: string; image?: { src: string; alt: string; width: number; height: number; }; venueId?: string; }; teamId: string; promoterId: string; eventId: string; eventSlug: string; id?: string; createdAt?: string; updatedAt?: string; available?: number; sold?: number; reserved?: number; }; }[]; price: { net: number; total: number; gross: number; base: number; booking: number; shipping: number; sms: number; refunded: number; discount: number; gateway: number; dispute: number; currency: \"AUD\" | \"AED\" | \"ALL\" | \"AMD\" | \"ANG\" | \"AOA\" | \"ARS\" | \"AWG\" | \"AZN\" | \"BAM\" | \"BBD\" | \"BDT\" | \"BGN\" | \"BHD\" | \"BIF\" | \"BMD\" | \"BND\" | \"BOB\" | \"BRL\" | \"BSD\" | \"BTN\" | \"BWP\" | \"BZD\" | \"CAD\" | \"CHF\" | \"CLP\" | \"CNY\" | \"COP\" | \"CRC\" | \"CVE\" | \"CZK\" | \"DJF\" | \"DKK\" | \"DOP\" | \"DZD\" | \"EGP\" | \"ERN\" | \"ETB\" | \"EUR\" | \"FJD\" | \"FKP\" | \"GBP\" | \"GEL\" | \"GHS\" | \"GIP\" | \"GMD\" | \"GNF\" | \"GTQ\" | \"GYD\" | \"HKD\" | \"HNL\" | \"HUF\" | \"IDR\" | \"ILS\" | \"INR\" | \"ISK\" | \"JMD\" | \"JOD\" | \"JPY\" | \"KES\" | \"KGS\" | \"KHR\" | \"KMF\" | \"KRW\" | \"KWD\" | \"KYD\" | \"KZT\" | \"LAK\" | \"LBP\" | \"LKR\" | \"LRD\" | \"LSL\" | \"LYD\" | \"MAD\" | \"MDL\" | \"MGA\" | \"MKD\" | \"MNT\" | \"MOP\" | \"MUR\" | \"MVR\" | \"MWK\" | \"MXN\" | \"MYR\" | \"NAD\" | \"NGN\" | \"NIO\" | \"NOK\" | \"NPR\" | \"NZD\" | \"OMR\" | \"PAB\" | \"PEN\" | \"PGK\" | \"PHP\" | \"PKR\" | \"PLN\" | \"PYG\" | \"QAR\" | \"RON\" | \"RSD\" | \"RWF\" | \"SAR\" | \"SBD\" | \"SCR\" | \"SEK\" | \"SGD\" | \"SHP\" | \"SLE\" | \"SRD\" | \"SVC\" | \"SZL\" | \"THB\" | \"TJS\" | \"TMT\" | \"TND\" | \"TOP\" | \"TRY\" | \"TTD\" | \"TWD\" | \"TZS\" | \"UAH\" | \"UGX\" | \"USD\" | \"UYU\" | \"UZS\" | \"VND\" | \"VUV\" | \"WST\" | \"XAF\" | \"XCD\" | \"XOF\" | \"XPF\" | \"ZAR\" | \"ZMW\" | \"ZWL\"; }; couponCode?: { name: string; active: boolean; couponId: string; teamId: string; id?: string; createdAt?: string; updatedAt?: string; uses?: number; }; }",
1569
1627
  "references": {
1570
1628
  "OrderQuote": {
1571
1629
  "location": "import",
@@ -1,6 +1,6 @@
1
1
  import { formatNaiveDateTime, isNaiveDateTimeFuture, isNaiveDateTimePast, } from "@session-services/utils/naive-datetime";
2
- import { createQuoteItemMap } from "@session-services/utils/ticket-quote";
3
2
  import { getAdmissionSelectionCapacity, isAdmissionSoldOut, } from "@session-services/utils/ticket-availability";
3
+ import { createQuoteItemMap } from "@session-services/utils/ticket-quote";
4
4
  const UNLIMITED_CAP = 10;
5
5
  const SCARCITY_THRESHOLD = 20;
6
6
  export function selectionKey(admissionId, sectionId) {
@@ -93,8 +93,7 @@ function endedStatus(admissions, zone) {
93
93
  }
94
94
  function salesStatus(event) {
95
95
  const sections = sectionsById(event);
96
- const admissions = event.admissions.filter((admission) => admission.visibility !== "HIDDEN" &&
97
- hasAdmissionSection(admission, sections));
96
+ const admissions = event.admissions.filter((admission) => hasAdmissionSection(admission, sections));
98
97
  if (admissions.length === 0)
99
98
  return undefined;
100
99
  if (hasPurchasableAdmissions(event))
@@ -133,14 +132,99 @@ export function visibleAdmissions(event, mode) {
133
132
  return event.admissions.filter((admission) => admission.saleEndsBehavior === "DOOR" &&
134
133
  isNaiveDateTimePast(admission.saleEndsAt, zone));
135
134
  }
136
- function sectionItems(sections, admissions) {
135
+ function isStackableAdmission(input) {
136
+ if (input.mode === "door")
137
+ return true;
138
+ if (!input.event)
139
+ return true;
140
+ return !getAdmissionDisplayState({
141
+ admission: input.admission,
142
+ event: input.event,
143
+ section: input.section,
144
+ }).disabled;
145
+ }
146
+ function stackedAdmissionBase(input) {
147
+ const key = selectionKey(input.admission.id, input.section.id);
148
+ return getAdmissionPriceDisplay({
149
+ admission: input.admission,
150
+ initialPrice: input.initialAdmissionPrices?.[key],
151
+ mode: input.mode,
152
+ previewItem: input.previewItems.get(key),
153
+ quoteItem: input.quoteItems.get(key),
154
+ }).base;
155
+ }
156
+ function compareStackedAdmissions(input, section) {
157
+ const mode = input.mode ?? "default";
158
+ const previewItems = quoteItemsBySelection(input.previewQuote ?? null);
159
+ const quoteItems = quoteItemsBySelection(input.quote ?? null);
160
+ return (a, b) => {
161
+ const price = stackedAdmissionBase({
162
+ admission: a,
163
+ initialAdmissionPrices: input.initialAdmissionPrices,
164
+ mode,
165
+ previewItems,
166
+ quoteItems,
167
+ section,
168
+ }) -
169
+ stackedAdmissionBase({
170
+ admission: b,
171
+ initialAdmissionPrices: input.initialAdmissionPrices,
172
+ mode,
173
+ previewItems,
174
+ quoteItems,
175
+ section,
176
+ });
177
+ if (price !== 0)
178
+ return price;
179
+ const order = a.order - b.order;
180
+ if (order !== 0)
181
+ return order;
182
+ return a.id.localeCompare(b.id);
183
+ };
184
+ }
185
+ function cap(value) {
186
+ if (value == null || value === -1)
187
+ return Number.POSITIVE_INFINITY;
188
+ return Math.max(0, value);
189
+ }
190
+ function shouldShowNextStackedAdmission(admission) {
191
+ const remaining = cap(admission.available);
192
+ if (!Number.isFinite(remaining))
193
+ return false;
194
+ const limit = cap(admission.limit);
195
+ if (!Number.isFinite(limit))
196
+ return remaining < UNLIMITED_CAP;
197
+ return limit > remaining;
198
+ }
199
+ function displayedSectionAdmissions(section, admissions, input) {
200
+ const sorted = admissions
201
+ .filter((admission) => admission.sectionId === section.id)
202
+ .sort((a, b) => a.order - b.order);
203
+ if (section.visibility !== "STACKED" || sorted.length <= 1) {
204
+ return sorted;
205
+ }
206
+ const mode = input.mode ?? "default";
207
+ const stackable = sorted.filter((admission) => isStackableAdmission({
208
+ admission,
209
+ event: input.event,
210
+ mode,
211
+ section,
212
+ }));
213
+ const candidates = stackable.length > 0 ? stackable : sorted;
214
+ const [admission, next] = [...candidates].sort(compareStackedAdmissions(input, section));
215
+ if (!admission)
216
+ return [];
217
+ if (!next || !shouldShowNextStackedAdmission(admission)) {
218
+ return [admission];
219
+ }
220
+ return [admission, next];
221
+ }
222
+ function sectionItems(sections, admissions, input) {
137
223
  return sections
138
224
  .map((section) => ({
139
225
  type: "section",
140
226
  section,
141
- admissions: admissions
142
- .filter((admission) => admission.sectionId === section.id)
143
- .sort((a, b) => a.order - b.order),
227
+ admissions: displayedSectionAdmissions(section, admissions, input),
144
228
  }))
145
229
  .filter((item) => item.admissions.length > 0);
146
230
  }
@@ -149,9 +233,9 @@ function topLevelOrder(item) {
149
233
  return item.section.order;
150
234
  return item.admission.order;
151
235
  }
152
- export function topLevelTicketItems(sections, admissions) {
236
+ export function topLevelTicketItems(sections, admissions, input = {}) {
153
237
  return [
154
- ...sectionItems(sections, admissions),
238
+ ...sectionItems(sections, admissions, input),
155
239
  ...admissions
156
240
  .filter((admission) => !admission.sectionId)
157
241
  .map((admission) => ({ type: "admission", admission })),
@@ -42,6 +42,7 @@ function section(data = {}) {
42
42
  reserved: 0,
43
43
  limit: 10,
44
44
  order: 2,
45
+ visibility: "ALWAYS",
45
46
  teamId: "team_1",
46
47
  promoterId: "pro_1",
47
48
  eventId: "evt_1",
@@ -113,6 +114,25 @@ function quoteItem(data = {}) {
113
114
  ...data,
114
115
  };
115
116
  }
117
+ function quote(items) {
118
+ return {
119
+ items,
120
+ price: {
121
+ base: 0,
122
+ booking: 0,
123
+ currency: "AUD",
124
+ discount: 0,
125
+ dispute: 0,
126
+ gateway: 0,
127
+ gross: 0,
128
+ net: 0,
129
+ refunded: 0,
130
+ shipping: 0,
131
+ sms: 0,
132
+ total: 0,
133
+ },
134
+ };
135
+ }
116
136
  describe("session-services-ticketing logic", () => {
117
137
  it("reads discount coupon codes from query strings", () => {
118
138
  expect(discountCouponFromSearch("?discount=save20")).toBe("save20");
@@ -255,6 +275,169 @@ describe("session-services-ticketing logic", () => {
255
275
  const items = topLevelTicketItems([main], [sectioned, early]);
256
276
  expect(items.map((item) => item.type)).toEqual(["admission", "section"]);
257
277
  });
278
+ it("lists every visible admission in list sections", () => {
279
+ const main = section({ id: "sec_main", visibility: "ALWAYS" });
280
+ const first = admission({ id: "adm_first", order: 2, sectionId: main.id });
281
+ const second = admission({
282
+ id: "adm_second",
283
+ order: 1,
284
+ sectionId: main.id,
285
+ });
286
+ const [item] = topLevelTicketItems([main], [first, second]);
287
+ expect(item?.type).toBe("section");
288
+ expect(item?.type === "section" ? item.admissions.map((adm) => adm.id) : []).toEqual(["adm_second", "adm_first"]);
289
+ });
290
+ it("shows the cheapest base-price admission in stacked sections", () => {
291
+ const main = section({ visibility: "STACKED" });
292
+ const expensive = admission({
293
+ id: "adm_expensive",
294
+ order: 1,
295
+ price: { base: 3000, booking: 300, currency: "AUD" },
296
+ sectionId: main.id,
297
+ });
298
+ const cheap = admission({
299
+ id: "adm_cheap",
300
+ order: 2,
301
+ price: { base: 1500, booking: 150, currency: "AUD" },
302
+ sectionId: main.id,
303
+ });
304
+ const [item] = topLevelTicketItems([main], [expensive, cheap]);
305
+ expect(item?.type).toBe("section");
306
+ expect(item?.type === "section" ? item.admissions.map((adm) => adm.id) : []).toEqual(["adm_cheap"]);
307
+ });
308
+ it("skips sold-out admissions when stacking sections", () => {
309
+ const main = section({ visibility: "STACKED" });
310
+ const soldOut = admission({
311
+ id: "adm_sold_out",
312
+ available: 0,
313
+ capacity: 1,
314
+ order: 1,
315
+ price: { base: 1000, booking: 100, currency: "AUD" },
316
+ sectionId: main.id,
317
+ sold: 1,
318
+ });
319
+ const available = admission({
320
+ id: "adm_available",
321
+ order: 2,
322
+ price: { base: 2000, booking: 200, currency: "AUD" },
323
+ sectionId: main.id,
324
+ });
325
+ const data = event({
326
+ admissions: [soldOut, available],
327
+ sections: [main],
328
+ });
329
+ const [item] = topLevelTicketItems([main], data.admissions, {
330
+ event: data,
331
+ mode: "default",
332
+ });
333
+ expect(item?.type).toBe("section");
334
+ expect(item?.type === "section" ? item.admissions.map((adm) => adm.id) : []).toEqual(["adm_available"]);
335
+ });
336
+ it("shows the next stacked admission when the cheapest has fewer tickets than its per-order limit", () => {
337
+ const main = section({ visibility: "STACKED" });
338
+ const lowRemaining = admission({
339
+ id: "adm_low_remaining",
340
+ available: 3,
341
+ limit: 4,
342
+ price: { base: 1000, booking: 100, currency: "AUD" },
343
+ sectionId: main.id,
344
+ });
345
+ const next = admission({
346
+ id: "adm_next",
347
+ order: 2,
348
+ price: { base: 2000, booking: 200, currency: "AUD" },
349
+ sectionId: main.id,
350
+ });
351
+ const [item] = topLevelTicketItems([main], [lowRemaining, next]);
352
+ expect(item?.type).toBe("section");
353
+ expect(item?.type === "section" ? item.admissions.map((adm) => adm.id) : []).toEqual(["adm_low_remaining", "adm_next"]);
354
+ });
355
+ it("shows the next stacked admission when an unlimited per-order limit has fewer than ten tickets left", () => {
356
+ const main = section({ visibility: "STACKED" });
357
+ const lowRemaining = admission({
358
+ id: "adm_low_remaining",
359
+ available: 9,
360
+ limit: -1,
361
+ price: { base: 1000, booking: 100, currency: "AUD" },
362
+ sectionId: main.id,
363
+ });
364
+ const next = admission({
365
+ id: "adm_next",
366
+ order: 2,
367
+ price: { base: 2000, booking: 200, currency: "AUD" },
368
+ sectionId: main.id,
369
+ });
370
+ const [item] = topLevelTicketItems([main], [lowRemaining, next]);
371
+ expect(item?.type).toBe("section");
372
+ expect(item?.type === "section" ? item.admissions.map((adm) => adm.id) : []).toEqual(["adm_low_remaining", "adm_next"]);
373
+ });
374
+ it("keeps stacked admissions collapsed when an unlimited per-order limit has ten tickets left", () => {
375
+ const main = section({ visibility: "STACKED" });
376
+ const current = admission({
377
+ id: "adm_current",
378
+ available: 10,
379
+ limit: -1,
380
+ price: { base: 1000, booking: 100, currency: "AUD" },
381
+ sectionId: main.id,
382
+ });
383
+ const next = admission({
384
+ id: "adm_next",
385
+ order: 2,
386
+ price: { base: 2000, booking: 200, currency: "AUD" },
387
+ sectionId: main.id,
388
+ });
389
+ const [item] = topLevelTicketItems([main], [current, next]);
390
+ expect(item?.type).toBe("section");
391
+ expect(item?.type === "section" ? item.admissions.map((adm) => adm.id) : []).toEqual(["adm_current"]);
392
+ });
393
+ it("uses coupon-adjusted base prices when stacking sections", () => {
394
+ const main = section({ visibility: "STACKED" });
395
+ const general = admission({
396
+ id: "adm_general",
397
+ order: 1,
398
+ price: { base: 2000, booking: 200, currency: "AUD" },
399
+ sectionId: main.id,
400
+ });
401
+ const vip = admission({
402
+ id: "adm_vip",
403
+ order: 2,
404
+ price: { base: 3000, booking: 300, currency: "AUD" },
405
+ sectionId: main.id,
406
+ });
407
+ const [item] = topLevelTicketItems([main], [general, vip], {
408
+ mode: "default",
409
+ previewQuote: quote([
410
+ quoteItem({
411
+ admissionId: "adm_vip",
412
+ sectionId: main.id,
413
+ price: {
414
+ base: 3000,
415
+ booking: 300,
416
+ currency: "AUD",
417
+ discount: -2500,
418
+ gross: 3300,
419
+ net: 800,
420
+ refunded: 0,
421
+ total: 800,
422
+ },
423
+ }),
424
+ ]),
425
+ });
426
+ expect(item?.type).toBe("section");
427
+ expect(item?.type === "section" ? item.admissions.map((adm) => adm.id) : []).toEqual(["adm_vip"]);
428
+ });
429
+ it("does not stack unsectioned admissions", () => {
430
+ const main = section({ visibility: "STACKED", order: 2 });
431
+ const sectioned = admission({
432
+ id: "adm_sectioned",
433
+ order: 1,
434
+ sectionId: main.id,
435
+ });
436
+ const unsectioned = admission({ id: "adm_unsectioned", order: 1 });
437
+ const items = topLevelTicketItems([main], [sectioned, unsectioned]);
438
+ expect(items.map((item) => item.type)).toEqual(["admission", "section"]);
439
+ expect(items[0]?.type === "admission" ? items[0].admission.id : "").toBe("adm_unsectioned");
440
+ });
258
441
  it("caps unlimited admission quantity at the selector limit", () => {
259
442
  const data = event({
260
443
  admissions: [admission({ available: -1, capacity: -1 })],