@ordergroove/offers 2.46.0 → 2.46.1-alpha-PR-1285-2.53
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/dist/bundle-report.html +31 -31
- package/dist/offers.js +72 -72
- package/dist/offers.js.map +4 -4
- package/package.json +2 -2
- package/src/components/Offer.js +3 -1
- package/src/components/Price.js +31 -11
- package/src/components/__tests__/Price.spec.js +74 -1
- package/src/core/__tests__/experiments.spec.js +16 -3
- package/src/core/__tests__/reducer.spec.js +152 -1
- package/src/core/__tests__/selectors.spec.js +405 -1
- package/src/core/adapters.js +2 -0
- package/src/core/constants.js +7 -0
- package/src/core/experiments.js +3 -2
- package/src/core/reducer.ts +41 -9
- package/src/core/selectors.ts +66 -1
- package/src/core/types/api.ts +19 -1
- package/src/core/types/reducer.ts +14 -1
- package/src/shopify/__tests__/productPlan.spec.js +3 -3
- package/src/shopify/__tests__/shopifyMiddleware.spec.js +227 -6
- package/src/shopify/__tests__/shopifyReducer.spec.js +90 -17
- package/src/shopify/reducers/productPlans.ts +2 -1
- package/src/shopify/shopifyMiddleware.ts +45 -7
- package/src/shopify/shopifyReducer.ts +21 -0
- package/src/shopify/types/productPlan.ts +1 -0
|
@@ -2,6 +2,7 @@ import { Order, Incentive as ApiIncentive, MerchantSettings, OfferResponse } fro
|
|
|
2
2
|
import { type Offer } from '../../components/Offer';
|
|
3
3
|
import { ShopifyCart, ShopifyProductEntity } from '../../shopify/types/shopify';
|
|
4
4
|
import reducer from '../reducer';
|
|
5
|
+
import { ProductPlanEntity } from '../../shopify/types/productPlan';
|
|
5
6
|
|
|
6
7
|
export type State = ReturnType<typeof reducer>;
|
|
7
8
|
|
|
@@ -16,8 +17,16 @@ export type NextUpcomingOrderState = Partial<
|
|
|
16
17
|
|
|
17
18
|
export type IncentivesState = Record<string, IncentiveObject>;
|
|
18
19
|
|
|
19
|
-
type Incentive = ApiIncentive & {
|
|
20
|
+
export type Incentive = ApiIncentive & {
|
|
20
21
|
id: string;
|
|
22
|
+
/**
|
|
23
|
+
* undefined when the offer profile is not standardized
|
|
24
|
+
*/
|
|
25
|
+
criteria?: {
|
|
26
|
+
node_type: string;
|
|
27
|
+
premise_value: unknown;
|
|
28
|
+
standard: string;
|
|
29
|
+
};
|
|
21
30
|
};
|
|
22
31
|
|
|
23
32
|
export type IncentiveObject = {
|
|
@@ -68,6 +77,10 @@ export type OptedOutState = { id: string }[];
|
|
|
68
77
|
|
|
69
78
|
export type AutoshipByDefaultState = Record<string, boolean>;
|
|
70
79
|
|
|
80
|
+
export type PriceState = { [productId: string]: { value: number } };
|
|
81
|
+
|
|
82
|
+
export type ProductPlansState = { [productId: string]: ProductPlanEntity[] };
|
|
83
|
+
|
|
71
84
|
// payload types
|
|
72
85
|
|
|
73
86
|
export type ReceiveOfferPayload = OfferResponse & {
|
|
@@ -308,7 +308,7 @@ describe('Shopify productPlan Reducer', () => {
|
|
|
308
308
|
|
|
309
309
|
const productPlanCreated = mapSellingPlanToDiscount(allocation, [], 'USD');
|
|
310
310
|
|
|
311
|
-
expect(productPlanCreated).toEqual(expectedProductPlan);
|
|
311
|
+
expect(productPlanCreated).toEqual(jasmine.objectContaining(expectedProductPlan));
|
|
312
312
|
});
|
|
313
313
|
|
|
314
314
|
it('should create prepaid product plan', () => {
|
|
@@ -371,7 +371,7 @@ describe('Shopify productPlan Reducer', () => {
|
|
|
371
371
|
|
|
372
372
|
const productPlanCreated = mapSellingPlanToDiscount(allocation, sellingPlans, 'USD');
|
|
373
373
|
|
|
374
|
-
expect(productPlanCreated).toEqual(expectedProductPlan);
|
|
374
|
+
expect(productPlanCreated).toEqual(jasmine.objectContaining(expectedProductPlan));
|
|
375
375
|
});
|
|
376
376
|
|
|
377
377
|
it('should create prepaid product plan that rounds subscriptionPrice to nearest decimal', () => {
|
|
@@ -512,7 +512,7 @@ describe('Shopify productPlan Reducer', () => {
|
|
|
512
512
|
|
|
513
513
|
const productPlanCreated = mapSellingPlanToDiscount(allocation, sellingPlans, 'USD');
|
|
514
514
|
|
|
515
|
-
expect(productPlanCreated).toEqual(expectedProductPlan);
|
|
515
|
+
expect(productPlanCreated).toEqual(jasmine.objectContaining(expectedProductPlan));
|
|
516
516
|
});
|
|
517
517
|
});
|
|
518
518
|
|
|
@@ -7,7 +7,12 @@ import {
|
|
|
7
7
|
PRODUCT_CHANGE_PREPAID_SHIPMENTS,
|
|
8
8
|
SETUP_CART
|
|
9
9
|
} from '../../core/constants';
|
|
10
|
-
import {
|
|
10
|
+
import {
|
|
11
|
+
synchronizeCartOptin,
|
|
12
|
+
getTrackingEvent,
|
|
13
|
+
guessProductHandle,
|
|
14
|
+
synchronizeSellingPlan
|
|
15
|
+
} from '../shopifyMiddleware';
|
|
11
16
|
import { getOrCreateHidden } from '../../core/utils';
|
|
12
17
|
|
|
13
18
|
function makeForm(addInput = true) {
|
|
@@ -92,7 +97,7 @@ describe('getTrackingEvent', () => {
|
|
|
92
97
|
});
|
|
93
98
|
|
|
94
99
|
describe('synchronizeCartOptin', () => {
|
|
95
|
-
let store, offer, frequency, product;
|
|
100
|
+
let store, offer, frequency, product, defaultState;
|
|
96
101
|
beforeEach(() => {
|
|
97
102
|
store = {
|
|
98
103
|
dispatch: jasmine.createSpy('dispatch'),
|
|
@@ -106,6 +111,23 @@ describe('synchronizeCartOptin', () => {
|
|
|
106
111
|
frequency = '1234';
|
|
107
112
|
product = { id: '38995975209111:original-hash' };
|
|
108
113
|
|
|
114
|
+
defaultState = {
|
|
115
|
+
optedin: [],
|
|
116
|
+
offerId: 'offer-id-1234',
|
|
117
|
+
productPlans: {
|
|
118
|
+
38995975209111: [
|
|
119
|
+
{
|
|
120
|
+
frequency: '688815178030'
|
|
121
|
+
},
|
|
122
|
+
{
|
|
123
|
+
frequency: '1234'
|
|
124
|
+
}
|
|
125
|
+
]
|
|
126
|
+
}
|
|
127
|
+
};
|
|
128
|
+
|
|
129
|
+
store.getState.and.returnValue(defaultState);
|
|
130
|
+
|
|
109
131
|
fetchMock.route(
|
|
110
132
|
'/cart.js',
|
|
111
133
|
{
|
|
@@ -134,12 +156,64 @@ describe('synchronizeCartOptin', () => {
|
|
|
134
156
|
{ method: 'POST', repeat: 1 }
|
|
135
157
|
);
|
|
136
158
|
|
|
159
|
+
fetchMock.route(
|
|
160
|
+
'/cart/update.js',
|
|
161
|
+
{
|
|
162
|
+
attributes: {}
|
|
163
|
+
},
|
|
164
|
+
{ method: 'POST', repeat: 1 }
|
|
165
|
+
);
|
|
166
|
+
|
|
137
167
|
fetchMock.mockGlobal();
|
|
168
|
+
|
|
169
|
+
// mock the date so that the tracking key is predictable
|
|
170
|
+
jasmine.clock().install();
|
|
171
|
+
jasmine.clock().mockDate(new Date('2025-01-01T00:00:00.000Z'));
|
|
138
172
|
});
|
|
139
173
|
|
|
140
174
|
afterEach(() => {
|
|
141
175
|
fetchMock.removeRoutes().unmockGlobal();
|
|
142
176
|
offer.remove();
|
|
177
|
+
|
|
178
|
+
jasmine.clock().uninstall();
|
|
179
|
+
});
|
|
180
|
+
|
|
181
|
+
it('should update cart attributes', async () => {
|
|
182
|
+
await synchronizeCartOptin({ type: OPTIN_PRODUCT, payload: { offer, frequency, product } }, store);
|
|
183
|
+
|
|
184
|
+
const lastUpdateCall = fetchMock.callHistory.calls('/cart/update.js').at(-1);
|
|
185
|
+
const body = JSON.parse(lastUpdateCall.options.body);
|
|
186
|
+
|
|
187
|
+
expect(body).toEqual({
|
|
188
|
+
attributes: {
|
|
189
|
+
og__1735689600: '38995975209111:original-hash,optin_product,,1234,'
|
|
190
|
+
}
|
|
191
|
+
});
|
|
192
|
+
});
|
|
193
|
+
|
|
194
|
+
it('should update cart attributes when Shopify Discount Function in use', async () => {
|
|
195
|
+
store.getState.and.returnValue({
|
|
196
|
+
...defaultState,
|
|
197
|
+
productPlans: {
|
|
198
|
+
38995975209111: [
|
|
199
|
+
{
|
|
200
|
+
frequency: '688815178030',
|
|
201
|
+
hasPriceAdjustments: false
|
|
202
|
+
}
|
|
203
|
+
]
|
|
204
|
+
}
|
|
205
|
+
});
|
|
206
|
+
await synchronizeCartOptin({ type: OPTIN_PRODUCT, payload: { offer, frequency, product } }, store);
|
|
207
|
+
|
|
208
|
+
const lastUpdateCall = fetchMock.callHistory.calls('/cart/update.js').at(-1);
|
|
209
|
+
const body = JSON.parse(lastUpdateCall.options.body);
|
|
210
|
+
|
|
211
|
+
expect(body).toEqual({
|
|
212
|
+
attributes: {
|
|
213
|
+
og__1735689600: '38995975209111:original-hash,optin_product,,1234,',
|
|
214
|
+
__ordergroove_offer_id: 'offer-id-1234'
|
|
215
|
+
}
|
|
216
|
+
});
|
|
143
217
|
});
|
|
144
218
|
|
|
145
219
|
it('should set new has product id', async () => {
|
|
@@ -173,7 +247,9 @@ describe('synchronizeCartOptin', () => {
|
|
|
173
247
|
document.body.appendChild(sectionDiv);
|
|
174
248
|
|
|
175
249
|
await synchronizeCartOptin({ type: OPTIN_PRODUCT, payload: { offer, frequency, product } }, store);
|
|
176
|
-
expect(fetchMock.callHistory.
|
|
250
|
+
expect(fetchMock.callHistory.calls('/cart/change.js').at(-1).options.body).toContain(
|
|
251
|
+
'"sections":["123456789__cart-items"]'
|
|
252
|
+
);
|
|
177
253
|
sectionDiv.remove();
|
|
178
254
|
});
|
|
179
255
|
|
|
@@ -185,12 +261,15 @@ describe('synchronizeCartOptin', () => {
|
|
|
185
261
|
document.body.appendChild(sectionDiv);
|
|
186
262
|
|
|
187
263
|
await synchronizeCartOptin({ type: OPTIN_PRODUCT, payload: { offer, frequency, product } }, store);
|
|
188
|
-
expect(fetchMock.callHistory.
|
|
264
|
+
expect(fetchMock.callHistory.calls('/cart/change.js').at(-1).options.body).toContain(
|
|
265
|
+
'"sections":["123456789__cart-footer"]'
|
|
266
|
+
);
|
|
189
267
|
sectionDiv.remove();
|
|
190
268
|
});
|
|
191
269
|
|
|
192
270
|
it('should get the subscribed frequency when no frequency is provided in the action payload', async () => {
|
|
193
271
|
store.getState.and.returnValue({
|
|
272
|
+
...defaultState,
|
|
194
273
|
optedin: [
|
|
195
274
|
{
|
|
196
275
|
id: '38995975209111:original-hash',
|
|
@@ -223,11 +302,14 @@ describe('synchronizeCartOptin', () => {
|
|
|
223
302
|
}
|
|
224
303
|
});
|
|
225
304
|
|
|
226
|
-
expect(fetchMock.callHistory.
|
|
305
|
+
expect(fetchMock.callHistory.calls('/cart/change.js').at(-1).options.body).toContain(
|
|
306
|
+
'"selling_plan":"688815178030"'
|
|
307
|
+
);
|
|
227
308
|
});
|
|
228
309
|
|
|
229
310
|
it('should have no selling plan when product is opted out', async () => {
|
|
230
311
|
store.getState.and.returnValue({
|
|
312
|
+
...defaultState,
|
|
231
313
|
optedin: []
|
|
232
314
|
});
|
|
233
315
|
|
|
@@ -254,7 +336,7 @@ describe('synchronizeCartOptin', () => {
|
|
|
254
336
|
}
|
|
255
337
|
});
|
|
256
338
|
|
|
257
|
-
expect(fetchMock.callHistory.
|
|
339
|
+
expect(fetchMock.callHistory.calls('/cart/change.js').at(-1).options.body).toContain('"selling_plan":null');
|
|
258
340
|
});
|
|
259
341
|
});
|
|
260
342
|
|
|
@@ -291,3 +373,142 @@ describe('guessProductHandle', () => {
|
|
|
291
373
|
expect(guessProductHandle()).toEqual('some-meta-json');
|
|
292
374
|
});
|
|
293
375
|
});
|
|
376
|
+
|
|
377
|
+
describe('synchronizeSellingPlan', () => {
|
|
378
|
+
const testProduct = '123456';
|
|
379
|
+
const testSellingPlan = '688815178030';
|
|
380
|
+
const testSessionId = 'session-123';
|
|
381
|
+
const testOfferId = 'offer-id-1234';
|
|
382
|
+
|
|
383
|
+
function makeCartAddForm(productId = testProduct) {
|
|
384
|
+
const element = document.createElement('form');
|
|
385
|
+
element.action = '/cart/add';
|
|
386
|
+
element.innerHTML = `
|
|
387
|
+
<input value="${productId}" name="id" type="hidden">
|
|
388
|
+
`;
|
|
389
|
+
document.body.appendChild(element);
|
|
390
|
+
return element;
|
|
391
|
+
}
|
|
392
|
+
|
|
393
|
+
function getFormData(formElement) {
|
|
394
|
+
const data = Object.fromEntries(new FormData(formElement));
|
|
395
|
+
delete data.id;
|
|
396
|
+
return data;
|
|
397
|
+
}
|
|
398
|
+
|
|
399
|
+
let store;
|
|
400
|
+
let offerElement = {
|
|
401
|
+
isCart: false,
|
|
402
|
+
shouldEnableOffer: true
|
|
403
|
+
};
|
|
404
|
+
|
|
405
|
+
beforeEach(() => {
|
|
406
|
+
document.body.innerHTML = '';
|
|
407
|
+
store = {
|
|
408
|
+
getState: jasmine.createSpy('getState')
|
|
409
|
+
};
|
|
410
|
+
store.getState.and.returnValue({
|
|
411
|
+
sessionId: testSessionId,
|
|
412
|
+
optedin: [{ id: testProduct, frequency: testSellingPlan }],
|
|
413
|
+
productPlans: {},
|
|
414
|
+
offerId: testOfferId
|
|
415
|
+
});
|
|
416
|
+
});
|
|
417
|
+
|
|
418
|
+
afterEach(() => {
|
|
419
|
+
document.body.innerHTML = '';
|
|
420
|
+
});
|
|
421
|
+
|
|
422
|
+
it('should add attributes when product is opted in', () => {
|
|
423
|
+
const formElement = makeCartAddForm();
|
|
424
|
+
expect(getFormData(formElement)).toEqual({});
|
|
425
|
+
|
|
426
|
+
synchronizeSellingPlan(store, offerElement);
|
|
427
|
+
|
|
428
|
+
expect(getFormData(formElement)).toEqual({
|
|
429
|
+
selling_plan: testSellingPlan,
|
|
430
|
+
'attributes[og__session]': testSessionId
|
|
431
|
+
});
|
|
432
|
+
});
|
|
433
|
+
|
|
434
|
+
it('should add attributes when product is opted in and Shopify Discount Function is in use', () => {
|
|
435
|
+
store.getState.and.returnValue({
|
|
436
|
+
...store.getState(),
|
|
437
|
+
productPlans: {
|
|
438
|
+
[testProduct]: [
|
|
439
|
+
{
|
|
440
|
+
frequency: testSellingPlan,
|
|
441
|
+
hasPriceAdjustments: false
|
|
442
|
+
}
|
|
443
|
+
]
|
|
444
|
+
}
|
|
445
|
+
});
|
|
446
|
+
|
|
447
|
+
const formElement = makeCartAddForm();
|
|
448
|
+
expect(getFormData(formElement)).toEqual({});
|
|
449
|
+
|
|
450
|
+
synchronizeSellingPlan(store, offerElement);
|
|
451
|
+
|
|
452
|
+
expect(getFormData(formElement)).toEqual({
|
|
453
|
+
selling_plan: testSellingPlan,
|
|
454
|
+
'attributes[og__session]': testSessionId,
|
|
455
|
+
'attributes[__ordergroove_offer_id]': testOfferId
|
|
456
|
+
});
|
|
457
|
+
});
|
|
458
|
+
|
|
459
|
+
it('should handle multiple forms on the page', () => {
|
|
460
|
+
const formElement1 = makeCartAddForm(testProduct);
|
|
461
|
+
const formElement2 = makeCartAddForm(testProduct);
|
|
462
|
+
|
|
463
|
+
synchronizeSellingPlan(store, offerElement);
|
|
464
|
+
|
|
465
|
+
expect(getFormData(formElement1)).toEqual({
|
|
466
|
+
selling_plan: testSellingPlan,
|
|
467
|
+
'attributes[og__session]': testSessionId
|
|
468
|
+
});
|
|
469
|
+
expect(getFormData(formElement2)).toEqual({
|
|
470
|
+
selling_plan: testSellingPlan,
|
|
471
|
+
'attributes[og__session]': testSessionId
|
|
472
|
+
});
|
|
473
|
+
});
|
|
474
|
+
|
|
475
|
+
it('should remove selling_plan input when product is not opted in', () => {
|
|
476
|
+
store.getState.and.returnValue({
|
|
477
|
+
...store.getState(),
|
|
478
|
+
sessionId: testSessionId,
|
|
479
|
+
optedin: []
|
|
480
|
+
});
|
|
481
|
+
|
|
482
|
+
const formElement = makeCartAddForm();
|
|
483
|
+
// Add an existing selling_plan input
|
|
484
|
+
const existingInput = document.createElement('input');
|
|
485
|
+
existingInput.name = 'selling_plan';
|
|
486
|
+
existingInput.value = testSellingPlan;
|
|
487
|
+
existingInput.type = 'hidden';
|
|
488
|
+
formElement.appendChild(existingInput);
|
|
489
|
+
|
|
490
|
+
expect(getFormData(formElement).selling_plan).toEqual(testSellingPlan);
|
|
491
|
+
|
|
492
|
+
synchronizeSellingPlan(store, offerElement);
|
|
493
|
+
|
|
494
|
+
expect(getFormData(formElement).selling_plan).toEqual(undefined);
|
|
495
|
+
});
|
|
496
|
+
|
|
497
|
+
it('should not run when offerElement.isCart is true', () => {
|
|
498
|
+
const formElement = makeCartAddForm();
|
|
499
|
+
const offerElement = { isCart: true, shouldEnableOffer: true };
|
|
500
|
+
|
|
501
|
+
synchronizeSellingPlan(store, offerElement);
|
|
502
|
+
|
|
503
|
+
expect(getFormData(formElement)).toEqual({});
|
|
504
|
+
});
|
|
505
|
+
|
|
506
|
+
it('should not run when offerElement.shouldEnableOffer is false', () => {
|
|
507
|
+
const formElement = makeCartAddForm();
|
|
508
|
+
const offerElement = { isCart: false, shouldEnableOffer: false };
|
|
509
|
+
|
|
510
|
+
synchronizeSellingPlan(store, offerElement);
|
|
511
|
+
|
|
512
|
+
expect(getFormData(formElement)).toEqual({});
|
|
513
|
+
});
|
|
514
|
+
});
|
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
import * as constants from '../../core/constants';
|
|
2
|
-
import { autoshipEligible, inStock, offer, optedin, productOffer, productPlans } from '../shopifyReducer';
|
|
3
|
-
import { getObjectStructuredProductPlans } from '../../core/adapters';
|
|
2
|
+
import { autoshipEligible, inStock, offer, optedin, price, productOffer, productPlans } from '../shopifyReducer';
|
|
4
3
|
import { DEFAULT_PAY_AS_YOU_GO_GROUP_NAME } from '../utils';
|
|
5
4
|
|
|
6
5
|
describe('autoshipEligible', () => {
|
|
@@ -1052,6 +1051,65 @@ describe('optedin', () => {
|
|
|
1052
1051
|
});
|
|
1053
1052
|
});
|
|
1054
1053
|
|
|
1054
|
+
describe('price', () => {
|
|
1055
|
+
it('should return price for each variant given action SETUP_PRODUCT', () => {
|
|
1056
|
+
const actual = price(
|
|
1057
|
+
{},
|
|
1058
|
+
{
|
|
1059
|
+
type: constants.SETUP_PRODUCT,
|
|
1060
|
+
payload: {
|
|
1061
|
+
product: {
|
|
1062
|
+
id: 'yum product id',
|
|
1063
|
+
variants: [
|
|
1064
|
+
{
|
|
1065
|
+
id: 'yum variant id 1',
|
|
1066
|
+
price: 1000
|
|
1067
|
+
},
|
|
1068
|
+
{
|
|
1069
|
+
id: 'yum variant id 2',
|
|
1070
|
+
price: 2500
|
|
1071
|
+
}
|
|
1072
|
+
]
|
|
1073
|
+
}
|
|
1074
|
+
}
|
|
1075
|
+
}
|
|
1076
|
+
);
|
|
1077
|
+
|
|
1078
|
+
expect(actual).toEqual({
|
|
1079
|
+
'yum variant id 1': { value: 1000 },
|
|
1080
|
+
'yum variant id 2': { value: 2500 }
|
|
1081
|
+
});
|
|
1082
|
+
});
|
|
1083
|
+
|
|
1084
|
+
it('should return unmodified state given action SETUP_PRODUCT with no variants', () => {
|
|
1085
|
+
const actual = price(
|
|
1086
|
+
{ 'yum existing key': 'yum existing value' },
|
|
1087
|
+
{
|
|
1088
|
+
type: constants.SETUP_PRODUCT,
|
|
1089
|
+
payload: {
|
|
1090
|
+
product: {
|
|
1091
|
+
id: 'yum product id'
|
|
1092
|
+
}
|
|
1093
|
+
}
|
|
1094
|
+
}
|
|
1095
|
+
);
|
|
1096
|
+
|
|
1097
|
+
expect(actual).toEqual({ 'yum existing key': 'yum existing value' });
|
|
1098
|
+
});
|
|
1099
|
+
|
|
1100
|
+
it('should return unmodified state given unsupported action', () => {
|
|
1101
|
+
const actual = price(
|
|
1102
|
+
{ 'yum existing key': 'yum existing value' },
|
|
1103
|
+
{
|
|
1104
|
+
type: 'yum unsupported action',
|
|
1105
|
+
payload: {}
|
|
1106
|
+
}
|
|
1107
|
+
);
|
|
1108
|
+
|
|
1109
|
+
expect(actual).toEqual({ 'yum existing key': 'yum existing value' });
|
|
1110
|
+
});
|
|
1111
|
+
});
|
|
1112
|
+
|
|
1055
1113
|
describe('productOffer', () => {
|
|
1056
1114
|
it('should return unmodified state', () => {
|
|
1057
1115
|
const actual = productOffer({ 'yum existing key': 'yum existing value' });
|
|
@@ -1399,7 +1457,8 @@ describe('productPlans', () => {
|
|
|
1399
1457
|
prepaidShipments: null,
|
|
1400
1458
|
regularPrice: '$0.50',
|
|
1401
1459
|
subscriptionPrice: '$0.25',
|
|
1402
|
-
discountRate: '$0.25'
|
|
1460
|
+
discountRate: '$0.25',
|
|
1461
|
+
hasPriceAdjustments: true
|
|
1403
1462
|
}
|
|
1404
1463
|
],
|
|
1405
1464
|
'yum variant id 2': [
|
|
@@ -1408,7 +1467,8 @@ describe('productPlans', () => {
|
|
|
1408
1467
|
prepaidShipments: null,
|
|
1409
1468
|
regularPrice: '$0.10',
|
|
1410
1469
|
subscriptionPrice: '$0.08',
|
|
1411
|
-
discountRate: '$0.02'
|
|
1470
|
+
discountRate: '$0.02',
|
|
1471
|
+
hasPriceAdjustments: false
|
|
1412
1472
|
}
|
|
1413
1473
|
]
|
|
1414
1474
|
});
|
|
@@ -1424,7 +1484,8 @@ describe('productPlans', () => {
|
|
|
1424
1484
|
regularPrice: '$0.50',
|
|
1425
1485
|
subscriptionPrice: '$0.25',
|
|
1426
1486
|
discountRate: '$0.25',
|
|
1427
|
-
prepaidShipments: null
|
|
1487
|
+
prepaidShipments: null,
|
|
1488
|
+
hasPriceAdjustments: true
|
|
1428
1489
|
},
|
|
1429
1490
|
{
|
|
1430
1491
|
frequency: 'yum selling plan id prepaid 3 shipments',
|
|
@@ -1434,7 +1495,8 @@ describe('productPlans', () => {
|
|
|
1434
1495
|
prepaidShipments: 3,
|
|
1435
1496
|
regularPrepaidPrice: '$1.20',
|
|
1436
1497
|
prepaidSavingsPerShipment: '$0.10',
|
|
1437
|
-
prepaidSavingsTotal: '$0.30'
|
|
1498
|
+
prepaidSavingsTotal: '$0.30',
|
|
1499
|
+
hasPriceAdjustments: false
|
|
1438
1500
|
},
|
|
1439
1501
|
{
|
|
1440
1502
|
frequency: 'yum selling plan id prepaid 6 shipments',
|
|
@@ -1444,7 +1506,8 @@ describe('productPlans', () => {
|
|
|
1444
1506
|
prepaidShipments: 6,
|
|
1445
1507
|
regularPrepaidPrice: '$2.40',
|
|
1446
1508
|
prepaidSavingsPerShipment: '$0.10',
|
|
1447
|
-
prepaidSavingsTotal: '$0.60'
|
|
1509
|
+
prepaidSavingsTotal: '$0.60',
|
|
1510
|
+
hasPriceAdjustments: false
|
|
1448
1511
|
},
|
|
1449
1512
|
{
|
|
1450
1513
|
frequency: 'yum selling plan id prepaid 12 shipments',
|
|
@@ -1454,7 +1517,8 @@ describe('productPlans', () => {
|
|
|
1454
1517
|
prepaidShipments: 12,
|
|
1455
1518
|
regularPrepaidPrice: '$4.80',
|
|
1456
1519
|
prepaidSavingsPerShipment: '$0.10',
|
|
1457
|
-
prepaidSavingsTotal: '$1.20'
|
|
1520
|
+
prepaidSavingsTotal: '$1.20',
|
|
1521
|
+
hasPriceAdjustments: false
|
|
1458
1522
|
}
|
|
1459
1523
|
],
|
|
1460
1524
|
'yum variant id 2': [
|
|
@@ -1463,7 +1527,8 @@ describe('productPlans', () => {
|
|
|
1463
1527
|
regularPrice: '$0.10',
|
|
1464
1528
|
subscriptionPrice: '$0.08',
|
|
1465
1529
|
discountRate: '$0.02',
|
|
1466
|
-
prepaidShipments: null
|
|
1530
|
+
prepaidShipments: null,
|
|
1531
|
+
hasPriceAdjustments: false
|
|
1467
1532
|
}
|
|
1468
1533
|
]
|
|
1469
1534
|
});
|
|
@@ -1479,7 +1544,8 @@ describe('productPlans', () => {
|
|
|
1479
1544
|
prepaidShipments: null,
|
|
1480
1545
|
regularPrice: '£0.50',
|
|
1481
1546
|
subscriptionPrice: '£0.25',
|
|
1482
|
-
discountRate: '£0.25'
|
|
1547
|
+
discountRate: '£0.25',
|
|
1548
|
+
hasPriceAdjustments: true
|
|
1483
1549
|
}
|
|
1484
1550
|
],
|
|
1485
1551
|
'yum variant id 2': [
|
|
@@ -1488,7 +1554,8 @@ describe('productPlans', () => {
|
|
|
1488
1554
|
prepaidShipments: null,
|
|
1489
1555
|
regularPrice: '£0.10',
|
|
1490
1556
|
subscriptionPrice: '£0.08',
|
|
1491
|
-
discountRate: '£0.02'
|
|
1557
|
+
discountRate: '£0.02',
|
|
1558
|
+
hasPriceAdjustments: false
|
|
1492
1559
|
}
|
|
1493
1560
|
]
|
|
1494
1561
|
});
|
|
@@ -1504,7 +1571,8 @@ describe('productPlans', () => {
|
|
|
1504
1571
|
prepaidShipments: null,
|
|
1505
1572
|
regularPrice: '$0.50',
|
|
1506
1573
|
subscriptionPrice: '$0.25',
|
|
1507
|
-
discountRate: '$0.25'
|
|
1574
|
+
discountRate: '$0.25',
|
|
1575
|
+
hasPriceAdjustments: true
|
|
1508
1576
|
}
|
|
1509
1577
|
],
|
|
1510
1578
|
'yum variant key 2': [
|
|
@@ -1513,7 +1581,8 @@ describe('productPlans', () => {
|
|
|
1513
1581
|
prepaidShipments: null,
|
|
1514
1582
|
regularPrice: '$0.10',
|
|
1515
1583
|
subscriptionPrice: '$0.08',
|
|
1516
|
-
discountRate: '$0.02'
|
|
1584
|
+
discountRate: '$0.02',
|
|
1585
|
+
hasPriceAdjustments: false
|
|
1517
1586
|
}
|
|
1518
1587
|
]
|
|
1519
1588
|
});
|
|
@@ -1532,7 +1601,8 @@ describe('productPlans', () => {
|
|
|
1532
1601
|
prepaidShipments: 12,
|
|
1533
1602
|
regularPrepaidPrice: '$4.80',
|
|
1534
1603
|
prepaidSavingsPerShipment: '$0.10',
|
|
1535
|
-
prepaidSavingsTotal: '$1.20'
|
|
1604
|
+
prepaidSavingsTotal: '$1.20',
|
|
1605
|
+
hasPriceAdjustments: true
|
|
1536
1606
|
}
|
|
1537
1607
|
],
|
|
1538
1608
|
'yum variant key 2': [
|
|
@@ -1541,7 +1611,8 @@ describe('productPlans', () => {
|
|
|
1541
1611
|
prepaidShipments: null,
|
|
1542
1612
|
regularPrice: '$0.10',
|
|
1543
1613
|
subscriptionPrice: '$0.08',
|
|
1544
|
-
discountRate: '$0.02'
|
|
1614
|
+
discountRate: '$0.02',
|
|
1615
|
+
hasPriceAdjustments: false
|
|
1545
1616
|
}
|
|
1546
1617
|
]
|
|
1547
1618
|
});
|
|
@@ -1557,7 +1628,8 @@ describe('productPlans', () => {
|
|
|
1557
1628
|
prepaidShipments: null,
|
|
1558
1629
|
regularPrice: '£0.50',
|
|
1559
1630
|
subscriptionPrice: '£0.25',
|
|
1560
|
-
discountRate: '£0.25'
|
|
1631
|
+
discountRate: '£0.25',
|
|
1632
|
+
hasPriceAdjustments: true
|
|
1561
1633
|
}
|
|
1562
1634
|
],
|
|
1563
1635
|
'yum variant key 2': [
|
|
@@ -1566,7 +1638,8 @@ describe('productPlans', () => {
|
|
|
1566
1638
|
prepaidShipments: null,
|
|
1567
1639
|
regularPrice: '£0.10',
|
|
1568
1640
|
subscriptionPrice: '£0.08',
|
|
1569
|
-
discountRate: '£0.02'
|
|
1641
|
+
discountRate: '£0.02',
|
|
1642
|
+
hasPriceAdjustments: false
|
|
1570
1643
|
}
|
|
1571
1644
|
]
|
|
1572
1645
|
});
|
|
@@ -106,7 +106,8 @@ export const mapSellingPlanToDiscount = (
|
|
|
106
106
|
regularPrice: getAllocationRegularPrice(allocation, currency),
|
|
107
107
|
subscriptionPrice: getAllocationSubscriptionPrice(allocation, currency),
|
|
108
108
|
discountRate: getAllocationDiscountRate(allocation, currency),
|
|
109
|
-
prepaidShipments: getAllocationNumberOfShipments(allocation)
|
|
109
|
+
prepaidShipments: getAllocationNumberOfShipments(allocation),
|
|
110
|
+
hasPriceAdjustments: allocation.price_adjustments?.length > 0
|
|
110
111
|
};
|
|
111
112
|
|
|
112
113
|
if (isPrepaidAllocation(allocation)) {
|