@ordergroove/offers 2.43.0 → 2.44.0

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": "@ordergroove/offers",
3
- "version": "2.43.0",
3
+ "version": "2.44.0",
4
4
  "description": "offer state component",
5
5
  "author": "Eugenio Lattanzio <eugenio63@gmail.com>",
6
6
  "homepage": "https://github.com/ordergroove/plush-toys#readme",
@@ -49,5 +49,5 @@
49
49
  "@ordergroove/offers-templates": "^0.9.7",
50
50
  "@types/lodash.memoize": "^4.1.9"
51
51
  },
52
- "gitHead": "1d7eee6c50a2d2d57db5f8f94dd37f0640560c2c"
52
+ "gitHead": "6920106790e66edb68d2f452825f9dc4be5911d4"
53
53
  }
@@ -1,7 +1,7 @@
1
1
  import { READY, RECEIVE_MERCHANT_SETTINGS, REQUEST_OFFER, SET_EXPERIMENT_VARIANT, SETUP_PRODUCT } from './constants';
2
2
  import murmur from 'murmurhash-js';
3
3
  import { waitFor } from './waitUntilOffersReady';
4
- import { EXPERIMENT_SHOPIFY_APP_ID_PREFIX } from '../shopify/shopifyReducer';
4
+ import { isExperimentSellingPlanGroup } from '../shopify/utils';
5
5
 
