@zoxllc/shopify-checkout-extensions 0.0.8 → 0.1.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.
Files changed (161) hide show
  1. package/CLAUDE.md +136 -0
  2. package/EXAMPLES.md +384 -0
  3. package/INTEGRATION.md +482 -0
  4. package/README.md +5 -1
  5. package/dist/common/AndSelector.d.ts +11 -0
  6. package/dist/common/AndSelector.d.ts.map +1 -0
  7. package/dist/common/AndSelector.js +30 -0
  8. package/dist/common/Campaign.d.ts +24 -0
  9. package/dist/common/Campaign.d.ts.map +1 -0
  10. package/dist/common/Campaign.js +41 -0
  11. package/dist/common/CampaignConfiguration.d.ts +10 -0
  12. package/dist/common/CampaignConfiguration.d.ts.map +1 -0
  13. package/dist/common/CampaignConfiguration.js +7 -0
  14. package/dist/common/CampaignFactory.d.ts +22 -0
  15. package/dist/common/CampaignFactory.d.ts.map +1 -0
  16. package/dist/common/CampaignFactory.js +95 -0
  17. package/dist/common/CartAmountQualifier.d.ts +22 -0
  18. package/dist/common/CartAmountQualifier.d.ts.map +1 -0
  19. package/dist/common/CartAmountQualifier.js +46 -0
  20. package/dist/common/CartHasItemQualifier.d.ts +21 -0
  21. package/dist/common/CartHasItemQualifier.d.ts.map +1 -0
  22. package/dist/common/CartHasItemQualifier.js +54 -0
  23. package/dist/common/CartQuantityQualifier.d.ts +22 -0
  24. package/dist/common/CartQuantityQualifier.d.ts.map +1 -0
  25. package/dist/common/CartQuantityQualifier.js +62 -0
  26. package/dist/common/ConfigSchema.d.ts +71 -0
  27. package/dist/common/ConfigSchema.d.ts.map +1 -0
  28. package/dist/common/ConfigSchema.js +69 -0
  29. package/dist/common/ConfigValidator.d.ts +29 -0
  30. package/dist/common/ConfigValidator.d.ts.map +1 -0
  31. package/dist/common/ConfigValidator.js +84 -0
  32. package/dist/common/CountryCodeQualifier.d.ts +15 -0
  33. package/dist/common/CountryCodeQualifier.d.ts.map +1 -0
  34. package/dist/common/CountryCodeQualifier.js +30 -0
  35. package/dist/common/CustomerEmailQualifier.d.ts +16 -0
  36. package/dist/common/CustomerEmailQualifier.d.ts.map +1 -0
  37. package/dist/common/CustomerEmailQualifier.js +52 -0
  38. package/dist/common/CustomerSubscriberQualifier.d.ts +18 -0
  39. package/dist/common/CustomerSubscriberQualifier.d.ts.map +1 -0
  40. package/dist/common/CustomerSubscriberQualifier.js +28 -0
  41. package/dist/common/CustomerTagQualifier.d.ts +16 -0
  42. package/dist/common/CustomerTagQualifier.d.ts.map +1 -0
  43. package/dist/common/CustomerTagQualifier.js +45 -0
  44. package/dist/common/DiscountCart.d.ts +23 -0
  45. package/dist/common/DiscountCart.d.ts.map +1 -0
  46. package/dist/common/DiscountCart.js +103 -0
  47. package/dist/common/DiscountInterface.d.ts +17 -0
  48. package/dist/common/DiscountInterface.d.ts.map +1 -0
  49. package/dist/common/DiscountInterface.js +2 -0
  50. package/dist/common/OrSelector.d.ts +11 -0
  51. package/dist/common/OrSelector.d.ts.map +1 -0
  52. package/dist/common/OrSelector.js +30 -0
  53. package/dist/common/PostCartAmountQualifier.d.ts +9 -0
  54. package/dist/common/PostCartAmountQualifier.d.ts.map +1 -0
  55. package/dist/common/PostCartAmountQualifier.js +17 -0
  56. package/dist/common/ProductHandleSelector.d.ts +8 -0
  57. package/dist/common/ProductHandleSelector.d.ts.map +1 -0
  58. package/dist/common/ProductHandleSelector.js +22 -0
  59. package/dist/common/ProductIdSelector.d.ts +8 -0
  60. package/dist/common/ProductIdSelector.d.ts.map +1 -0
  61. package/dist/common/ProductIdSelector.js +22 -0
  62. package/dist/common/ProductTagSelector.d.ts +10 -0
  63. package/dist/common/ProductTagSelector.d.ts.map +1 -0
  64. package/dist/common/ProductTagSelector.js +39 -0
  65. package/dist/common/ProductTypeSelector.d.ts +8 -0
  66. package/dist/common/ProductTypeSelector.d.ts.map +1 -0
  67. package/dist/common/ProductTypeSelector.js +25 -0
  68. package/dist/common/Qualifier.d.ts +30 -0
  69. package/dist/common/Qualifier.d.ts.map +1 -0
  70. package/dist/common/Qualifier.js +61 -0
  71. package/dist/common/SaleItemSelector.d.ts +11 -0
  72. package/dist/common/SaleItemSelector.d.ts.map +1 -0
  73. package/dist/common/SaleItemSelector.js +30 -0
  74. package/dist/common/Selector.d.ts +27 -0
  75. package/dist/common/Selector.d.ts.map +1 -0
  76. package/dist/common/Selector.js +51 -0
  77. package/dist/common/SubscriptionItemSelector.d.ts +7 -0
  78. package/dist/common/SubscriptionItemSelector.d.ts.map +1 -0
  79. package/dist/common/SubscriptionItemSelector.js +19 -0
  80. package/dist/form/CampaignForm.d.ts +1 -0
  81. package/dist/form/CampaignForm.d.ts.map +1 -0
  82. package/dist/form/CampaignForm.js +1 -0
  83. package/{src/index.ts → dist/index.d.ts} +22 -27
  84. package/dist/index.d.ts.map +1 -0
  85. package/dist/index.js +78 -0
  86. package/dist/lineItem/BuyXGetY.d.ts +18 -0
  87. package/dist/lineItem/BuyXGetY.d.ts.map +1 -0
  88. package/dist/lineItem/BuyXGetY.js +85 -0
  89. package/dist/lineItem/ConditionalDiscount.d.ts +14 -0
  90. package/dist/lineItem/ConditionalDiscount.d.ts.map +1 -0
  91. package/dist/lineItem/ConditionalDiscount.js +81 -0
  92. package/dist/lineItem/FixedItemDiscount.d.ts +9 -0
  93. package/dist/lineItem/FixedItemDiscount.d.ts.map +1 -0
  94. package/dist/lineItem/FixedItemDiscount.js +35 -0
  95. package/dist/lineItem/PercentageDiscount.d.ts +8 -0
  96. package/dist/lineItem/PercentageDiscount.d.ts.map +1 -0
  97. package/dist/lineItem/PercentageDiscount.js +32 -0
  98. package/dist/lineItem/api.d.ts +2026 -0
  99. package/dist/lineItem/api.d.ts.map +1 -0
  100. package/dist/lineItem/api.js +1157 -0
  101. package/dist/shipping/FixedDiscount.d.ts +8 -0
  102. package/dist/shipping/FixedDiscount.d.ts.map +1 -0
  103. package/dist/shipping/FixedDiscount.js +30 -0
  104. package/dist/shipping/RateNameSelector.d.ts +10 -0
  105. package/dist/shipping/RateNameSelector.d.ts.map +1 -0
  106. package/dist/shipping/RateNameSelector.js +45 -0
  107. package/dist/shipping/ShippingDiscount.d.ts +14 -0
  108. package/dist/shipping/ShippingDiscount.d.ts.map +1 -0
  109. package/dist/shipping/ShippingDiscount.js +48 -0
  110. package/dist/shipping/api.d.ts +2019 -0
  111. package/dist/shipping/api.d.ts.map +1 -0
  112. package/dist/shipping/api.js +1147 -0
  113. package/package.json +26 -7
  114. package/migrate.ts +0 -64
  115. package/src/common/AndSelector.ts +0 -42
  116. package/src/common/Campaign.ts +0 -70
  117. package/src/common/CampaignConfiguration.ts +0 -10
  118. package/src/common/CampaignFactory.ts +0 -233
  119. package/src/common/CartAmountQualifier.ts +0 -64
  120. package/src/common/CartHasItemQualifier.ts +0 -80
  121. package/src/common/CartQuantityQualifier.ts +0 -94
  122. package/src/common/CountryCodeQualifier.ts +0 -49
  123. package/src/common/CustomerEmailQualifier.ts +0 -67
  124. package/src/common/CustomerSubscriberQualifier.ts +0 -32
  125. package/src/common/CustomerTagQualifier.ts +0 -69
  126. package/src/common/DiscountCart.ts +0 -161
  127. package/src/common/DiscountInterface.ts +0 -26
  128. package/src/common/OrSelector.ts +0 -40
  129. package/src/common/PostCartAmountQualifier.ts +0 -21
  130. package/src/common/ProductHandleSelector.ts +0 -32
  131. package/src/common/ProductIdSelector.ts +0 -34
  132. package/src/common/ProductTagSelector.ts +0 -63
  133. package/src/common/ProductTypeSelector.ts +0 -40
  134. package/src/common/Qualifier.ts +0 -67
  135. package/src/common/SaleItemSelector.ts +0 -36
  136. package/src/common/Selector.ts +0 -66
  137. package/src/common/SubscriptionItemSelector.ts +0 -23
  138. package/src/lineItem/BuyXGetY.ts +0 -131
  139. package/src/lineItem/ConditionalDiscount.ts +0 -102
  140. package/src/lineItem/FixedItemDiscount.ts +0 -51
  141. package/src/lineItem/PercentageDiscount.ts +0 -44
  142. package/src/lineItem/api.ts +0 -2103
  143. package/src/shipping/FixedDiscount.ts +0 -37
  144. package/src/shipping/RateNameSelector.ts +0 -54
  145. package/src/shipping/ShippingDiscount.ts +0 -75
  146. package/src/shipping/api.ts +0 -2014
  147. package/tests/AndSelector.test.ts +0 -27
  148. package/tests/CartQuantityQualifier.test.ts +0 -381
  149. package/tests/CountryCodeQualifier.test.ts +0 -55
  150. package/tests/CustomerSubscriberQualifier.test.ts +0 -101
  151. package/tests/CustomerTagQualifier.test.ts +0 -71
  152. package/tests/DiscountCart.test.ts +0 -115
  153. package/tests/OrSelector.test.ts +0 -27
  154. package/tests/ProductIdSelector.test.ts +0 -83
  155. package/tests/ProductTagSelector.test.ts +0 -75
  156. package/tests/Qualifier.test.ts +0 -193
  157. package/tests/RateNameSelector.test.ts +0 -107
  158. package/tests/SaleItemSelector.test.ts +0 -113
  159. package/tests/Selector.test.ts +0 -83
  160. package/tests/ShippingDiscount.test.ts +0 -147
  161. package/tsconfig.json +0 -25
