@ticketboothapp/booking 1.2.153 → 1.2.154

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
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ticketboothapp/booking",
3
- "version": "1.2.153",
3
+ "version": "1.2.154",
4
4
  "private": false,
5
5
  "sideEffects": [
6
6
  "**/*.css",
@@ -1058,7 +1058,11 @@ export function AdminChangeBookingFlow({
1058
1058
  serverAmendmentLines: latestChangeQuote?.serverPreview?.priceSummaryLines ?? null,
1059
1059
  serverAmountDue: latestChangeQuote?.serverPreview?.amountDue ?? null,
1060
1060
  serverUpdatedTotal: latestChangeQuote?.serverPreview?.totalNewBooking ?? null,
1061
- serverQuoteError: changeQuoteFetchError,
1061
+ serverQuoteError:
1062
+ changeQuoteFetchError ??
1063
+ (isChangeQuoteBlocked
1064
+ ? (latestChangeQuote?.reasonIfBlocked ?? 'This change cannot be priced right now.')
1065
+ : null),
1062
1066
  refundDecisionOperations: activeRefundDecisionContext?.operations ?? [],
1063
1067
  allowedRefundDispositionsByOperationId:
1064
1068
  activeRefundDecisionContext?.allowedByOperationId ?? {},
@@ -153,7 +153,9 @@ export function useAdminChangeQuotePreview({
153
153
  !!initialValues?.bookingReference?.trim() &&
154
154
  !!lastName.trim();
155
155
 
156
- const isChangeQuoteBlocked = isCustomerSelfServeChange && latestChangeQuote?.canProceed === false;
156
+ const isChangeQuoteBlocked =
157
+ latestChangeQuote?.canProceed === false &&
158
+ (latestChangeQuote.refundDecisionOperations?.length ?? 0) === 0;
157
159
  const refundDecisionRequired = (latestChangeQuote?.refundDecisionOperations?.length ?? 0) > 0;
158
160
  const changeQuoteInputsKey = useMemo(() => buildAdminChangeQuoteRequestKey({
159
161
  bookingReference: initialValues?.bookingReference,
@@ -192,11 +194,19 @@ export function useAdminChangeQuotePreview({
192
194
  const changeCheckoutButtonLabel = (() => {
193
195
  if (!hasEffectiveChangeSelection) return undefined;
194
196
  if (isProviderDashboardChange) {
195
- const est = Math.round(changeFlowClientEstimateDue * 100) / 100;
196
- return est > 0
197
- ? `Change booking (${formatCurrencyAmount(est, currency, locale as 'en' | 'fr')})`
198
- : est < 0
199
- ? `Change booking (${formatCurrencyAmount(est, currency, locale as 'en' | 'fr')})`
197
+ if (isChangeQuoteBlocked) {
198
+ const tr = t('booking.changeBookingNotAvailable');
199
+ return tr !== 'booking.changeBookingNotAvailable' ? tr : 'Change not available';
200
+ }
201
+ // Prefer authoritative V2 signed due (charge positive / refund negative). Do not use the
202
+ // FE cart estimate once a server quote exists — receipt total deltas can disagree with
203
+ // floored/settlement amounts (DEFECT-PV2-018 follow-up).
204
+ const serverDue = latestChangeQuote?.serverPreview?.amountDue;
205
+ const due = Math.round((serverDue ?? changeFlowClientEstimateDue) * 100) / 100;
206
+ return due > 0
207
+ ? `Change booking (${formatCurrencyAmount(due, currency, locale as 'en' | 'fr')})`
208
+ : due < 0
209
+ ? `Change booking (${formatCurrencyAmount(due, currency, locale as 'en' | 'fr')})`
200
210
  : 'Change booking (no charge)';
201
211
  }
202
212
  if (changeFlowNeedsServerPrice) {
@@ -234,10 +244,10 @@ export function useAdminChangeQuotePreview({
234
244
  const checkoutFormError =
235
245
  (error || '') ||
236
246
  (missingRequiredReturnSelection ? 'Please select a return time for this product.' : '') ||
237
- (isCustomerSelfServeChange && isChangeQuoteBlocked && !refundDecisionRequired
238
- ? (latestChangeQuote?.reasonIfBlocked ?? '')
247
+ (isChangeQuoteBlocked && !refundDecisionRequired
248
+ ? (latestChangeQuote?.reasonIfBlocked ?? 'This change cannot be priced right now.')
239
249
  : '') ||
240
- (isCustomerSelfServeChange ? changeQuoteFetchError ?? '' : '');
250
+ (changeQuoteFetchError ?? '');
241
251
 
242
252
  const changeFlowSelectionPreview = useMemo((): ChangeFlowSelectionPreview | null => {
243
253
  if (!selectedAvailability || totalQuantity <= 0) return null;
@@ -251,12 +251,14 @@ export function mapQuoteLineItemsToPriceSummaryLines(
251
251
 
252
252
  function signedAmountDueFromQuote(quote: ChangeBookingQuoteResponse): number {
253
253
  const pricingQuote = quote.pricingQuote ?? quote.quote;
254
- if (quote.balanceDeltaMajorUnits != null) return quote.balanceDeltaMajorUnits;
255
- if (quote.balanceDelta != null) return quote.balanceDelta;
256
- if (pricingQuote?.balanceDelta != null) return pricingQuote.balanceDelta;
254
+ // Prefer explicit settlement fields over balanceDelta. Receipt-total math and balanceDelta
255
+ // can disagree with charge/refund when value is removed but not yet dispositioned.
257
256
  const charge = pricingQuote?.amountToCharge ?? quote.amountToCharge;
258
257
  const refund = pricingQuote?.refundCandidate ?? quote.refundCandidate;
259
258
  if (charge != null || refund != null) return (charge ?? 0) - (refund ?? 0);
259
+ if (quote.balanceDeltaMajorUnits != null) return quote.balanceDeltaMajorUnits;
260
+ if (quote.balanceDelta != null) return quote.balanceDelta;
261
+ if (pricingQuote?.balanceDelta != null) return pricingQuote.balanceDelta;
260
262
  if (quote.amountDueCents != null) return quote.amountDueCents / 100;
261
263
  return quote.priceDiff ?? 0;
262
264
  }
@@ -271,12 +271,14 @@ export function sliceChangeQuoteForUi(
271
271
  const pricingQuote = quote.pricingQuote ?? quote.quote;
272
272
  /** Staff JWT on quote: signed new − previous (refund owed negative). Otherwise same as legacy nonnegative amount-due. */
273
273
  const priceDiff = (() => {
274
+ const charge = quote.amountToCharge ?? pricingQuote?.amountToCharge;
275
+ const refund = quote.refundCandidate ?? pricingQuote?.refundCandidate;
276
+ if (charge != null || refund != null) {
277
+ return (charge ?? 0) - (refund ?? 0);
278
+ }
274
279
  if (quote.balanceDeltaMajorUnits != null) return quote.balanceDeltaMajorUnits;
275
280
  if (quote.balanceDelta != null) return quote.balanceDelta;
276
281
  if (pricingQuote?.balanceDelta != null) return pricingQuote.balanceDelta;
277
- if (quote.amountToCharge != null || quote.refundCandidate != null) {
278
- return (quote.amountToCharge ?? 0) - (quote.refundCandidate ?? 0);
279
- }
280
282
  if (quote.amountDueCents != null) return quote.amountDueCents / 100;
281
283
  return quote.priceDiff ?? 0;
282
284
  })();