@ticketboothapp/booking 1.2.69 → 1.2.71
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/package.json
CHANGED
|
@@ -826,17 +826,12 @@ export function AdminChangeBookingFlow({
|
|
|
826
826
|
/** Any change from an existing booking (public or provider). */
|
|
827
827
|
const isChangeBookingContext = Boolean(initialValues?.bookingReference?.trim());
|
|
828
828
|
/**
|
|
829
|
-
*
|
|
830
|
-
*
|
|
831
|
-
*
|
|
832
|
-
* `handleConfirmWithoutPayment` (or after paying in the checkout modal).
|
|
829
|
+
* Public `POST .../change/quote` path whenever we are editing an existing booking — including when the host passes
|
|
830
|
+
* `onChangeBooking`. Provider apply (`onChangeBooking`) runs only after Pay now / Confirm without payment, never from
|
|
831
|
+
* Continue alone.
|
|
833
832
|
*/
|
|
834
|
-
const
|
|
835
|
-
|
|
836
|
-
isChangeBookingContext &&
|
|
837
|
-
bookingAppMode === 'provider-dashboard' &&
|
|
838
|
-
isProviderDashboardChange;
|
|
839
|
-
const isCustomerSelfServeChange = !isProviderDashboardChange || deferProviderApplyToAdminPaymentChoice;
|
|
833
|
+
const isCustomerSelfServeChange =
|
|
834
|
+
!isProviderDashboardChange || isChangeBookingContext;
|
|
840
835
|
/** Do not render catalog-/FE-derived dollar amounts in UI until `quoteChangeBooking` returns `serverDisplay`. */
|
|
841
836
|
const suppressSelfServeCurrencyUi = isCustomerSelfServeChange;
|
|
842
837
|
|
|
@@ -1722,14 +1717,14 @@ export function AdminChangeBookingFlow({
|
|
|
1722
1717
|
}, [initialValues?.productId, product.productId]);
|
|
1723
1718
|
|
|
1724
1719
|
/**
|
|
1725
|
-
* Receipt pricing on protected seats/fees
|
|
1726
|
-
*
|
|
1720
|
+
* Receipt pricing on protected seats/fees: Rule A / B per `change-flow-pricing.ts`, same as public self-serve whenever
|
|
1721
|
+
* `POST .../change/quote` runs (`isCustomerSelfServeChange`, including provider dashboard with `onChangeBooking`).
|
|
1727
1722
|
*/
|
|
1728
1723
|
const changeFlowApplyReceiptPaidFloors = useMemo(
|
|
1729
1724
|
() =>
|
|
1730
|
-
|
|
1725
|
+
isCustomerSelfServeChange &&
|
|
1731
1726
|
changeFlowBookingParentProductIdForFloors === product.productId.trim(),
|
|
1732
|
-
[
|
|
1727
|
+
[isCustomerSelfServeChange, changeFlowBookingParentProductIdForFloors, product.productId],
|
|
1733
1728
|
);
|
|
1734
1729
|
|
|
1735
1730
|
useEffect(() => {
|
|
@@ -2585,7 +2580,7 @@ export function AdminChangeBookingFlow({
|
|
|
2585
2580
|
latestChangeQuote?.serverPreview?.returnOptionPriceByReturnAvailabilityId,
|
|
2586
2581
|
]);
|
|
2587
2582
|
|
|
2588
|
-
/** Order-summary return row uses self-serve floors via [selectedReturnOptionWithFloor]
|
|
2583
|
+
/** Order-summary return row uses self-serve floors via [selectedReturnOptionWithFloor] when `isCustomerSelfServeChange`. */
|
|
2589
2584
|
const returnOptionForOrderSummary = useMemo(
|
|
2590
2585
|
() => selectedReturnOptionWithFloor,
|
|
2591
2586
|
[selectedReturnOptionWithFloor],
|
|
@@ -2839,7 +2834,7 @@ export function AdminChangeBookingFlow({
|
|
|
2839
2834
|
*/
|
|
2840
2835
|
const changeFlowProtectedReturnAdjustment = useMemo(() => {
|
|
2841
2836
|
if (totalQuantity <= 0) return returnPriceAdjustment;
|
|
2842
|
-
if (
|
|
2837
|
+
if (!isCustomerSelfServeChange) return returnPriceAdjustment;
|
|
2843
2838
|
if (effectiveChangeFlowReturnUnitFloorPerPerson == null) return returnPriceAdjustment;
|
|
2844
2839
|
const livePerPerson =
|
|
2845
2840
|
returnOptionCatalogPerPerson ?? (selectedReturnOption?.priceAdjustmentByCurrency?.[currency] ?? 0);
|
|
@@ -2853,13 +2848,13 @@ export function AdminChangeBookingFlow({
|
|
|
2853
2848
|
}, [
|
|
2854
2849
|
totalQuantity,
|
|
2855
2850
|
returnPriceAdjustment,
|
|
2856
|
-
isProviderDashboardChange,
|
|
2857
2851
|
effectiveChangeFlowReturnUnitFloorPerPerson,
|
|
2858
2852
|
selectedReturnOption,
|
|
2859
2853
|
returnOptionCatalogPerPerson,
|
|
2860
2854
|
currency,
|
|
2861
2855
|
changeFlowInitialTicketCount,
|
|
2862
2856
|
changeFlowReturnPricingRuleA,
|
|
2857
|
+
isCustomerSelfServeChange,
|
|
2863
2858
|
]);
|
|
2864
2859
|
|
|
2865
2860
|
/** Return row amount for PriceSummary, Stripe breakdown, and CheckoutModal (catalog vs protected same-product-option). */
|
|
@@ -4476,49 +4471,6 @@ export function AdminChangeBookingFlow({
|
|
|
4476
4471
|
return;
|
|
4477
4472
|
}
|
|
4478
4473
|
|
|
4479
|
-
if (onChangeBooking && !deferProviderApplyToAdminPaymentChoice) {
|
|
4480
|
-
const pickupForChange = pickupLocationId
|
|
4481
|
-
? product.pickupLocations?.find((loc) => loc.id === pickupLocationId)
|
|
4482
|
-
: null;
|
|
4483
|
-
await onChangeBooking({
|
|
4484
|
-
productId: availabilityProductOptionId,
|
|
4485
|
-
dateTime: selectedAvailability.dateTime,
|
|
4486
|
-
bookingItems,
|
|
4487
|
-
returnAvailabilityId: selectedReturnOption?.returnAvailabilityId ?? null,
|
|
4488
|
-
pickupLocationId: pickupLocationId ?? null,
|
|
4489
|
-
travelerHotel: pickupForChange?.name ?? null,
|
|
4490
|
-
startTime: selectedAvailability.dateTime ?? null,
|
|
4491
|
-
passengerCount: null,
|
|
4492
|
-
childSafetySeatsCount: null,
|
|
4493
|
-
foodRestrictions: null,
|
|
4494
|
-
addOnSelections: addOnSelections.length > 0 ? addOnSelections : null,
|
|
4495
|
-
cancellationPolicyId: cancellationPolicyId ?? initialValues?.cancellationPolicyId ?? null,
|
|
4496
|
-
promoCode: appliedPromoCode ?? null,
|
|
4497
|
-
newTotalAmount: displayChangeFlowProposedTotal,
|
|
4498
|
-
additionalHoursCount: null,
|
|
4499
|
-
pricingAdjustment:
|
|
4500
|
-
providerPricingOverrides.length > 0 || providerAdditionalAdjustments.length > 0
|
|
4501
|
-
? {
|
|
4502
|
-
mode: 'MANUAL_LINES',
|
|
4503
|
-
lineOverrides: providerPricingOverrides,
|
|
4504
|
-
additionalAdjustments: providerAdditionalAdjustments,
|
|
4505
|
-
}
|
|
4506
|
-
: undefined,
|
|
4507
|
-
capacitySeatCredit: {
|
|
4508
|
-
enabled: true,
|
|
4509
|
-
previousPassengerCount: changeFlowInitialTicketCount,
|
|
4510
|
-
previousAvailabilityId: initialValues?.availabilityId ?? null,
|
|
4511
|
-
previousReturnAvailabilityId: initialValues?.returnAvailabilityId ?? null,
|
|
4512
|
-
},
|
|
4513
|
-
});
|
|
4514
|
-
const refAfterChange = initialValues?.bookingReference?.trim();
|
|
4515
|
-
if (refAfterChange) {
|
|
4516
|
-
onSuccess?.({ reservationReference: refAfterChange });
|
|
4517
|
-
}
|
|
4518
|
-
setLoading(false);
|
|
4519
|
-
return;
|
|
4520
|
-
}
|
|
4521
|
-
|
|
4522
4474
|
const bookingSourceContext = buildBookingSourceContext(bookingSourceAttribution, {
|
|
4523
4475
|
clientChannelSource: inferClientBookingSourceFromProductIds(
|
|
4524
4476
|
product.productId,
|
|
@@ -4836,22 +4788,31 @@ export function AdminChangeBookingFlow({
|
|
|
4836
4788
|
reservationExpiration: undefined,
|
|
4837
4789
|
customerLastName: lastName.trim(),
|
|
4838
4790
|
bookingDate: datePart,
|
|
4839
|
-
// Paid change:
|
|
4840
|
-
//
|
|
4791
|
+
// Paid change: customer site returns to /manage-booking with change_payment intent.
|
|
4792
|
+
// Provider dashboard embed uses getSuccessUrl (same as main booking tab) so Stripe does not 404 on /manage-booking.
|
|
4841
4793
|
successUrlOverride:
|
|
4842
4794
|
isCustomerSelfServeChange && changeBookingReferenceForPaidFlow
|
|
4843
|
-
?
|
|
4844
|
-
|
|
4845
|
-
|
|
4846
|
-
|
|
4847
|
-
|
|
4848
|
-
|
|
4849
|
-
|
|
4850
|
-
|
|
4851
|
-
|
|
4852
|
-
: '';
|
|
4853
|
-
|
|
4854
|
-
|
|
4795
|
+
? bookingAppMode === 'provider-dashboard' && getSuccessUrl
|
|
4796
|
+
? getSuccessUrl({
|
|
4797
|
+
reservationRef:
|
|
4798
|
+
formatBookingRefForDisplay(changeBookingReferenceForPaidFlow) ||
|
|
4799
|
+
changeBookingReferenceForPaidFlow,
|
|
4800
|
+
lastName: lastName.trim(),
|
|
4801
|
+
focusDate: datePart,
|
|
4802
|
+
})
|
|
4803
|
+
: (() => {
|
|
4804
|
+
const origin = typeof window !== 'undefined' ? window.location.origin : '';
|
|
4805
|
+
const ref = encodeURIComponent(
|
|
4806
|
+
formatBookingRefForDisplay(changeBookingReferenceForPaidFlow) ||
|
|
4807
|
+
changeBookingReferenceForPaidFlow,
|
|
4808
|
+
);
|
|
4809
|
+
const ln = encodeURIComponent(lastName.trim());
|
|
4810
|
+
const fromQ = `${MANAGE_BOOKING_QUERY_FROM}=${encodeURIComponent(MANAGE_BOOKING_FROM_CHANGE_PAYMENT)}`;
|
|
4811
|
+
const intentQ = changeIntentIdForCheckout
|
|
4812
|
+
? `&changeIntentId=${encodeURIComponent(changeIntentIdForCheckout)}`
|
|
4813
|
+
: '';
|
|
4814
|
+
return `${origin}/manage-booking?ref=${ref}&lastName=${ln}&${fromQ}${intentQ}`;
|
|
4815
|
+
})()
|
|
4855
4816
|
: undefined,
|
|
4856
4817
|
ticketLines: ticketLinesForModal,
|
|
4857
4818
|
feeLineItems: feeLineItemsWithAddOns,
|
|
@@ -4992,6 +4953,7 @@ export function AdminChangeBookingFlow({
|
|
|
4992
4953
|
previousAvailabilityId: initialValues?.availabilityId ?? null,
|
|
4993
4954
|
previousReturnAvailabilityId: initialValues?.returnAvailabilityId ?? null,
|
|
4994
4955
|
},
|
|
4956
|
+
deferPaymentToBalance: true,
|
|
4995
4957
|
});
|
|
4996
4958
|
const bookRef = initialValues?.bookingReference?.trim() || adminChoiceData.reservationReference;
|
|
4997
4959
|
setShowAdminPaymentChoice(false);
|
|
@@ -28,6 +28,11 @@ export type ProviderDashboardChangeBookingPayload = {
|
|
|
28
28
|
previousAvailabilityId?: string | null;
|
|
29
29
|
previousReturnAvailabilityId?: string | null;
|
|
30
30
|
} | null;
|
|
31
|
+
/**
|
|
32
|
+
* When true, apply the change now but do not run an immediate card charge: record the amount still
|
|
33
|
+
* owed (e.g. pending charge on file) and update the receipt. Provider /change API must support this.
|
|
34
|
+
*/
|
|
35
|
+
deferPaymentToBalance?: boolean;
|
|
31
36
|
};
|
|
32
37
|
|
|
33
38
|
/** Seeds the flow when opening provider change-booking (matches TicketBooth `BookingWidget` `initialBooking`). */
|
|
@@ -5,9 +5,9 @@
|
|
|
5
5
|
* channel) on top of these formulas.
|
|
6
6
|
*
|
|
7
7
|
* ### 1. When receipt “paid floors” apply
|
|
8
|
-
*
|
|
9
|
-
* (`
|
|
10
|
-
*
|
|
8
|
+
* When the booking’s **parent catalog product** matches the **loaded product** and the flow uses the public
|
|
9
|
+
* `POST .../change/quote` path (`isCustomerSelfServeChange` in AdminChangeBookingFlow, including provider dashboard with
|
|
10
|
+
* `onChangeBooking`).
|
|
11
11
|
*
|
|
12
12
|
* ### 2. Tickets (per category)
|
|
13
13
|
* **Unchanged itinerary** (same calendar departure date **and** same product option as the booking): among seats up to the
|
|
@@ -26,12 +26,12 @@
|
|
|
26
26
|
* BE `PublicChangeBookingQuotePricing`: **baseline party** (originally booked headcount) vs **incremental** seats. **Rule A**
|
|
27
27
|
* (same `returnAvailabilityId` as the booking **and** unchanged outbound itinerary): protected pay exact locked per person;
|
|
28
28
|
* incremental pay **live catalog** return only ($0 when free). **Else Rule B:** protected pay **`max(floor, live)`**;
|
|
29
|
-
* incremental pay **live** only.
|
|
29
|
+
* incremental pay **live** only.
|
|
30
30
|
*
|
|
31
31
|
* ### 5. Return option — **picker UI only** (BookingFlow)
|
|
32
32
|
* **Self-serve:** return cards use the floored per-person price when a floor exists (aligned with §4), for every return
|
|
33
33
|
* slot, regardless of date/option change.
|
|
34
|
-
*
|
|
34
|
+
* With `POST .../change/quote`, return cards follow the same floor behavior as self-serve.
|
|
35
35
|
*
|
|
36
36
|
* ### 6. Quote “new booking” total & balance
|
|
37
37
|
* **FE proposed total** = full cart math (subtotal + tax − promo), cent-rounded; optional **1¢ reconcile** to old receipt
|