@hartl-services/medusa-base 3.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.
- package/.medusa/server/src/admin/admin-components/features/plugin-features/components/PluginActionsSection.d.ts +1 -1
- package/.medusa/server/src/admin/admin-components/features/plugin-features/components/PluginFeaturesCard.d.ts +1 -1
- package/.medusa/server/src/admin/admin-components/features/plugin-features/components/PluginHubCard.d.ts +1 -1
- package/.medusa/server/src/admin/admin-components/features/plugin-features/components/PluginSettingsForm.d.ts +1 -1
- package/.medusa/server/src/admin/admin-components/features/plugin-features/components/PluginStatusChips.d.ts +1 -1
- package/.medusa/server/src/admin/admin-components/features/plugin-features/components/ShopMasterDataBanner.d.ts +1 -1
- package/.medusa/server/src/admin/admin-components/features/plugin-features/hooks/usePluginFeatureEnabled.d.ts +1 -1
- package/.medusa/server/src/admin/admin-components/features/plugin-features/hooks/usePluginSettingsForm.d.ts +1 -1
- package/.medusa/server/src/admin/admin-components/features/plugin-features/hooks/usePluginSwitch.d.ts +1 -1
- package/.medusa/server/src/admin/admin-components/features/plugin-features/lib/action-runs.d.ts +1 -1
- package/.medusa/server/src/admin/admin-components/features/plugin-features/lib/plugin-features-admin-client.d.ts +1 -1
- package/.medusa/server/src/admin/admin-components/features/plugin-features/lib/plugin-features-admin-client.js +1 -1
- package/.medusa/server/src/admin/admin-components/features/plugin-features/lib/plugin-view.d.ts +1 -1
- package/.medusa/server/src/admin/admin-components/features/plugin-features/lib/settings-draft.d.ts +1 -1
- package/.medusa/server/src/admin/admin-components/features/plugin-features/lib/settings-layout.d.ts +1 -1
- package/.medusa/server/src/admin/index.js +51 -51
- package/.medusa/server/src/admin/index.mjs +51 -51
- package/.medusa/server/src/api/admin/draft-orders/[id]/order-confirmation/route.js +2 -2
- package/.medusa/server/src/api/admin/email/attachments/[id]/mail-kinds/route.js +2 -2
- package/.medusa/server/src/api/admin/email/attachments/[id]/route.js +2 -2
- package/.medusa/server/src/api/admin/email/attachments/[id]/versions/route.js +2 -2
- package/.medusa/server/src/api/admin/email/attachments/route.js +2 -2
- package/.medusa/server/src/api/admin/email/messages/[id]/resends/route.js +2 -2
- package/.medusa/server/src/api/admin/email/messages/[id]/route.js +2 -2
- package/.medusa/server/src/api/admin/email/messages/route.js +2 -2
- package/.medusa/server/src/api/admin/email/templates/[kind]/preview/route.js +2 -2
- package/.medusa/server/src/api/admin/email/templates/[kind]/route.js +2 -2
- package/.medusa/server/src/api/admin/email/templates/[kind]/send-test/route.js +2 -2
- package/.medusa/server/src/api/admin/email/templates/[kind]/test-sources/route.js +2 -2
- package/.medusa/server/src/api/admin/email/templates/route.js +2 -2
- package/.medusa/server/src/api/admin/plugin-features/[plugin_key]/actions/[action_key]/route.js +2 -2
- package/.medusa/server/src/api/admin/plugin-features/[plugin_key]/actions/[action_key]/runs/route.js +2 -2
- package/.medusa/server/src/api/admin/plugin-features/[plugin_key]/route.js +2 -2
- package/.medusa/server/src/api/admin/plugin-features/[plugin_key]/settings/route.js +2 -2
- package/.medusa/server/src/api/admin/plugin-features/route.js +2 -2
- package/.medusa/server/src/api/admin-first-login-password-policy.js +2 -2
- package/.medusa/server/src/api/answer-code-provider-route-not-found.js +2 -2
- package/.medusa/server/src/api/check-customer-address-tax-identification.js +3 -3
- package/.medusa/server/src/api/code-account-password-routes.js +2 -2
- package/.medusa/server/src/api/middlewares.js +9 -9
- package/.medusa/server/src/api/password-policy.js +2 -2
- package/.medusa/server/src/api/plugin-actions.js +2 -2
- package/.medusa/server/src/api/plugin-features-http.js +2 -2
- package/.medusa/server/src/api/require-login-code-customer-email.js +2 -2
- package/.medusa/server/src/api/store/carts/[id]/completion-check/route.js +2 -2
- package/.medusa/server/src/api/store/carts/[id]/tax-identification/route.js +2 -2
- package/.medusa/server/src/api/store/customer-auth/password-policy/route.js +2 -2
- package/.medusa/server/src/api/store/plugin-features/[plugin_key]/route.js +2 -2
- package/.medusa/server/src/api/store/plugin-features/route.js +2 -2
- package/.medusa/server/src/customer-auth/application/prepare-code-account-password-reset.js +2 -2
- package/.medusa/server/src/customer-auth/application/request-login-code.js +2 -2
- package/.medusa/server/src/customer-auth/customer-password-policy.js +2 -2
- package/.medusa/server/src/customer-auth/domain/auth-methods.js +2 -2
- package/.medusa/server/src/customer-auth/domain/login-code.js +2 -2
- package/.medusa/server/src/customer-auth/login-code-state.js +2 -2
- package/.medusa/server/src/customer-auth/plugin-features.js +2 -2
- package/.medusa/server/src/documents/paths/documents.js +2 -2
- package/.medusa/server/src/documents/schemas/documents.js +2 -2
- package/.medusa/server/src/email/application/deliver-login-code.js +2 -2
- package/.medusa/server/src/email/domain/business-keys.js +2 -2
- package/.medusa/server/src/email/templates/blocks/render-document.js +2 -2
- package/.medusa/server/src/email/templates/render.js +2 -2
- package/.medusa/server/src/email/templates/validate.js +2 -2
- package/.medusa/server/src/email/types/template-data.js +2 -2
- package/.medusa/server/src/free-shipping/free-shipping-settings.js +38 -0
- package/.medusa/server/src/free-shipping/plugin-features.js +45 -0
- package/.medusa/server/src/jobs/free-shipping-promotion-sync.js +22 -0
- package/.medusa/server/src/modules/documents/service.js +2 -2
- package/.medusa/server/src/modules/email/domain/attachment.js +2 -2
- package/.medusa/server/src/modules/email/service.js +3 -3
- package/.medusa/server/src/modules/free-shipping/index.js +13 -0
- package/.medusa/server/src/modules/free-shipping/migrations/Migration20260911114515.js +16 -0
- package/.medusa/server/src/modules/free-shipping/migrations/Migration20260928201511.js +19 -0
- package/.medusa/server/src/modules/free-shipping/migrations/Migration20260928211756.js +110 -0
- package/.medusa/server/src/modules/free-shipping/service.js +17 -0
- package/.medusa/server/src/modules/tax-compliance/service.js +2 -2
- package/.medusa/server/src/providers/email-otp/service.js +2 -2
- package/.medusa/server/src/public/shop-config.js +6 -6
- package/.medusa/server/src/shop-config/{build-food-shop-config.js → build-shop-config.js} +14 -18
- package/.medusa/server/src/shop-config/options.js +4 -4
- package/.medusa/server/src/subscribers/affiliate-application-submitted.js +2 -2
- package/.medusa/server/src/subscribers/affiliate-consignment-reminder-due.js +2 -2
- package/.medusa/server/src/subscribers/documents-order-cancellation-ready.js +2 -2
- package/.medusa/server/src/subscribers/documents-refund-ready.js +2 -2
- package/.medusa/server/src/subscribers/documents-shipment-invoice-assignment-decided.js +2 -2
- package/.medusa/server/src/subscribers/free-shipping-plugin-features-updated.js +25 -0
- package/.medusa/server/src/subscribers/free-shipping-plugin-settings-updated.js +26 -0
- package/.medusa/server/src/subscribers/packing-list-allocation-revised.js +2 -2
- package/.medusa/server/src/subscribers/tax-compliance-plugin-features-updated.js +2 -2
- package/.medusa/server/src/tax-compliance/lib/tax-compliance-state.js +2 -2
- package/.medusa/server/src/tax-compliance/plugin-features.js +2 -2
- package/.medusa/server/src/workflows/free-shipping/sync-free-shipping-promotions.js +143 -0
- package/.medusa/server/src/workflows/hooks/set-free-shipping-promotion-context.js +86 -0
- package/README.md +754 -562
- package/dist/customer-auth/domain/auth-methods.js +1 -1
- package/dist/customer-auth/plugin-features.js +1 -1
- package/dist/documents/types/admin-api.d.ts +1 -1
- package/dist/documents/types/document-summary.d.ts +1 -1
- package/dist/documents/types/store-api.d.ts +1 -1
- package/dist/email/types/template-data.js +1 -1
- package/dist/public/shop-config.d.ts +4 -4
- package/dist/public/shop-config.js +5 -5
- package/dist/shop-config/{build-food-shop-config.d.ts → build-shop-config.d.ts} +12 -12
- package/dist/shop-config/{build-food-shop-config.js → build-shop-config.js} +13 -17
- package/dist/shop-config/options.d.ts +3 -3
- package/dist/shop-config/options.js +3 -3
- package/package.json +6 -6
|
@@ -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,eyJ2ZXJzaW9uIjozLCJmaWxlIjoic3luYy1mcmVlLXNoaXBwaW5nLXByb21vdGlvbnMuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi8uLi8uLi9zcmMvd29ya2Zsb3dzL2ZyZWUtc2hpcHBpbmcvc3luYy1mcmVlLXNoaXBwaW5nLXByb21vdGlvbnMudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6Ijs7O0FBS0EscURBQTZEO0FBQzdELDREQUlvQztBQUVwQyx5Q0FBcUQ7QUFFckQseUVBQWdGO0FBQ2hGLHVGQUF3RjtBQUV4Rjs7Ozs7R0FLRztBQUNVLFFBQUEsaUNBQWlDLEdBQzVDLDRDQUE0QyxDQUFBO0FBRWpDLFFBQUEscUNBQXFDLEdBQ2hELDZCQUE2QixDQUFBO0FBQ2xCLFFBQUEsc0NBQXNDLEdBQ2pELDhCQUE4QixDQUFBO0FBRWhDLDZFQUE2RTtBQUNoRSxRQUFBLHFDQUFxQyxHQUNoRCw4QkFBOEIsQ0FBQTtBQUNoQyxpRkFBaUY7QUFDakYsTUFBTSx5QkFBeUIsR0FBRyxFQUFFLENBQUE7QUFRcEMsTUFBTSxVQUFVLEdBQUcsQ0FDakIsU0FBaUIsRUFDakIsY0FBZ0MsRUFDcEIsRUFBRSxDQUFDO0lBQ2YsRUFBRSxTQUFTLEVBQUUsWUFBWSxFQUFFLFFBQVEsRUFBRSxLQUFLLEVBQUUsTUFBTSxFQUFFLENBQUMsTUFBTSxDQUFDLFNBQVMsQ0FBQyxDQUFDLEVBQUU7SUFDekU7UUFDRSxTQUFTLEVBQUUseUNBQWlDO1FBQzVDLFFBQVEsRUFBRSxJQUFJO1FBQ2QsTUFBTSxFQUFFLENBQUMsY0FBYyxDQUFDO0tBQ3pCO0NBQ0YsQ0FBQTtBQUVELE1BQU0sT0FBTyxHQUFHLENBQUMsSUFJaEIsRUFBVSxFQUFFLENBQ1gsSUFBSSxDQUFDLFNBQVMsQ0FBQyxDQUFDLElBQUksQ0FBQyxTQUFTLEVBQUUsSUFBSSxDQUFDLFFBQVEsRUFBRSxDQUFDLEdBQUcsSUFBSSxDQUFDLE1BQU0sQ0FBQyxDQUFDLElBQUksRUFBRSxDQUFDLENBQUMsQ0FBQTtBQUUxRSxNQUFN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
|
|
@@ -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,eyJ2ZXJzaW9uIjozLCJmaWxlIjoic2V0LWZyZWUtc2hpcHBpbmctcHJvbW90aW9uLWNvbnRleHQuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi8uLi8uLi9zcmMvd29ya2Zsb3dzL2hvb2tzL3NldC1mcmVlLXNoaXBwaW5nLXByb21vdGlvbi1jb250ZXh0LnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7OztBQUFBLHFFQUFnRTtBQUNoRSxxREFBcUU7QUFFckUsNERBQTBFO0FBQzFFLDBDQUFxRTtBQUVyRSx5RUFBZ0Y7QUFDaEYsdUZBR21EO0FBQ25ELGtHQUFrRztBQTJCbEcsTUFBTSxzQkFBc0IsR0FBRyxDQUFDLEdBQXlCLEVBQVcsRUFBRSxDQUNwRSw0Q0FBMEIsQ0FBQyxRQUFRLEVBQUUsSUFBSSxDQUFDLENBQUMsT0FBTyxFQUFFLEVBQUUsQ0FBQyxPQUFPLENBQUMsR0FBRyxLQUFLLEdBQUcsQ0FBQztJQUN6RSxFQUFFLE9BQU8sS0FBSyxJQUFJLENBQUE7QUFFdEIsNkVBQTZFO0FBQzdFLE1BQU0sZ0NBQWdDLEdBQW1CO0lBQ3ZELG9DQUFvQyxFQUFFLHNCQUFzQixDQUMxRCxzQ0FBc0MsQ0FDdkM7SUFDRCx1Q0FBdUMsRUFBRSxzQkFBc0IsQ0FDN0QseUNBQXlDLENBQzFDO0NBQ0YsQ0FBQTtBQUVELGdGQUFnRjtBQUNoRixJQUFJLHVCQUF1QixHQUEwQixJQUFJLENBQUE7QUFFekQ7Ozs7Ozs7R0FPRztBQUNILE1BQU0sa0JBQWtCLEdBQUcsS0FBSyxFQUM5QixTQUEwQixFQUMxQixNQUFjLEVBQ1csRUFBRTtJQUMzQixJQUFJLENBQUM7UUFDSCxNQUFNLFFBQVEsR0FBRyxNQUFNLElBQUEsb0RBQTJCLEVBQUMsU0FBUyxDQUFDLENBQUE7UUFDN0QsdUJBQXVCLEdBQUc7WUFDeEIsb0NBQW9DLEVBQ2xDLFFBQVEsQ0FBQyxvQ0FBb0M7WUFDL0MsdUNBQXVDLEVBQ3JDLFFBQVEsQ0FBQyx1Q0FBdUM7U0FDbkQsQ0FBQTtRQUNELE9BQU8sUUFBUSxDQUFB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
|