@ticketboothapp/booking 1.2.75 → 1.2.76
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
|
@@ -126,6 +126,9 @@ function mergeQuoteSliceWithServerPreview(
|
|
|
126
126
|
serverPreview: buildChangeBookingServerPreview(quote, fallbackCart, currency),
|
|
127
127
|
pricingDriftDetail: normalizePricingDriftDetailFromQuote(quote),
|
|
128
128
|
ticketPricingTrace: normalizeTicketPricingTraceFromQuote(quote),
|
|
129
|
+
/** Same cent pair the BE uses for `amountDueCents` / intent & receipt "New Booking Difference" — use for signed refund display. */
|
|
130
|
+
quotePreviousTotalCents: quote.previousTotalCents,
|
|
131
|
+
quoteNewTotalCents: quote.newTotalCents,
|
|
129
132
|
};
|
|
130
133
|
}
|
|
131
134
|
|
|
@@ -852,9 +855,10 @@ export function AdminChangeBookingFlow({
|
|
|
852
855
|
const lockedPromoCode = initialValues?.promoCode?.trim()
|
|
853
856
|
? initialValues.promoCode.trim().toUpperCase()
|
|
854
857
|
: null;
|
|
855
|
-
/** Public self-serve only: cannot reduce tickets below original counts. */
|
|
858
|
+
/** Public self-serve only: cannot reduce tickets below original counts. Provider-dashboard admins may reduce party size. */
|
|
856
859
|
const changeBookingMinimumQuantities = useMemo(() => {
|
|
857
860
|
if (!isCustomerSelfServeChange || !initialValues?.bookingItems?.length) return undefined;
|
|
861
|
+
if (isAdmin && isProviderDashboardChange) return undefined;
|
|
858
862
|
const m: Record<string, number> = {};
|
|
859
863
|
for (const item of initialValues.bookingItems) {
|
|
860
864
|
const key = item.category?.trim();
|
|
@@ -862,7 +866,7 @@ export function AdminChangeBookingFlow({
|
|
|
862
866
|
m[key] = Math.max(0, Number(item.count) || 0);
|
|
863
867
|
}
|
|
864
868
|
return m;
|
|
865
|
-
}, [isCustomerSelfServeChange, initialValues?.bookingItems]);
|
|
869
|
+
}, [isCustomerSelfServeChange, initialValues?.bookingItems, isAdmin, isProviderDashboardChange]);
|
|
866
870
|
const [adminChoiceData, setAdminChoiceData] = useState<{
|
|
867
871
|
reservationReference: string;
|
|
868
872
|
reservationExpiration?: string;
|
|
@@ -895,6 +899,9 @@ export function AdminChangeBookingFlow({
|
|
|
895
899
|
quotedTotal?: number;
|
|
896
900
|
/** From `quoteChangeBooking` receipt fields — drives PriceSummary when self-serve. */
|
|
897
901
|
serverDisplay?: { total: number; subtotal: number; tax: number };
|
|
902
|
+
/** Server quote cents — authoritative vs `serverDisplay` scaling (aligns with receipt difference line). */
|
|
903
|
+
quotePreviousTotalCents?: number;
|
|
904
|
+
quoteNewTotalCents?: number;
|
|
898
905
|
/** Parsed from last quote — unified server-owned preview for lines + picker overrides. */
|
|
899
906
|
serverPreview: ReturnType<typeof buildChangeBookingServerPreview>;
|
|
900
907
|
pricingDriftDetail?: ChangeBookingQuotePricingDriftDetail;
|
|
@@ -3687,6 +3694,23 @@ export function AdminChangeBookingFlow({
|
|
|
3687
3694
|
providerHasAdditionalAdjustments ||
|
|
3688
3695
|
Math.abs(adminCustomAdjustmentTotal) >= 0.005;
|
|
3689
3696
|
|
|
3697
|
+
/**
|
|
3698
|
+
* True until `quoteChangeBooking` returns a confirmed `serverDisplay` for the current selection.
|
|
3699
|
+
* Named so manual price-line UI can align with “still settling final price” without touching ticket/receipt math.
|
|
3700
|
+
*/
|
|
3701
|
+
const changeFlowFinalPricePending =
|
|
3702
|
+
suppressSelfServeCurrencyUi &&
|
|
3703
|
+
selectedAvailability != null &&
|
|
3704
|
+
totalQuantity > 0 &&
|
|
3705
|
+
!selfServePricingConfirmed;
|
|
3706
|
+
|
|
3707
|
+
/**
|
|
3708
|
+
* Provider inline edits + admin custom lines: show while waiting on or after the authoritative quote.
|
|
3709
|
+
* UI-only gate — does not alter ticket line items or receipt-floor rules.
|
|
3710
|
+
*/
|
|
3711
|
+
const showChangeFlowManualPriceLines =
|
|
3712
|
+
changeFlowFinalPricePending || selfServePricingConfirmed;
|
|
3713
|
+
|
|
3690
3714
|
const displayedChangeAmountsRaw = resolveChangeFlowDisplayedAmounts({
|
|
3691
3715
|
providerPreview: providerTotalsPreview,
|
|
3692
3716
|
serverQuotePreview:
|
|
@@ -3713,25 +3737,112 @@ export function AdminChangeBookingFlow({
|
|
|
3713
3737
|
);
|
|
3714
3738
|
const displayChangeFlowTax = roundMoney(displayedChangeAmountsRaw.tax + adminTaxDeltaForExternalDisplay);
|
|
3715
3739
|
const displayChangeFlowProposedTotal = roundMoney(
|
|
3716
|
-
|
|
3740
|
+
displayLayerUsesExternalPricing
|
|
3741
|
+
? displayedChangeAmountsRaw.total + adminCustomAdjustmentTotal + adminTaxDeltaForExternalDisplay
|
|
3742
|
+
: displayedChangeAmountsRaw.total
|
|
3717
3743
|
);
|
|
3718
3744
|
|
|
3719
3745
|
const changeFlowClientEstimateDue = (() => {
|
|
3720
3746
|
if (!originalReceipt) return totalPrice;
|
|
3721
|
-
//
|
|
3747
|
+
// Self-serve quote: match BE receipt / intent: (newTotalCents − previousTotalCents) / 100.
|
|
3722
3748
|
if (isCustomerSelfServeChange && latestChangeQuote != null && !changeQuoteFetchError) {
|
|
3749
|
+
const pq = latestChangeQuote.quotePreviousTotalCents;
|
|
3750
|
+
const nq = latestChangeQuote.quoteNewTotalCents;
|
|
3751
|
+
if (pq != null && nq != null) {
|
|
3752
|
+
return normalizeNearZeroOwed(roundMoney((nq - pq) / 100));
|
|
3753
|
+
}
|
|
3754
|
+
if (latestChangeQuote.serverDisplay != null) {
|
|
3755
|
+
return normalizeNearZeroOwed(
|
|
3756
|
+
roundMoney(latestChangeQuote.serverDisplay.total - originalReceipt.total),
|
|
3757
|
+
);
|
|
3758
|
+
}
|
|
3723
3759
|
return normalizeNearZeroOwed(latestChangeQuote.priceDiff);
|
|
3724
3760
|
}
|
|
3725
3761
|
return changeFlowBalanceVsOriginal({
|
|
3726
3762
|
newTotal: displayChangeFlowProposedTotal,
|
|
3727
3763
|
originalReceiptTotal: originalReceipt.total,
|
|
3728
|
-
audience:
|
|
3764
|
+
audience: 'admin',
|
|
3729
3765
|
});
|
|
3730
3766
|
})();
|
|
3731
3767
|
|
|
3732
3768
|
const changeFlowAmountDueRaw = changeFlowClientEstimateDue;
|
|
3733
3769
|
const changeFlowAmountDue = normalizeNearZeroOwed(changeFlowAmountDueRaw);
|
|
3734
3770
|
|
|
3771
|
+
const changeFlowAdminPricingDebugPanel = useMemo(() => {
|
|
3772
|
+
if (!isAdmin || !selectedAvailability || totalQuantity <= 0) return null;
|
|
3773
|
+
const fmt = (n: number) => formatCurrencyAmount(roundMoney(n), currency, locale as 'en' | 'fr');
|
|
3774
|
+
const path = (() => {
|
|
3775
|
+
if (!originalReceipt) return 'totalPrice (no original receipt)';
|
|
3776
|
+
if (isCustomerSelfServeChange && latestChangeQuote != null && !changeQuoteFetchError) {
|
|
3777
|
+
if (
|
|
3778
|
+
latestChangeQuote.quotePreviousTotalCents != null &&
|
|
3779
|
+
latestChangeQuote.quoteNewTotalCents != null
|
|
3780
|
+
) {
|
|
3781
|
+
return 'POST /change/quote: (quoteNewTotalCents − quotePreviousTotalCents) / 100';
|
|
3782
|
+
}
|
|
3783
|
+
if (latestChangeQuote.serverDisplay != null) {
|
|
3784
|
+
return 'POST /change/quote: serverDisplay.total − originalReceipt.total';
|
|
3785
|
+
}
|
|
3786
|
+
return 'POST /change/quote: priceDiff (API balance delta)';
|
|
3787
|
+
}
|
|
3788
|
+
return 'FE: displayChangeFlowProposedTotal − originalReceipt.total (signed; used when quote not driving amount-due)';
|
|
3789
|
+
})();
|
|
3790
|
+
const quoteTotalPreview =
|
|
3791
|
+
latestChangeQuote?.serverDisplay != null ? fmt(latestChangeQuote.serverDisplay.total) : '—';
|
|
3792
|
+
return (
|
|
3793
|
+
<details className="mt-3 rounded-md border border-amber-200/80 bg-amber-50/50 p-2 text-left text-xs text-amber-950">
|
|
3794
|
+
<summary className="cursor-pointer select-none font-medium text-stone-800">
|
|
3795
|
+
Price calculation (admin debug)
|
|
3796
|
+
</summary>
|
|
3797
|
+
<pre className="mt-2 max-h-64 overflow-auto whitespace-pre-wrap break-words font-mono text-[11px] leading-relaxed text-stone-800">
|
|
3798
|
+
{[
|
|
3799
|
+
`Amount-due path: ${path}`,
|
|
3800
|
+
`displayLayerUsesExternalPricing: ${String(displayLayerUsesExternalPricing)} (server/provider totals omit FE admin lines until overlaid)`,
|
|
3801
|
+
`selfServePricingConfirmed: ${String(selfServePricingConfirmed)} · changeQuoteLoading: ${String(changeQuoteLoading)}`,
|
|
3802
|
+
`Cart subtotal (excl. admin custom lines): ${fmt(effectiveSubtotal)}`,
|
|
3803
|
+
`Admin custom lines (sum): ${fmt(adminCustomAdjustmentTotal)}`,
|
|
3804
|
+
`Checkout subtotal (incl. admin lines): ${fmt(effectiveSubtotalForCheckout)}`,
|
|
3805
|
+
`effectiveTax · promo discount: ${fmt(effectiveTax)} · ${fmt(effectivePromoDiscountAmount)}`,
|
|
3806
|
+
`totalPrice (subtotal + tax − promo): ${fmt(totalPrice)}`,
|
|
3807
|
+
`changeFlowNewBookingTotal (after cent reconcile vs receipt): ${fmt(changeFlowNewBookingTotal)}`,
|
|
3808
|
+
`Displayed layer subtotal / tax / total: ${fmt(displayedChangeAmountsRaw.subtotal)} / ${fmt(displayedChangeAmountsRaw.tax)} / ${fmt(displayedChangeAmountsRaw.total)}`,
|
|
3809
|
+
`displayChangeFlowProposedTotal (summary / preview footer): ${fmt(displayChangeFlowProposedTotal)}`,
|
|
3810
|
+
originalReceipt ? `originalReceipt.total: ${fmt(originalReceipt.total)}` : 'originalReceipt: —',
|
|
3811
|
+
`Quote serverDisplay.total (if any): ${quoteTotalPreview}`,
|
|
3812
|
+
`changeFlowClientEstimateDue (before near-zero): ${fmt(changeFlowClientEstimateDue)}`,
|
|
3813
|
+
`changeFlowAmountDue (PriceSummary total row): ${fmt(changeFlowAmountDue)}`,
|
|
3814
|
+
].join('\n')}
|
|
3815
|
+
</pre>
|
|
3816
|
+
</details>
|
|
3817
|
+
);
|
|
3818
|
+
}, [
|
|
3819
|
+
isAdmin,
|
|
3820
|
+
selectedAvailability,
|
|
3821
|
+
totalQuantity,
|
|
3822
|
+
currency,
|
|
3823
|
+
locale,
|
|
3824
|
+
originalReceipt,
|
|
3825
|
+
isCustomerSelfServeChange,
|
|
3826
|
+
latestChangeQuote,
|
|
3827
|
+
changeQuoteFetchError,
|
|
3828
|
+
displayLayerUsesExternalPricing,
|
|
3829
|
+
selfServePricingConfirmed,
|
|
3830
|
+
changeQuoteLoading,
|
|
3831
|
+
effectiveSubtotal,
|
|
3832
|
+
adminCustomAdjustmentTotal,
|
|
3833
|
+
effectiveSubtotalForCheckout,
|
|
3834
|
+
effectiveTax,
|
|
3835
|
+
effectivePromoDiscountAmount,
|
|
3836
|
+
totalPrice,
|
|
3837
|
+
changeFlowNewBookingTotal,
|
|
3838
|
+
displayedChangeAmountsRaw.subtotal,
|
|
3839
|
+
displayedChangeAmountsRaw.tax,
|
|
3840
|
+
displayedChangeAmountsRaw.total,
|
|
3841
|
+
displayChangeFlowProposedTotal,
|
|
3842
|
+
changeFlowClientEstimateDue,
|
|
3843
|
+
changeFlowAmountDue,
|
|
3844
|
+
]);
|
|
3845
|
+
|
|
3735
3846
|
const changeCheckoutButtonLabel = (() => {
|
|
3736
3847
|
if (!hasEffectiveChangeSelection) return undefined;
|
|
3737
3848
|
if (isProviderDashboardChange) {
|
|
@@ -3759,7 +3870,9 @@ export function AdminChangeBookingFlow({
|
|
|
3759
3870
|
const d = Math.round(changeFlowClientEstimateDue * 100) / 100;
|
|
3760
3871
|
return d > 0
|
|
3761
3872
|
? `Change booking (${formatCurrencyAmount(d, currency, locale as 'en' | 'fr')})`
|
|
3762
|
-
:
|
|
3873
|
+
: d < 0
|
|
3874
|
+
? `Change booking (${formatCurrencyAmount(d, currency, locale as 'en' | 'fr')})`
|
|
3875
|
+
: 'Change booking (no charge)';
|
|
3763
3876
|
}
|
|
3764
3877
|
const tr = t('booking.changeBooking');
|
|
3765
3878
|
return tr !== 'booking.changeBooking' ? tr : 'Change booking';
|
|
@@ -3767,7 +3880,9 @@ export function AdminChangeBookingFlow({
|
|
|
3767
3880
|
const est = Math.round(changeFlowClientEstimateDue * 100) / 100;
|
|
3768
3881
|
return est > 0
|
|
3769
3882
|
? `Change booking (${formatCurrencyAmount(est, currency, locale as 'en' | 'fr')})`
|
|
3770
|
-
:
|
|
3883
|
+
: est < 0
|
|
3884
|
+
? `Change booking (${formatCurrencyAmount(est, currency, locale as 'en' | 'fr')})`
|
|
3885
|
+
: 'Change booking (no charge)';
|
|
3771
3886
|
})();
|
|
3772
3887
|
/** Partner deferred-invoice path applies to {@link NewBookingFlow} only. */
|
|
3773
3888
|
const deferredInvoiceSubmitLabel = undefined;
|
|
@@ -4611,30 +4726,41 @@ export function AdminChangeBookingFlow({
|
|
|
4611
4726
|
quote.proposed?.total ??
|
|
4612
4727
|
quote.newReceipt?.total ??
|
|
4613
4728
|
changeFlowNewBookingTotal;
|
|
4614
|
-
|
|
4615
|
-
|
|
4616
|
-
|
|
4617
|
-
|
|
4618
|
-
|
|
4619
|
-
const
|
|
4620
|
-
|
|
4621
|
-
? Math.max(0,
|
|
4622
|
-
:
|
|
4623
|
-
|
|
4729
|
+
/** Signed proposed − previous (major units). Matches quote slices when cents present; refund owed < 0. */
|
|
4730
|
+
const signedBalanceMajor =
|
|
4731
|
+
quote.previousTotalCents != null && quote.newTotalCents != null
|
|
4732
|
+
? (quote.newTotalCents - quote.previousTotalCents) / 100
|
|
4733
|
+
: quote.balanceDeltaMajorUnits ?? null;
|
|
4734
|
+
const chargeDue =
|
|
4735
|
+
signedBalanceMajor != null
|
|
4736
|
+
? Math.max(0, signedBalanceMajor)
|
|
4737
|
+
: quote.amountDueCents != null
|
|
4738
|
+
? quote.amountDueCents / 100
|
|
4739
|
+
: Math.max(0, quote.priceDiff ?? 0);
|
|
4740
|
+
const feChangeDue =
|
|
4741
|
+
signedBalanceMajor ??
|
|
4742
|
+
changeFlowBalanceVsOriginal({
|
|
4743
|
+
newTotal: serverNewTotalForGuard,
|
|
4744
|
+
originalReceiptTotal: originalReceipt?.total ?? 0,
|
|
4745
|
+
audience: 'admin',
|
|
4746
|
+
});
|
|
4747
|
+
if (feChangeDue > 0.02 && chargeDue <= 0.009) {
|
|
4624
4748
|
throw new Error(
|
|
4625
4749
|
'This change requires payment, but the price could not be confirmed. Please refresh and try again.'
|
|
4626
4750
|
);
|
|
4627
4751
|
}
|
|
4628
|
-
// No
|
|
4629
|
-
if (
|
|
4752
|
+
// No additional charge (includes refund-owed / downgrade): confirm-free apply only when server agrees no payment due.
|
|
4753
|
+
if (chargeDue <= 0.009) {
|
|
4630
4754
|
if (feChangeDue > 0.02) {
|
|
4631
4755
|
throw new Error(
|
|
4632
4756
|
'This change requires payment, but the price could not be confirmed. Please refresh and try again.'
|
|
4633
4757
|
);
|
|
4634
4758
|
}
|
|
4635
|
-
const
|
|
4636
|
-
|
|
4637
|
-
|
|
4759
|
+
const upgradeWithoutCharge =
|
|
4760
|
+
quote.newTotalCents != null &&
|
|
4761
|
+
quote.previousTotalCents != null &&
|
|
4762
|
+
quote.newTotalCents > quote.previousTotalCents + 1;
|
|
4763
|
+
if (upgradeWithoutCharge) {
|
|
4638
4764
|
throw new Error(
|
|
4639
4765
|
'This change requires payment, but the price could not be confirmed. Please refresh and try again.'
|
|
4640
4766
|
);
|
|
@@ -4686,11 +4812,14 @@ export function AdminChangeBookingFlow({
|
|
|
4686
4812
|
// Backend will charge totalAmount and store this as the receipt so /manage matches.
|
|
4687
4813
|
const taxForBreakdown = effectivePromoDiscountAmount > 0 ? effectiveTax : tax;
|
|
4688
4814
|
const amountDueForCheckout = isCustomerSelfServeChange
|
|
4689
|
-
?
|
|
4690
|
-
|
|
4691
|
-
|
|
4692
|
-
|
|
4693
|
-
|
|
4815
|
+
? Math.max(
|
|
4816
|
+
0,
|
|
4817
|
+
changeFlowBalanceVsOriginal({
|
|
4818
|
+
newTotal: changeFlowNewBookingTotal,
|
|
4819
|
+
originalReceiptTotal: originalReceipt?.total ?? 0,
|
|
4820
|
+
audience: 'admin',
|
|
4821
|
+
}),
|
|
4822
|
+
)
|
|
4694
4823
|
: totalPrice;
|
|
4695
4824
|
const lines = [
|
|
4696
4825
|
...ticketLineItemsForChangeFlowDisplay.map((line) => ({
|
|
@@ -5406,10 +5535,12 @@ export function AdminChangeBookingFlow({
|
|
|
5406
5535
|
replacePriceSummary={selfServeCheckoutPlaceholder}
|
|
5407
5536
|
totalPrice={changeFlowAmountDue}
|
|
5408
5537
|
totalSummaryLabel={
|
|
5409
|
-
|
|
5410
|
-
|
|
5411
|
-
|
|
5412
|
-
|
|
5538
|
+
changeFlowAmountDue < -0.005
|
|
5539
|
+
? 'Refund owed (vs original booking)'
|
|
5540
|
+
: t('booking.totalOwedForBookingChange') &&
|
|
5541
|
+
t('booking.totalOwedForBookingChange') !== 'booking.totalOwedForBookingChange'
|
|
5542
|
+
? t('booking.totalOwedForBookingChange')
|
|
5543
|
+
: 'Total owed for booking difference'
|
|
5413
5544
|
}
|
|
5414
5545
|
subtotal={displayChangeFlowSubtotal}
|
|
5415
5546
|
taxAmount={
|
|
@@ -5438,9 +5569,11 @@ export function AdminChangeBookingFlow({
|
|
|
5438
5569
|
!providerPricingUi.error ? (
|
|
5439
5570
|
<div className="mt-2 text-xs text-stone-500">{providerPricingUi.helperText}</div>
|
|
5440
5571
|
) : null}
|
|
5572
|
+
{changeFlowAdminPricingDebugPanel}
|
|
5441
5573
|
</>
|
|
5442
5574
|
}
|
|
5443
5575
|
extraBeforeSubtotal={
|
|
5576
|
+
showChangeFlowManualPriceLines ? (
|
|
5444
5577
|
<>
|
|
5445
5578
|
{showProviderPricingInlineEditor && (providerPricingUi?.additionalAdjustments?.length ?? 0) > 0 ? (
|
|
5446
5579
|
<div className="space-y-1">
|
|
@@ -5623,6 +5756,7 @@ export function AdminChangeBookingFlow({
|
|
|
5623
5756
|
})}
|
|
5624
5757
|
</div>
|
|
5625
5758
|
</>
|
|
5759
|
+
) : null
|
|
5626
5760
|
}
|
|
5627
5761
|
firstName={firstName}
|
|
5628
5762
|
lastName={lastName}
|
|
@@ -146,6 +146,7 @@ export function CheckoutForm({
|
|
|
146
146
|
<div className={styles.summaryWrapper}>
|
|
147
147
|
{replacePriceSummary ? (
|
|
148
148
|
<>
|
|
149
|
+
{extraBeforeSubtotal ? <div className="mb-4 min-w-0">{extraBeforeSubtotal}</div> : null}
|
|
149
150
|
{replacePriceSummary}
|
|
150
151
|
<div className="mt-4">{extraBetweenTaxAndTotal}</div>
|
|
151
152
|
</>
|
|
@@ -178,16 +178,16 @@ export function resolveChangeFlowNewBookingTotal(input: {
|
|
|
178
178
|
|
|
179
179
|
/**
|
|
180
180
|
* Product: **What the customer owes** for the difference is `max(0, newTotal − oldReceipt)`.
|
|
181
|
-
* **Provider dashboard** may show a signed delta (
|
|
181
|
+
* **Provider dashboard** and **admin change booking** may show a signed delta (refund owed as negative).
|
|
182
182
|
*/
|
|
183
183
|
export function changeFlowBalanceVsOriginal(input: {
|
|
184
184
|
newTotal: number;
|
|
185
185
|
originalReceiptTotal: number;
|
|
186
|
-
/** `customer` = self-serve
|
|
187
|
-
audience: 'customer' | 'provider';
|
|
186
|
+
/** `customer` = self-serve change only; `provider` | `admin` = signed newTotal − original receipt total. */
|
|
187
|
+
audience: 'customer' | 'provider' | 'admin';
|
|
188
188
|
}): number {
|
|
189
189
|
const delta = input.newTotal - input.originalReceiptTotal;
|
|
190
|
-
return input.audience === '
|
|
190
|
+
return input.audience === 'customer' ? Math.max(0, delta) : delta;
|
|
191
191
|
}
|
|
192
192
|
|
|
193
193
|
/**
|
|
@@ -255,8 +255,13 @@ export function sliceChangeQuoteForUi(
|
|
|
255
255
|
fallbackCart: { total: number; subtotal: number; tax: number },
|
|
256
256
|
currencyFallback: string
|
|
257
257
|
): ChangeQuoteUiSlice {
|
|
258
|
+
/** Staff JWT on quote: signed new − previous (refund owed negative). Otherwise same as legacy nonnegative amount-due. */
|
|
258
259
|
const priceDiff =
|
|
259
|
-
quote.
|
|
260
|
+
quote.balanceDeltaMajorUnits != null
|
|
261
|
+
? quote.balanceDeltaMajorUnits
|
|
262
|
+
: quote.amountDueCents != null
|
|
263
|
+
? quote.amountDueCents / 100
|
|
264
|
+
: quote.priceDiff ?? 0;
|
|
260
265
|
const serverDisplay = serverTotalsFromChangeQuoteResponse(quote, fallbackCart);
|
|
261
266
|
return {
|
|
262
267
|
priceDiff,
|
package/src/lib/booking-api.ts
CHANGED
|
@@ -987,6 +987,11 @@ export interface ChangeBookingQuoteResponse {
|
|
|
987
987
|
originalReceipt?: ChangeBookingQuoteReceipt;
|
|
988
988
|
newReceipt?: ChangeBookingQuoteReceipt;
|
|
989
989
|
priceDiff: number;
|
|
990
|
+
/**
|
|
991
|
+
* Present when the quote was requested with a **staff** JWT: signed (new total − previous receipt total) in major units.
|
|
992
|
+
* Negative = refund owed to the guest. Omitted for unauthenticated / customer-only quotes.
|
|
993
|
+
*/
|
|
994
|
+
balanceDeltaMajorUnits?: number;
|
|
990
995
|
currency?: string;
|
|
991
996
|
canProceed?: boolean;
|
|
992
997
|
reasonIfBlocked?: string;
|