@ticketboothapp/booking 1.2.114 → 1.2.116

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.114",
3
+ "version": "1.2.116",
4
4
  "private": false,
5
5
  "sideEffects": [
6
6
  "**/*.css",
@@ -3194,6 +3194,33 @@ export function AdminChangeBookingFlow({
3194
3194
  [quantities]
3195
3195
  );
3196
3196
 
3197
+ /** Fee rows shown in the editor must use the same receipt-floor math as the subtotal. */
3198
+ const feeLineItemsForChangeFlowDisplay = useMemo(() => {
3199
+ if (!changeFlowApplyReceiptPaidFloors || totalQuantity <= 0) return feeLineItems;
3200
+ const initialParty = changeFlowInitialTicketCount;
3201
+ return feeLineItems.map((line) => {
3202
+ const key = normalizeLineLabelForCompare(line.name || '');
3203
+ const bookedFeePerPerson = key ? changeFlowBookedFeeUnitByNormalizedLabel.get(key) : undefined;
3204
+ return {
3205
+ ...line,
3206
+ totalAmount: changeFlowFeeLineTotalWithReceiptFloor({
3207
+ totalQuantity,
3208
+ initialTicketCount: initialParty,
3209
+ bookedFeePerPerson,
3210
+ liveFeeLineTotal: Number(line.totalAmount) || 0,
3211
+ protectedReceiptPricing: changeFlowProtectedReceiptPricing,
3212
+ }),
3213
+ };
3214
+ });
3215
+ }, [
3216
+ changeFlowApplyReceiptPaidFloors,
3217
+ totalQuantity,
3218
+ feeLineItems,
3219
+ changeFlowInitialTicketCount,
3220
+ changeFlowBookedFeeUnitByNormalizedLabel,
3221
+ changeFlowProtectedReceiptPricing,
3222
+ ]);
3223
+
3197
3224
  // Fee line items including add-ons (for PriceSummary and CheckoutModal)
3198
3225
  const feeLineItemsWithAddOns = useMemo(() => {
3199
3226
  const addOnLines = addOnSelections
@@ -3210,8 +3237,8 @@ export function AdminChangeBookingFlow({
3210
3237
  return { name, totalAmount: amt, description: addOn.description ?? undefined };
3211
3238
  })
3212
3239
  .filter((x): x is NonNullable<typeof x> => x != null);
3213
- return [...feeLineItems, ...addOnLines];
3214
- }, [feeLineItems, addOnSelections, addOns]);
3240
+ return [...feeLineItemsForChangeFlowDisplay, ...addOnLines];
3241
+ }, [feeLineItemsForChangeFlowDisplay, addOnSelections, addOns]);
3215
3242
 
3216
3243
  const providerPricingUi = flowUi?.providerDashboardChangePricingUi;
3217
3244
  const providerQuotedLines = providerPricingUi?.quotedLines ?? [];
