@hartl-services/medusa-base 4.0.0 → 5.0.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.
@@ -0,0 +1,143 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.syncFreeShippingPromotions = exports.FREE_SHIPPING_PROMOTION_SYNC_LOCK_KEY = exports.AFFILIATE_FREE_SHIPPING_PROMOTION_CODE = exports.STANDARD_FREE_SHIPPING_PROMOTION_CODE = exports.AFFILIATE_QUALIFICATION_ATTRIBUTE = void 0;
4
+ const utils_1 = require("@medusajs/framework/utils");
5
+ const core_flows_1 = require("@medusajs/medusa/core-flows");
6
+ const public_1 = require("../../public");
7
+ const plugin_features_1 = require("../../free-shipping/plugin-features");
8
+ const free_shipping_settings_1 = require("../../free-shipping/free-shipping-settings");
9
+ /**
10
+ * Context attribute the `set-free-shipping-promotion-context` hook injects
11
+ * into every cart-promotion computation. Both promotions below key off it so
12
+ * a cart between the two thresholds can't get free shipping through the
13
+ * standard promotion just because it also satisfies `item_total >= X`.
14
+ */
15
+ exports.AFFILIATE_QUALIFICATION_ATTRIBUTE = "qualifies_for_affiliate_shipping_threshold";
16
+ exports.STANDARD_FREE_SHIPPING_PROMOTION_CODE = "AUTO-FREE-SHIPPING-STANDARD";
17
+ exports.AFFILIATE_FREE_SHIPPING_PROMOTION_CODE = "AUTO-FREE-SHIPPING-AFFILIATE";
18
+ /** Serializes every sync run (job and both subscribers) across processes. */
19
+ exports.FREE_SHIPPING_PROMOTION_SYNC_LOCK_KEY = "free-shipping-promotion-sync";
20
+ /** Seconds to wait for the lock; the in-memory provider also expires it then. */
21
+ const SYNC_LOCK_TIMEOUT_SECONDS = 60;
22
+ const buildRules = (threshold, qualifiesValue) => [
23
+ { attribute: "item_total", operator: "gte", values: [String(threshold)] },
24
+ {
25
+ attribute: exports.AFFILIATE_QUALIFICATION_ATTRIBUTE,
26
+ operator: "eq",
27
+ values: [qualifiesValue],
28
+ },
29
+ ];
30
+ const ruleKey = (rule) => JSON.stringify([rule.attribute, rule.operator, [...rule.values].sort()]);
31
+ const ensurePromotion = async (container, promotionService, code, status, threshold, qualifiesValue) => {
32
+ const rules = buildRules(threshold, qualifiesValue);
33
+ const existing = await promotionService.listPromotions({ code: [code] }, { relations: ["rules"] });
34
+ if (!existing[0]) {
35
+ try {
36
+ await (0, core_flows_1.createPromotionsWorkflow)(container).run({
37
+ input: {
38
+ promotionsData: [
39
+ {
40
+ code,
41
+ type: "standard",
42
+ status,
43
+ is_automatic: true,
44
+ application_method: {
45
+ type: "percentage",
46
+ value: 100,
47
+ target_type: "shipping_methods",
48
+ allocation: "across",
49
+ },
50
+ rules,
51
+ },
52
+ ],
53
+ },
54
+ });
55
+ return;
56
+ }
57
+ catch (error) {
58
+ // Concurrent boot across server/worker processes can race on the
59
+ // unique promotion code. Whoever loses the race falls through to the
60
+ // update path below, which is idempotent either way.
61
+ const createdByAnotherProcess = await promotionService.listPromotions({ code: [code] }, { relations: ["rules"] });
62
+ if (!createdByAnotherProcess[0]) {
63
+ throw error;
64
+ }
65
+ }
66
+ }
67
+ const current = (await promotionService.listPromotions({ code: [code] }, { relations: ["application_method", "rules", "rules.values"] }))[0];
68
+ if (!current) {
69
+ return;
70
+ }
71
+ const desiredKeys = new Set(rules.map(ruleKey));
72
+ const currentRules = (current.rules ?? []).map((rule) => ({
73
+ id: rule.id,
74
+ key: ruleKey({
75
+ attribute: rule.attribute,
76
+ operator: rule.operator,
77
+ values: (rule.values ?? []).map(({ value }) => String(value)),
78
+ }),
79
+ }));
80
+ const currentKeys = new Set(currentRules.map(({ key }) => key));
81
+ const rulesToCreate = rules.filter((rule) => !currentKeys.has(ruleKey(rule)));
82
+ const ruleIdsToDelete = currentRules
83
+ .filter(({ key }) => !desiredKeys.has(key))
84
+ .map(({ id }) => id);
85
+ // Create before delete: meanwhile the old and new rules apply together,
86
+ // which can only narrow which carts qualify. Deleting first would briefly
87
+ // leave an automatic promotion without rules - free shipping for every cart.
88
+ if (rulesToCreate.length) {
89
+ await (0, core_flows_1.batchPromotionRulesWorkflow)(container).run({
90
+ input: { id: current.id, rule_type: utils_1.RuleType.RULES, create: rulesToCreate },
91
+ });
92
+ }
93
+ if (ruleIdsToDelete.length) {
94
+ await (0, core_flows_1.batchPromotionRulesWorkflow)(container).run({
95
+ input: {
96
+ id: current.id,
97
+ rule_type: utils_1.RuleType.RULES,
98
+ delete: ruleIdsToDelete,
99
+ },
100
+ });
101
+ }
102
+ if (current.status !== status ||
103
+ Number(current.application_method?.value) !== 100) {
104
+ await (0, core_flows_1.updatePromotionsWorkflow)(container).run({
105
+ input: {
106
+ promotionsData: [
107
+ {
108
+ id: current.id,
109
+ status,
110
+ application_method: { value: 100 },
111
+ },
112
+ ],
113
+ },
114
+ });
115
+ }
116
+ };
117
+ /**
118
+ * Keeps the two automatic free-shipping promotions in sync with the plugin's
119
+ * settings (thresholds) and the base plugin toggle `free_shipping` (status:
120
+ * active while the plugin is on, inactive while it is off). Called by the
121
+ * `free-shipping-promotion-sync` job and by the `plugin-features-updated`
122
+ * and `plugin-settings-updated` subscribers.
123
+ *
124
+ * The whole run (toggle and settings read, both reconciliations) holds one
125
+ * Locking-module lock. Unlocked runs could interleave their rule diffs, e.g.
126
+ * one run deleting the threshold rule another run just created, and leave an
127
+ * automatic promotion without its `item_total` rule. Reading inside the lock
128
+ * also means the last run always writes the latest values. A read failure
129
+ * propagates; nothing is written then.
130
+ */
131
+ const syncFreeShippingPromotions = async (container) => {
132
+ const locking = container.resolve(utils_1.Modules.LOCKING);
133
+ await locking.execute(exports.FREE_SHIPPING_PROMOTION_SYNC_LOCK_KEY, async () => {
134
+ const promotionService = container.resolve(utils_1.Modules.PROMOTION);
135
+ const enabled = await (0, public_1.isPluginFeatureEnabled)(container, plugin_features_1.freeShippingPluginFeatures);
136
+ const settings = await (0, free_shipping_settings_1.resolveFreeShippingSettings)(container);
137
+ const status = enabled ? "active" : "inactive";
138
+ await ensurePromotion(container, promotionService, exports.STANDARD_FREE_SHIPPING_PROMOTION_CODE, status, settings.default_threshold, "false");
139
+ await ensurePromotion(container, promotionService, exports.AFFILIATE_FREE_SHIPPING_PROMOTION_CODE, status, settings.affiliate_threshold, "true");
140
+ }, { timeout: SYNC_LOCK_TIMEOUT_SECONDS });
141
+ };
142
+ exports.syncFreeShippingPromotions = syncFreeShippingPromotions;
143
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoic3luYy1mcmVlLXNoaXBwaW5nLXByb21vdGlvbnMuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi8uLi8uLi9zcmMvd29ya2Zsb3dzL2ZyZWUtc2hpcHBpbmcvc3luYy1mcmVlLXNoaXBwaW5nLXByb21vdGlvbnMudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6Ijs7O0FBS0EscURBQTZEO0FBQzdELDREQUlvQztBQUVwQyx5Q0FBcUQ7QUFFckQseUVBQWdGO0FBQ2hGLHVGQUF3RjtBQUV4Rjs7Ozs7R0FLRztBQUNVLFFBQUEsaUNBQWlDLEdBQzVDLDRDQUE0QyxDQUFBO0FBRWpDLFFBQUEscUNBQXFDLEdBQ2hELDZCQUE2QixDQUFBO0FBQ2xCLFFBQUEsc0NBQXNDLEdBQ2pELDhCQUE4QixDQUFBO0FBRWhDLDZFQUE2RTtBQUNoRSxRQUFBLHFDQUFxQyxHQUNoRCw4QkFBOEIsQ0FBQTtBQUNoQyxpRkFBaUY7QUFDakYsTUFBTSx5QkFBeUIsR0FBRyxFQUFFLENBQUE7QUFRcEMsTUFBTSxVQUFVLEdBQUcsQ0FDakIsU0FBaUIsRUFDakIsY0FBZ0MsRUFDcEIsRUFBRSxDQUFDO0lBQ2YsRUFBRSxTQUFTLEVBQUUsWUFBWSxFQUFFLFFBQVEsRUFBRSxLQUFLLEVBQUUsTUFBTSxFQUFFLENBQUMsTUFBTSxDQUFDLFNBQVMsQ0FBQyxDQUFDLEVBQUU7SUFDekU7UUFDRSxTQUFTLEVBQUUseUNBQWlDO1FBQzVDLFFBQVEsRUFBRSxJQUFJO1FBQ2QsTUFBTSxFQUFFLENBQUMsY0FBYyxDQUFDO0tBQ3pCO0NBQ0YsQ0FBQTtBQUVELE1BQU0sT0FBTyxHQUFHLENBQUMsSUFJaEIsRUFBVSxFQUFFLENBQ1gsSUFBSSxDQUFDLFNBQVMsQ0FBQyxDQUFDLElBQUksQ0FBQyxTQUFTLEVBQUUsSUFBSSxDQUFDLFFBQVEsRUFBRSxDQUFDLEdBQUcsSUFBSSxDQUFDLE1BQU0sQ0FBQyxDQUFDLElBQUksRUFBRSxDQUFDLENBQUMsQ0FBQTtBQUUxRSxNQUFNLGVBQWUsR0FBRyxLQUFLLEVBQzNCLFNBQTBCLEVBQzFCLGdCQUF5QyxFQUN6QyxJQUFZLEVBQ1osTUFBNkIsRUFDN0IsU0FBaUIsRUFDakIsY0FBZ0MsRUFDakIsRUFBRTtJQUNqQixNQUFNLEtBQUssR0FBRyxVQUFVLENBQUMsU0FBUyxFQUFFLGNBQWMsQ0FBQyxDQUFBO0lBQ25ELE1BQU0sUUFBUSxHQUFHLE1BQU0sZ0JBQWdCLENBQUMsY0FBYyxDQUNwRCxFQUFFLElBQUksRUFBRSxDQUFDLElBQUksQ0FBQyxFQUFFLEVBQ2hCLEVBQUUsU0FBUyxFQUFFLENBQUMsT0FBTyxDQUFDLEVBQUUsQ0FDekIsQ0FBQTtJQUVELElBQUksQ0FBQyxRQUFRLENBQUMsQ0FBQyxDQUFDLEVBQUUsQ0FBQztRQUNqQixJQUFJLENBQUM7WUFDSCxNQUFNLElBQUEscUNBQXdCLEVBQUMsU0FBUyxDQUFDLENBQUMsR0FBRyxDQUFDO2dCQUM1QyxLQUFLLEVBQUU7b0JBQ0wsY0FBYyxFQUFFO3dCQUNkOzRCQUNFLElBQUk7NEJBQ0osSUFBSSxFQUFFLFVBQVU7NEJBQ2hCLE1BQU07NEJBQ04sWUFBWSxFQUFFLElBQUk7NEJBQ2xCLGtCQUFrQixFQUFFO2dDQUNsQixJQUFJLEVBQUUsWUFBWTtnQ0FDbEIsS0FBSyxFQUFFLEdBQUc7Z0NBQ1YsV0FBVyxFQUFFLGtCQUFrQjtnQ0FDL0IsVUFBVSxFQUFFLFFBQVE7NkJBQ3JCOzRCQUNELEtBQUs7eUJBQ047cUJBQ0Y7aUJBQ0Y7YUFDRixDQUFDLENBQUE7WUFDRixPQUFNO1FBQ1IsQ0FBQztRQUFDLE9BQU8sS0FBSyxFQUFFLENBQUM7WUFDZixpRUFBaUU7WUFDakUscUVBQXFFO1lBQ3JFLHFEQUFxRDtZQUNyRCxNQUFNLHVCQUF1QixHQUFHLE1BQU0sZ0JBQWdCLENBQUMsY0FBYyxDQUNuRSxFQUFFLElBQUksRUFBRSxDQUFDLElBQUksQ0FBQyxFQUFFLEVBQ2hCLEVBQUUsU0FBUyxFQUFFLENBQUMsT0FBTyxDQUFDLEVBQUUsQ0FDekIsQ0FBQTtZQUNELElBQUksQ0FBQyx1QkFBdUIsQ0FBQyxDQUFDLENBQUMsRUFBRSxDQUFDO2dCQUNoQyxNQUFNLEtBQUssQ0FBQTtZQUNiLENBQUM7UUFDSCxDQUFDO0lBQ0gsQ0FBQztJQUVELE1BQU0sT0FBTyxHQUFHLENBQ2QsTUFBTSxnQkFBZ0IsQ0FBQyxjQUFjLENBQ25DLEVBQUUsSUFBSSxFQUFFLENBQUMsSUFBSSxDQUFDLEVBQUUsRUFDaEIsRUFBRSxTQUFTLEVBQUUsQ0FBQyxvQkFBb0IsRUFBRSxPQUFPLEVBQUUsY0FBYyxDQUFDLEVBQUUsQ0FDL0QsQ0FDRixDQUFDLENBQUMsQ0FBQyxDQUFBO0lBQ0osSUFBSSxDQUFDLE9BQU8sRUFBRSxDQUFDO1FBQ2IsT0FBTTtJQUNSLENBQUM7SUFFRCxNQUFNLFdBQVcsR0FBRyxJQUFJLEdBQUcsQ0FBQyxLQUFLLENBQUMsR0FBRyxDQUFDLE9BQU8sQ0FBQyxDQUFDLENBQUE7SUFDL0MsTUFBTSxZQUFZLEdBQUcsQ0FBQyxPQUFPLENBQUMsS0FBSyxJQUFJLEVBQUUsQ0FBQyxDQUFDLEdBQUcsQ0FBQyxDQUFDLElBQUksRUFBRSxFQUFFLENBQUMsQ0FBQztRQUN4RCxFQUFFLEVBQUUsSUFBSSxDQUFDLEVBQUU7UUFDWCxHQUFHLEVBQUUsT0FBTyxDQUFDO1lBQ1gsU0FBUyxFQUFFLElBQUksQ0FBQyxTQUFTO1lBQ3pCLFFBQVEsRUFBRSxJQUFJLENBQUMsUUFBUTtZQUN2QixNQUFNLEVBQUUsQ0FBQyxJQUFJLENBQUMsTUFBTSxJQUFJLEVBQUUsQ0FBQyxDQUFDLEdBQUcsQ0FBQyxDQUFDLEVBQUUsS0FBSyxFQUFFLEVBQUUsRUFBRSxDQUFDLE1BQU0sQ0FBQyxLQUFLLENBQUMsQ0FBQztTQUM5RCxDQUFDO0tBQ0gsQ0FBQyxDQUFDLENBQUE7SUFDSCxNQUFNLFdBQVcsR0FBRyxJQUFJLEdBQUcsQ0FBQyxZQUFZLENBQUMsR0FBRyxDQUFDLENBQUMsRUFBRSxHQUFHLEVBQUUsRUFBRSxFQUFFLENBQUMsR0FBRyxDQUFDLENBQUMsQ0FBQTtJQUMvRCxNQUFNLGFBQWEsR0FBRyxLQUFLLENBQUMsTUFBTSxDQUFDLENBQUMsSUFBSSxFQUFFLEVBQUUsQ0FBQyxDQUFDLFdBQVcsQ0FBQyxHQUFHLENBQUMsT0FBTyxDQUFDLElBQUksQ0FBQyxDQUFDLENBQUMsQ0FBQTtJQUM3RSxNQUFNLGVBQWUsR0FBRyxZQUFZO1NBQ2pDLE1BQU0sQ0FBQyxDQUFDLEVBQUUsR0FBRyxFQUFFLEVBQUUsRUFBRSxDQUFDLENBQUMsV0FBVyxDQUFDLEdBQUcsQ0FBQyxHQUFHLENBQUMsQ0FBQztTQUMxQyxHQUFHLENBQUMsQ0FBQyxFQUFFLEVBQUUsRUFBRSxFQUFFLEVBQUUsQ0FBQyxFQUFFLENBQUMsQ0FBQTtJQUV0Qix3RUFBd0U7SUFDeEUsMEVBQTBFO0lBQzFFLDZFQUE2RTtJQUM3RSxJQUFJLGFBQWEsQ0FBQyxNQUFNLEVBQUUsQ0FBQztRQUN6QixNQUFNLElBQUEsd0NBQTJCLEVBQUMsU0FBUyxDQUFDLENBQUMsR0FBRyxDQUFDO1lBQy9DLEtBQUssRUFBRSxFQUFFLEVBQUUsRUFBRSxPQUFPLENBQUMsRUFBRSxFQUFFLFNBQVMsRUFBRSxnQkFBUSxDQUFDLEtBQUssRUFBRSxNQUFNLEVBQUUsYUFBYSxFQUFFO1NBQzVFLENBQUMsQ0FBQTtJQUNKLENBQUM7SUFDRCxJQUFJLGVBQWUsQ0FBQyxNQUFNLEVBQUUsQ0FBQztRQUMzQixNQUFNLElBQUEsd0NBQTJCLEVBQUMsU0FBUyxDQUFDLENBQUMsR0FBRyxDQUFDO1lBQy9DLEtBQUssRUFBRTtnQkFDTCxFQUFFLEVBQUUsT0FBTyxDQUFDLEVBQUU7Z0JBQ2QsU0FBUyxFQUFFLGdCQUFRLENBQUMsS0FBSztnQkFDekIsTUFBTSxFQUFFLGVBQWU7YUFDeEI7U0FDRixDQUFDLENBQUE7SUFDSixDQUFDO0lBQ0QsSUFDRSxPQUFPLENBQUMsTUFBTSxLQUFLLE1BQU07UUFDekIsTUFBTSxDQUFDLE9BQU8sQ0FBQyxrQkFBa0IsRUFBRSxLQUFLLENBQUMsS0FBSyxHQUFHLEVBQ2pELENBQUM7UUFDRCxNQUFNLElBQUEscUNBQXdCLEVBQUMsU0FBUyxDQUFDLENBQUMsR0FBRyxDQUFDO1lBQzVDLEtBQUssRUFBRTtnQkFDTCxjQUFjLEVBQUU7b0JBQ2Q7d0JBQ0UsRUFBRSxFQUFFLE9BQU8sQ0FBQyxFQUFFO3dCQUNkLE1BQU07d0JBQ04sa0JBQWtCLEVBQUUsRUFBRSxLQUFLLEVBQUUsR0FBRyxFQUFFO3FCQUNuQztpQkFDRjthQUNGO1NBQ0YsQ0FBQyxDQUFBO0lBQ0osQ0FBQztBQUNILENBQUMsQ0FBQTtBQUVEOzs7Ozs7Ozs7Ozs7O0dBYUc7QUFDSSxNQUFNLDBCQUEwQixHQUFHLEtBQUssRUFDN0MsU0FBMEIsRUFDWCxFQUFFO0lBQ2pCLE1BQU0sT0FBTyxHQUFHLFNBQVMsQ0FBQyxPQUFPLENBQUMsZUFBTyxDQUFDLE9BQU8sQ0FBbUIsQ0FBQTtJQUVwRSxNQUFNLE9BQU8sQ0FBQyxPQUFPLENBQ25CLDZDQUFxQyxFQUNyQyxLQUFLLElBQUksRUFBRTtRQUNULE1BQU0sZ0JBQWdCLEdBQUcsU0FBUyxDQUFDLE9BQU8sQ0FDeEMsZUFBTyxDQUFDLFNBQVMsQ0FDUyxDQUFBO1FBQzVCLE1BQU0sT0FBTyxHQUFHLE1BQU0sSUFBQSwrQkFBc0IsRUFDMUMsU0FBUyxFQUNULDRDQUEwQixDQUMzQixDQUFBO1FBQ0QsTUFBTSxRQUFRLEdBQUcsTUFBTSxJQUFBLG9EQUEyQixFQUFDLFNBQVMsQ0FBQyxDQUFBO1FBQzdELE1BQU0sTUFBTSxHQUFHLE9BQU8sQ0FBQyxDQUFDLENBQUMsUUFBUSxDQUFDLENBQUMsQ0FBQyxVQUFVLENBQUE7UUFFOUMsTUFBTSxlQUFlLENBQ25CLFNBQVMsRUFDVCxnQkFBZ0IsRUFDaEIsNkNBQXFDLEVBQ3JDLE1BQU0sRUFDTixRQUFRLENBQUMsaUJBQWlCLEVBQzFCLE9BQU8sQ0FDUixDQUFBO1FBQ0QsTUFBTSxlQUFlLENBQ25CLFNBQVMsRUFDVCxnQkFBZ0IsRUFDaEIsOENBQXNDLEVBQ3RDLE1BQU0sRUFDTixRQUFRLENBQUMsbUJBQW1CLEVBQzVCLE1BQU0sQ0FDUCxDQUFBO0lBQ0gsQ0FBQyxFQUNELEVBQUUsT0FBTyxFQUFFLHlCQUF5QixFQUFFLENBQ3ZDLENBQUE7QUFDSCxDQUFDLENBQUE7QUFyQ1ksUUFBQSwwQkFBMEIsOEJBcUN0QyJ9
@@ -0,0 +1,86 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.setFreeShippingPromotionContext = void 0;
4
+ const workflows_sdk_1 = require("@medusajs/framework/workflows-sdk");
5
+ const utils_1 = require("@medusajs/framework/utils");
6
+ const core_flows_1 = require("@medusajs/medusa/core-flows");
7
+ const lib_1 = require("../../shared/lib");
8
+ const plugin_features_1 = require("../../free-shipping/plugin-features");
9
+ const free_shipping_settings_1 = require("../../free-shipping/free-shipping-settings");
10
+ const sync_free_shipping_promotions_1 = require("../free-shipping/sync-free-shipping-promotions");
11
+ const declaredBooleanDefault = (key) => plugin_features_1.freeShippingPluginFeatures.settings?.find((setting) => setting.key === key)
12
+ ?.default === true;
13
+ /** The descriptor's defaults: account holders on, referred customers off. */
14
+ const DECLARED_DEFAULT_AFFILIATE_RULES = {
15
+ affiliate_applies_to_account_holders: declaredBooleanDefault("affiliate_applies_to_account_holders"),
16
+ affiliate_applies_to_referred_customers: declaredBooleanDefault("affiliate_applies_to_referred_customers"),
17
+ };
18
+ /** Last successfully read rules of this process (null until the first read). */
19
+ let lastKnownAffiliateRules = null;
20
+ /**
21
+ * This hook runs in every cart-promotion computation, so a failing settings
22
+ * read must not fail the cart. It is reported (`logger.error`, which the base
23
+ * plugin's logger wrapper forwards to Sentry) and the cart is computed with
24
+ * the last rules this process read successfully, or with the declared
25
+ * defaults when there are none yet. That keeps affiliate carts on the
26
+ * affiliate threshold instead of silently moving them to the standard one.
27
+ */
28
+ const readAffiliateRules = async (container, cartId) => {
29
+ try {
30
+ const settings = await (0, free_shipping_settings_1.resolveFreeShippingSettings)(container);
31
+ lastKnownAffiliateRules = {
32
+ affiliate_applies_to_account_holders: settings.affiliate_applies_to_account_holders,
33
+ affiliate_applies_to_referred_customers: settings.affiliate_applies_to_referred_customers,
34
+ };
35
+ return settings;
36
+ }
37
+ catch (error) {
38
+ const fallback = lastKnownAffiliateRules;
39
+ try {
40
+ container
41
+ .resolve(utils_1.ContainerRegistrationKeys.LOGGER)
42
+ .error(`Free-shipping settings could not be read for cart ${cartId}; computing the promotion context with the ${fallback ? "last known" : "default"} affiliate rules.`, error instanceof Error ? error : new Error(String(error)));
43
+ }
44
+ catch {
45
+ // A missing logger must not turn the fail-safe itself into a failure.
46
+ }
47
+ return fallback ?? DECLARED_DEFAULT_AFFILIATE_RULES;
48
+ }
49
+ };
50
+ /**
51
+ * Computes whether the cart qualifies for the affiliate free-shipping
52
+ * threshold, so the two automatic promotions (whose rules are static, see
53
+ * `sync-free-shipping-promotions.ts`) can tell them apart at evaluation
54
+ * time. Which criteria count as "affiliate" is controlled entirely by the
55
+ * two boolean settings - no promotion resync is needed when they change,
56
+ * only this computation.
57
+ */
58
+ const setFreeShippingPromotionContext = async ({ cart }, { container }) => {
59
+ const typedCart = cart;
60
+ let qualifies = false;
61
+ if (typedCart.customer_id) {
62
+ // The Affiliate plugin is optional: without it no cart qualifies.
63
+ const affiliateService = (0, lib_1.tryResolveOptional)(container, "affiliate");
64
+ if (affiliateService) {
65
+ const settings = await readAffiliateRules(container, typedCart.id);
66
+ if (settings.affiliate_applies_to_account_holders) {
67
+ qualifies = await affiliateService.isCustomerAffiliate(typedCart.customer_id);
68
+ }
69
+ if (!qualifies && settings.affiliate_applies_to_referred_customers) {
70
+ const query = container.resolve(utils_1.ContainerRegistrationKeys.QUERY);
71
+ const state = await affiliateService.inspectAffiliateCartReferralForCheckout({
72
+ cart_id: typedCart.id,
73
+ customer_id: typedCart.customer_id,
74
+ normalized_email: (0, lib_1.normalizeEmail)(typedCart.email),
75
+ }, query);
76
+ qualifies = state.assignment !== null;
77
+ }
78
+ }
79
+ }
80
+ return new workflows_sdk_1.StepResponse({
81
+ [sync_free_shipping_promotions_1.AFFILIATE_QUALIFICATION_ATTRIBUTE]: qualifies ? "true" : "false",
82
+ });
83
+ };
84
+ exports.setFreeShippingPromotionContext = setFreeShippingPromotionContext;
85
+ core_flows_1.updateCartPromotionsWorkflow.hooks.setPromotionContext(exports.setFreeShippingPromotionContext);
86
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoic2V0LWZyZWUtc2hpcHBpbmctcHJvbW90aW9uLWNvbnRleHQuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi8uLi8uLi9zcmMvd29ya2Zsb3dzL2hvb2tzL3NldC1mcmVlLXNoaXBwaW5nLXByb21vdGlvbi1jb250ZXh0LnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7OztBQUFBLHFFQUFnRTtBQUNoRSxxREFBcUU7QUFFckUsNERBQTBFO0FBQzFFLDBDQUFxRTtBQUVyRSx5RUFBZ0Y7QUFDaEYsdUZBR21EO0FBQ25ELGtHQUFrRztBQTJCbEcsTUFBTSxzQkFBc0IsR0FBRyxDQUFDLEdBQXlCLEVBQVcsRUFBRSxDQUNwRSw0Q0FBMEIsQ0FBQyxRQUFRLEVBQUUsSUFBSSxDQUFDLENBQUMsT0FBTyxFQUFFLEVBQUUsQ0FBQyxPQUFPLENBQUMsR0FBRyxLQUFLLEdBQUcsQ0FBQztJQUN6RSxFQUFFLE9BQU8sS0FBSyxJQUFJLENBQUE7QUFFdEIsNkVBQTZFO0FBQzdFLE1BQU0sZ0NBQWdDLEdBQW1CO0lBQ3ZELG9DQUFvQyxFQUFFLHNCQUFzQixDQUMxRCxzQ0FBc0MsQ0FDdkM7SUFDRCx1Q0FBdUMsRUFBRSxzQkFBc0IsQ0FDN0QseUNBQXlDLENBQzFDO0NBQ0YsQ0FBQTtBQUVELGdGQUFnRjtBQUNoRixJQUFJLHVCQUF1QixHQUEwQixJQUFJLENBQUE7QUFFekQ7Ozs7Ozs7R0FPRztBQUNILE1BQU0sa0JBQWtCLEdBQUcsS0FBSyxFQUM5QixTQUEwQixFQUMxQixNQUFjLEVBQ1csRUFBRTtJQUMzQixJQUFJLENBQUM7UUFDSCxNQUFNLFFBQVEsR0FBRyxNQUFNLElBQUEsb0RBQTJCLEVBQUMsU0FBUyxDQUFDLENBQUE7UUFDN0QsdUJBQXVCLEdBQUc7WUFDeEIsb0NBQW9DLEVBQ2xDLFFBQVEsQ0FBQyxvQ0FBb0M7WUFDL0MsdUNBQXVDLEVBQ3JDLFFBQVEsQ0FBQyx1Q0FBdUM7U0FDbkQsQ0FBQTtRQUNELE9BQU8sUUFBUSxDQUFBO0lBQ2pCLENBQUM7SUFBQyxPQUFPLEtBQUssRUFBRSxDQUFDO1FBQ2YsTUFBTSxRQUFRLEdBQUcsdUJBQXVCLENBQUE7UUFDeEMsSUFBSSxDQUFDO1lBQ0gsU0FBUztpQkFDTixPQUFPLENBQVMsaUNBQXlCLENBQUMsTUFBTSxDQUFDO2lCQUNqRCxLQUFLLENBQ0oscURBQXFELE1BQU0sOENBQ3pELFFBQVEsQ0FBQyxDQUFDLENBQUMsWUFBWSxDQUFDLENBQUMsQ0FBQyxTQUM1QixtQkFBbUIsRUFDbkIsS0FBSyxZQUFZLEtBQUssQ0FBQyxDQUFDLENBQUMsS0FBSyxDQUFDLENBQUMsQ0FBQyxJQUFJLEtBQUssQ0FBQyxNQUFNLENBQUMsS0FBSyxDQUFDLENBQUMsQ0FDMUQsQ0FBQTtRQUNMLENBQUM7UUFBQyxNQUFNLENBQUM7WUFDUCxzRUFBc0U7UUFDeEUsQ0FBQztRQUNELE9BQU8sUUFBUSxJQUFJLGdDQUFnQyxDQUFBO0lBQ3JELENBQUM7QUFDSCxDQUFDLENBQUE7QUFRRDs7Ozs7OztHQU9HO0FBQ0ksTUFBTSwrQkFBK0IsR0FFckMsS0FBSyxFQUFFLEVBQUUsSUFBSSxFQUFFLEVBQUUsRUFBRSxTQUFTLEVBQUUsRUFBRSxFQUFFO0lBQ3ZDLE1BQU0sU0FBUyxHQUFHLElBQXFCLENBQUE7SUFDdkMsSUFBSSxTQUFTLEdBQUcsS0FBSyxDQUFBO0lBRXJCLElBQUksU0FBUyxDQUFDLFdBQVcsRUFBRSxDQUFDO1FBQzFCLGtFQUFrRTtRQUNsRSxNQUFNLGdCQUFnQixHQUFHLElBQUEsd0JBQWtCLEVBQ3pDLFNBQVMsRUFDVCxXQUFXLENBQ1osQ0FBQTtRQUVELElBQUksZ0JBQWdCLEVBQUUsQ0FBQztZQUNyQixNQUFNLFFBQVEsR0FBRyxNQUFNLGtCQUFrQixDQUN2QyxTQUE0QixFQUM1QixTQUFTLENBQUMsRUFBRSxDQUNiLENBQUE7WUFFRCxJQUFJLFFBQVEsQ0FBQyxvQ0FBb0MsRUFBRSxDQUFDO2dCQUNsRCxTQUFTLEdBQUcsTUFBTSxnQkFBZ0IsQ0FBQyxtQkFBbUIsQ0FDcEQsU0FBUyxDQUFDLFdBQVcsQ0FDdEIsQ0FBQTtZQUNILENBQUM7WUFFRCxJQUFJLENBQUMsU0FBUyxJQUFJLFFBQVEsQ0FBQyx1Q0FBdUMsRUFBRSxDQUFDO2dCQUNuRSxNQUFNLEtBQUssR0FBRyxTQUFTLENBQUMsT0FBTyxDQUFDLGlDQUF5QixDQUFDLEtBQUssQ0FBQyxDQUFBO2dCQUNoRSxNQUFNLEtBQUssR0FDVCxNQUFNLGdCQUFnQixDQUFDLHVDQUF1QyxDQUM1RDtvQkFDRSxPQUFPLEVBQUUsU0FBUyxDQUFDLEVBQUU7b0JBQ3JCLFdBQVcsRUFBRSxTQUFTLENBQUMsV0FBVztvQkFDbEMsZ0JBQWdCLEVBQUUsSUFBQSxvQkFBYyxFQUFDLFNBQVMsQ0FBQyxLQUFLLENBQUM7aUJBQ2xELEVBQ0QsS0FBSyxDQUNOLENBQUE7Z0JBQ0gsU0FBUyxHQUFHLEtBQUssQ0FBQyxVQUFVLEtBQUssSUFBSSxDQUFBO1lBQ3ZDLENBQUM7UUFDSCxDQUFDO0lBQ0gsQ0FBQztJQUVELE9BQU8sSUFBSSw0QkFBWSxDQUFDO1FBQ3RCLENBQUMsaUVBQWlDLENBQUMsRUFBRSxTQUFTLENBQUMsQ0FBQyxDQUFDLE1BQU0sQ0FBQyxDQUFDLENBQUMsT0FBTztLQUNsRSxDQUFDLENBQUE7QUFDSixDQUFDLENBQUE7QUE1Q1ksUUFBQSwrQkFBK0IsbUNBNEMzQztBQUVELHlDQUE0QixDQUFDLEtBQUssQ0FBQyxtQkFBbUIsQ0FDcEQsdUNBQStCLENBQ2hDLENBQUEifQ==