6
6
  /**
7
7
  * Returns the index of a variant based on the provided key and variants.
@@ -77,9 +77,7 @@ function resolveShopifySetupProductWhenExperiment(variant, product, experimentSe
77
77
 
78
78
  if (experimentSettings.variants.length === 0) return;
79
79
 
80
- const sellingPlanGroups = product.selling_plan_groups.filter(group =>
81
- group.app_id?.startsWith(EXPERIMENT_SHOPIFY_APP_ID_PREFIX)
82
- );
80
+ const sellingPlanGroups = product.selling_plan_groups.filter(isExperimentSellingPlanGroup);
83
81
 
84
82
  if (sellingPlanGroups.length !== experimentSettings.variants.length) return;
85
83
 
@@ -6,9 +6,9 @@ import {
6
6
  getAllocationDiscountRate,
7
7
  addPrepaidPriceAndSavings,
8
8
  mapSellingPlanToDiscount,
9
- getSellingPlans,
10
- DEFAULT_PAY_AS_YOU_GO_GROUP_NAME
9
+ getSellingPlans
11
10
  } from '../reducers/productPlans';
11
+ import { DEFAULT_PAY_AS_YOU_GO_GROUP_NAME } from '../utils';
12
12
 
13
13
  describe('Shopify productPlan Reducer', () => {
14
14
  describe('isPrepaidAllocation', () => {
@@ -329,6 +329,9 @@ describe('Shopify productPlan Reducer', () => {
329
329
  const sellingPlans = [
330
330
  {
331
331
  id: 688412983572,
332
+ group: {
333
+ name: 'Prepaid-'
334
+ },
332
335
  name: 'Delivered every 1 month, prepaid for 3 shipments',
333
336
  description: null,
334
337
  options: [
@@ -410,7 +413,10 @@ describe('Shopify productPlan Reducer', () => {
410
413
  value_type: 'price',
411
414
  value: 4798
412
415
  }
413
- ]
416
+ ],
417
+ group: {
418
+ name: 'Prepaid-'
419
+ }
414
420
  }
415
421
  ];
416
422
 
@@ -462,7 +468,9 @@ describe('Shopify productPlan Reducer', () => {
462
468
  value: 4800
463
469
  }
464
470
  ],
465
- group_name: 'Prepaid-'
471
+ group: {
472
+ name: 'Prepaid-'
473
+ }
466
474
  },
467
475
  {
468
476
  id: 688412983573,
@@ -484,7 +492,9 @@ describe('Shopify productPlan Reducer', () => {
484
492
  value: 10
485
493
  }
486
494
  ],
487
- group_name: DEFAULT_PAY_AS_YOU_GO_GROUP_NAME
495
+ group: {
496
+ name: DEFAULT_PAY_AS_YOU_GO_GROUP_NAME
497
+ }
488
498
  }
489
499
  ];
490
500
 
@@ -560,7 +570,7 @@ describe('Shopify productPlan Reducer', () => {
560
570
 
561
571
  const expectedSellingPlans = [
562
572
  {
563
- group_name: 'Prepaid-',
573
+ group: product.selling_plan_groups[0],
564
574
  id: 688412721428,
565
575
  options: [
566
576
  {
@@ -576,7 +586,7 @@ describe('Shopify productPlan Reducer', () => {
576
586
  ]
577
587
  },
578
588
  {
579
- group_name: DEFAULT_PAY_AS_YOU_GO_GROUP_NAME,
589
+ group: product.selling_plan_groups[1],
580
590
  id: 688412623124,
581
591
  options: [
582
592
  {
@@ -587,7 +597,7 @@ describe('Shopify productPlan Reducer', () => {
587
597
  ]
588
598
  },
589
599
  {
590
- group_name: DEFAULT_PAY_AS_YOU_GO_GROUP_NAME,
600
+ group: product.selling_plan_groups[1],
591
601
  id: 688412655892,
592
602
  options: [
593
603
  {
@@ -10,7 +10,7 @@ import {
10
10
  textToFreq
11
11
  } from '../shopifyReducer';
12
12
  import { getObjectStructuredProductPlans } from '../../core/adapters';
13
- import { DEFAULT_PAY_AS_YOU_GO_GROUP_NAME } from '../reducers/productPlans';
13
+ import { DEFAULT_PAY_AS_YOU_GO_GROUP_NAME } from '../utils';
14
14
 
15
15
  describe('autoshipEligible', () => {
16
16
  it('should return true for each id given action RECEIVE_PRODUCT_PLANS', () => {
@@ -1760,6 +1760,7 @@ function getSetupProductActionForPrepaidProduct(currency = 'USD') {
1760
1760
  ],
1761
1761
  selling_plan_groups: [
1762
1762
  {
1763
+ name: 'Prepaid-1',
1763
1764
  selling_plans: [
1764
1765
  {
1765
1766
  id: 'yum selling plan id 1',
@@ -1795,6 +1796,7 @@ function getSetupProductActionForPrepaidProduct(currency = 'USD') {
1795
1796
  ]
1796
1797
  },
1797
1798
  {
1799
+ name: 'Prepaid-2',
1798
1800
  selling_plans: [
1799
1801
  {
1800
1802
  id: 'yum selling plan id prepaid 3 shipments',
@@ -1,4 +1,4 @@
1
- import { money, percentage } from '../utils';
1
+ import { getPayAsYouGoSellingPlanGroups, money, percentage } from '../utils';
2
2
 
3
3
  describe('Shopify Utils', () => {
4
4
  describe('Money', () => {
@@ -27,3 +27,47 @@ describe('Shopify Utils', () => {
27
27
  });
28
28
  });
29
29
  });
30
+
31
+ describe('selling plan queries', () => {
32
+ describe('getPayAsYouGoSellingPlanGroups', () => {
33
+ it('returns default group with app ID', () => {
34
+ expect(
35
+ getPayAsYouGoSellingPlanGroups([{ name: 'Subscribe and Save', app_id: 'ordergroove-subscribe-and-save' }])
36
+ .length
37
+ ).toBe(1);
38
+ });
39
+
40
+ it('returns default group without app ID', () => {
41
+ expect(getPayAsYouGoSellingPlanGroups([{ name: 'Subscribe and Save', app_id: null }]).length).toBe(1);
42
+ });
43
+
44
+ it('returns PSI selling plan groups', () => {
45
+ expect(
46
+ getPayAsYouGoSellingPlanGroups([{ name: 'incentive-group', app_id: 'ordergroove-subscribe-and-save' }]).length
47
+ ).toBe(1);
48
+ });
49
+
50
+ it('does not return prepaid selling plan groups', () => {
51
+ expect(
52
+ getPayAsYouGoSellingPlanGroups([{ name: 'Prepaid-1', app_id: 'ordergroove-prepaid-and-save' }]).length
53
+ ).toBe(0);
54
+ });
55
+
56
+ it('returns PSFL group with app ID', () => {
57
+ expect(
58
+ getPayAsYouGoSellingPlanGroups([
59
+ {
60
+ // name probably still starts with og_psfl
61
+ // but changing it so that the app_id branch is hit
62
+ name: 'changed-psfl-name',
63
+ app_id: 'ordergroove-product-specific-frequency-list'
64
+ }
65
+ ]).length
66
+ ).toBe(1);
67
+ });
68
+
69
+ it('returns PSFL group without app ID', () => {
70
+ expect(getPayAsYouGoSellingPlanGroups([{ name: 'og_psfl_1w', app_id: null }]).length).toBe(1);
71
+ });
72
+ });
73
+ });
@@ -1,4 +1,4 @@
1
- import { money, percentage } from '../utils';
1
+ import { getPayAsYouGoSellingPlan, money, percentage } from '../utils';
2
2
  import { ShopifyProductEntity, ShopifySellingPlanAllocationsEntity, ShopifySellingPlansEntity } from '../types/shopify';
3
3
  import { ProductPlanEntity } from '../types/productPlan';
4
4
 
@@ -92,8 +92,6 @@ export const addPrepaidPriceAndSavings = (
92
92
  return productPlan;
93
93
  };
94
94
 
95
- export const DEFAULT_PAY_AS_YOU_GO_GROUP_NAME = 'Subscribe and Save';
96
-
97
95
  export const mapSellingPlanToDiscount = (
98
96
  allocation: ShopifySellingPlanAllocationsEntity,
99
97
  sellingPlans: ShopifySellingPlansEntity[],
@@ -112,9 +110,7 @@ export const mapSellingPlanToDiscount = (
112
110
  };
113
111
 
114
112
  if (isPrepaidAllocation(allocation)) {
115
- const payAsYouGoPlan = sellingPlans.find(
116
- plan => plan.group_name === DEFAULT_PAY_AS_YOU_GO_GROUP_NAME && plan.options.length === 1
117
- );
113
+ const payAsYouGoPlan = getPayAsYouGoSellingPlan(sellingPlans);
118
114
  return addPrepaidPriceAndSavings(allocation, productPlan, payAsYouGoPlan, currency);
119
115
  }
120
116
 
@@ -130,9 +126,6 @@ export const sellingPlanAllocationsReducer = (
130
126
 
131
127
  export const getSellingPlans = (product: ShopifyProductEntity) =>
132
128
  product.selling_plan_groups.reduce<ShopifySellingPlansEntity[]>(
133
- (allGroups, group) => [
134
- ...allGroups,
135
- ...group.selling_plans.map(selling_plan => ({ ...selling_plan, group_name: group.name }))
136
- ],
129
+ (allGroups, group) => [...allGroups, ...group.selling_plans.map(selling_plan => ({ ...selling_plan, group }))],
137
130
  []
138
131
  );
@@ -34,14 +34,13 @@ import {
34
34
 
35
35
  import { getObjectStructuredProductPlans } from '../core/adapters';
36
36
 
37
- import {
38
- sellingPlanAllocationsReducer,
39
- getSellingPlans,
40
- DEFAULT_PAY_AS_YOU_GO_GROUP_NAME
41
- } from './reducers/productPlans';
37
+ import { sellingPlanAllocationsReducer, getSellingPlans } from './reducers/productPlans';
42
38
  import { experimentsReducer } from '../core/experiments';
43
-
44
- export const EXPERIMENT_SHOPIFY_APP_ID_PREFIX = 'ordergroove-subscribe-and-save-';
39
+ import {
40
+ getPayAsYouGoSellingPlanGroup,
41
+ getPayAsYouGoSellingPlanGroups,
42
+ isProductSpecificFrequencySellingPlanGroup
43
+ } from './utils';
45
44
 
46
45
  const overrideLineKey = (state, productId, newValue) => {
47
46
  const keys = Object.keys(state).filter(it => it.startsWith(productId.toString()));
@@ -129,42 +128,6 @@ export const reduceNewOptinsFromOfferResponse = (
129
128
  return acc;
130
129
  }, []);
131
130
 
132
- const getExperimentSellingPlanGroup = product => {
133
- return product?.selling_plan_groups.find(group => group.app_id?.startsWith(EXPERIMENT_SHOPIFY_APP_ID_PREFIX));
134
- };
135
-
136
- const getOGSellingPlanGroup = product => {
137
- // retrieve an OG Default or PSFL Selling Plan Group, preferring to return PSFL groups if they exist
138
- const productSpecificFrequencySellingPlanGroup = product?.selling_plan_groups.find(
139
- isProductSpecificFrequencySellingPlanGroup
140
- );
141
-
142
- return (
143
- productSpecificFrequencySellingPlanGroup ||
144
- getDefaultSubscriptionSellingPlanGroup(product) ||
145
- getExperimentSellingPlanGroup(product)
146
- );
147
- };
148
-
149
- const getOGSellingPlanGroups = product => {
150
- const sellingPlanGroups = (product?.selling_plan_groups || []).filter(
151
- group =>
152
- isDefaultSellingPlanGroup(group) ||
153
- isProductSpecificFrequencySellingPlanGroup(group) ||
154
- group.app_id?.startsWith(EXPERIMENT_SHOPIFY_APP_ID_PREFIX)
155
- );
156
- return sellingPlanGroups;
157
- };
158
-
159
- const getDefaultSubscriptionSellingPlanGroup = product => {
160
- // retrieve the OG Default Selling Plan Group
161
- return product?.selling_plan_groups.find(isDefaultSellingPlanGroup);
162
- };
163
-
164
- const isDefaultSellingPlanGroup = group => group.name === DEFAULT_PAY_AS_YOU_GO_GROUP_NAME;
165
-
166
- const isProductSpecificFrequencySellingPlanGroup = group => group.name.startsWith('og_psfl');
167
-
168
131
  const productOrVariantInStockReducer = (acc, cur) => ({
169
132
  ...overrideLineKey(acc, cur.id, cur.available),
170
133
  [cur.id]: cur.available
@@ -189,7 +152,7 @@ export const autoshipEligible = (state = {}, action) => {
189
152
  const {
190
153
  payload: { product }
191
154
  } = action;
192
- const applicableSellingPlanGroups = getOGSellingPlanGroups(product);
155
+ const applicableSellingPlanGroups = getPayAsYouGoSellingPlanGroups(product?.selling_plan_groups);
193
156
 
194
157
  const ogSellingPlanIds = new Set(
195
158
  applicableSellingPlanGroups.flatMap(group => group.selling_plans.map(sellingPlan => sellingPlan.id)) ?? []
@@ -281,7 +244,7 @@ export const config = (
281
244
  } = action;
282
245
  let configToAdd = {};
283
246
  // pay as you go selling plans
284
- const sellingPlanGroup = getOGSellingPlanGroup(product);
247
+ const sellingPlanGroup = getPayAsYouGoSellingPlanGroup(product?.selling_plan_groups);
285
248
  const frequencies = sellingPlansToFrequencies(sellingPlanGroup);
286
249
  if (frequencies?.length) {
287
250
  const frequenciesEveryPeriod = sellingPlansToEveryPeriod(sellingPlanGroup);
@@ -430,7 +393,7 @@ export const optedin = (state = [], action) => {
430
393
 
431
394
  if (constants.SETUP_PRODUCT === action.type) {
432
395
  const { product } = action.payload;
433
- const sellingPlanGroup = getOGSellingPlanGroup(product);
396
+ const sellingPlanGroup = getPayAsYouGoSellingPlanGroup(product?.selling_plan_groups);
434
397
  if (!sellingPlanGroup) {
435
398
  return state;
436
399
  }
@@ -25,7 +25,7 @@ export interface ShopifySellingPlansEntity {
25
25
  options?: ShopifyOptionsEntity[] | null;
26
26
  recurring_deliveries: boolean;
27
27
  price_adjustments?: ShopifyPriceAdjustmentsEntity[] | null;
28
- group_name?: string;
28
+ group: ShopifySellingPlanGroupsEntity;
29
29
  }
30
30
 
31
31
  export interface ShopifySellingPlanGroupsEntity {
@@ -1,3 +1,5 @@
1
+ import { ShopifySellingPlanGroupsEntity, ShopifySellingPlansEntity } from './types/shopify';
2
+
1
3
  export const money = (val: number, currency: string) =>
2
4
  val === null
3
5
  ? ''
@@ -7,3 +9,46 @@ export const money = (val: number, currency: string) =>
7
9
  }).format(val / 100);
8
10
 
9
11
  export const percentage = val => `${val}%`;
12
+
13
+ export const DEFAULT_PAY_AS_YOU_GO_GROUP_NAME = 'Subscribe and Save';
14
+ const EXPERIMENT_SHOPIFY_APP_ID_PREFIX = 'ordergroove-subscribe-and-save-';
15
+
16
+ // returns the non-prepaid OG selling plan to use for displaying frequencies
17
+ export const getPayAsYouGoSellingPlanGroup = (sellingPlanGroups: ShopifySellingPlanGroupsEntity[] = []) => {
18
+ // retrieve an OG Default or PSFL Selling Plan Group, preferring to return PSFL groups if they exist
19
+ const productSpecificFrequencySellingPlanGroup = sellingPlanGroups.find(isProductSpecificFrequencySellingPlanGroup);
20
+
21
+ return (
22
+ productSpecificFrequencySellingPlanGroup ||
23
+ sellingPlanGroups.find(isDefaultSellingPlanGroup) ||
24
+ sellingPlanGroups.find(isExperimentSellingPlanGroup)
25
+ );
26
+ };
27
+
28
+ // returns OG selling plan groups that are not prepaid
29
+ export const getPayAsYouGoSellingPlanGroups = (sellingPlanGroups: ShopifySellingPlanGroupsEntity[] = []) => {
30
+ return sellingPlanGroups.filter(
31
+ group =>
32
+ isDefaultSellingPlanGroup(group) ||
33
+ isProductSpecificFrequencySellingPlanGroup(group) ||
34
+ isExperimentSellingPlanGroup(group)
35
+ );
36
+ };
37
+
38
+ const isDefaultSellingPlanGroup = (group: ShopifySellingPlanGroupsEntity) =>
39
+ // we need to check name or app_id - the app_id is newer and not all selling plans have it
40
+ // the default group name is only applied to the default selling plan group
41
+ // flex incentives selling plan groups have a different name but the same subscribe-and-save app ID
42
+ group.name === DEFAULT_PAY_AS_YOU_GO_GROUP_NAME || group.app_id === 'ordergroove-subscribe-and-save';
43
+
44
+ export const isProductSpecificFrequencySellingPlanGroup = (group: ShopifySellingPlanGroupsEntity) =>
45
+ group.name.startsWith('og_psfl') || group.app_id === 'ordergroove-product-specific-frequency-list';
46
+
47
+ export const isExperimentSellingPlanGroup = (group: ShopifySellingPlanGroupsEntity) =>
48
+ // @ts-expect-error 18047
49
+ group.app_id?.startsWith(EXPERIMENT_SHOPIFY_APP_ID_PREFIX);
50
+
51
+ export const getPayAsYouGoSellingPlan = (sellingPlans: ShopifySellingPlansEntity[]) => {
52
+ const group = getPayAsYouGoSellingPlanGroup(sellingPlans.map(plan => plan.group));
53
+ return sellingPlans.find(plan => plan.group === group);
54
+ };