@ticketboothapp/booking 1.2.156 → 1.2.159
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 +1 -1
- package/src/components/booking/AdminChangeReceiptComparison.tsx +4 -2
- package/src/components/booking/CheckoutModal.tsx +1 -1
- package/src/components/booking/PrivateShuttleCheckoutSection.tsx +1 -1
- package/src/components/booking/admin-change-provider-payload.ts +3 -0
- package/src/components/booking/admin-refund-disposition.ts +8 -0
- package/src/components/booking/provider-dashboard-change-booking.ts +2 -0
- package/src/components/booking/useAdminChangeCheckoutController.ts +1 -0
- package/src/lib/booking/i18n/messages/en.json +1 -1
- package/test/change-booking-helpers.test.ts +54 -0
package/package.json
CHANGED
|
@@ -12,6 +12,7 @@ import { PriceSummary, type PriceSummaryLine } from './PriceSummary';
|
|
|
12
12
|
import {
|
|
13
13
|
adminRemovalOperationLabel,
|
|
14
14
|
noRefundRemovedValue,
|
|
15
|
+
normalizeReturnPriceTreatment,
|
|
15
16
|
refundDecisionsComplete,
|
|
16
17
|
releaseRefundDispositionOptions,
|
|
17
18
|
returnPriceTreatmentOptions,
|
|
@@ -173,8 +174,9 @@ export function AdminChangeReceiptComparison({
|
|
|
173
174
|
const options = returnPriceTreatmentOptions(
|
|
174
175
|
allowedRefundDispositionsByOperationId[operation.operationId],
|
|
175
176
|
);
|
|
176
|
-
const selectedValue: AdminReturnPriceTreatment =
|
|
177
|
-
refundDispositionsByOperationId[operation.operationId]
|
|
177
|
+
const selectedValue: AdminReturnPriceTreatment = normalizeReturnPriceTreatment(
|
|
178
|
+
refundDispositionsByOperationId[operation.operationId],
|
|
179
|
+
);
|
|
178
180
|
const selected = options.find((option) => option.value === selectedValue);
|
|
179
181
|
return (
|
|
180
182
|
<div key={operation.operationId} className="rounded-md border border-sky-200 bg-white p-3">
|
|
@@ -411,7 +411,7 @@ export function CheckoutModal({
|
|
|
411
411
|
{balanceChargeDaysBefore > 0
|
|
412
412
|
? (t('booking.balanceChargeNotice', { days: balanceChargeDaysBefore }) !== 'booking.balanceChargeNotice'
|
|
413
413
|
? t('booking.balanceChargeNotice', { days: balanceChargeDaysBefore })
|
|
414
|
-
: `The remaining balance
|
|
414
|
+
: `The remaining balance is due ${balanceChargeDaysBefore} days before your booking. You can pay it from your Manage Booking page.`)
|
|
415
415
|
: (t('booking.balancePayEarlier') !== 'booking.balancePayEarlier'
|
|
416
416
|
? t('booking.balancePayEarlier')
|
|
417
417
|
: 'You can pay the remaining balance anytime from your Manage Booking page.')}
|
|
@@ -179,7 +179,7 @@ export function PrivateShuttleCheckoutSection({
|
|
|
179
179
|
{balanceChargeDaysBefore && balanceChargeDaysBefore > 0
|
|
180
180
|
? (t('booking.balanceChargeNotice', { days: balanceChargeDaysBefore }) !== 'booking.balanceChargeNotice'
|
|
181
181
|
? t('booking.balanceChargeNotice', { days: balanceChargeDaysBefore })
|
|
182
|
-
: `The remaining balance
|
|
182
|
+
: `The remaining balance is due ${balanceChargeDaysBefore} days before your booking. You can pay it from your Manage Booking page.`)
|
|
183
183
|
: (t('booking.balancePayEarlier') !== 'booking.balancePayEarlier'
|
|
184
184
|
? t('booking.balancePayEarlier')
|
|
185
185
|
: 'You can pay the remaining balance anytime from your Manage Booking page.')}
|
|
@@ -40,6 +40,7 @@ export interface BuildAdminChangeProviderPayloadParams {
|
|
|
40
40
|
previousPassengerCount: number;
|
|
41
41
|
previousAvailabilityId?: string | null;
|
|
42
42
|
previousReturnAvailabilityId?: string | null;
|
|
43
|
+
itineraryDisplay?: ProviderDashboardChangeBookingPayload['itineraryDisplay'];
|
|
43
44
|
}
|
|
44
45
|
|
|
45
46
|
export function buildAdminChangeProviderPayload({
|
|
@@ -62,6 +63,7 @@ export function buildAdminChangeProviderPayload({
|
|
|
62
63
|
previousPassengerCount,
|
|
63
64
|
previousAvailabilityId,
|
|
64
65
|
previousReturnAvailabilityId,
|
|
66
|
+
itineraryDisplay,
|
|
65
67
|
}: BuildAdminChangeProviderPayloadParams): ProviderDashboardChangeBookingPayload | null {
|
|
66
68
|
if (!selectedAvailability) return null;
|
|
67
69
|
const pickupForChange = pickupLocationId
|
|
@@ -77,6 +79,7 @@ export function buildAdminChangeProviderPayload({
|
|
|
77
79
|
pickupLocationId: pickupLocationId ?? null,
|
|
78
80
|
travelerHotel: pickupForChange?.name ?? null,
|
|
79
81
|
startTime: selectedAvailability.dateTime ?? null,
|
|
82
|
+
itineraryDisplay: itineraryDisplay ?? null,
|
|
80
83
|
passengerCount: null,
|
|
81
84
|
childSafetySeatsCount: null,
|
|
82
85
|
foodRestrictions: null,
|
|
@@ -66,6 +66,14 @@ export function returnPriceTreatmentOptions(
|
|
|
66
66
|
];
|
|
67
67
|
}
|
|
68
68
|
|
|
69
|
+
export function normalizeReturnPriceTreatment(
|
|
70
|
+
disposition: AdminAmendmentRefundDisposition | undefined,
|
|
71
|
+
): AdminReturnPriceTreatment {
|
|
72
|
+
return disposition === 'PENDING_REFUND' || disposition === 'NO_REFUND'
|
|
73
|
+
? disposition
|
|
74
|
+
: 'KEEP_FLOOR';
|
|
75
|
+
}
|
|
76
|
+
|
|
69
77
|
export function adminRemovalOperationLabel(operation: AdminAmendmentOperationSnapshot): string {
|
|
70
78
|
const component = operation.componentKey.split(':').slice(1).join(':') || operation.componentKey;
|
|
71
79
|
const quantity = operation.quantityDelta ? ` (${Math.abs(operation.quantityDelta)})` : '';
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import type { Currency } from './CurrencySwitcher';
|
|
2
|
+
import type { ItineraryDisplayStep } from '../../lib/booking-api';
|
|
2
3
|
|
|
3
4
|
export type AdminAmendmentAdjustmentMode =
|
|
4
5
|
| 'FIXED_AMOUNT'
|
|
@@ -42,6 +43,7 @@ export type ProviderDashboardChangeBookingPayload = {
|
|
|
42
43
|
pickupLocationId?: string | null;
|
|
43
44
|
travelerHotel?: string | null;
|
|
44
45
|
startTime?: string | null;
|
|
46
|
+
itineraryDisplay?: ItineraryDisplayStep[] | null;
|
|
45
47
|
passengerCount?: number | null;
|
|
46
48
|
childSafetySeatsCount?: number | null;
|
|
47
49
|
foodRestrictions?: string | null;
|
|
@@ -342,6 +342,7 @@ export function useAdminChangeCheckoutController({
|
|
|
342
342
|
previousPassengerCount: changeFlowInitialTicketCount,
|
|
343
343
|
previousAvailabilityId: initialValues?.availabilityId ?? null,
|
|
344
344
|
previousReturnAvailabilityId: initialValues?.returnAvailabilityId ?? null,
|
|
345
|
+
itineraryDisplay: computeItineraryDisplayForStorage() ?? computeItineraryDisplay(),
|
|
345
346
|
});
|
|
346
347
|
};
|
|
347
348
|
|
|
@@ -153,7 +153,7 @@
|
|
|
153
153
|
"included": "Included",
|
|
154
154
|
"flexibleCancellation": "Flexible cancellation",
|
|
155
155
|
"depositPaymentNotice": "You're paying the deposit today.",
|
|
156
|
-
"balanceChargeNotice": "The remaining balance
|
|
156
|
+
"balanceChargeNotice": "The remaining balance is due {days} days before your booking. You can pay it from your Manage Booking page.",
|
|
157
157
|
"balancePayEarlier": "You can pay the remaining balance anytime from your Manage Booking page.",
|
|
158
158
|
"remainingBalance": "Remaining Balance"
|
|
159
159
|
},
|
|
@@ -16,6 +16,7 @@ import {
|
|
|
16
16
|
import { buildAdminChangeQuoteRequestKey } from '../src/components/booking/admin-change-quote-request-key';
|
|
17
17
|
import {
|
|
18
18
|
noRefundRemovedValue,
|
|
19
|
+
normalizeReturnPriceTreatment,
|
|
19
20
|
refundDecisionsComplete,
|
|
20
21
|
releaseRefundDispositionOptions,
|
|
21
22
|
returnPriceTreatmentOptions,
|
|
@@ -31,6 +32,7 @@ import {
|
|
|
31
32
|
reservationHoldHasExpired,
|
|
32
33
|
reservationHoldSecondsRemaining,
|
|
33
34
|
} from '../src/components/booking/reservation-hold';
|
|
35
|
+
import { buildAdminChangeProviderPayload } from '../src/components/booking/admin-change-provider-payload';
|
|
34
36
|
|
|
35
37
|
function quote(overrides: Partial<ChangeBookingQuoteResponse>): ChangeBookingQuoteResponse {
|
|
36
38
|
return {
|
|
@@ -139,6 +141,51 @@ test('admin quote response display state cannot invalidate its request identity'
|
|
|
139
141
|
assert.equal(keyAfterResponse, keyBeforeResponse);
|
|
140
142
|
});
|
|
141
143
|
|
|
144
|
+
test('admin no-charge provider payload carries the selected pickup itinerary', () => {
|
|
145
|
+
const itineraryDisplay: NonNullable<
|
|
146
|
+
Parameters<typeof buildAdminChangeProviderPayload>[0]['itineraryDisplay']
|
|
147
|
+
> = [
|
|
148
|
+
{ stepType: 'pickup', time: '3:00 AM', place: 'A Bear and Bison Inn' },
|
|
149
|
+
{ stepType: 'arrive', time: '4:45 AM', place: 'Moraine Lake' },
|
|
150
|
+
{ stepType: 'depart', time: '1:00 PM', place: 'Moraine Lake' },
|
|
151
|
+
{ stepType: 'drop_off', time: '3:00 PM', place: 'A Bear and Bison Inn' },
|
|
152
|
+
];
|
|
153
|
+
const payload = buildAdminChangeProviderPayload({
|
|
154
|
+
selectedAvailability: {
|
|
155
|
+
availabilityId: 'availability_1',
|
|
156
|
+
productId: 'option_1',
|
|
157
|
+
dateTime: '2026-07-27T03:00:00-06:00',
|
|
158
|
+
vacancies: 10,
|
|
159
|
+
} as Parameters<typeof buildAdminChangeProviderPayload>[0]['selectedAvailability'],
|
|
160
|
+
availabilityProductOptionId: 'option_1',
|
|
161
|
+
bookingItems: [{ category: 'ADULT', count: 1 }],
|
|
162
|
+
product: {
|
|
163
|
+
productId: 'product_1',
|
|
164
|
+
name: 'Moraine Lake Sunrise Experience',
|
|
165
|
+
pickupLocations: [{ id: 'pickup_new', name: 'A Bear and Bison Inn' }],
|
|
166
|
+
} as Parameters<typeof buildAdminChangeProviderPayload>[0]['product'],
|
|
167
|
+
pickupLocationId: 'pickup_new',
|
|
168
|
+
selectedReturnOption: null,
|
|
169
|
+
addOnSelections: [],
|
|
170
|
+
cancellationPolicyId: 'standard',
|
|
171
|
+
initialCancellationPolicyId: 'standard',
|
|
172
|
+
appliedPromoCode: null,
|
|
173
|
+
newTotalAmount: 202.87,
|
|
174
|
+
providerPricingOverrides: [],
|
|
175
|
+
mergedProviderAdditionalAdjustments: [],
|
|
176
|
+
adminStructuredAdjustments: [],
|
|
177
|
+
refundDispositionsByOperationId: {},
|
|
178
|
+
previousPassengerCount: 1,
|
|
179
|
+
previousAvailabilityId: 'availability_1',
|
|
180
|
+
previousReturnAvailabilityId: 'return_1',
|
|
181
|
+
itineraryDisplay,
|
|
182
|
+
});
|
|
183
|
+
|
|
184
|
+
assert.deepEqual(payload?.itineraryDisplay, itineraryDisplay);
|
|
185
|
+
assert.equal(payload?.pickupLocationId, 'pickup_new');
|
|
186
|
+
assert.equal(payload?.travelerHotel, 'A Bear and Bison Inn');
|
|
187
|
+
});
|
|
188
|
+
|
|
142
189
|
test('admin removal quote preserves explicit release refund decisions for the preview', () => {
|
|
143
190
|
const operation = {
|
|
144
191
|
operationId: 'op_remove_adult',
|
|
@@ -217,6 +264,13 @@ test('admin return price treatment defaults to keep floor and maps optional repr
|
|
|
217
264
|
);
|
|
218
265
|
});
|
|
219
266
|
|
|
267
|
+
test('unsupported immediate refund cannot become a return price treatment', () => {
|
|
268
|
+
assert.equal(normalizeReturnPriceTreatment(undefined), 'KEEP_FLOOR');
|
|
269
|
+
assert.equal(normalizeReturnPriceTreatment('REFUND_TO_ORIGINAL_PAYMENT'), 'KEEP_FLOOR');
|
|
270
|
+
assert.equal(normalizeReturnPriceTreatment('PENDING_REFUND'), 'PENDING_REFUND');
|
|
271
|
+
assert.equal(normalizeReturnPriceTreatment('NO_REFUND'), 'NO_REFUND');
|
|
272
|
+
});
|
|
273
|
+
|
|
220
274
|
test('changing admin refund treatment creates a distinct authoritative quote request', () => {
|
|
221
275
|
const base = {
|
|
222
276
|
bookingReference: 'DE8H04DX',
|