@@ -3298,7 +3325,7 @@ export function AdminChangeBookingFlow({
3298
3325
  showProviderPricingInlineEditor
3299
3326
  ? providerEditableLineByNormalizedLabel.get(
3300
3327
  normalizeReceiptLabel(
3301
- feeLineItems.some((f) => f.name === fee.name)
3328
+ feeLineItemsForChangeFlowDisplay.some((f) => f.name === fee.name)
3302
3329
  ? `${fee.name} (${totalQuantity} ${totalQuantity === 1 ? 'person' : 'people'})`
3303
3330
  : fee.name
3304
3331
  )
@@ -3308,12 +3335,12 @@ export function AdminChangeBookingFlow({
3308
3335
  showProviderPricingInlineEditor &&
3309
3336
  providerEditableLineByNormalizedLabel.has(
3310
3337
  normalizeReceiptLabel(
3311
- feeLineItems.some((f) => f.name === fee.name)
3338
+ feeLineItemsForChangeFlowDisplay.some((f) => f.name === fee.name)
3312
3339
  ? `${fee.name} (${totalQuantity} ${totalQuantity === 1 ? 'person' : 'people'})`
3313
3340
  : fee.name
3314
3341
  )
3315
3342
  ),
3316
- label: feeLineItems.some((f) => f.name === fee.name)
3343
+ label: feeLineItemsForChangeFlowDisplay.some((f) => f.name === fee.name)
3317
3344
  ? `${fee.name} (${totalQuantity} ${totalQuantity === 1 ? 'person' : 'people'})`
3318
3345
  : fee.name,
3319
3346
  amount: fee.totalAmount,
@@ -3337,7 +3364,7 @@ export function AdminChangeBookingFlow({
3337
3364
  selectedCancellationPolicy,
3338
3365
  effectiveCancellationPolicyLabel,
3339
3366
  feeLineItemsWithAddOns,
3340
- feeLineItems,
3367
+ feeLineItemsForChangeFlowDisplay,
3341
3368
  showProviderPricingInlineEditor,
3342
3369
  providerEditableLineByNormalizedLabel,
3343
3370
  ]);
@@ -3351,8 +3378,9 @@ export function AdminChangeBookingFlow({
3351
3378
  /** Latest cart context for get-promo-discount; effect only keys off promoDiscountFetchKey. */
3352
3379
  const promoDiscountParamsRef = useRef({
3353
3380
  selectedAvailability: null as Availability | null,
3354
- ticketLineItems: [] as Array<{ category: string; qty: number }>,
3381
+ ticketLineItems: [] as Array<{ category: string; qty: number; itemTotal: number }>,
3355
3382
  effectiveSubtotal: 0,
3383
+ displayedProductFeeTotal: 0,
3356
3384
  appliedPromoCode: null as string | null,
3357
3385
  changeBookingPromo: null as { priorAmount?: number } | null,
3358
3386
  });
@@ -3377,6 +3405,11 @@ export function AdminChangeBookingFlow({
3377
3405
  selectedAvailability.availabilityId ?? '',
3378
3406
  currency,
3379
3407
  quantitiesSignature,
3408
+ ticketLineItemsForChangeFlowDisplay
3409
+ .map((line) => `${line.category}:${line.qty}:${Math.round(line.itemTotal * 100)}`)
3410
+ .sort()
3411
+ .join('|'),
3412
+ String(Math.round(feeLineItems.reduce((sum, fee) => sum + fee.totalAmount, 0) * 100)),
3380
3413
  String(Math.round(effectiveSubtotalForCheckout * 100)),
3381
3414
  lockedPromoCode ? String(Math.round(originalReceiptPromoAdjustment.amount * 100)) : '',
3382
3415
  ].join('::');
@@ -3390,6 +3423,8 @@ export function AdminChangeBookingFlow({
3390
3423
  product.productId,
3391
3424
  currency,
3392
3425
  quantitiesSignature,
3426
+ ticketLineItemsForChangeFlowDisplay,
3427
+ feeLineItems,
3393
3428
  effectiveSubtotalForCheckout,
3394
3429
  lockedPromoCode,
3395
3430
  originalReceiptPromoAdjustment.amount,
@@ -3397,8 +3432,9 @@ export function AdminChangeBookingFlow({
3397
3432
 
3398
3433
  promoDiscountParamsRef.current = {
3399
3434
  selectedAvailability,
3400
- ticketLineItems: ticketLineItems.map((l) => ({ category: l.category, qty: l.qty })),
3435
+ ticketLineItems: ticketLineItemsForChangeFlowDisplay.map((l) => ({ category: l.category, qty: l.qty, itemTotal: l.itemTotal })),
3401
3436
  effectiveSubtotal: effectiveSubtotalForCheckout,
3437
+ displayedProductFeeTotal: feeLineItems.reduce((sum, fee) => sum + fee.totalAmount, 0),
3402
3438
  appliedPromoCode,
3403
3439
  changeBookingPromo: lockedPromoCode
3404
3440
  ? { priorAmount: originalReceiptPromoAdjustment.amount }
@@ -3421,6 +3457,7 @@ export function AdminChangeBookingFlow({
3421
3457
  selectedAvailability: sel,
3422
3458
  ticketLineItems: lines,
3423
3459
  effectiveSubtotal: sub,
3460
+ displayedProductFeeTotal,
3424
3461
  appliedPromoCode: code,
3425
3462
  changeBookingPromo,
3426
3463
  } = promoDiscountParamsRef.current;
@@ -3445,8 +3482,13 @@ export function AdminChangeBookingFlow({
3445
3482
  ? {
3446
3483
  forBookingChange: true,
3447
3484
  priorPromoDiscountAmount: changeBookingPromo.priorAmount,
3485
+ displayedTicketLines: lines,
3486
+ displayedProductFeeTotal,
3487
+ }
3488
+ : {
3489
+ displayedTicketLines: lines,
3490
+ displayedProductFeeTotal,
3448
3491
  }
3449
- : undefined
3450
3492
  )
3451
3493
  .then((res) => {
3452
3494
  if (cancelled) return;
@@ -4030,6 +4072,14 @@ export function AdminChangeBookingFlow({
4030
4072
  providerHasAdditionalAdjustments ||
4031
4073
  providerHasEditableSummaryLineOverrides ||
4032
4074
  Math.abs(adminCustomAdjustmentTotal) >= 0.005;
4075
+ const unchangedReceiptAnchor =
4076
+ originalReceipt && !hasEffectiveChangeSelection
4077
+ ? {
4078
+ subtotal: roundMoney(originalReceipt.subtotal),
4079
+ tax: roundMoney(originalReceipt.tax),
4080
+ total: roundMoney(originalReceipt.total),
4081
+ }
4082
+ : null;
4033
4083
 
4034
4084
  /**
4035
4085
  * True until `quoteChangeBooking` returns a confirmed `serverDisplay` for the current selection.
@@ -4073,14 +4123,22 @@ export function AdminChangeBookingFlow({
4073
4123
  ? roundMoney(adminCustomAdjustmentTotal * (pricingConfig?.taxRate ?? 0))
4074
4124
  : 0;
4075
4125
  const displayChangeFlowSubtotal = roundMoney(
4076
- displayedChangeAmountsRaw.subtotal +
4077
- (displayLayerUsesExternalPricing ? adminCustomAdjustmentTotal : 0)
4126
+ unchangedReceiptAnchor
4127
+ ? unchangedReceiptAnchor.subtotal
4128
+ : displayedChangeAmountsRaw.subtotal +
4129
+ (displayLayerUsesExternalPricing ? adminCustomAdjustmentTotal : 0)
4130
+ );
4131
+ const displayChangeFlowTax = roundMoney(
4132
+ unchangedReceiptAnchor
4133
+ ? unchangedReceiptAnchor.tax
4134
+ : displayedChangeAmountsRaw.tax + adminTaxDeltaForExternalDisplay
4078
4135
  );
4079
- const displayChangeFlowTax = roundMoney(displayedChangeAmountsRaw.tax + adminTaxDeltaForExternalDisplay);
4080
4136
  const displayChangeFlowProposedTotal = roundMoney(
4081
- displayLayerUsesExternalPricing
4082
- ? displayedChangeAmountsRaw.total + adminCustomAdjustmentTotal + adminTaxDeltaForExternalDisplay
4083
- : displayedChangeAmountsRaw.total
4137
+ unchangedReceiptAnchor
4138
+ ? unchangedReceiptAnchor.total
4139
+ : displayLayerUsesExternalPricing
4140
+ ? displayedChangeAmountsRaw.total + adminCustomAdjustmentTotal + adminTaxDeltaForExternalDisplay
4141
+ : displayedChangeAmountsRaw.total
4084
4142
  );
4085
4143
  const displayChangeFlowProposedTotalWithEditableLines = roundMoney(
4086
4144
  displayChangeFlowProposedTotal + editableSummaryPreSubtotalDelta
@@ -4176,6 +4234,7 @@ export function AdminChangeBookingFlow({
4176
4234
 
4177
4235
  const changeFlowClientEstimateDueBase = (() => {
4178
4236
  if (!originalReceipt) return totalPrice;
4237
+ if (unchangedReceiptAnchor) return 0;
4179
4238
  // Self-serve quote: match BE receipt / intent: (newTotalCents − previousTotalCents) / 100.
4180
4239
  if (isCustomerSelfServeChange && latestChangeQuote != null && !changeQuoteFetchError) {
4181
4240
  const pq = latestChangeQuote.quotePreviousTotalCents;
@@ -4291,6 +4350,7 @@ export function AdminChangeBookingFlow({
4291
4350
  displayedChangeAmountsRaw.tax,
4292
4351
  displayedChangeAmountsRaw.total,
4293
4352
  editableSummaryPreSubtotalDelta,
4353
+ unchangedReceiptAnchor,
4294
4354
  displayChangeFlowProposedTotal,
4295
4355
  displayChangeFlowProposedTotalWithEditableLines,
4296
4356
  adminFeAuthoritativeReceipt,
@@ -3173,8 +3173,9 @@ export function ChangeBookingFlow({
3173
3173
  /** Latest cart context for get-promo-discount; effect only keys off promoDiscountFetchKey. */
3174
3174
  const promoDiscountParamsRef = useRef({
3175
3175
  selectedAvailability: null as Availability | null,
3176
- ticketLineItems: [] as Array<{ category: string; qty: number }>,
3176
+ ticketLineItems: [] as Array<{ category: string; qty: number; itemTotal: number }>,
3177
3177
  effectiveSubtotal: 0,
3178
+ displayedProductFeeTotal: 0,
3178
3179
  appliedPromoCode: null as string | null,
3179
3180
  /** Change flow: pass BE stored promo discount for expired / fixed promo locking. */
3180
3181
  changeBookingPromo: null as { priorAmount?: number } | null,
@@ -3195,6 +3196,11 @@ export function ChangeBookingFlow({
3195
3196
  selectedAvailability.availabilityId ?? '',
3196
3197
  currency,
3197
3198
  quantitiesSignature,
3199
+ ticketLineItemsForChangeFlowDisplay
3200
+ .map((line) => `${line.category}:${line.qty}:${Math.round(line.itemTotal * 100)}`)
3201
+ .sort()
3202
+ .join('|'),
3203
+ String(Math.round(feeLineItems.reduce((sum, fee) => sum + fee.totalAmount, 0) * 100)),
3198
3204
  String(Math.round(effectiveSubtotal * 100)),
3199
3205
  lockedPromoCode ? String(Math.round((originalReceipt?.promoAmount ?? 0) * 100)) : '',
3200
3206
  ].join('::');
@@ -3208,6 +3214,8 @@ export function ChangeBookingFlow({
3208
3214
  product.productId,
3209
3215
  currency,
3210
3216
  quantitiesSignature,
3217
+ ticketLineItemsForChangeFlowDisplay,
3218
+ feeLineItems,
3211
3219
  effectiveSubtotal,
3212
3220
  lockedPromoCode,
3213
3221
  originalReceipt?.promoAmount,
@@ -3215,8 +3223,9 @@ export function ChangeBookingFlow({
3215
3223
 
3216
3224
  promoDiscountParamsRef.current = {
3217
3225
  selectedAvailability,
3218
- ticketLineItems: ticketLineItems.map((l) => ({ category: l.category, qty: l.qty })),
3226
+ ticketLineItems: ticketLineItemsForChangeFlowDisplay.map((l) => ({ category: l.category, qty: l.qty, itemTotal: l.itemTotal })),
3219
3227
  effectiveSubtotal,
3228
+ displayedProductFeeTotal: feeLineItems.reduce((sum, fee) => sum + fee.totalAmount, 0),
3220
3229
  appliedPromoCode,
3221
3230
  changeBookingPromo: lockedPromoCode
3222
3231
  ? { priorAmount: originalReceipt?.promoAmount }
@@ -3239,6 +3248,7 @@ export function ChangeBookingFlow({
3239
3248
  selectedAvailability: sel,
3240
3249
  ticketLineItems: lines,
3241
3250
  effectiveSubtotal: sub,
3251
+ displayedProductFeeTotal,
3242
3252
  appliedPromoCode: code,
3243
3253
  changeBookingPromo,
3244
3254
  } = promoDiscountParamsRef.current;
@@ -3263,8 +3273,13 @@ export function ChangeBookingFlow({
3263
3273
  ? {
3264
3274
  forBookingChange: true,
3265
3275
  priorPromoDiscountAmount: changeBookingPromo.priorAmount,
3276
+ displayedTicketLines: lines,
3277
+ displayedProductFeeTotal,
3278
+ }
3279
+ : {
3280
+ displayedTicketLines: lines,
3281
+ displayedProductFeeTotal,
3266
3282
  }
3267
- : undefined
3268
3283
  )
3269
3284
  .then((res) => {
3270
3285
  if (cancelled) return;