@@ -1,40 +0,0 @@
1
- import type {
2
- CartLine,
3
- ProductVariant,
4
- } from '../lineItem/api';
5
- import { MatchType, Selector } from './Selector';
6
-
7
- export class ProductTypeSelector extends Selector {
8
- invert: boolean;
9
- productTypes: string[];
10
-
11
- constructor(
12
- matchType: MatchType,
13
- productTypes: string[]
14
- ) {
15
- super();
16
- this.invert = matchType == MatchType.NOT_ONE;
17
- this.productTypes = productTypes.map((item) =>
18
- item.toLowerCase()
19
- );
20
- }
21
-
22
- match(subject: unknown): boolean;
23
- match(lineItem: CartLine) {
24
- const variant = lineItem.merchandise as ProductVariant;
25
-
26
- if (variant.product.productType) {
27
- const matchResult = this.productTypes.includes(
28
- variant.product.productType.toLowerCase()
29
- );
30
-
31
- if (this.invert) {
32
- return !matchResult;
33
- }
34
-
35
- return matchResult;
36
- }
37
-
38
- return false;
39
- }
40
- }
@@ -1,67 +0,0 @@
1
- import type { DiscountCart } from './DiscountCart';
2
- import type { Selector } from './Selector';
3
-
4
- export enum QualifierMatchType {
5
- DOES = ':does',
6
- DOES_NOT = ':does_not',
7
- }
8
-
9
- export enum StringComparisonType {
10
- MATCH = ':match',
11
- CONTAINS = ':contains',
12
- START_WITH = ':start_with',
13
- END_WITH = ':end_with',
14
- }
15
-
16
- export enum NumericalComparisonType {
17
- GREATER_THAN = ':greater_than',
18
- GREATER_THAN_OR_EQUAL = ':greater_than_or_equal',
19
- LESS_THAN = ':less_than',
20
- LESS_THAN_OR_EQUAL = ':less_than_or_equal',
21
- EQUAL_TO = ':equal_to',
22
- }
23
-
24
- // export enum ComparisonType {
25
- // GREATER_THAN = ":greater_than",
26
- // GREATER_THAN_OR_EQUAL = ":greater_than_or_equal",
27
- // LESS_THAN = ":less_than",
28
- // LESS_THAN_OR_EQUAL = ":less_than_or_equal",
29
- // EQUAL_TO = ":equal_to",
30
- // }
31
-
32
- export enum QualifierBehavior {
33
- ALL = ':all',
34
- ANY = ':any',
35
- }
36
- export class Qualifier {
37
- is_a: 'Qualifier';
38
-
39
- constructor() {
40
- this.is_a = 'Qualifier';
41
- }
42
-
43
- compareAmounts(
44
- compare: number,
45
- comparisonType: NumericalComparisonType,
46
- compareTo: number
47
- ) {
48
- switch (comparisonType) {
49
- case NumericalComparisonType.GREATER_THAN:
50
- return compare > compareTo;
51
- case NumericalComparisonType.GREATER_THAN_OR_EQUAL:
52
- return compare >= compareTo;
53
- case NumericalComparisonType.LESS_THAN:
54
- return compare < compareTo;
55
- case NumericalComparisonType.LESS_THAN_OR_EQUAL:
56
- return compare <= compareTo;
57
- case NumericalComparisonType.EQUAL_TO:
58
- return compare == compareTo;
59
- default:
60
- throw new Error('Invalid comparison type');
61
- }
62
- }
63
-
64
- match(discountCart: DiscountCart, selector?: Selector) {
65
- return false;
66
- }
67
- }
@@ -1,36 +0,0 @@
1
- import { CartLine } from '../lineItem/api';
2
- import { Selector } from './Selector';
3
-
4
- export enum SaleItemSelectorMatchType {
5
- IS = ':is',
6
- NOT = ':not',
7
- }
8
-
9
- export class SaleItemSelector extends Selector {
10
- invert: boolean;
11
-
12
- constructor(matchType: SaleItemSelectorMatchType) {
13
- super();
14
- // Unlike other common scenarios, we invert if we pass an :IS
15
- // because it is easier to figure out of the item is NOT on sale.
16
- this.invert = matchType == SaleItemSelectorMatchType.IS;
17
- }
18
-
19
- match(subject: unknown): boolean;
20
- match(lineItem: CartLine) {
21
- // Check to see if the item is NOT on sale
22
- const matchResult =
23
- !lineItem.cost.compareAtAmountPerQuantity ||
24
- parseFloat(
25
- lineItem.cost.compareAtAmountPerQuantity.amount
26
- ) <=
27
- parseFloat(lineItem.cost.amountPerQuantity.amount);
28
-
29
- // If we want to check that the item IS on sale, we'll invert the result
30
- if (this.invert) {
31
- return !matchResult;
32
- }
33
-
34
- return matchResult;
35
- }
36
- }
@@ -1,66 +0,0 @@
1
- import type { CartDeliveryOption } from '../shipping/api';
2
- import type { CartLine } from '../lineItem/api';
3
- import { StringComparisonType } from './Qualifier';
4
-
5
- export enum MatchType {
6
- 'ALL' = ':all',
7
- 'IS_ONE' = ':is_one',
8
- 'NOT_ONE' = ':not_one',
9
- 'DOES' = ':does',
10
- 'DOES_NOT' = ':does_not',
11
- }
12
-
13
- export type SelectorInterface = {
14
- match(subject: CartLine): boolean;
15
- match(subject: CartDeliveryOption): boolean;
16
- };
17
-
18
- export class Selector implements SelectorInterface {
19
- match(subject: CartLine): boolean;
20
- match(subject: CartDeliveryOption): boolean;
21
- match(subject: unknown): boolean {
22
- return true;
23
- }
24
-
25
- /**
26
- * Checks each member of the subject array for possible matches. Returns true when any possible match is made.
27
- * @param matchType StringComparisonType
28
- * @param itemInfo string | string[]
29
- * @param possibleMatches string[]
30
- * @returns boolean
31
- */
32
- partialMatch(
33
- matchType:
34
- | StringComparisonType.CONTAINS
35
- | StringComparisonType.START_WITH
36
- | StringComparisonType.END_WITH,
37
- itemInfo: string | string[],
38
- possibleMatches: string[]
39
- ) {
40
- // Convert to an array if it isn't one
41
- const subject = Array.isArray(itemInfo)
42
- ? itemInfo
43
- : [itemInfo];
44
- let foundMatch = false;
45
- possibleMatches.forEach((possibility) => {
46
- subject.forEach((search) => {
47
- switch (matchType) {
48
- case StringComparisonType.CONTAINS:
49
- if (search.search(possibility) > -1)
50
- foundMatch = true;
51
- break;
52
- case StringComparisonType.START_WITH:
53
- if (search.startsWith(possibility))
54
- foundMatch = true;
55
- break;
56
- case StringComparisonType.END_WITH:
57
- if (search.endsWith(possibility))
58
- foundMatch = true;
59
- break;
60
- }
61
- });
62
- });
63
-
64
- return foundMatch;
65
- }
66
- }
@@ -1,23 +0,0 @@
1
- import type { CartLine } from '../lineItem/api';
2
- import { MatchType, Selector } from './Selector';
3
-
4
- export class SubscriptionItemSelector extends Selector {
5
- invert: boolean;
6
-
7
- constructor(matchType: MatchType) {
8
- super();
9
- this.invert = matchType == MatchType.NOT_ONE;
10
- }
11
-
12
- match(subject: unknown): boolean;
13
- match(lineItem: CartLine) {
14
- const matchResult =
15
- lineItem.sellingPlanAllocation !== undefined;
16
-
17
- if (this.invert) {
18
- return !matchResult;
19
- }
20
-
21
- return false;
22
- }
23
- }
@@ -1,131 +0,0 @@
1
- import { Campaign } from '../common/Campaign';
2
- import type { AndSelector } from '../common/AndSelector';
3
- import type { DiscountCart } from '../common/DiscountCart';
4
- import type {
5
- ApplyDiscount,
6
- DiscountInterface,
7
- } from '../common/DiscountInterface';
8
- import type { OrSelector } from '../common/OrSelector';
9
- import type {
10
- Qualifier,
11
- QualifierBehavior,
12
- } from '../common/Qualifier';
13
- import type { Selector } from '../common/Selector';
14
-
15
- export class BuyXGetY extends Campaign {
16
- lineItemSelector?: Selector;
17
- getItemSelector?: Selector;
18
- discount: DiscountInterface;
19
- buyX: number;
20
- getY: number;
21
- maxSets?: number;
22
-
23
- constructor(
24
- behavior: QualifierBehavior,
25
- conditions: [AndSelector | OrSelector | Qualifier],
26
- discount: DiscountInterface,
27
- buyItemSelector: Selector,
28
- getItemSelector: Selector,
29
- buyX: number,
30
- getY: number,
31
- maxSets?: number
32
- ) {
33
- super(behavior, conditions);
34
- this.lineItemSelector = buyItemSelector;
35
- this.getItemSelector = getItemSelector;
36
- this.discount = discount;
37
- this.buyX = buyX;
38
- this.getY = getY;
39
- this.maxSets = maxSets;
40
- }
41
-
42
- run(discountCart: DiscountCart) {
43
- if (this.qualifies(discountCart)) {
44
- // Find the items that qualify for buyX
45
- let applicableBuyItems = discountCart.cart.lines;
46
- if (this.lineItemSelector) {
47
- applicableBuyItems = discountCart.cart.lines.filter(
48
- (lineItem) => {
49
- // @ts-ignore
50
- return this.lineItemSelector?.match(lineItem);
51
- }
52
- );
53
- }
54
-
55
- if (
56
- applicableBuyItems.reduce(
57
- (qty, item) => (qty += item.quantity),
58
- 0
59
- ) < this.buyX
60
- ) {
61
- return discountCart;
62
- }
63
-
64
- // Find the items that qualify for getX
65
- let eligibleGetItems = discountCart.cart.lines;
66
- if (this.getItemSelector) {
67
- eligibleGetItems = discountCart.cart.lines.filter(
68
- (lineItem) => {
69
- // @ts-ignore
70
- return this.getItemSelector?.match(lineItem);
71
- }
72
- );
73
- }
74
-
75
- // Check if cart qualifies for discounts and limit the discount sets
76
- const purchasedQuantity = applicableBuyItems.reduce(
77
- (total, item) => (total += item.quantity),
78
- 0
79
- );
80
- const discountableSets = this.maxSets
81
- ? [
82
- purchasedQuantity / this.buyX,
83
- this.maxSets,
84
- ].sort((a, b) => a - b)[0]
85
- : Math.floor(purchasedQuantity / this.buyX);
86
-
87
- if (discountableSets > 0) {
88
- let discountableQuantity =
89
- discountableSets *
90
- (this.getY
91
- ? this.getY
92
- : discountCart.totalLineItemQuantity());
93
-
94
- // Apply the discounts (sort to discount lower priced items first)
95
- eligibleGetItems = eligibleGetItems.sort(
96
- (item) => item.cost.amountPerQuantity.amount
97
- );
98
-
99
- const itemsToApplyDiscounts: ApplyDiscount[] = [];
100
-
101
- eligibleGetItems.forEach((lineItem) => {
102
- if (discountableQuantity == 0) {
103
- return;
104
- }
105
-
106
- if (lineItem.quantity <= discountableQuantity) {
107
- itemsToApplyDiscounts.push({
108
- lineItem,
109
- } as ApplyDiscount);
110
- discountableQuantity -= lineItem.quantity;
111
- } else {
112
- itemsToApplyDiscounts.push({
113
- lineItem,
114
- maxDiscounts: discountableQuantity,
115
- } as ApplyDiscount);
116
- discountableQuantity = 0;
117
- }
118
- });
119
-
120
- if (itemsToApplyDiscounts.length) {
121
- const discount = this.discount.apply(
122
- itemsToApplyDiscounts
123
- );
124
- discountCart.addDiscount(discount);
125
- }
126
- }
127
- }
128
-
129
- return discountCart;
130
- }
131
- }
@@ -1,102 +0,0 @@
1
- import type { CartLine } from './api';
2
- import { Campaign } from '../common/Campaign';
3
- import type { DiscountCart } from '../common/DiscountCart';
4
- import type {
5
- ApplyDiscount,
6
- DiscountInterface,
7
- } from '../common/DiscountInterface';
8
- import type {
9
- QualifierBehavior,
10
- Qualifier,
11
- } from '../common/Qualifier';
12
- import type { Selector } from '../common/Selector';
13
- import type { AndSelector } from '../common/AndSelector';
14
- import type { OrSelector } from '../common/OrSelector';
15
-
16
- export class ConditionalDiscount extends Campaign {
17
- discount: DiscountInterface;
18
- itemsToDiscount?: number;
19
-
20
- constructor(
21
- behavior: QualifierBehavior,
22
- qualifiers: [Qualifier | AndSelector | OrSelector],
23
- discount: DiscountInterface,
24
- lineItemSelector?: Selector,
25
- maxDiscounts?: number
26
- ) {
27
- super(behavior, qualifiers);
28
- this.discount = discount;
29
- this.lineItemSelector = lineItemSelector;
30
- this.itemsToDiscount =
31
- maxDiscounts == 0 ? undefined : maxDiscounts;
32
- }
33
-
34
- run(discountCart: DiscountCart) {
35
- // First we see if this cart qualifies for this discount
36
- if (this.qualifies(discountCart)) {
37
- // Now that it qualifies, we can determine the applicableLineItems
38
- // to apply discounts to
39
-
40
- // figure out applicable lineItems...
41
- const applicableLineItems = discountCart.cart.lines
42
- .filter((lineItem) => {
43
- if (this.lineItemSelector === undefined) {
44
- return true;
45
- }
46
- return this.lineItemSelector.match(
47
- lineItem as CartLine
48
- );
49
- })
50
- .sort((a, b) => {
51
- const priceA = a.cost.amountPerQuantity
52
- .amount as number;
53
- const priceB = b.cost.amountPerQuantity
54
- .amount as number;
55
-
56
- if (priceA < priceB) return -1;
57
- if (priceA == priceB) return 0;
58
- return 1;
59
- });
60
-
61
- const itemsToApplyDiscounts: ApplyDiscount[] = [];
62
-
63
- // Loop over the applicable line items and deduct the itemsToDiscount count
64
- // as they are applied to not exceed a maximum.
65
- applicableLineItems.forEach((lineItem) => {
66
- // If there are no more items to discount, return/skip
67
- if (this.itemsToDiscount === 0) return;
68
-
69
- // If items to discount is not undefined, apply as many as possible
70
- if (this.itemsToDiscount !== undefined) {
71
- // There are more than enough qty to apply, apply the maximum
72
- if (lineItem.quantity >= this.itemsToDiscount) {
73
- itemsToApplyDiscounts.push({
74
- lineItem,
75
- maxDiscounts: this.itemsToDiscount,
76
- } as ApplyDiscount);
77
- this.itemsToDiscount = 0;
78
- } else {
79
- itemsToApplyDiscounts.push({
80
- lineItem,
81
- } as ApplyDiscount);
82
- this.itemsToDiscount -= lineItem.quantity;
83
- }
84
- } else {
85
- // items to discount is undefined, so apply to entire item count
86
- itemsToApplyDiscounts.push({
87
- lineItem,
88
- } as ApplyDiscount);
89
- }
90
-
91
- if (itemsToApplyDiscounts.length) {
92
- // append the discount to the discountCart singleton
93
- const discount = this.discount.apply(
94
- itemsToApplyDiscounts
95
- );
96
- discountCart.addDiscount(discount);
97
- }
98
- });
99
- }
100
- return discountCart;
101
- }
102
- }
@@ -1,51 +0,0 @@
1
- import type { ProductVariant } from './api';
2
- import type {
3
- ApplyDiscount,
4
- Discount,
5
- DiscountInterface,
6
- } from '../common/DiscountInterface';
7
-
8
- export class FixedItemDiscount
9
- implements DiscountInterface
10
- {
11
- amount: number;
12
- appliesToEachItem: boolean;
13
- message: string;
14
-
15
- constructor(
16
- amount: number,
17
- appliesToEachItem: boolean,
18
- message: string
19
- ) {
20
- this.amount = amount;
21
- this.appliesToEachItem = appliesToEachItem;
22
- this.message = message;
23
- }
24
-
25
- apply(items: ApplyDiscount[]): Discount {
26
- const targets = items.map(
27
- ({ lineItem, maxDiscounts }) => {
28
- const variant =
29
- lineItem.merchandise as ProductVariant;
30
- return {
31
- productVariant: {
32
- id: variant.id,
33
- quantity:
34
- maxDiscounts == 0 ? undefined : maxDiscounts,
35
- },
36
- };
37
- }
38
- );
39
-
40
- return {
41
- targets,
42
- value: {
43
- fixedAmount: {
44
- amount: this.amount,
45
- appliesToEachItem: this.appliesToEachItem,
46
- },
47
- },
48
- message: this.message,
49
- } as Discount;
50
- }
51
- }
@@ -1,44 +0,0 @@
1
- import type { ProductVariant } from './api';
2
- import type {
3
- Discount,
4
- ApplyDiscount,
5
- DiscountInterface,
6
- } from '../common/DiscountInterface';
7
-
8
- export class PercentageDiscount
9
- implements DiscountInterface
10
- {
11
- discount: number;
12
- message?: string;
13
-
14
- constructor(percentage: number, message?: string) {
15
- this.discount = percentage;
16
- this.message = message;
17
- }
18
-
19
- apply(items: ApplyDiscount[]): Discount {
20
- const targets = items.map(
21
- ({ lineItem, maxDiscounts }) => {
22
- const variant =
23
- lineItem.merchandise as ProductVariant;
24
- return {
25
- productVariant: {
26
- id: variant.id,
27
- quantity:
28
- maxDiscounts == 0 ? undefined : maxDiscounts,
29
- },
30
- };
31
- }
32
- );
33
-
34
- return {
35
- targets,
36
- value: {
37
- percentage: {
38
- value: this.discount,
39
- },
40
- },
41
- message: this.message,
42
- } as Discount;
43
- }
44
- }