@ticketboothapp/booking 1.2.154 → 1.2.156
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/AdminChangeBookingContent.tsx +1 -0
- package/src/components/booking/AdminChangeBookingFlow.tsx +26 -8
- package/src/components/booking/AdminChangeCheckoutPanel.tsx +3 -0
- package/src/components/booking/AdminChangeReceiptComparison.tsx +58 -0
- package/src/components/booking/admin-refund-disposition.ts +32 -0
- package/src/components/booking/useAdminChangeCheckoutController.ts +1 -0
- package/src/lib/booking/change-flow-pricing.ts +2 -0
- package/src/lib/booking-api.ts +11 -0
- package/test/change-booking-helpers.test.ts +31 -0
package/package.json
CHANGED
|
@@ -160,6 +160,7 @@ const checkoutPanelPropKeys = [
|
|
|
160
160
|
'serverUpdatedTotal',
|
|
161
161
|
'serverQuoteError',
|
|
162
162
|
'refundDecisionOperations',
|
|
163
|
+
'returnPriceTreatmentOperations',
|
|
163
164
|
'allowedRefundDispositionsByOperationId',
|
|
164
165
|
'removedValueByOperationId',
|
|
165
166
|
'refundDispositionsByOperationId',
|
|
@@ -706,6 +706,8 @@ export function AdminChangeBookingFlow({
|
|
|
706
706
|
useAdminFeAuthoritativeQuote,
|
|
707
707
|
]);
|
|
708
708
|
const responseRefundDecisionOperations = latestChangeQuote?.refundDecisionOperations ?? [];
|
|
709
|
+
const responseReturnPriceTreatmentOperations =
|
|
710
|
+
latestChangeQuote?.returnPriceTreatmentOperations ?? [];
|
|
709
711
|
useEffect(() => {
|
|
710
712
|
if (responseRefundDecisionOperations.length === 0) return;
|
|
711
713
|
setRefundDecisionContext({
|
|
@@ -730,12 +732,25 @@ export function AdminChangeBookingFlow({
|
|
|
730
732
|
: refundDecisionContext?.selectionKey === refundDecisionSelectionKey
|
|
731
733
|
? refundDecisionContext
|
|
732
734
|
: null;
|
|
733
|
-
const
|
|
734
|
-
|
|
735
|
-
|
|
736
|
-
|
|
737
|
-
|
|
738
|
-
|
|
735
|
+
const activeReturnPriceTreatmentOperations =
|
|
736
|
+
responseReturnPriceTreatmentOperations.length > 0
|
|
737
|
+
? responseReturnPriceTreatmentOperations
|
|
738
|
+
: [];
|
|
739
|
+
const activeRefundDispositionsByOperationId = useMemo(() => {
|
|
740
|
+
const relevantOperationIds = new Set([
|
|
741
|
+
...(activeRefundDecisionContext?.operations ?? []).map((operation) => operation.operationId),
|
|
742
|
+
...activeReturnPriceTreatmentOperations.map((operation) => operation.operationId),
|
|
743
|
+
]);
|
|
744
|
+
return Object.fromEntries(
|
|
745
|
+
Object.entries(refundDispositionsByOperationId).filter(([operationId]) =>
|
|
746
|
+
relevantOperationIds.has(operationId),
|
|
747
|
+
),
|
|
748
|
+
);
|
|
749
|
+
}, [
|
|
750
|
+
activeRefundDecisionContext?.operations,
|
|
751
|
+
activeReturnPriceTreatmentOperations,
|
|
752
|
+
refundDispositionsByOperationId,
|
|
753
|
+
]);
|
|
739
754
|
const handleRefundDispositionChange = useCallback((
|
|
740
755
|
operationId: string,
|
|
741
756
|
disposition: AdminReleaseRefundDisposition | null,
|
|
@@ -1064,8 +1079,11 @@ export function AdminChangeBookingFlow({
|
|
|
1064
1079
|
? (latestChangeQuote?.reasonIfBlocked ?? 'This change cannot be priced right now.')
|
|
1065
1080
|
: null),
|
|
1066
1081
|
refundDecisionOperations: activeRefundDecisionContext?.operations ?? [],
|
|
1067
|
-
|
|
1068
|
-
|
|
1082
|
+
returnPriceTreatmentOperations: activeReturnPriceTreatmentOperations,
|
|
1083
|
+
allowedRefundDispositionsByOperationId: {
|
|
1084
|
+
...(activeRefundDecisionContext?.allowedByOperationId ?? {}),
|
|
1085
|
+
...(latestChangeQuote?.allowedRefundDispositionsByOperationId ?? {}),
|
|
1086
|
+
},
|
|
1069
1087
|
removedValueByOperationId:
|
|
1070
1088
|
activeRefundDecisionContext?.removedValueByOperationId ?? {},
|
|
1071
1089
|
refundDispositionsByOperationId: activeRefundDispositionsByOperationId,
|
|
@@ -41,6 +41,7 @@ export interface AdminChangeCheckoutPanelProps {
|
|
|
41
41
|
serverUpdatedTotal: number | null;
|
|
42
42
|
serverQuoteError?: string | null;
|
|
43
43
|
refundDecisionOperations?: AdminAmendmentOperationSnapshot[];
|
|
44
|
+
returnPriceTreatmentOperations?: AdminAmendmentOperationSnapshot[];
|
|
44
45
|
allowedRefundDispositionsByOperationId?: Record<string, AdminAmendmentRefundDisposition[]>;
|
|
45
46
|
removedValueByOperationId?: Record<string, number>;
|
|
46
47
|
refundDispositionsByOperationId?: Record<string, AdminAmendmentRefundDisposition>;
|
|
@@ -123,6 +124,7 @@ export function AdminChangeCheckoutPanel({
|
|
|
123
124
|
serverUpdatedTotal,
|
|
124
125
|
serverQuoteError,
|
|
125
126
|
refundDecisionOperations,
|
|
127
|
+
returnPriceTreatmentOperations,
|
|
126
128
|
allowedRefundDispositionsByOperationId,
|
|
127
129
|
removedValueByOperationId,
|
|
128
130
|
refundDispositionsByOperationId,
|
|
@@ -216,6 +218,7 @@ export function AdminChangeCheckoutPanel({
|
|
|
216
218
|
selectionChanged={hasEffectiveChangeSelection}
|
|
217
219
|
quoteError={serverQuoteError}
|
|
218
220
|
refundDecisionOperations={refundDecisionOperations}
|
|
221
|
+
returnPriceTreatmentOperations={returnPriceTreatmentOperations}
|
|
219
222
|
allowedRefundDispositionsByOperationId={allowedRefundDispositionsByOperationId}
|
|
220
223
|
removedValueByOperationId={removedValueByOperationId}
|
|
221
224
|
refundDispositionsByOperationId={refundDispositionsByOperationId}
|
|
@@ -14,7 +14,9 @@ import {
|
|
|
14
14
|
noRefundRemovedValue,
|
|
15
15
|
refundDecisionsComplete,
|
|
16
16
|
releaseRefundDispositionOptions,
|
|
17
|
+
returnPriceTreatmentOptions,
|
|
17
18
|
type AdminReleaseRefundDisposition,
|
|
19
|
+
type AdminReturnPriceTreatment,
|
|
18
20
|
} from './admin-refund-disposition';
|
|
19
21
|
|
|
20
22
|
type TranslationFn = (key: string, params?: Record<string, string>) => string;
|
|
@@ -37,6 +39,7 @@ export interface AdminChangeReceiptComparisonProps {
|
|
|
37
39
|
taxRate?: number;
|
|
38
40
|
adjustments?: ReactNode;
|
|
39
41
|
refundDecisionOperations?: AdminAmendmentOperationSnapshot[];
|
|
42
|
+
returnPriceTreatmentOperations?: AdminAmendmentOperationSnapshot[];
|
|
40
43
|
allowedRefundDispositionsByOperationId?: Record<string, AdminAmendmentRefundDisposition[]>;
|
|
41
44
|
removedValueByOperationId?: Record<string, number>;
|
|
42
45
|
refundDispositionsByOperationId?: Record<string, AdminAmendmentRefundDisposition>;
|
|
@@ -86,6 +89,7 @@ export function AdminChangeReceiptComparison({
|
|
|
86
89
|
taxRate,
|
|
87
90
|
adjustments,
|
|
88
91
|
refundDecisionOperations = [],
|
|
92
|
+
returnPriceTreatmentOperations = [],
|
|
89
93
|
allowedRefundDispositionsByOperationId = {},
|
|
90
94
|
removedValueByOperationId = {},
|
|
91
95
|
refundDispositionsByOperationId = {},
|
|
@@ -97,11 +101,17 @@ export function AdminChangeReceiptComparison({
|
|
|
97
101
|
const originalCurrency = originalReceipt.currency ?? currency;
|
|
98
102
|
const quoteReady = amendmentLines != null && amountDue != null && updatedTotal != null;
|
|
99
103
|
const hasRefundDecisions = refundDecisionOperations.length > 0;
|
|
104
|
+
const hasReturnPriceTreatments = returnPriceTreatmentOperations.length > 0;
|
|
100
105
|
const refundSelectionsComplete = refundDecisionsComplete(
|
|
101
106
|
refundDecisionOperations,
|
|
102
107
|
refundDispositionsByOperationId,
|
|
103
108
|
);
|
|
104
109
|
const settlementPending = hasRefundDecisions && (!refundSelectionsComplete || refundQuoteLoading);
|
|
110
|
+
const returnRepricePending = hasReturnPriceTreatments &&
|
|
111
|
+
returnPriceTreatmentOperations.some(
|
|
112
|
+
(operation) => refundDispositionsByOperationId[operation.operationId] != null,
|
|
113
|
+
) &&
|
|
114
|
+
refundQuoteLoading;
|
|
105
115
|
const displayedAmountDue = settlementPending ? null : amountDue;
|
|
106
116
|
const removedWithoutRefund = noRefundRemovedValue(
|
|
107
117
|
refundDecisionOperations,
|
|
@@ -150,6 +160,54 @@ export function AdminChangeReceiptComparison({
|
|
|
150
160
|
|
|
151
161
|
return (
|
|
152
162
|
<div className="min-w-0 space-y-3 overflow-visible">
|
|
163
|
+
{hasReturnPriceTreatments ? (
|
|
164
|
+
<section className="rounded-lg border border-sky-300 bg-sky-50 p-3" aria-label="Return price treatment">
|
|
165
|
+
<div className="mb-3">
|
|
166
|
+
<h3 className="text-sm font-semibold text-stone-900">Return price</h3>
|
|
167
|
+
<p className="mt-1 text-xs text-stone-600">
|
|
168
|
+
By default the original paid return price stays on the booking. You can optionally reduce it and choose refund treatment.
|
|
169
|
+
</p>
|
|
170
|
+
</div>
|
|
171
|
+
<div className="space-y-3">
|
|
172
|
+
{returnPriceTreatmentOperations.map((operation) => {
|
|
173
|
+
const options = returnPriceTreatmentOptions(
|
|
174
|
+
allowedRefundDispositionsByOperationId[operation.operationId],
|
|
175
|
+
);
|
|
176
|
+
const selectedValue: AdminReturnPriceTreatment =
|
|
177
|
+
refundDispositionsByOperationId[operation.operationId] ?? 'KEEP_FLOOR';
|
|
178
|
+
const selected = options.find((option) => option.value === selectedValue);
|
|
179
|
+
return (
|
|
180
|
+
<div key={operation.operationId} className="rounded-md border border-sky-200 bg-white p-3">
|
|
181
|
+
<div className="mb-2 text-sm font-medium capitalize text-stone-900">
|
|
182
|
+
{adminRemovalOperationLabel(operation)}
|
|
183
|
+
</div>
|
|
184
|
+
<select
|
|
185
|
+
className="w-full rounded-md border border-stone-300 bg-white px-3 py-2 text-sm text-stone-900"
|
|
186
|
+
value={selectedValue}
|
|
187
|
+
onChange={(event) => {
|
|
188
|
+
const value = event.target.value as AdminReturnPriceTreatment;
|
|
189
|
+
onRefundDispositionChange?.(
|
|
190
|
+
operation.operationId,
|
|
191
|
+
value === 'KEEP_FLOOR' ? null : value,
|
|
192
|
+
);
|
|
193
|
+
}}
|
|
194
|
+
aria-label={`Return price treatment for ${adminRemovalOperationLabel(operation)}`}
|
|
195
|
+
>
|
|
196
|
+
{options.map((option) => (
|
|
197
|
+
<option key={option.value} value={option.value}>{option.label}</option>
|
|
198
|
+
))}
|
|
199
|
+
</select>
|
|
200
|
+
{selected ? <p className="mt-2 text-xs text-stone-600">{selected.description}</p> : null}
|
|
201
|
+
</div>
|
|
202
|
+
);
|
|
203
|
+
})}
|
|
204
|
+
</div>
|
|
205
|
+
{returnRepricePending ? (
|
|
206
|
+
<p className="mt-3 text-xs font-medium text-sky-800">Recalculating settlement…</p>
|
|
207
|
+
) : null}
|
|
208
|
+
</section>
|
|
209
|
+
) : null}
|
|
210
|
+
|
|
153
211
|
{hasRefundDecisions ? (
|
|
154
212
|
<section className="rounded-lg border border-amber-300 bg-amber-50 p-3" aria-label="Refund treatment">
|
|
155
213
|
<div className="mb-3">
|
|
@@ -8,12 +8,21 @@ export type AdminReleaseRefundDisposition = Exclude<
|
|
|
8
8
|
'REFUND_TO_ORIGINAL_PAYMENT'
|
|
9
9
|
>;
|
|
10
10
|
|
|
11
|
+
/** Local UI value: omit disposition on the quote request to keep the paid-return floor. */
|
|
12
|
+
export type AdminReturnPriceTreatment = 'KEEP_FLOOR' | AdminReleaseRefundDisposition;
|
|
13
|
+
|
|
11
14
|
export type AdminRefundDispositionOption = {
|
|
12
15
|
value: AdminReleaseRefundDisposition;
|
|
13
16
|
label: string;
|
|
14
17
|
description: string;
|
|
15
18
|
};
|
|
16
19
|
|
|
20
|
+
export type AdminReturnPriceTreatmentOption = {
|
|
21
|
+
value: AdminReturnPriceTreatment;
|
|
22
|
+
label: string;
|
|
23
|
+
description: string;
|
|
24
|
+
};
|
|
25
|
+
|
|
17
26
|
const RELEASE_OPTIONS: AdminRefundDispositionOption[] = [
|
|
18
27
|
{
|
|
19
28
|
value: 'PENDING_REFUND',
|
|
@@ -27,6 +36,12 @@ const RELEASE_OPTIONS: AdminRefundDispositionOption[] = [
|
|
|
27
36
|
},
|
|
28
37
|
];
|
|
29
38
|
|
|
39
|
+
const KEEP_FLOOR_OPTION: AdminReturnPriceTreatmentOption = {
|
|
40
|
+
value: 'KEEP_FLOOR',
|
|
41
|
+
label: 'Keep original return price',
|
|
42
|
+
description: 'Change the return time but keep what was already paid for the return on the booking total.',
|
|
43
|
+
};
|
|
44
|
+
|
|
30
45
|
export function releaseRefundDispositionOptions(
|
|
31
46
|
allowed: readonly AdminAmendmentRefundDisposition[] | undefined,
|
|
32
47
|
): AdminRefundDispositionOption[] {
|
|
@@ -34,6 +49,23 @@ export function releaseRefundDispositionOptions(
|
|
|
34
49
|
return RELEASE_OPTIONS.filter((option) => allowed.includes(option.value));
|
|
35
50
|
}
|
|
36
51
|
|
|
52
|
+
export function returnPriceTreatmentOptions(
|
|
53
|
+
allowed: readonly AdminAmendmentRefundDisposition[] | undefined,
|
|
54
|
+
): AdminReturnPriceTreatmentOption[] {
|
|
55
|
+
return [
|
|
56
|
+
KEEP_FLOOR_OPTION,
|
|
57
|
+
...releaseRefundDispositionOptions(allowed).map((option) => ({
|
|
58
|
+
value: option.value,
|
|
59
|
+
label: option.value === 'NO_REFUND'
|
|
60
|
+
? 'Reduce return price — no refund'
|
|
61
|
+
: 'Reduce return price — pending refund',
|
|
62
|
+
description: option.value === 'NO_REFUND'
|
|
63
|
+
? 'Lower the booking total to the cheaper return price without creating a customer credit.'
|
|
64
|
+
: 'Lower the booking total and record a pending refund for the removed return value.',
|
|
65
|
+
})),
|
|
66
|
+
];
|
|
67
|
+
}
|
|
68
|
+
|
|
37
69
|
export function adminRemovalOperationLabel(operation: AdminAmendmentOperationSnapshot): string {
|
|
38
70
|
const component = operation.componentKey.split(':').slice(1).join(':') || operation.componentKey;
|
|
39
71
|
const quantity = operation.quantityDelta ? ` (${Math.abs(operation.quantityDelta)})` : '';
|
|
@@ -85,6 +85,7 @@ export interface AdminChangeLatestQuote {
|
|
|
85
85
|
quotedTotal?: number;
|
|
86
86
|
paymentCreditTotal?: number;
|
|
87
87
|
refundDecisionOperations?: AdminAmendmentOperationSnapshot[];
|
|
88
|
+
returnPriceTreatmentOperations?: AdminAmendmentOperationSnapshot[];
|
|
88
89
|
allowedRefundDispositionsByOperationId?: Record<string, AdminAmendmentRefundDisposition[]>;
|
|
89
90
|
removedValueByOperationId?: Record<string, number>;
|
|
90
91
|
serverDisplay?: { total: number; subtotal: number; tax: number };
|
|
@@ -257,6 +257,7 @@ export interface ChangeQuoteUiSlice {
|
|
|
257
257
|
quotedTotal?: number;
|
|
258
258
|
paymentCreditTotal?: number;
|
|
259
259
|
refundDecisionOperations?: ChangeBookingQuoteResponse['refundDecisionOperations'];
|
|
260
|
+
returnPriceTreatmentOperations?: ChangeBookingQuoteResponse['returnPriceTreatmentOperations'];
|
|
260
261
|
allowedRefundDispositionsByOperationId?: ChangeBookingQuoteResponse['allowedRefundDispositionsByOperationId'];
|
|
261
262
|
removedValueByOperationId?: ChangeBookingQuoteResponse['removedValueByOperationId'];
|
|
262
263
|
serverDisplay?: { total: number; subtotal: number; tax: number };
|
|
@@ -297,6 +298,7 @@ export function sliceChangeQuoteForUi(
|
|
|
297
298
|
quotedTotal: pricingQuote?.payableTotal ?? pricingQuote?.totalAmount ?? quote.proposed?.total ?? quote.newReceipt?.total,
|
|
298
299
|
paymentCreditTotal: pricingQuote?.paymentCreditTotal ?? quote.paymentCreditTotal,
|
|
299
300
|
refundDecisionOperations: quote.refundDecisionOperations,
|
|
301
|
+
returnPriceTreatmentOperations: quote.returnPriceTreatmentOperations,
|
|
300
302
|
allowedRefundDispositionsByOperationId: quote.allowedRefundDispositionsByOperationId,
|
|
301
303
|
removedValueByOperationId: quote.removedValueByOperationId,
|
|
302
304
|
...(serverDisplay ? { serverDisplay } : {}),
|
package/src/lib/booking-api.ts
CHANGED
|
@@ -1335,6 +1335,11 @@ export interface AdminChangeBookingQuoteV2Data {
|
|
|
1335
1335
|
reasonIfBlocked?: string | null;
|
|
1336
1336
|
unsupportedFeatures?: string[];
|
|
1337
1337
|
refundDecisionOperations?: AdminAmendmentOperationSnapshot[];
|
|
1338
|
+
/**
|
|
1339
|
+
* CHANGE_RETURN ops. Omit disposition to keep the paid-return floor; send
|
|
1340
|
+
* PENDING_REFUND / NO_REFUND to reprice and settle removed value.
|
|
1341
|
+
*/
|
|
1342
|
+
returnPriceTreatmentOperations?: AdminAmendmentOperationSnapshot[];
|
|
1338
1343
|
allowedRefundDispositionsByOperationId?: Record<string, AdminAmendmentRefundDisposition[]>;
|
|
1339
1344
|
removedValueByOperationId?: Record<string, number>;
|
|
1340
1345
|
}
|
|
@@ -1475,6 +1480,11 @@ export interface ChangeBookingQuoteResponse {
|
|
|
1475
1480
|
reasonIfBlocked?: string;
|
|
1476
1481
|
/** Admin-only removal decisions required before this quote can be applied. */
|
|
1477
1482
|
refundDecisionOperations?: AdminAmendmentOperationSnapshot[];
|
|
1483
|
+
/**
|
|
1484
|
+
* Admin CHANGE_RETURN ops. Default (no disposition) keeps the paid return floor;
|
|
1485
|
+
* PENDING_REFUND / NO_REFUND reprices the return component.
|
|
1486
|
+
*/
|
|
1487
|
+
returnPriceTreatmentOperations?: AdminAmendmentOperationSnapshot[];
|
|
1478
1488
|
/** Server-authorized choices. Release UI intentionally filters out immediate refund. */
|
|
1479
1489
|
allowedRefundDispositionsByOperationId?: Record<string, AdminAmendmentRefundDisposition[]>;
|
|
1480
1490
|
/** Original paid basis plus allocated refundable tax for each removal operation. */
|
|
@@ -1665,6 +1675,7 @@ export function mapAdminChangeBookingQuoteV2Data(
|
|
|
1665
1675
|
canProceed: data.canApply,
|
|
1666
1676
|
reasonIfBlocked: data.reasonIfBlocked ?? undefined,
|
|
1667
1677
|
refundDecisionOperations: data.refundDecisionOperations ?? [],
|
|
1678
|
+
returnPriceTreatmentOperations: data.returnPriceTreatmentOperations ?? [],
|
|
1668
1679
|
allowedRefundDispositionsByOperationId:
|
|
1669
1680
|
data.allowedRefundDispositionsByOperationId ?? {},
|
|
1670
1681
|
removedValueByOperationId: data.removedValueByOperationId ?? {},
|
|
@@ -18,6 +18,7 @@ import {
|
|
|
18
18
|
noRefundRemovedValue,
|
|
19
19
|
refundDecisionsComplete,
|
|
20
20
|
releaseRefundDispositionOptions,
|
|
21
|
+
returnPriceTreatmentOptions,
|
|
21
22
|
} from '../src/components/booking/admin-refund-disposition';
|
|
22
23
|
import {
|
|
23
24
|
applyResourceAdjustments,
|
|
@@ -186,6 +187,36 @@ test('admin removal quote preserves explicit release refund decisions for the pr
|
|
|
186
187
|
);
|
|
187
188
|
});
|
|
188
189
|
|
|
190
|
+
test('admin return price treatment defaults to keep floor and maps optional reprice choices', () => {
|
|
191
|
+
const operation = {
|
|
192
|
+
operationId: 'op_change_return',
|
|
193
|
+
type: 'CHANGE_RETURN',
|
|
194
|
+
componentKey: 'return',
|
|
195
|
+
};
|
|
196
|
+
const mapped = mapAdminChangeBookingQuoteV2Data({
|
|
197
|
+
oldReceipt: { currency: 'CAD', grossSubtotal: 214.48, taxAmount: 18.23, payableTotal: 232.71 },
|
|
198
|
+
newQuote: { currency: 'CAD', payableTotal: 232.71, balanceDelta: 0, amountToCharge: 0, refundCandidate: 0 },
|
|
199
|
+
canApply: true,
|
|
200
|
+
returnPriceTreatmentOperations: [operation],
|
|
201
|
+
allowedRefundDispositionsByOperationId: {
|
|
202
|
+
[operation.operationId]: ['PENDING_REFUND', 'NO_REFUND'],
|
|
203
|
+
},
|
|
204
|
+
});
|
|
205
|
+
const slice = sliceChangeQuoteForUi(
|
|
206
|
+
mapped,
|
|
207
|
+
{ total: 232.71, subtotal: 214.48, tax: 18.23 },
|
|
208
|
+
'CAD',
|
|
209
|
+
);
|
|
210
|
+
|
|
211
|
+
assert.deepEqual(slice.returnPriceTreatmentOperations, [operation]);
|
|
212
|
+
assert.deepEqual(
|
|
213
|
+
returnPriceTreatmentOptions(
|
|
214
|
+
slice.allowedRefundDispositionsByOperationId?.[operation.operationId],
|
|
215
|
+
).map((option) => option.value),
|
|
216
|
+
['KEEP_FLOOR', 'PENDING_REFUND', 'NO_REFUND'],
|
|
217
|
+
);
|
|
218
|
+
});
|
|
219
|
+
|
|
189
220
|
test('changing admin refund treatment creates a distinct authoritative quote request', () => {
|
|
190
221
|
const base = {
|
|
191
222
|
bookingReference: 'DE8H04DX',
|