@zoxllc/shopify-checkout-extensions 0.0.7 → 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.
- package/CLAUDE.md +136 -0
- package/EXAMPLES.md +384 -0
- package/INTEGRATION.md +482 -0
- package/README.md +5 -1
- package/dist/common/AndSelector.d.ts +11 -0
- package/dist/common/AndSelector.d.ts.map +1 -0
- package/dist/common/AndSelector.js +30 -0
- package/dist/common/Campaign.d.ts +24 -0
- package/dist/common/Campaign.d.ts.map +1 -0
- package/dist/common/Campaign.js +41 -0
- package/dist/common/CampaignConfiguration.d.ts +10 -0
- package/dist/common/CampaignConfiguration.d.ts.map +1 -0
- package/dist/common/CampaignConfiguration.js +7 -0
- package/dist/common/CampaignFactory.d.ts +22 -0
- package/dist/common/CampaignFactory.d.ts.map +1 -0
- package/dist/common/CampaignFactory.js +95 -0
- package/dist/common/CartAmountQualifier.d.ts +22 -0
- package/dist/common/CartAmountQualifier.d.ts.map +1 -0
- package/dist/common/CartAmountQualifier.js +46 -0
- package/dist/common/CartHasItemQualifier.d.ts +21 -0
- package/dist/common/CartHasItemQualifier.d.ts.map +1 -0
- package/dist/common/CartHasItemQualifier.js +54 -0
- package/dist/common/CartQuantityQualifier.d.ts +22 -0
- package/dist/common/CartQuantityQualifier.d.ts.map +1 -0
- package/dist/common/CartQuantityQualifier.js +62 -0
- package/dist/common/ConfigSchema.d.ts +71 -0
- package/dist/common/ConfigSchema.d.ts.map +1 -0
- package/dist/common/ConfigSchema.js +69 -0
- package/dist/common/ConfigValidator.d.ts +29 -0
- package/dist/common/ConfigValidator.d.ts.map +1 -0
- package/dist/common/ConfigValidator.js +84 -0
- package/dist/common/CountryCodeQualifier.d.ts +15 -0
- package/dist/common/CountryCodeQualifier.d.ts.map +1 -0
- package/dist/common/CountryCodeQualifier.js +30 -0
- package/dist/common/CustomerEmailQualifier.d.ts +16 -0
- package/dist/common/CustomerEmailQualifier.d.ts.map +1 -0
- package/dist/common/CustomerEmailQualifier.js +52 -0
- package/dist/common/CustomerSubscriberQualifier.d.ts +18 -0
- package/dist/common/CustomerSubscriberQualifier.d.ts.map +1 -0
- package/dist/common/CustomerSubscriberQualifier.js +28 -0
- package/dist/common/CustomerTagQualifier.d.ts +16 -0
- package/dist/common/CustomerTagQualifier.d.ts.map +1 -0
- package/dist/common/CustomerTagQualifier.js +45 -0
- package/dist/common/DiscountCart.d.ts +23 -0
- package/dist/common/DiscountCart.d.ts.map +1 -0
- package/dist/common/DiscountCart.js +103 -0
- package/dist/common/DiscountInterface.d.ts +17 -0
- package/dist/common/DiscountInterface.d.ts.map +1 -0
- package/dist/common/DiscountInterface.js +2 -0
- package/dist/common/OrSelector.d.ts +11 -0
- package/dist/common/OrSelector.d.ts.map +1 -0
- package/dist/common/OrSelector.js +30 -0
- package/dist/common/PostCartAmountQualifier.d.ts +9 -0
- package/dist/common/PostCartAmountQualifier.d.ts.map +1 -0
- package/dist/common/PostCartAmountQualifier.js +17 -0
- package/dist/common/ProductHandleSelector.d.ts +8 -0
- package/dist/common/ProductHandleSelector.d.ts.map +1 -0
- package/dist/common/ProductHandleSelector.js +22 -0
- package/dist/common/ProductIdSelector.d.ts +8 -0
- package/dist/common/ProductIdSelector.d.ts.map +1 -0
- package/dist/common/ProductIdSelector.js +22 -0
- package/dist/common/ProductTagSelector.d.ts +10 -0
- package/dist/common/ProductTagSelector.d.ts.map +1 -0
- package/dist/common/ProductTagSelector.js +39 -0
- package/dist/common/ProductTypeSelector.d.ts +8 -0
- package/dist/common/ProductTypeSelector.d.ts.map +1 -0
- package/dist/common/ProductTypeSelector.js +25 -0
- package/dist/common/Qualifier.d.ts +30 -0
- package/dist/common/Qualifier.d.ts.map +1 -0
- package/dist/common/Qualifier.js +61 -0
- package/dist/common/SaleItemSelector.d.ts +11 -0
- package/dist/common/SaleItemSelector.d.ts.map +1 -0
- package/dist/common/SaleItemSelector.js +30 -0
- package/dist/common/Selector.d.ts +27 -0
- package/dist/common/Selector.d.ts.map +1 -0
- package/dist/common/Selector.js +51 -0
- package/dist/common/SubscriptionItemSelector.d.ts +7 -0
- package/dist/common/SubscriptionItemSelector.d.ts.map +1 -0
- package/dist/common/SubscriptionItemSelector.js +19 -0
- package/dist/form/CampaignForm.d.ts +1 -0
- package/dist/form/CampaignForm.d.ts.map +1 -0
- package/dist/form/CampaignForm.js +1 -0
- package/{src/index.ts → dist/index.d.ts} +22 -27
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +78 -0
- package/dist/lineItem/BuyXGetY.d.ts +18 -0
- package/dist/lineItem/BuyXGetY.d.ts.map +1 -0
- package/dist/lineItem/BuyXGetY.js +85 -0
- package/dist/lineItem/ConditionalDiscount.d.ts +14 -0
- package/dist/lineItem/ConditionalDiscount.d.ts.map +1 -0
- package/dist/lineItem/ConditionalDiscount.js +81 -0
- package/dist/lineItem/FixedItemDiscount.d.ts +9 -0
- package/dist/lineItem/FixedItemDiscount.d.ts.map +1 -0
- package/dist/lineItem/FixedItemDiscount.js +35 -0
- package/dist/lineItem/PercentageDiscount.d.ts +8 -0
- package/dist/lineItem/PercentageDiscount.d.ts.map +1 -0
- package/dist/lineItem/PercentageDiscount.js +32 -0
- package/dist/lineItem/api.d.ts +2026 -0
- package/dist/lineItem/api.d.ts.map +1 -0
- package/dist/lineItem/api.js +1157 -0
- package/dist/shipping/FixedDiscount.d.ts +8 -0
- package/dist/shipping/FixedDiscount.d.ts.map +1 -0
- package/dist/shipping/FixedDiscount.js +30 -0
- package/dist/shipping/RateNameSelector.d.ts +10 -0
- package/dist/shipping/RateNameSelector.d.ts.map +1 -0
- package/dist/shipping/RateNameSelector.js +45 -0
- package/dist/shipping/ShippingDiscount.d.ts +14 -0
- package/dist/shipping/ShippingDiscount.d.ts.map +1 -0
- package/dist/shipping/ShippingDiscount.js +48 -0
- package/dist/shipping/api.d.ts +2019 -0
- package/dist/shipping/api.d.ts.map +1 -0
- package/dist/shipping/api.js +1147 -0
- package/package.json +26 -7
- package/migrate.ts +0 -64
- package/src/common/AndSelector.ts +0 -42
- package/src/common/Campaign.ts +0 -70
- package/src/common/CampaignConfiguration.ts +0 -10
- package/src/common/CampaignFactory.ts +0 -234
- package/src/common/CartAmountQualifier.ts +0 -64
- package/src/common/CartHasItemQualifier.ts +0 -80
- package/src/common/CartQuantityQualifier.ts +0 -94
- package/src/common/CountryCodeQualifier.ts +0 -49
- package/src/common/CustomerEmailQualifier.ts +0 -67
- package/src/common/CustomerSubscriberQualifier.ts +0 -32
- package/src/common/CustomerTagQualifier.ts +0 -69
- package/src/common/DiscountCart.ts +0 -161
- package/src/common/DiscountInterface.ts +0 -26
- package/src/common/OrSelector.ts +0 -40
- package/src/common/PostCartAmountQualifier.ts +0 -21
- package/src/common/ProductHandleSelector.ts +0 -31
- package/src/common/ProductIdSelector.ts +0 -34
- package/src/common/ProductTagSelector.ts +0 -63
- package/src/common/ProductTypeSelector.ts +0 -40
- package/src/common/Qualifier.ts +0 -67
- package/src/common/SaleItemSelector.ts +0 -36
- package/src/common/Selector.ts +0 -66
- package/src/common/SubscriptionItemSelector.ts +0 -23
- package/src/lineItem/BuyXGetY.ts +0 -131
- package/src/lineItem/ConditionalDiscount.ts +0 -102
- package/src/lineItem/FixedItemDiscount.ts +0 -51
- package/src/lineItem/PercentageDiscount.ts +0 -44
- package/src/lineItem/api.ts +0 -2103
- package/src/shipping/FixedDiscount.ts +0 -37
- package/src/shipping/RateNameSelector.ts +0 -54
- package/src/shipping/ShippingDiscount.ts +0 -75
- package/src/shipping/api.ts +0 -2014
- package/tests/AndSelector.test.ts +0 -27
- package/tests/CartQuantityQualifier.test.ts +0 -381
- package/tests/CountryCodeQualifier.test.ts +0 -55
- package/tests/CustomerSubscriberQualifier.test.ts +0 -101
- package/tests/CustomerTagQualifier.test.ts +0 -71
- package/tests/DiscountCart.test.ts +0 -115
- package/tests/OrSelector.test.ts +0 -27
- package/tests/ProductIdSelector.test.ts +0 -83
- package/tests/ProductTagSelector.test.ts +0 -75
- package/tests/Qualifier.test.ts +0 -193
- package/tests/RateNameSelector.test.ts +0 -107
- package/tests/SaleItemSelector.test.ts +0 -113
- package/tests/Selector.test.ts +0 -83
- package/tests/ShippingDiscount.test.ts +0 -147
- package/tsconfig.json +0 -25
|
@@ -1,94 +0,0 @@
|
|
|
1
|
-
import type { CartLine } from '../lineItem/api';
|
|
2
|
-
import type { DiscountCart } from './DiscountCart';
|
|
3
|
-
import {
|
|
4
|
-
type NumericalComparisonType,
|
|
5
|
-
Qualifier,
|
|
6
|
-
} from './Qualifier';
|
|
7
|
-
import { type Selector } from './Selector';
|
|
8
|
-
|
|
9
|
-
export enum CartQuantityBehavior {
|
|
10
|
-
CART = ':cart',
|
|
11
|
-
ITEM = ':item',
|
|
12
|
-
LINE_ANY = ':line_any',
|
|
13
|
-
LINE_ALL = ':line_all',
|
|
14
|
-
}
|
|
15
|
-
|
|
16
|
-
export class CartQuantityQualifier extends Qualifier {
|
|
17
|
-
totalMethod: CartQuantityBehavior;
|
|
18
|
-
comparisonType: NumericalComparisonType;
|
|
19
|
-
quantity: number;
|
|
20
|
-
|
|
21
|
-
constructor(
|
|
22
|
-
totalMethod: CartQuantityBehavior,
|
|
23
|
-
comparisonType: NumericalComparisonType,
|
|
24
|
-
quantity: number
|
|
25
|
-
) {
|
|
26
|
-
super();
|
|
27
|
-
this.totalMethod = totalMethod;
|
|
28
|
-
this.comparisonType = comparisonType;
|
|
29
|
-
this.quantity = quantity;
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
/**
|
|
33
|
-
* Determines if the carts amount
|
|
34
|
-
* @param cart
|
|
35
|
-
* @param selector
|
|
36
|
-
*/
|
|
37
|
-
match(discountCart: DiscountCart, selector?: Selector) {
|
|
38
|
-
let total = 0;
|
|
39
|
-
|
|
40
|
-
switch (this.totalMethod) {
|
|
41
|
-
case CartQuantityBehavior.ITEM:
|
|
42
|
-
total = discountCart.cart.lines.reduce(
|
|
43
|
-
(totalQty, line) => {
|
|
44
|
-
return (
|
|
45
|
-
totalQty +
|
|
46
|
-
((
|
|
47
|
-
selector
|
|
48
|
-
? selector.match(line as CartLine)
|
|
49
|
-
: true
|
|
50
|
-
)
|
|
51
|
-
? line.quantity
|
|
52
|
-
: 0)
|
|
53
|
-
);
|
|
54
|
-
},
|
|
55
|
-
0
|
|
56
|
-
);
|
|
57
|
-
break;
|
|
58
|
-
case CartQuantityBehavior.CART:
|
|
59
|
-
total =
|
|
60
|
-
discountCart.totalLineItemQuantityExcludingGifts();
|
|
61
|
-
break;
|
|
62
|
-
}
|
|
63
|
-
|
|
64
|
-
if (
|
|
65
|
-
this.totalMethod == CartQuantityBehavior.LINE_ANY ||
|
|
66
|
-
this.totalMethod == CartQuantityBehavior.LINE_ALL
|
|
67
|
-
) {
|
|
68
|
-
const qualifiedItems = discountCart.cart.lines
|
|
69
|
-
.filter((line) =>
|
|
70
|
-
selector ? selector.match(line as CartLine) : true
|
|
71
|
-
)
|
|
72
|
-
.map((line) =>
|
|
73
|
-
this.compareAmounts(
|
|
74
|
-
line.quantity,
|
|
75
|
-
this.comparisonType,
|
|
76
|
-
this.quantity
|
|
77
|
-
)
|
|
78
|
-
);
|
|
79
|
-
|
|
80
|
-
switch (this.totalMethod) {
|
|
81
|
-
case CartQuantityBehavior.LINE_ANY:
|
|
82
|
-
return qualifiedItems.indexOf(true) > -1;
|
|
83
|
-
case CartQuantityBehavior.LINE_ALL:
|
|
84
|
-
return qualifiedItems.indexOf(false) == -1;
|
|
85
|
-
}
|
|
86
|
-
} else {
|
|
87
|
-
return this.compareAmounts(
|
|
88
|
-
total,
|
|
89
|
-
this.comparisonType,
|
|
90
|
-
this.quantity
|
|
91
|
-
);
|
|
92
|
-
}
|
|
93
|
-
}
|
|
94
|
-
}
|
|
@@ -1,49 +0,0 @@
|
|
|
1
|
-
import type { DiscountCart } from './DiscountCart';
|
|
2
|
-
import {
|
|
3
|
-
StringComparisonType,
|
|
4
|
-
QualifierMatchType,
|
|
5
|
-
Qualifier,
|
|
6
|
-
} from './Qualifier';
|
|
7
|
-
import { type Selector } from './Selector';
|
|
8
|
-
|
|
9
|
-
export class CountryCodeQualifier extends Qualifier {
|
|
10
|
-
invert: boolean;
|
|
11
|
-
countryCodes: string[];
|
|
12
|
-
|
|
13
|
-
constructor(
|
|
14
|
-
matchType: QualifierMatchType,
|
|
15
|
-
countryCodes: string[]
|
|
16
|
-
) {
|
|
17
|
-
super();
|
|
18
|
-
this.invert = matchType == QualifierMatchType.DOES_NOT;
|
|
19
|
-
this.countryCodes = countryCodes.map((e) =>
|
|
20
|
-
e.toLowerCase()
|
|
21
|
-
);
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
/**
|
|
25
|
-
* Determines if the customer has specified tags
|
|
26
|
-
* @param discountCart DiscountCart
|
|
27
|
-
* @param selector Selector
|
|
28
|
-
*/
|
|
29
|
-
match(discountCart: DiscountCart, selector?: Selector) {
|
|
30
|
-
const matchResult =
|
|
31
|
-
(
|
|
32
|
-
discountCart.cart.deliveryGroups.filter(
|
|
33
|
-
(deliveryGroup) => {
|
|
34
|
-
const countryCode =
|
|
35
|
-
deliveryGroup?.deliveryAddress?.countryCode?.toLowerCase() ||
|
|
36
|
-
'';
|
|
37
|
-
|
|
38
|
-
return this.countryCodes.includes(countryCode);
|
|
39
|
-
}
|
|
40
|
-
) || []
|
|
41
|
-
).length > 0;
|
|
42
|
-
|
|
43
|
-
if (this.invert) {
|
|
44
|
-
return !matchResult;
|
|
45
|
-
}
|
|
46
|
-
|
|
47
|
-
return matchResult;
|
|
48
|
-
}
|
|
49
|
-
}
|
|
@@ -1,67 +0,0 @@
|
|
|
1
|
-
import type { DiscountCart } from './DiscountCart';
|
|
2
|
-
import {
|
|
3
|
-
StringComparisonType,
|
|
4
|
-
QualifierMatchType,
|
|
5
|
-
Qualifier,
|
|
6
|
-
} from './Qualifier';
|
|
7
|
-
import { type Selector } from './Selector';
|
|
8
|
-
|
|
9
|
-
export class CustomerEmailQualifier extends Qualifier {
|
|
10
|
-
invert: boolean;
|
|
11
|
-
matchCondition: StringComparisonType;
|
|
12
|
-
emails: string[];
|
|
13
|
-
|
|
14
|
-
constructor(
|
|
15
|
-
matchType: QualifierMatchType,
|
|
16
|
-
matchCondition: StringComparisonType,
|
|
17
|
-
emails: string[]
|
|
18
|
-
) {
|
|
19
|
-
super();
|
|
20
|
-
this.invert = matchType == QualifierMatchType.DOES_NOT;
|
|
21
|
-
this.matchCondition = matchCondition;
|
|
22
|
-
this.emails = emails.map((e) => e.toLowerCase());
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
/**
|
|
26
|
-
* Determines if the customer's email matches
|
|
27
|
-
* @param discountCart DiscountCart
|
|
28
|
-
* @param selector Selector
|
|
29
|
-
*/
|
|
30
|
-
match(discountCart: DiscountCart, selector?: Selector) {
|
|
31
|
-
if (!discountCart.cart.buyerIdentity?.customer?.email) {
|
|
32
|
-
return false;
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
let matchResult = false;
|
|
36
|
-
|
|
37
|
-
const email =
|
|
38
|
-
discountCart.cart.buyerIdentity.customer.email.toLowerCase();
|
|
39
|
-
|
|
40
|
-
switch (this.matchCondition) {
|
|
41
|
-
case StringComparisonType.MATCH:
|
|
42
|
-
matchResult = this.emails.includes(email);
|
|
43
|
-
break;
|
|
44
|
-
case StringComparisonType.CONTAINS:
|
|
45
|
-
matchResult =
|
|
46
|
-
this.emails.filter((e) => email.includes(e))
|
|
47
|
-
.length > 0;
|
|
48
|
-
break;
|
|
49
|
-
case StringComparisonType.START_WITH:
|
|
50
|
-
matchResult =
|
|
51
|
-
this.emails.filter((e) => email.startsWith(e))
|
|
52
|
-
.length > 0;
|
|
53
|
-
break;
|
|
54
|
-
case StringComparisonType.END_WITH:
|
|
55
|
-
matchResult =
|
|
56
|
-
this.emails.filter((e) => email.endsWith(e))
|
|
57
|
-
.length > 0;
|
|
58
|
-
break;
|
|
59
|
-
}
|
|
60
|
-
|
|
61
|
-
if (this.invert) {
|
|
62
|
-
return !matchResult;
|
|
63
|
-
}
|
|
64
|
-
|
|
65
|
-
return matchResult;
|
|
66
|
-
}
|
|
67
|
-
}
|
|
@@ -1,32 +0,0 @@
|
|
|
1
|
-
import type { DiscountCart } from "./DiscountCart";
|
|
2
|
-
import { QualifierMatchType, Qualifier } from "./Qualifier";
|
|
3
|
-
import { type Selector } from "./Selector";
|
|
4
|
-
|
|
5
|
-
export class CustomerSubscriberQualifier extends Qualifier {
|
|
6
|
-
invert: boolean;
|
|
7
|
-
|
|
8
|
-
/**
|
|
9
|
-
* Whether the customer contains an active subscription or not.
|
|
10
|
-
* @param matchType Pass :DOES or :DOES_NOT respectively
|
|
11
|
-
*/
|
|
12
|
-
constructor(matchType: QualifierMatchType) {
|
|
13
|
-
super();
|
|
14
|
-
this.invert = matchType == QualifierMatchType.DOES_NOT;
|
|
15
|
-
}
|
|
16
|
-
|
|
17
|
-
/**
|
|
18
|
-
* Determines if the customer has specified tags
|
|
19
|
-
* @param discountCart DiscountCart
|
|
20
|
-
* @param selector Selector
|
|
21
|
-
*/
|
|
22
|
-
match(discountCart: DiscountCart, selector?: Selector) {
|
|
23
|
-
const matchResult =
|
|
24
|
-
discountCart.cart.buyerIdentity?.customer?.isActiveSubscriber || false;
|
|
25
|
-
|
|
26
|
-
if (this.invert) {
|
|
27
|
-
return !matchResult;
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
return matchResult;
|
|
31
|
-
}
|
|
32
|
-
}
|
|
@@ -1,69 +0,0 @@
|
|
|
1
|
-
import type { DiscountCart } from './DiscountCart';
|
|
2
|
-
import {
|
|
3
|
-
StringComparisonType,
|
|
4
|
-
QualifierMatchType,
|
|
5
|
-
Qualifier,
|
|
6
|
-
} from './Qualifier';
|
|
7
|
-
import { type Selector } from './Selector';
|
|
8
|
-
|
|
9
|
-
export class CustomerTagQualifier extends Qualifier {
|
|
10
|
-
invert: boolean;
|
|
11
|
-
matchCondition: StringComparisonType;
|
|
12
|
-
tags: string[];
|
|
13
|
-
|
|
14
|
-
constructor(
|
|
15
|
-
matchType: QualifierMatchType,
|
|
16
|
-
matchCondition: StringComparisonType,
|
|
17
|
-
tags: string[]
|
|
18
|
-
) {
|
|
19
|
-
super();
|
|
20
|
-
this.invert = matchType == QualifierMatchType.DOES_NOT;
|
|
21
|
-
this.matchCondition = matchCondition;
|
|
22
|
-
this.tags = tags.map((e) => e.toLowerCase());
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
/**
|
|
26
|
-
* Determines if the customer has specified tags
|
|
27
|
-
* @param discountCart DiscountCart
|
|
28
|
-
* @param selector Selector
|
|
29
|
-
*/
|
|
30
|
-
match(discountCart: DiscountCart, selector?: Selector) {
|
|
31
|
-
const matchResult =
|
|
32
|
-
(
|
|
33
|
-
discountCart.cart.buyerIdentity?.customer?.hasTags.filter(
|
|
34
|
-
(t) => {
|
|
35
|
-
if (t.hasTag) {
|
|
36
|
-
const tag = t.tag.toLowerCase();
|
|
37
|
-
switch (this.matchCondition) {
|
|
38
|
-
case StringComparisonType.MATCH:
|
|
39
|
-
return this.tags.includes(tag);
|
|
40
|
-
case StringComparisonType.CONTAINS:
|
|
41
|
-
return (
|
|
42
|
-
this.tags.filter((e) => tag.includes(e))
|
|
43
|
-
.length > 0
|
|
44
|
-
);
|
|
45
|
-
case StringComparisonType.START_WITH:
|
|
46
|
-
return (
|
|
47
|
-
this.tags.filter((e) =>
|
|
48
|
-
tag.startsWith(e)
|
|
49
|
-
).length > 0
|
|
50
|
-
);
|
|
51
|
-
case StringComparisonType.END_WITH:
|
|
52
|
-
return (
|
|
53
|
-
this.tags.filter((e) => tag.endsWith(e))
|
|
54
|
-
.length > 0
|
|
55
|
-
);
|
|
56
|
-
}
|
|
57
|
-
}
|
|
58
|
-
return false;
|
|
59
|
-
}
|
|
60
|
-
) || []
|
|
61
|
-
).length > 0;
|
|
62
|
-
|
|
63
|
-
if (this.invert) {
|
|
64
|
-
return !matchResult;
|
|
65
|
-
}
|
|
66
|
-
|
|
67
|
-
return matchResult;
|
|
68
|
-
}
|
|
69
|
-
}
|
|
@@ -1,161 +0,0 @@
|
|
|
1
|
-
import type {
|
|
2
|
-
RunInput as LineItemRunInput,
|
|
3
|
-
Discount as DiscountItem,
|
|
4
|
-
} from '../lineItem/api';
|
|
5
|
-
import type {
|
|
6
|
-
RunInput as ShippingRunInput,
|
|
7
|
-
Discount as DiscountShipping,
|
|
8
|
-
} from '../shipping/api';
|
|
9
|
-
import { Discount } from './DiscountInterface';
|
|
10
|
-
|
|
11
|
-
type RunInput = {
|
|
12
|
-
cart: LineItemRunInput['cart'] & ShippingRunInput['cart'];
|
|
13
|
-
};
|
|
14
|
-
|
|
15
|
-
export class DiscountCart {
|
|
16
|
-
cart: RunInput['cart'];
|
|
17
|
-
subtotalAmount: number;
|
|
18
|
-
appliedDiscountTotal: number;
|
|
19
|
-
discounts: Discount[];
|
|
20
|
-
|
|
21
|
-
constructor(cart: RunInput['cart']) {
|
|
22
|
-
this.cart = cart;
|
|
23
|
-
this.subtotalAmount = 0;
|
|
24
|
-
this.appliedDiscountTotal = 0;
|
|
25
|
-
this.discounts = [];
|
|
26
|
-
|
|
27
|
-
this.setupCart(cart);
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
subtotalExcludingVariants(variants: string[]) {
|
|
31
|
-
return this.cart.lines.reduce((prev, curr) => {
|
|
32
|
-
if (curr.merchandise.__typename == 'ProductVariant') {
|
|
33
|
-
if (variants.indexOf(curr.merchandise.id) > -1) {
|
|
34
|
-
return prev - curr.cost.subtotalAmount.amount;
|
|
35
|
-
}
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
return prev;
|
|
39
|
-
}, this.subtotalExcludingGifts());
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
private subtotalExcludingGifts() {
|
|
43
|
-
return this.cart.lines.reduce((prev, curr) => {
|
|
44
|
-
if (curr.merchandise.__typename == 'ProductVariant') {
|
|
45
|
-
if (
|
|
46
|
-
curr.merchandise.product.hasTags.filter(
|
|
47
|
-
(t) => t.hasTag && t.tag == 'meta-exclude-gift'
|
|
48
|
-
).length
|
|
49
|
-
) {
|
|
50
|
-
return prev - curr.cost.subtotalAmount.amount;
|
|
51
|
-
}
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
return prev;
|
|
55
|
-
}, this.subtotalAmount);
|
|
56
|
-
}
|
|
57
|
-
|
|
58
|
-
totalLineItemQuantity() {
|
|
59
|
-
return this.cart.lines.reduce(
|
|
60
|
-
(total, item) => total + item.quantity,
|
|
61
|
-
0
|
|
62
|
-
);
|
|
63
|
-
}
|
|
64
|
-
|
|
65
|
-
totalLineItemQuantityExcludingGifts() {
|
|
66
|
-
return this.cart.lines.reduce((total, item) => {
|
|
67
|
-
if (item.merchandise.__typename == 'ProductVariant') {
|
|
68
|
-
if (
|
|
69
|
-
item.merchandise.product.hasTags.filter(
|
|
70
|
-
(t) => t.hasTag && t.tag == 'meta-exclude-gift'
|
|
71
|
-
).length
|
|
72
|
-
) {
|
|
73
|
-
return total;
|
|
74
|
-
}
|
|
75
|
-
}
|
|
76
|
-
return total + item.quantity;
|
|
77
|
-
}, 0);
|
|
78
|
-
}
|
|
79
|
-
|
|
80
|
-
private setupCart(cart: RunInput['cart']) {
|
|
81
|
-
this.subtotalAmount = cart.cost.subtotalAmount
|
|
82
|
-
.amount as number;
|
|
83
|
-
// Adjust the subtotal amount by excluding the value from gift items
|
|
84
|
-
this.subtotalAmount = this.subtotalExcludingGifts();
|
|
85
|
-
this.appliedDiscountTotal = 0;
|
|
86
|
-
this.discounts = [];
|
|
87
|
-
}
|
|
88
|
-
|
|
89
|
-
addShippingDiscount(discount: DiscountShipping) {
|
|
90
|
-
this.discounts.push(discount as Discount);
|
|
91
|
-
}
|
|
92
|
-
|
|
93
|
-
addDiscount(discount: DiscountItem) {
|
|
94
|
-
// Figure out how much discount has been applied
|
|
95
|
-
const totalDiscounts = discount.targets.reduce(
|
|
96
|
-
(total, target) => {
|
|
97
|
-
// gather target lineItem
|
|
98
|
-
const lineItems = this.cart.lines.filter((line) =>
|
|
99
|
-
line.merchandise.__typename == 'ProductVariant'
|
|
100
|
-
? line.merchandise.id ==
|
|
101
|
-
target.productVariant.id
|
|
102
|
-
: false
|
|
103
|
-
);
|
|
104
|
-
|
|
105
|
-
// loop over the line items and do maths
|
|
106
|
-
lineItems.forEach((line) => {
|
|
107
|
-
let discountableItems = target.productVariant
|
|
108
|
-
.quantity
|
|
109
|
-
? target.productVariant.quantity
|
|
110
|
-
: line.quantity;
|
|
111
|
-
|
|
112
|
-
const lineItemCost = parseFloat(
|
|
113
|
-
line.cost.amountPerQuantity.amount
|
|
114
|
-
);
|
|
115
|
-
|
|
116
|
-
// When it's a fixed amount, calculate the items per but only if it applies to each individual item...
|
|
117
|
-
if (discount.value.fixedAmount) {
|
|
118
|
-
if (
|
|
119
|
-
discount.value.fixedAmount.appliesToEachItem
|
|
120
|
-
) {
|
|
121
|
-
total +=
|
|
122
|
-
lineItemCost -
|
|
123
|
-
discount.value.fixedAmount?.amount >
|
|
124
|
-
0
|
|
125
|
-
? discount.value.fixedAmount?.amount *
|
|
126
|
-
discountableItems
|
|
127
|
-
: lineItemCost * discountableItems;
|
|
128
|
-
} else {
|
|
129
|
-
total +=
|
|
130
|
-
lineItemCost -
|
|
131
|
-
discount.value.fixedAmount?.amount >
|
|
132
|
-
0
|
|
133
|
-
? discount.value.fixedAmount?.amount
|
|
134
|
-
: lineItemCost;
|
|
135
|
-
}
|
|
136
|
-
} else if (discount.value.percentage) {
|
|
137
|
-
total +=
|
|
138
|
-
lineItemCost *
|
|
139
|
-
(discount.value.percentage?.value / 100) *
|
|
140
|
-
discountableItems;
|
|
141
|
-
}
|
|
142
|
-
});
|
|
143
|
-
|
|
144
|
-
return total;
|
|
145
|
-
},
|
|
146
|
-
0
|
|
147
|
-
);
|
|
148
|
-
|
|
149
|
-
this.appliedDiscountTotal += totalDiscounts;
|
|
150
|
-
console.error(
|
|
151
|
-
'appliedDiscountTotal',
|
|
152
|
-
this.appliedDiscountTotal
|
|
153
|
-
);
|
|
154
|
-
|
|
155
|
-
this.discounts.push(discount as Discount);
|
|
156
|
-
}
|
|
157
|
-
|
|
158
|
-
reset() {
|
|
159
|
-
this.setupCart(this.cart);
|
|
160
|
-
}
|
|
161
|
-
}
|
|
@@ -1,26 +0,0 @@
|
|
|
1
|
-
import type {
|
|
2
|
-
CartDeliveryOption,
|
|
3
|
-
CartLine,
|
|
4
|
-
} from '../lineItem/api';
|
|
5
|
-
|
|
6
|
-
import type { Discount as DiscountItem } from '../lineItem/api';
|
|
7
|
-
import type { Discount as DiscountShipping } from '../shipping/api';
|
|
8
|
-
|
|
9
|
-
export type Discount = DiscountItem & DiscountShipping;
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
type ApplyLineItemDiscount = {
|
|
13
|
-
lineItem: CartLine;
|
|
14
|
-
maxDiscounts?: number;
|
|
15
|
-
};
|
|
16
|
-
|
|
17
|
-
type ApplyShippingDiscount = {
|
|
18
|
-
deliveryOption: CartDeliveryOption;
|
|
19
|
-
};
|
|
20
|
-
|
|
21
|
-
export type ApplyDiscount = ApplyLineItemDiscount &
|
|
22
|
-
ApplyShippingDiscount;
|
|
23
|
-
|
|
24
|
-
export interface DiscountInterface {
|
|
25
|
-
apply(items: ApplyDiscount[]): Discount;
|
|
26
|
-
}
|
package/src/common/OrSelector.ts
DELETED
|
@@ -1,40 +0,0 @@
|
|
|
1
|
-
import type { DiscountCart } from './DiscountCart';
|
|
2
|
-
import type { Qualifier } from './Qualifier';
|
|
3
|
-
import type { Selector } from './Selector';
|
|
4
|
-
import type { CartLine } from '../lineItem/api';
|
|
5
|
-
|
|
6
|
-
export class OrSelector {
|
|
7
|
-
is_a: 'OrSelector';
|
|
8
|
-
conditions: (Selector | Qualifier)[];
|
|
9
|
-
|
|
10
|
-
constructor(conditions: (Selector | Qualifier)[]) {
|
|
11
|
-
this.is_a = 'OrSelector';
|
|
12
|
-
this.conditions = conditions;
|
|
13
|
-
}
|
|
14
|
-
|
|
15
|
-
match(
|
|
16
|
-
item: CartLine | DiscountCart,
|
|
17
|
-
selector?: Selector
|
|
18
|
-
) {
|
|
19
|
-
try {
|
|
20
|
-
const conditionsResult = this.conditions
|
|
21
|
-
.map((condition) => {
|
|
22
|
-
if (selector) {
|
|
23
|
-
return (condition as Qualifier).match(
|
|
24
|
-
item as DiscountCart,
|
|
25
|
-
selector
|
|
26
|
-
);
|
|
27
|
-
} else {
|
|
28
|
-
return (condition as Selector).match(
|
|
29
|
-
item as CartLine
|
|
30
|
-
);
|
|
31
|
-
}
|
|
32
|
-
})
|
|
33
|
-
.filter((result) => result === true);
|
|
34
|
-
|
|
35
|
-
return conditionsResult.length > 0;
|
|
36
|
-
} catch (e) {
|
|
37
|
-
return false;
|
|
38
|
-
}
|
|
39
|
-
}
|
|
40
|
-
}
|
|
@@ -1,21 +0,0 @@
|
|
|
1
|
-
import type { DiscountCart } from "./DiscountCart";
|
|
2
|
-
import { type NumericalComparisonType, Qualifier } from "./Qualifier";
|
|
3
|
-
|
|
4
|
-
export class PostCartAmountQualifier extends Qualifier {
|
|
5
|
-
comparisonType: NumericalComparisonType;
|
|
6
|
-
amount: number;
|
|
7
|
-
|
|
8
|
-
constructor(comparisonType: NumericalComparisonType, amount: number) {
|
|
9
|
-
super();
|
|
10
|
-
this.comparisonType = comparisonType;
|
|
11
|
-
this.amount = amount;
|
|
12
|
-
}
|
|
13
|
-
|
|
14
|
-
match(discountCart: DiscountCart) {
|
|
15
|
-
return this.compareAmounts(
|
|
16
|
-
discountCart.subtotalAmount - discountCart.appliedDiscountTotal,
|
|
17
|
-
this.comparisonType,
|
|
18
|
-
this.amount
|
|
19
|
-
);
|
|
20
|
-
}
|
|
21
|
-
}
|
|
@@ -1,31 +0,0 @@
|
|
|
1
|
-
import type {
|
|
2
|
-
CartLine,
|
|
3
|
-
ProductVariant,
|
|
4
|
-
} from '../lineItem/api';
|
|
5
|
-
import { MatchType, Selector } from './Selector';
|
|
6
|
-
|
|
7
|
-
export class ProductHandleSelector extends Selector {
|
|
8
|
-
invert: boolean;
|
|
9
|
-
handles: string[];
|
|
10
|
-
|
|
11
|
-
constructor(matchType: MatchType, handles: string[]) {
|
|
12
|
-
super();
|
|
13
|
-
this.invert = matchType == MatchType.NOT_ONE;
|
|
14
|
-
this.handles = handles.map((t) => t.toLowerCase());
|
|
15
|
-
}
|
|
16
|
-
|
|
17
|
-
match(lineItem: CartLine) {
|
|
18
|
-
const variant = lineItem.merchandise as ProductVariant;
|
|
19
|
-
|
|
20
|
-
const matchResult =
|
|
21
|
-
this.handles.indexOf(
|
|
22
|
-
variant.product.handle.toLowerCase()
|
|
23
|
-
) > -1;
|
|
24
|
-
|
|
25
|
-
if (this.invert) {
|
|
26
|
-
return !matchResult;
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
return matchResult;
|
|
30
|
-
}
|
|
31
|
-
}
|
|
@@ -1,34 +0,0 @@
|
|
|
1
|
-
import type {
|
|
2
|
-
CartLine,
|
|
3
|
-
ProductVariant,
|
|
4
|
-
} from '../lineItem/api';
|
|
5
|
-
import { MatchType, Selector } from './Selector';
|
|
6
|
-
|
|
7
|
-
export class ProductIdSelector extends Selector {
|
|
8
|
-
invert: boolean;
|
|
9
|
-
productIds: string[];
|
|
10
|
-
|
|
11
|
-
constructor(
|
|
12
|
-
matchType: MatchType.IS_ONE | MatchType.NOT_ONE,
|
|
13
|
-
productIds: string[]
|
|
14
|
-
) {
|
|
15
|
-
super();
|
|
16
|
-
this.invert = matchType == MatchType.NOT_ONE;
|
|
17
|
-
this.productIds = productIds;
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
match(subject: unknown): boolean;
|
|
21
|
-
match(lineItem: CartLine) {
|
|
22
|
-
const variant = lineItem.merchandise as ProductVariant;
|
|
23
|
-
|
|
24
|
-
const matchResult = this.productIds.includes(
|
|
25
|
-
variant.product.id
|
|
26
|
-
);
|
|
27
|
-
|
|
28
|
-
if (this.invert) {
|
|
29
|
-
return !matchResult;
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
return matchResult;
|
|
33
|
-
}
|
|
34
|
-
}
|
|
@@ -1,63 +0,0 @@
|
|
|
1
|
-
import type {
|
|
2
|
-
CartLine,
|
|
3
|
-
ProductVariant,
|
|
4
|
-
} from '../lineItem/api';
|
|
5
|
-
import { Selector } from './Selector';
|
|
6
|
-
import {
|
|
7
|
-
QualifierMatchType,
|
|
8
|
-
StringComparisonType,
|
|
9
|
-
} from './Qualifier';
|
|
10
|
-
|
|
11
|
-
export class ProductTagSelector extends Selector {
|
|
12
|
-
invert: boolean;
|
|
13
|
-
matchCondition: StringComparisonType;
|
|
14
|
-
tags: string[];
|
|
15
|
-
|
|
16
|
-
constructor(
|
|
17
|
-
matchType: QualifierMatchType,
|
|
18
|
-
matchCondition: StringComparisonType,
|
|
19
|
-
tags: string[]
|
|
20
|
-
) {
|
|
21
|
-
super();
|
|
22
|
-
this.matchCondition = matchCondition;
|
|
23
|
-
this.invert = matchType == QualifierMatchType.DOES_NOT;
|
|
24
|
-
this.tags = tags.map((t) => t.toLowerCase());
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
match(subject: unknown): boolean;
|
|
28
|
-
match(lineItem: CartLine) {
|
|
29
|
-
const variant = lineItem.merchandise as ProductVariant;
|
|
30
|
-
const productTags = variant.product.hasTags.reduce(
|
|
31
|
-
(tags, t) => {
|
|
32
|
-
if (t.hasTag) {
|
|
33
|
-
tags.push(t.tag.toLowerCase());
|
|
34
|
-
}
|
|
35
|
-
return tags;
|
|
36
|
-
},
|
|
37
|
-
[] as string[]
|
|
38
|
-
);
|
|
39
|
-
|
|
40
|
-
let matchResult: boolean;
|
|
41
|
-
|
|
42
|
-
switch (this.matchCondition) {
|
|
43
|
-
case StringComparisonType.MATCH:
|
|
44
|
-
matchResult =
|
|
45
|
-
productTags.filter((tag) =>
|
|
46
|
-
this.tags.includes(tag)
|
|
47
|
-
).length > 0;
|
|
48
|
-
break;
|
|
49
|
-
default:
|
|
50
|
-
matchResult = this.partialMatch(
|
|
51
|
-
this.matchCondition,
|
|
52
|
-
productTags,
|
|
53
|
-
this.tags
|
|
54
|
-
);
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
if (this.invert) {
|
|
58
|
-
return !matchResult;
|
|
59
|
-
}
|
|
60
|
-
|
|
61
|
-
return matchResult;
|
|
62
|
-
}
|
|
63
|
-
}
|