@hartl-services/medusa-affiliate 0.3.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/index.js +3739 -0
- package/.medusa/server/src/admin/index.mjs +3738 -0
- package/.medusa/server/src/api/admin/affiliate-applications/[id]/approve/route.js +28 -0
- package/.medusa/server/src/api/admin/affiliate-applications/[id]/reject/route.js +19 -0
- package/.medusa/server/src/api/admin/affiliate-applications/route.js +23 -0
- package/.medusa/server/src/api/admin/affiliate-distribution-reports/query.js +171 -0
- package/.medusa/server/src/api/admin/affiliate-distribution-reports/route.js +13 -0
- package/.medusa/server/src/api/admin/affiliate-program-settings/route.js +27 -0
- package/.medusa/server/src/api/admin/affiliate-reports/[id]/route.js +45 -0
- package/.medusa/server/src/api/admin/affiliate-reports/route.js +27 -0
- package/.medusa/server/src/api/admin/affiliates/[id]/consignment-reminders/route.js +31 -0
- package/.medusa/server/src/api/admin/affiliates/[id]/consignment-transfers/route.js +41 -0
- package/.medusa/server/src/api/admin/affiliates/[id]/coupon-codes/[coupon_id]/reconcile/route.js +34 -0
- package/.medusa/server/src/api/admin/affiliates/[id]/coupon-codes/[coupon_id]/revoke/route.js +36 -0
- package/.medusa/server/src/api/admin/affiliates/[id]/coupon-codes/[coupon_id]/rotate/route.js +40 -0
- package/.medusa/server/src/api/admin/affiliates/[id]/coupon-codes/route.js +56 -0
- package/.medusa/server/src/api/admin/affiliates/[id]/distribution/route.js +45 -0
- package/.medusa/server/src/api/admin/affiliates/[id]/inactive/route.js +20 -0
- package/.medusa/server/src/api/admin/affiliates/[id]/route.js +50 -0
- package/.medusa/server/src/api/admin/affiliates/[id]/slugs/[slug_id]/route.js +19 -0
- package/.medusa/server/src/api/admin/affiliates/[id]/slugs/route.js +26 -0
- package/.medusa/server/src/api/admin/affiliates/route.js +43 -0
- package/.medusa/server/src/api/admin/consignment-report-response.js +36 -0
- package/.medusa/server/src/api/admin/consignment-reports/[id]/approve/route.js +25 -0
- package/.medusa/server/src/api/admin/consignment-reports/[id]/correct/route.js +18 -0
- package/.medusa/server/src/api/admin/consignment-reports/[id]/reject/route.js +15 -0
- package/.medusa/server/src/api/admin/consignment-reports/[id]/route.js +11 -0
- package/.medusa/server/src/api/admin/consignment-reports/route.js +27 -0
- package/.medusa/server/src/api/admin/customers/[id]/affiliate/route.js +50 -0
- package/.medusa/server/src/api/admin/orders/[id]/affiliate-attribution/route.js +30 -0
- package/.medusa/server/src/api/affiliate-coupon-http.js +152 -0
- package/.medusa/server/src/api/affiliate-referral-cookie.js +34 -0
- package/.medusa/server/src/api/affiliate-self-service-http.js +37 -0
- package/.medusa/server/src/api/middlewares.js +786 -0
- package/.medusa/server/src/api/store/affiliate-referrals/apply-coupon/route.js +47 -0
- package/.medusa/server/src/api/store/affiliate-referrals/capture/route.js +76 -0
- package/.medusa/server/src/api/store/affiliate-referrals/carts/[cart_id]/route.js +20 -0
- package/.medusa/server/src/api/store/affiliates/consignment-inventory/route.js +53 -0
- package/.medusa/server/src/api/store/affiliates/consignment-report-response.js +31 -0
- package/.medusa/server/src/api/store/affiliates/consignment-reports/[id]/submit/route.js +40 -0
- package/.medusa/server/src/api/store/affiliates/consignment-reports/route.js +43 -0
- package/.medusa/server/src/api/store/affiliates/coupon-labels/route.js +14 -0
- package/.medusa/server/src/api/store/affiliates/me/commissions/route.js +35 -0
- package/.medusa/server/src/api/store/affiliates/me/coupon-codes/[coupon_id]/revoke/route.js +36 -0
- package/.medusa/server/src/api/store/affiliates/me/coupon-codes/[coupon_id]/rotate/route.js +40 -0
- package/.medusa/server/src/api/store/affiliates/me/coupon-codes/route.js +55 -0
- package/.medusa/server/src/api/store/affiliates/me/dashboard/route.js +15 -0
- package/.medusa/server/src/api/store/affiliates/me/route.js +85 -0
- package/.medusa/server/src/api/store/affiliates/me/slugs/[slug_id]/route.js +29 -0
- package/.medusa/server/src/api/store/affiliates/me/slugs/route.js +34 -0
- package/.medusa/server/src/api/store/affiliates/own-order-discount/route.js +22 -0
- package/.medusa/server/src/api/store/affiliates/own-order-promotion/route.js +30 -0
- package/.medusa/server/src/api/store/affiliates/register/route.js +27 -0
- package/.medusa/server/src/api/store/affiliates/resolve-referral/route.js +34 -0
- package/.medusa/server/src/api/validators.js +52 -0
- package/.medusa/server/src/api/wire-response.js +10 -0
- package/.medusa/server/src/integration/email-events.js +51 -0
- package/.medusa/server/src/integrations/inventory-transfer/batch-management-transfer-adapter.js +36 -0
- package/.medusa/server/src/integrations/inventory-transfer/native-inventory-transfer-adapter.js +30 -0
- package/.medusa/server/src/integrations/inventory-transfer/resolve-inventory-transfer-adapter.js +46 -0
- package/.medusa/server/src/integrations/inventory-transfer/types.js +3 -0
- package/.medusa/server/src/jobs/affiliate-attribution-expiry.js +20 -0
- package/.medusa/server/src/jobs/affiliate-consignment-report-reminders.js +15 -0
- package/.medusa/server/src/jobs/affiliate-promotion-freshness.js +24 -0
- package/.medusa/server/src/lib/query-string.js +15 -0
- package/.medusa/server/src/modules/affiliate/domain/affiliate-attribution-policy.js +81 -0
- package/.medusa/server/src/modules/affiliate/domain/affiliate-coupon-policy.js +61 -0
- package/.medusa/server/src/modules/affiliate/domain/commission-policy.js +33 -0
- package/.medusa/server/src/modules/affiliate/domain/consignment-reminder-rules.js +74 -0
- package/.medusa/server/src/modules/affiliate/domain/email-normalization.js +20 -0
- package/.medusa/server/src/modules/affiliate/domain/own-order-coupon-code.js +37 -0
- package/.medusa/server/src/modules/affiliate/domain/plugin-options.js +40 -0
- package/.medusa/server/src/modules/affiliate/index.js +13 -0
- package/.medusa/server/src/modules/affiliate/migrations/Migration20260827085154.js +423 -0
- package/.medusa/server/src/modules/affiliate/models/affiliate-application.js +38 -0
- package/.medusa/server/src/modules/affiliate/models/affiliate-cart-referral.js +65 -0
- package/.medusa/server/src/modules/affiliate/models/affiliate-code-redemption.js +41 -0
- package/.medusa/server/src/modules/affiliate/models/affiliate-coupon.js +55 -0
- package/.medusa/server/src/modules/affiliate/models/affiliate-distribution-settings.js +22 -0
- package/.medusa/server/src/modules/affiliate/models/affiliate-order-attribution.js +49 -0
- package/.medusa/server/src/modules/affiliate/models/affiliate-program-settings.js +28 -0
- package/.medusa/server/src/modules/affiliate/models/affiliate-referral-session.js +34 -0
- package/.medusa/server/src/modules/affiliate/models/affiliate-slug.js +27 -0
- package/.medusa/server/src/modules/affiliate/models/affiliate.js +49 -0
- package/.medusa/server/src/modules/affiliate/models/commission-entry.js +62 -0
- package/.medusa/server/src/modules/affiliate/models/consignment-report-line.js +21 -0
- package/.medusa/server/src/modules/affiliate/models/consignment-report.js +31 -0
- package/.medusa/server/src/modules/affiliate/models/consignment-transfer-line.js +16 -0
- package/.medusa/server/src/modules/affiliate/models/consignment-transfer.js +20 -0
- package/.medusa/server/src/modules/affiliate/models/customer-affiliate-assignment.js +58 -0
- package/.medusa/server/src/modules/affiliate/service.js +2321 -0
- package/.medusa/server/src/modules/affiliate/services/affiliate-application-manager.js +171 -0
- package/.medusa/server/src/modules/affiliate/services/affiliate-coupon-manager.js +441 -0
- package/.medusa/server/src/modules/affiliate/services/affiliate-discount.service.js +55 -0
- package/.medusa/server/src/modules/affiliate/services/affiliate-manager.js +242 -0
- package/.medusa/server/src/modules/affiliate/services/affiliate-partner-portal.service.js +138 -0
- package/.medusa/server/src/modules/affiliate/services/affiliate-report.service.js +436 -0
- package/.medusa/server/src/modules/affiliate/services/affiliate-slug-manager.js +163 -0
- package/.medusa/server/src/modules/affiliate/services/commission-ledger.service.js +729 -0
- package/.medusa/server/src/modules/affiliate/services/customer-affiliate-assignment-manager.js +350 -0
- package/.medusa/server/src/modules/affiliate/services/order-attribution-manager.js +1051 -0
- package/.medusa/server/src/modules/affiliate/services/referral-lifecycle-manager.js +1420 -0
- package/.medusa/server/src/modules/affiliate/services/utils.js +49 -0
- package/.medusa/server/src/modules/affiliate/types/internal.js +3 -0
- package/.medusa/server/src/paths/affiliate.js +7 -0
- package/.medusa/server/src/paths/index.js +18 -0
- package/.medusa/server/src/schemas/index.js +18 -0
- package/.medusa/server/src/schemas/store.js +24 -0
- package/.medusa/server/src/subscribers/affiliate-cart-updated.js +92 -0
- package/.medusa/server/src/subscribers/affiliate-order-canceled.js +70 -0
- package/.medusa/server/src/subscribers/affiliate-order-placed.js +63 -0
- package/.medusa/server/src/subscribers/affiliate-order-return-received.js +67 -0
- package/.medusa/server/src/subscribers/affiliate-product-eligibility-updated.js +87 -0
- package/.medusa/server/src/types/admin-api.js +3 -0
- package/.medusa/server/src/types/enums.js +53 -0
- package/.medusa/server/src/types/index.js +32 -0
- package/.medusa/server/src/types/public.js +3 -0
- package/.medusa/server/src/types/store-api.js +3 -0
- package/.medusa/server/src/utils/affiliate-cart-operation-lock.js +316 -0
- package/.medusa/server/src/utils/affiliate-promotion-mutation-authorization.js +49 -0
- package/.medusa/server/src/utils/cart-promotions.js +9 -0
- package/.medusa/server/src/utils/money.js +79 -0
- package/.medusa/server/src/utils/promotion-code-availability.js +34 -0
- package/.medusa/server/src/utils/registered-email-checkout.js +101 -0
- package/.medusa/server/src/utils/resolve-services.js +7 -0
- package/.medusa/server/src/utils/settle-cart-promotions.js +44 -0
- package/.medusa/server/src/workflows/affiliate/affiliate-coupon-cart.js +215 -0
- package/.medusa/server/src/workflows/affiliate/affiliate-coupon-command-authorization.js +20 -0
- package/.medusa/server/src/workflows/affiliate/apply-affiliate-coupon.js +174 -0
- package/.medusa/server/src/workflows/affiliate/apply-own-order-promotion.js +89 -0
- package/.medusa/server/src/workflows/affiliate/approve-consignment-report.js +186 -0
- package/.medusa/server/src/workflows/affiliate/correct-approved-consignment-report.js +263 -0
- package/.medusa/server/src/workflows/affiliate/create-affiliate-coupon.js +35 -0
- package/.medusa/server/src/workflows/affiliate/create-commission-correction-for-cancellation.js +21 -0
- package/.medusa/server/src/workflows/affiliate/create-commission-correction-for-refund.js +24 -0
- package/.medusa/server/src/workflows/affiliate/create-commission-for-order.js +17 -0
- package/.medusa/server/src/workflows/affiliate/deactivate-affiliate.js +89 -0
- package/.medusa/server/src/workflows/affiliate/enable-distribution.js +120 -0
- package/.medusa/server/src/workflows/affiliate/enrich-affiliate-report.js +75 -0
- package/.medusa/server/src/workflows/affiliate/ensure-affiliate-coupon-promotion.js +410 -0
- package/.medusa/server/src/workflows/affiliate/ensure-affiliate-own-order-promotion.js +240 -0
- package/.medusa/server/src/workflows/affiliate/ensure-default-affiliate-coupon.js +32 -0
- package/.medusa/server/src/workflows/affiliate/expire-affiliate-attribution-state.js +131 -0
- package/.medusa/server/src/workflows/affiliate/finalize-affiliate-order-attribution.js +82 -0
- package/.medusa/server/src/workflows/affiliate/payment-authorization.js +33 -0
- package/.medusa/server/src/workflows/affiliate/promotion-eligibility.js +179 -0
- package/.medusa/server/src/workflows/affiliate/reconcile-affiliate-cart-referral.js +219 -0
- package/.medusa/server/src/workflows/affiliate/reconcile-affiliate-coupon.js +388 -0
- package/.medusa/server/src/workflows/affiliate/refresh-affiliate-promotions.js +114 -0
- package/.medusa/server/src/workflows/affiliate/resolve-coupon-labels.js +40 -0
- package/.medusa/server/src/workflows/affiliate/revoke-affiliate-coupon.js +29 -0
- package/.medusa/server/src/workflows/affiliate/rotate-affiliate-coupon.js +36 -0
- package/.medusa/server/src/workflows/affiliate/run-consignment-report-reminders.js +58 -0
- package/.medusa/server/src/workflows/affiliate/submit-consignment-report.js +279 -0
- package/.medusa/server/src/workflows/affiliate/transfer-batch-aware-inventory.js +172 -0
- package/.medusa/server/src/workflows/affiliate/transfer-consignment-stock.js +106 -0
- package/.medusa/server/src/workflows/affiliate/update-affiliate-coupon-discounts.js +129 -0
- package/.medusa/server/src/workflows/affiliate/utils.js +118 -0
- package/.medusa/server/src/workflows/hooks/complete-cart-affiliate-attribution.js +57 -0
- package/.medusa/server/src/workflows/hooks/complete-cart-order-created-composition.js +111 -0
- package/.medusa/server/src/workflows/hooks/complete-cart-own-order-discount.js +75 -0
- package/.medusa/server/src/workflows/hooks/enforce-unique-promotion-codes.js +33 -0
- package/.medusa/server/src/workflows/hooks/validate-affiliate-customer-code.js +239 -0
- package/.medusa/server/src/workflows/hooks/validate-complete-cart-affiliate-referral.js +137 -0
- package/LICENSE +21 -0
- package/README.md +799 -0
- package/dist/integration/email-events.d.ts +20 -0
- package/dist/integration/email-events.js +50 -0
- package/package.json +84 -0
|
@@ -0,0 +1,1051 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.OrderAttributionManager = void 0;
|
|
4
|
+
const utils_1 = require("@medusajs/framework/utils");
|
|
5
|
+
const toDate = (value) => value instanceof Date ? value : new Date(value);
|
|
6
|
+
class OrderAttributionManager {
|
|
7
|
+
constructor(store, assignmentManager) {
|
|
8
|
+
this.store = store;
|
|
9
|
+
this.assignmentManager = assignmentManager;
|
|
10
|
+
}
|
|
11
|
+
async finalizeOrderAttribution(input, context = {}) {
|
|
12
|
+
await this.lockKeysInOrder([
|
|
13
|
+
`affiliate-cart-state:${input.cart_id}`,
|
|
14
|
+
...[
|
|
15
|
+
input.customer_id
|
|
16
|
+
? input.validated_coupon
|
|
17
|
+
? `affiliate-code-redemption-customer:${input.customer_id}`
|
|
18
|
+
: null
|
|
19
|
+
: null,
|
|
20
|
+
input.customer_id ? `affiliate-customer:${input.customer_id}` : null,
|
|
21
|
+
input.normalized_email
|
|
22
|
+
? input.validated_coupon
|
|
23
|
+
? `affiliate-code-redemption-email:${input.normalized_email}`
|
|
24
|
+
: null
|
|
25
|
+
: null,
|
|
26
|
+
input.normalized_email
|
|
27
|
+
? `affiliate-email:${input.normalized_email}`
|
|
28
|
+
: null,
|
|
29
|
+
]
|
|
30
|
+
.filter((value) => value !== null)
|
|
31
|
+
.sort(),
|
|
32
|
+
`affiliate-order:${input.order_id}`,
|
|
33
|
+
], context);
|
|
34
|
+
const [existingAttribution] = await this.store.listAffiliateOrderAttributions({ order_id: input.order_id }, { take: 1 }, context);
|
|
35
|
+
if (existingAttribution) {
|
|
36
|
+
return { attribution: existingAttribution, compensation: null };
|
|
37
|
+
}
|
|
38
|
+
// Global lock order is operation identities, then sorted Affiliate state,
|
|
39
|
+
// then assignment/referral rows. Candidate discovery is deliberately an
|
|
40
|
+
// unlocked pre-read; the locked reads below remain authoritative.
|
|
41
|
+
const [candidateAssignments, candidateReferrals, buyerAffiliates] = await Promise.all([
|
|
42
|
+
this.listAssignmentsByIdentity({
|
|
43
|
+
customer_id: input.customer_id,
|
|
44
|
+
normalized_email: input.normalized_email,
|
|
45
|
+
}, context),
|
|
46
|
+
this.store.listAffiliateCartReferrals({
|
|
47
|
+
cart_id: input.cart_id,
|
|
48
|
+
status: ["active", "pending_email_validation"],
|
|
49
|
+
}, undefined, context),
|
|
50
|
+
input.customer_id
|
|
51
|
+
? this.store.listAffiliates({ customer_id: input.customer_id }, undefined, context)
|
|
52
|
+
: Promise.resolve([]),
|
|
53
|
+
]);
|
|
54
|
+
const registeredBuyerAffiliate = buyerAffiliates.find((affiliate) => affiliate.status !== "rejected") ??
|
|
55
|
+
null;
|
|
56
|
+
const affiliateStateKeys = [
|
|
57
|
+
...candidateAssignments.map(({ affiliate_id }) => affiliate_id),
|
|
58
|
+
...candidateReferrals.map(({ affiliate_id }) => affiliate_id),
|
|
59
|
+
...buyerAffiliates.map(({ id }) => id),
|
|
60
|
+
input.validated_coupon?.affiliate_id,
|
|
61
|
+
]
|
|
62
|
+
.filter((id) => Boolean(id))
|
|
63
|
+
.filter((id, index, ids) => ids.indexOf(id) === index)
|
|
64
|
+
.sort()
|
|
65
|
+
.map((id) => `affiliate-state:${id}`);
|
|
66
|
+
await this.lockKeysInOrder(affiliateStateKeys, context);
|
|
67
|
+
const lockedAssignments = await this.readLockedAssignmentsByIdentity({
|
|
68
|
+
customer_id: input.customer_id,
|
|
69
|
+
normalized_email: input.normalized_email,
|
|
70
|
+
}, context);
|
|
71
|
+
const assignmentStatesBeforeCheckout = lockedAssignments.map((assignment) => this.assignmentCompensationState(assignment));
|
|
72
|
+
const expiredLockedAssignments = lockedAssignments.filter((candidate) => candidate.valid_until !== null &&
|
|
73
|
+
candidate.valid_until !== undefined &&
|
|
74
|
+
toDate(candidate.valid_until).getTime() <= input.attributed_at.getTime());
|
|
75
|
+
const lockedAssignment = this.chooseLockedValidAssignment(lockedAssignments.filter((candidate) => !expiredLockedAssignments.includes(candidate)), {
|
|
76
|
+
customer_id: input.customer_id,
|
|
77
|
+
normalized_email: input.normalized_email,
|
|
78
|
+
});
|
|
79
|
+
let assignment;
|
|
80
|
+
let expiredAssignment = null;
|
|
81
|
+
const expiredAssignments = [];
|
|
82
|
+
for (const expiredCandidate of expiredLockedAssignments) {
|
|
83
|
+
const previous = this.assignmentExpiryState(expiredCandidate);
|
|
84
|
+
const expired = await this.assignmentManager.endAssignment(expiredCandidate.id, "expired", context, input.attributed_at);
|
|
85
|
+
await this.store.flush(context);
|
|
86
|
+
const marker = await this.readRawAssignmentExpiryState(expired.id, context);
|
|
87
|
+
if (!marker) {
|
|
88
|
+
throw new utils_1.MedusaError(utils_1.MedusaError.Types.UNEXPECTED_STATE, "The expired Affiliate assignment has no mutation version.");
|
|
89
|
+
}
|
|
90
|
+
const expiredAssignmentState = {
|
|
91
|
+
previous,
|
|
92
|
+
marker,
|
|
93
|
+
};
|
|
94
|
+
expiredAssignments.push(expiredAssignmentState);
|
|
95
|
+
expiredAssignment ??= expiredAssignmentState;
|
|
96
|
+
}
|
|
97
|
+
assignment = lockedAssignment
|
|
98
|
+
? await this.store.retrieveCustomerAffiliateAssignment(lockedAssignment.id, context)
|
|
99
|
+
: null;
|
|
100
|
+
const lockedReferral = await this.readLockedActiveReferralByCart(input.cart_id, context);
|
|
101
|
+
const [currentReferral] = lockedReferral
|
|
102
|
+
? await this.store.listAffiliateCartReferrals({ id: lockedReferral.id }, { take: 1 }, context)
|
|
103
|
+
: [];
|
|
104
|
+
if (lockedReferral && !currentReferral) {
|
|
105
|
+
throw new utils_1.MedusaError(utils_1.MedusaError.Types.UNEXPECTED_STATE, "The locked Affiliate cart referral could not be retrieved.");
|
|
106
|
+
}
|
|
107
|
+
let referral = currentReferral ?? null;
|
|
108
|
+
let expiredReferral = null;
|
|
109
|
+
if (registeredBuyerAffiliate) {
|
|
110
|
+
for (const candidate of lockedAssignments.filter((candidate) => candidate.active && !expiredLockedAssignments.includes(candidate))) {
|
|
111
|
+
await this.assignmentManager.endAssignment(candidate.id, "affiliate_customer", context, input.attributed_at);
|
|
112
|
+
}
|
|
113
|
+
if (lockedReferral) {
|
|
114
|
+
const previous = this.referralExpiryState(lockedReferral);
|
|
115
|
+
const invalidated = (await this.store.updateAffiliateCartReferrals({
|
|
116
|
+
id: lockedReferral.id,
|
|
117
|
+
status: "invalidated",
|
|
118
|
+
applied_affiliate_coupon_id: null,
|
|
119
|
+
applied_promotion_id: null,
|
|
120
|
+
invalidated_reason: "affiliate_customer",
|
|
121
|
+
}, context));
|
|
122
|
+
await this.store.flush(context);
|
|
123
|
+
const marker = await this.readRawReferralExpiryState(invalidated.id, context);
|
|
124
|
+
if (!marker) {
|
|
125
|
+
throw new utils_1.MedusaError(utils_1.MedusaError.Types.UNEXPECTED_STATE, "The Affiliate-customer referral has no mutation version.");
|
|
126
|
+
}
|
|
127
|
+
expiredReferral = { previous, marker };
|
|
128
|
+
}
|
|
129
|
+
await this.store.flush(context);
|
|
130
|
+
return this.expiryOnlyResult(input, expiredAssignment, expiredAssignments, expiredReferral, await this.collectAssignmentMutations(assignmentStatesBeforeCheckout, null, context));
|
|
131
|
+
}
|
|
132
|
+
if (input.validated_coupon &&
|
|
133
|
+
assignment &&
|
|
134
|
+
input.validated_coupon.affiliate_id !== assignment.affiliate_id) {
|
|
135
|
+
throw new utils_1.MedusaError(utils_1.MedusaError.Types.NOT_ALLOWED, "Der Affiliate-Rabatt stimmt nicht mit der bestehenden Kundenzuordnung überein.");
|
|
136
|
+
}
|
|
137
|
+
if (!assignment && !referral) {
|
|
138
|
+
if (input.validated_coupon) {
|
|
139
|
+
throw new utils_1.MedusaError(utils_1.MedusaError.Types.NOT_ALLOWED, "The affiliate coupon has no active cart referral.");
|
|
140
|
+
}
|
|
141
|
+
return this.expiryOnlyResult(input, expiredAssignment, expiredAssignments, expiredReferral, await this.collectAssignmentMutations(assignmentStatesBeforeCheckout, null, context));
|
|
142
|
+
}
|
|
143
|
+
if (lockedReferral &&
|
|
144
|
+
toDate(lockedReferral.captured_at).getTime() >
|
|
145
|
+
input.attributed_at.getTime()) {
|
|
146
|
+
const previous = this.referralExpiryState(lockedReferral);
|
|
147
|
+
const invalidated = (await this.store.updateAffiliateCartReferrals({
|
|
148
|
+
id: lockedReferral.id,
|
|
149
|
+
status: "invalidated",
|
|
150
|
+
applied_affiliate_coupon_id: null,
|
|
151
|
+
applied_promotion_id: null,
|
|
152
|
+
invalidated_reason: "captured_after_order_creation",
|
|
153
|
+
}, context));
|
|
154
|
+
await this.store.flush(context);
|
|
155
|
+
const marker = await this.readRawReferralExpiryState(invalidated.id, context);
|
|
156
|
+
if (!marker) {
|
|
157
|
+
throw new utils_1.MedusaError(utils_1.MedusaError.Types.UNEXPECTED_STATE, "The late Affiliate cart referral has no mutation version.");
|
|
158
|
+
}
|
|
159
|
+
expiredReferral = { previous, marker };
|
|
160
|
+
referral = null;
|
|
161
|
+
if (lockedReferral.source === "coupon" && input.validated_coupon) {
|
|
162
|
+
throw new utils_1.MedusaError(utils_1.MedusaError.Types.NOT_ALLOWED, "The affiliate coupon was captured after the order was created.");
|
|
163
|
+
}
|
|
164
|
+
if (!assignment) {
|
|
165
|
+
return this.expiryOnlyResult(input, expiredAssignment, expiredAssignments, expiredReferral, await this.collectAssignmentMutations(assignmentStatesBeforeCheckout, null, context));
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
else if (lockedReferral &&
|
|
169
|
+
toDate(lockedReferral.expires_at).getTime() <=
|
|
170
|
+
input.attributed_at.getTime()) {
|
|
171
|
+
const previous = this.referralExpiryState(lockedReferral);
|
|
172
|
+
const expired = (await this.store.updateAffiliateCartReferrals({
|
|
173
|
+
id: lockedReferral.id,
|
|
174
|
+
status: "expired",
|
|
175
|
+
invalidated_reason: "referral_window_expired",
|
|
176
|
+
}, context));
|
|
177
|
+
await this.store.flush(context);
|
|
178
|
+
const marker = await this.readRawReferralExpiryState(expired.id, context);
|
|
179
|
+
if (!marker) {
|
|
180
|
+
throw new utils_1.MedusaError(utils_1.MedusaError.Types.UNEXPECTED_STATE, "The expired Affiliate cart referral has no mutation version.");
|
|
181
|
+
}
|
|
182
|
+
expiredReferral = {
|
|
183
|
+
previous,
|
|
184
|
+
marker,
|
|
185
|
+
};
|
|
186
|
+
referral = null;
|
|
187
|
+
if (!assignment) {
|
|
188
|
+
if (input.validated_coupon) {
|
|
189
|
+
throw new utils_1.MedusaError(utils_1.MedusaError.Types.NOT_ALLOWED, "The affiliate coupon referral has expired.");
|
|
190
|
+
}
|
|
191
|
+
return this.expiryOnlyResult(input, expiredAssignment, expiredAssignments, expiredReferral, await this.collectAssignmentMutations(assignmentStatesBeforeCheckout, null, context));
|
|
192
|
+
}
|
|
193
|
+
}
|
|
194
|
+
const affiliateId = assignment?.affiliate_id ?? referral.affiliate_id;
|
|
195
|
+
const affiliate = await this.store.retrieveAffiliate(affiliateId, context);
|
|
196
|
+
this.assertActiveAffiliate(affiliate);
|
|
197
|
+
const coupon = input.validated_coupon
|
|
198
|
+
? await this.resolveValidatedCoupon(input.validated_coupon, context)
|
|
199
|
+
: null;
|
|
200
|
+
const couponReferralMismatch = coupon
|
|
201
|
+
? !referral ||
|
|
202
|
+
referral.affiliate_id !== coupon.affiliate_id ||
|
|
203
|
+
referral.applied_affiliate_coupon_id !== coupon.id ||
|
|
204
|
+
referral.applied_promotion_id !== coupon.promotion_id ||
|
|
205
|
+
(referral.source === "coupon" &&
|
|
206
|
+
(referral.source_affiliate_coupon_id !== coupon.id ||
|
|
207
|
+
referral.source_value_snapshot !== coupon.code))
|
|
208
|
+
: Boolean(referral &&
|
|
209
|
+
(referral.source === "coupon" ||
|
|
210
|
+
referral.applied_affiliate_coupon_id ||
|
|
211
|
+
referral.applied_promotion_id));
|
|
212
|
+
if (couponReferralMismatch ||
|
|
213
|
+
(coupon && coupon.affiliate_id !== affiliate.id)) {
|
|
214
|
+
throw new utils_1.MedusaError(utils_1.MedusaError.Types.NOT_ALLOWED, "The affiliate coupon and cart referral do not match.");
|
|
215
|
+
}
|
|
216
|
+
const previousReferrals = [];
|
|
217
|
+
const previousSessions = [];
|
|
218
|
+
const rememberReferral = (candidate) => {
|
|
219
|
+
if (!previousReferrals.some(({ id }) => id === candidate.id)) {
|
|
220
|
+
previousReferrals.push({ ...candidate });
|
|
221
|
+
}
|
|
222
|
+
};
|
|
223
|
+
const rememberSession = (candidate) => {
|
|
224
|
+
if (!previousSessions.some(({ id }) => id === candidate.id)) {
|
|
225
|
+
previousSessions.push({ ...candidate });
|
|
226
|
+
}
|
|
227
|
+
};
|
|
228
|
+
let usedReferral = null;
|
|
229
|
+
if (referral) {
|
|
230
|
+
rememberReferral(referral);
|
|
231
|
+
if (referral.affiliate_id === affiliate.id) {
|
|
232
|
+
usedReferral = referral;
|
|
233
|
+
}
|
|
234
|
+
else {
|
|
235
|
+
await this.store.updateAffiliateCartReferrals({
|
|
236
|
+
id: referral.id,
|
|
237
|
+
status: "ignored_existing_assignment",
|
|
238
|
+
invalidated_reason: `existing_customer_assignment:${input.order_id}`,
|
|
239
|
+
}, context);
|
|
240
|
+
}
|
|
241
|
+
}
|
|
242
|
+
if (coupon) {
|
|
243
|
+
if (!input.normalized_email) {
|
|
244
|
+
throw new utils_1.MedusaError(utils_1.MedusaError.Types.INVALID_DATA, "A completed affiliate coupon checkout requires an email.");
|
|
245
|
+
}
|
|
246
|
+
if ((await this.listCodeRedemptionsByIdentity(input.customer_id, input.normalized_email, context)).length) {
|
|
247
|
+
throw this.couponAlreadyRedeemed();
|
|
248
|
+
}
|
|
249
|
+
}
|
|
250
|
+
const previousAssignment = assignment ? { ...assignment } : null;
|
|
251
|
+
const assignmentResult = await this.assignmentManager.createAssignmentFromAffiliate({
|
|
252
|
+
affiliate,
|
|
253
|
+
affiliate_id: affiliate.id,
|
|
254
|
+
customer_id: input.customer_id,
|
|
255
|
+
normalized_email: input.normalized_email,
|
|
256
|
+
source: "system",
|
|
257
|
+
assigned_at: input.attributed_at,
|
|
258
|
+
metadata: {
|
|
259
|
+
cart_id: input.cart_id,
|
|
260
|
+
order_id: input.order_id,
|
|
261
|
+
...(usedReferral ? { cart_referral_id: usedReferral.id } : {}),
|
|
262
|
+
},
|
|
263
|
+
}, context);
|
|
264
|
+
await this.store.flush(context);
|
|
265
|
+
const assignmentMutations = await this.collectAssignmentMutations(assignmentStatesBeforeCheckout, assignmentResult.created
|
|
266
|
+
? (assignmentResult.assignment?.id ?? null)
|
|
267
|
+
: null, context);
|
|
268
|
+
let redemptionId = null;
|
|
269
|
+
if (coupon) {
|
|
270
|
+
try {
|
|
271
|
+
const redemption = await this.store.createAffiliateCodeRedemptions({
|
|
272
|
+
affiliate_id: affiliate.id,
|
|
273
|
+
affiliate_coupon_id: coupon.id,
|
|
274
|
+
promotion_id: coupon.promotion_id,
|
|
275
|
+
code_snapshot: coupon.code,
|
|
276
|
+
normalized_email: input.normalized_email,
|
|
277
|
+
customer_id: input.customer_id,
|
|
278
|
+
assignment_id: assignmentResult.assignment?.id ?? null,
|
|
279
|
+
cart_id: input.cart_id,
|
|
280
|
+
order_id: input.order_id,
|
|
281
|
+
redeemed_at: input.attributed_at,
|
|
282
|
+
}, context);
|
|
283
|
+
redemptionId = redemption.id;
|
|
284
|
+
await this.store.flush(context);
|
|
285
|
+
}
|
|
286
|
+
catch (error) {
|
|
287
|
+
if (this.isRedemptionIdentityConstraintError(error)) {
|
|
288
|
+
throw this.couponAlreadyRedeemed();
|
|
289
|
+
}
|
|
290
|
+
throw error;
|
|
291
|
+
}
|
|
292
|
+
}
|
|
293
|
+
const [referrer, programSettings] = await Promise.all([
|
|
294
|
+
this.resolveActiveReferrer(affiliate, context),
|
|
295
|
+
this.store.retrieveProgramSettings(context),
|
|
296
|
+
]);
|
|
297
|
+
const attribution = await this.store.createAffiliateOrderAttributions({
|
|
298
|
+
order_id: input.order_id,
|
|
299
|
+
cart_id: input.cart_id,
|
|
300
|
+
affiliate_id: affiliate.id,
|
|
301
|
+
customer_id: input.customer_id,
|
|
302
|
+
normalized_email: input.normalized_email,
|
|
303
|
+
source: assignment
|
|
304
|
+
? "customer_assignment"
|
|
305
|
+
: usedReferral?.source === "coupon"
|
|
306
|
+
? "coupon"
|
|
307
|
+
: "referral_link",
|
|
308
|
+
customer_affiliate_assignment_id: assignmentResult.assignment?.id ?? null,
|
|
309
|
+
affiliate_cart_referral_id: usedReferral?.id ?? null,
|
|
310
|
+
affiliate_slug_id: usedReferral?.affiliate_slug_id ?? null,
|
|
311
|
+
affiliate_code_redemption_id: redemptionId,
|
|
312
|
+
promotion_id: coupon?.promotion_id ?? null,
|
|
313
|
+
slug_or_code_snapshot: usedReferral?.source_value_snapshot ?? coupon?.code ?? null,
|
|
314
|
+
currency_code: input.currency_code.trim().toLowerCase(),
|
|
315
|
+
customer_assignment_mode: assignmentResult.assignment?.customer_assignment_mode ??
|
|
316
|
+
affiliate.customer_assignment_mode,
|
|
317
|
+
assignment_duration_days: assignmentResult.assignment?.assignment_duration_days ??
|
|
318
|
+
affiliate.assignment_duration_days,
|
|
319
|
+
commission_rate: affiliate.commission_rate,
|
|
320
|
+
referrer_affiliate_id: referrer?.id ?? null,
|
|
321
|
+
referrer_commission_rate: referrer
|
|
322
|
+
? (affiliate.referrer_commission_rate ?? null)
|
|
323
|
+
: null,
|
|
324
|
+
policy_version: programSettings.policy_version,
|
|
325
|
+
commission_base_strategy: programSettings.commission_base,
|
|
326
|
+
referrer_base_strategy: programSettings.referrer_base,
|
|
327
|
+
attributed_at: input.attributed_at,
|
|
328
|
+
}, context);
|
|
329
|
+
await this.store.flush(context);
|
|
330
|
+
if (usedReferral) {
|
|
331
|
+
await this.consumeReferralAndSession(usedReferral, input, rememberReferral, rememberSession, context);
|
|
332
|
+
}
|
|
333
|
+
return {
|
|
334
|
+
attribution,
|
|
335
|
+
compensation: {
|
|
336
|
+
order_id: input.order_id,
|
|
337
|
+
cart_id: input.cart_id,
|
|
338
|
+
attributed_at: input.attributed_at,
|
|
339
|
+
customer_id: input.customer_id,
|
|
340
|
+
normalized_email: input.normalized_email,
|
|
341
|
+
attribution_id: attribution.id,
|
|
342
|
+
redemption_id: redemptionId,
|
|
343
|
+
created_assignment_id: assignmentResult.created
|
|
344
|
+
? (assignmentResult.assignment?.id ?? null)
|
|
345
|
+
: null,
|
|
346
|
+
previous_assignment: assignmentResult.created
|
|
347
|
+
? null
|
|
348
|
+
: previousAssignment,
|
|
349
|
+
affected_affiliate_ids: this.collectAffectedAffiliateIds({
|
|
350
|
+
assignment_mutations: assignmentMutations,
|
|
351
|
+
expired_assignments: expiredAssignments,
|
|
352
|
+
expired_referral: expiredReferral,
|
|
353
|
+
previous_referrals: previousReferrals,
|
|
354
|
+
previous_sessions: previousSessions,
|
|
355
|
+
}),
|
|
356
|
+
assignment_mutations: assignmentMutations,
|
|
357
|
+
expired_assignment: expiredAssignment,
|
|
358
|
+
expired_assignments: expiredAssignments,
|
|
359
|
+
expired_referral: expiredReferral,
|
|
360
|
+
previous_referrals: previousReferrals,
|
|
361
|
+
previous_sessions: previousSessions,
|
|
362
|
+
coupon_states: coupon ? [this.couponStateReceipt(coupon)] : [],
|
|
363
|
+
},
|
|
364
|
+
};
|
|
365
|
+
}
|
|
366
|
+
async compensateOrderAttribution(compensation, context = {}) {
|
|
367
|
+
await this.lockKeysInOrder([
|
|
368
|
+
`affiliate-cart-state:${compensation.cart_id}`,
|
|
369
|
+
...[
|
|
370
|
+
compensation.customer_id
|
|
371
|
+
? compensation.redemption_id
|
|
372
|
+
? `affiliate-code-redemption-customer:${compensation.customer_id}`
|
|
373
|
+
: null
|
|
374
|
+
: null,
|
|
375
|
+
compensation.customer_id
|
|
376
|
+
? `affiliate-customer:${compensation.customer_id}`
|
|
377
|
+
: null,
|
|
378
|
+
compensation.normalized_email
|
|
379
|
+
? compensation.redemption_id
|
|
380
|
+
? `affiliate-code-redemption-email:${compensation.normalized_email}`
|
|
381
|
+
: null
|
|
382
|
+
: null,
|
|
383
|
+
compensation.normalized_email
|
|
384
|
+
? `affiliate-email:${compensation.normalized_email}`
|
|
385
|
+
: null,
|
|
386
|
+
]
|
|
387
|
+
.filter((value) => value !== null)
|
|
388
|
+
.sort(),
|
|
389
|
+
`affiliate-order:${compensation.order_id}`,
|
|
390
|
+
], context);
|
|
391
|
+
const affectedAffiliateIds = this.collectAffectedAffiliateIds(compensation);
|
|
392
|
+
await this.lockKeysInOrder(affectedAffiliateIds.map((id) => `affiliate-state:${id}`), context);
|
|
393
|
+
const restorableAffiliateIds = await this.readActiveAffiliateIds(affectedAffiliateIds, context);
|
|
394
|
+
const restorableCouponIds = await this.readRestorableCouponIds(compensation.coupon_states, context);
|
|
395
|
+
if (compensation.attribution_id) {
|
|
396
|
+
const attribution = await this.readRawOwnedOrderRow("affiliate_order_attribution", compensation.attribution_id, context);
|
|
397
|
+
if (attribution?.order_id === compensation.order_id) {
|
|
398
|
+
await this.hardDeleteOwnedRow("affiliate_order_attribution", attribution.id, compensation.order_id, context);
|
|
399
|
+
}
|
|
400
|
+
}
|
|
401
|
+
if (compensation.redemption_id) {
|
|
402
|
+
const redemption = await this.readRawOwnedOrderRow("affiliate_code_redemption", compensation.redemption_id, context);
|
|
403
|
+
if (redemption?.order_id === compensation.order_id) {
|
|
404
|
+
await this.hardDeleteOwnedRow("affiliate_code_redemption", redemption.id, compensation.order_id, context);
|
|
405
|
+
}
|
|
406
|
+
}
|
|
407
|
+
const hasAssignmentReceipts = compensation.assignment_mutations.length > 0;
|
|
408
|
+
if (hasAssignmentReceipts) {
|
|
409
|
+
await this.restoreAssignmentMutations(compensation.assignment_mutations, restorableAffiliateIds, context);
|
|
410
|
+
}
|
|
411
|
+
if (!hasAssignmentReceipts &&
|
|
412
|
+
compensation.created_assignment_id === null &&
|
|
413
|
+
compensation.previous_assignment === null) {
|
|
414
|
+
const expiredAssignments = compensation.expired_assignments.length
|
|
415
|
+
? compensation.expired_assignments
|
|
416
|
+
: compensation.expired_assignment
|
|
417
|
+
? [compensation.expired_assignment]
|
|
418
|
+
: [];
|
|
419
|
+
for (const expiredAssignment of expiredAssignments) {
|
|
420
|
+
if (restorableAffiliateIds.has(expiredAssignment.previous.affiliate_id)) {
|
|
421
|
+
await this.restoreExpiredAssignment(expiredAssignment, context);
|
|
422
|
+
}
|
|
423
|
+
}
|
|
424
|
+
}
|
|
425
|
+
if (compensation.expired_referral &&
|
|
426
|
+
restorableAffiliateIds.has(compensation.expired_referral.previous.affiliate_id)) {
|
|
427
|
+
await this.restoreExpiredReferral(compensation.expired_referral, restorableCouponIds, context);
|
|
428
|
+
}
|
|
429
|
+
for (const previous of compensation.previous_referrals) {
|
|
430
|
+
if (!restorableAffiliateIds.has(previous.affiliate_id))
|
|
431
|
+
continue;
|
|
432
|
+
const [current] = await this.store.listAffiliateCartReferrals({ id: previous.id }, { take: 1 }, context);
|
|
433
|
+
if (current &&
|
|
434
|
+
(current.consumed_order_id === compensation.order_id ||
|
|
435
|
+
current.invalidated_reason ===
|
|
436
|
+
`referral_session_consumed:${compensation.order_id}` ||
|
|
437
|
+
current.invalidated_reason ===
|
|
438
|
+
`existing_customer_assignment:${compensation.order_id}`)) {
|
|
439
|
+
await this.restoreReferral(previous, restorableCouponIds, context);
|
|
440
|
+
}
|
|
441
|
+
}
|
|
442
|
+
for (const previous of compensation.previous_sessions) {
|
|
443
|
+
if (!restorableAffiliateIds.has(previous.affiliate_id))
|
|
444
|
+
continue;
|
|
445
|
+
const [current] = await this.store.listAffiliateReferralSessions({ id: previous.id }, { take: 1 }, context);
|
|
446
|
+
if (current?.status === "consumed" &&
|
|
447
|
+
current.consumed_at &&
|
|
448
|
+
toDate(current.consumed_at).getTime() ===
|
|
449
|
+
toDate(compensation.attributed_at).getTime()) {
|
|
450
|
+
await this.restoreSession(previous, context);
|
|
451
|
+
}
|
|
452
|
+
}
|
|
453
|
+
}
|
|
454
|
+
expiryOnlyResult(input, expiredAssignment, expiredAssignments, expiredReferral, assignmentMutations) {
|
|
455
|
+
if (!expiredAssignment &&
|
|
456
|
+
!expiredReferral &&
|
|
457
|
+
assignmentMutations.length === 0) {
|
|
458
|
+
return { attribution: null, compensation: null };
|
|
459
|
+
}
|
|
460
|
+
return {
|
|
461
|
+
attribution: null,
|
|
462
|
+
compensation: {
|
|
463
|
+
order_id: input.order_id,
|
|
464
|
+
cart_id: input.cart_id,
|
|
465
|
+
attributed_at: input.attributed_at,
|
|
466
|
+
customer_id: input.customer_id,
|
|
467
|
+
normalized_email: input.normalized_email,
|
|
468
|
+
attribution_id: null,
|
|
469
|
+
redemption_id: null,
|
|
470
|
+
created_assignment_id: null,
|
|
471
|
+
previous_assignment: null,
|
|
472
|
+
affected_affiliate_ids: this.collectAffectedAffiliateIds({
|
|
473
|
+
assignment_mutations: assignmentMutations,
|
|
474
|
+
expired_assignments: expiredAssignments,
|
|
475
|
+
expired_referral: expiredReferral,
|
|
476
|
+
previous_referrals: [],
|
|
477
|
+
previous_sessions: [],
|
|
478
|
+
}),
|
|
479
|
+
assignment_mutations: assignmentMutations,
|
|
480
|
+
expired_assignment: expiredAssignment,
|
|
481
|
+
expired_assignments: expiredAssignments,
|
|
482
|
+
expired_referral: expiredReferral,
|
|
483
|
+
previous_referrals: [],
|
|
484
|
+
previous_sessions: [],
|
|
485
|
+
coupon_states: [],
|
|
486
|
+
},
|
|
487
|
+
};
|
|
488
|
+
}
|
|
489
|
+
async consumeReferralAndSession(referral, input, rememberReferral, rememberSession, context) {
|
|
490
|
+
await this.store.updateAffiliateCartReferrals({
|
|
491
|
+
id: referral.id,
|
|
492
|
+
status: "consumed",
|
|
493
|
+
consumed_order_id: input.order_id,
|
|
494
|
+
invalidated_reason: null,
|
|
495
|
+
}, context);
|
|
496
|
+
if (!referral.referral_session_id) {
|
|
497
|
+
return;
|
|
498
|
+
}
|
|
499
|
+
const [session] = await this.store.listAffiliateReferralSessions({ id: referral.referral_session_id }, { take: 1 }, context);
|
|
500
|
+
if (session) {
|
|
501
|
+
rememberSession(session);
|
|
502
|
+
await this.store.updateAffiliateReferralSessions({
|
|
503
|
+
id: session.id,
|
|
504
|
+
status: "consumed",
|
|
505
|
+
consumed_at: input.attributed_at,
|
|
506
|
+
}, context);
|
|
507
|
+
}
|
|
508
|
+
const related = await this.store.listAffiliateCartReferrals({
|
|
509
|
+
referral_session_id: referral.referral_session_id,
|
|
510
|
+
status: "active",
|
|
511
|
+
}, undefined, context);
|
|
512
|
+
for (const candidate of related) {
|
|
513
|
+
if (candidate.id === referral.id)
|
|
514
|
+
continue;
|
|
515
|
+
rememberReferral(candidate);
|
|
516
|
+
await this.store.updateAffiliateCartReferrals({
|
|
517
|
+
id: candidate.id,
|
|
518
|
+
status: "invalidated",
|
|
519
|
+
invalidated_reason: `referral_session_consumed:${input.order_id}`,
|
|
520
|
+
}, context);
|
|
521
|
+
}
|
|
522
|
+
}
|
|
523
|
+
async resolveValidatedCoupon(input, context) {
|
|
524
|
+
await this.lockKeysInOrder([`affiliate-coupon:${input.affiliate_coupon_id}`], context);
|
|
525
|
+
const [coupon] = await this.store.listAffiliateCoupons({ id: input.affiliate_coupon_id }, { take: 1 }, context);
|
|
526
|
+
if (!coupon ||
|
|
527
|
+
coupon.affiliate_id !== input.affiliate_id ||
|
|
528
|
+
coupon.lifecycle_status !== "enabled" ||
|
|
529
|
+
coupon.provisioning_status !== "ready" ||
|
|
530
|
+
!coupon.promotion_id ||
|
|
531
|
+
coupon.promotion_id !== input.promotion_id ||
|
|
532
|
+
coupon.code !== input.code.trim().toUpperCase()) {
|
|
533
|
+
throw new utils_1.MedusaError(utils_1.MedusaError.Types.NOT_ALLOWED, "The affiliate coupon is inactive or no longer matches the checkout state.");
|
|
534
|
+
}
|
|
535
|
+
return coupon;
|
|
536
|
+
}
|
|
537
|
+
async listCodeRedemptionsByIdentity(customerId, normalizedEmail, context) {
|
|
538
|
+
const [customerRedemptions, emailRedemptions] = await Promise.all([
|
|
539
|
+
customerId
|
|
540
|
+
? this.store.listAffiliateCodeRedemptions({ customer_id: customerId }, { take: 1 }, context)
|
|
541
|
+
: Promise.resolve([]),
|
|
542
|
+
normalizedEmail
|
|
543
|
+
? this.store.listAffiliateCodeRedemptions({ normalized_email: normalizedEmail }, { take: 1 }, context)
|
|
544
|
+
: Promise.resolve([]),
|
|
545
|
+
]);
|
|
546
|
+
return [
|
|
547
|
+
...new Map([...customerRedemptions, ...emailRedemptions].map((redemption) => [
|
|
548
|
+
redemption.id,
|
|
549
|
+
redemption,
|
|
550
|
+
])).values(),
|
|
551
|
+
];
|
|
552
|
+
}
|
|
553
|
+
couponAlreadyRedeemed() {
|
|
554
|
+
return new utils_1.MedusaError(utils_1.MedusaError.Types.CONFLICT, "coupon_already_redeemed");
|
|
555
|
+
}
|
|
556
|
+
isRedemptionIdentityConstraintError(error) {
|
|
557
|
+
const identityConstraints = new Set([
|
|
558
|
+
"IDX_affiliate_code_redemption_email",
|
|
559
|
+
"IDX_affiliate_code_redemption_customer_id_unique",
|
|
560
|
+
]);
|
|
561
|
+
const pending = [error];
|
|
562
|
+
const visited = new Set();
|
|
563
|
+
while (pending.length) {
|
|
564
|
+
const candidate = pending.shift();
|
|
565
|
+
if (!candidate || visited.has(candidate)) {
|
|
566
|
+
continue;
|
|
567
|
+
}
|
|
568
|
+
visited.add(candidate);
|
|
569
|
+
if (typeof candidate === "string") {
|
|
570
|
+
if ([...identityConstraints].some((constraint) => candidate.includes(constraint))) {
|
|
571
|
+
return true;
|
|
572
|
+
}
|
|
573
|
+
continue;
|
|
574
|
+
}
|
|
575
|
+
if (typeof candidate !== "object") {
|
|
576
|
+
continue;
|
|
577
|
+
}
|
|
578
|
+
const record = candidate;
|
|
579
|
+
if (typeof record.constraint === "string" &&
|
|
580
|
+
identityConstraints.has(record.constraint)) {
|
|
581
|
+
return true;
|
|
582
|
+
}
|
|
583
|
+
for (const key of [
|
|
584
|
+
"message",
|
|
585
|
+
"detail",
|
|
586
|
+
"cause",
|
|
587
|
+
"driverException",
|
|
588
|
+
"originalError",
|
|
589
|
+
]) {
|
|
590
|
+
if (record[key] !== undefined) {
|
|
591
|
+
pending.push(record[key]);
|
|
592
|
+
}
|
|
593
|
+
}
|
|
594
|
+
}
|
|
595
|
+
return false;
|
|
596
|
+
}
|
|
597
|
+
couponStateReceipt(coupon) {
|
|
598
|
+
if (!coupon.updated_at) {
|
|
599
|
+
throw new utils_1.MedusaError(utils_1.MedusaError.Types.UNEXPECTED_STATE, "The Affiliate coupon has no mutation version.");
|
|
600
|
+
}
|
|
601
|
+
return {
|
|
602
|
+
id: coupon.id,
|
|
603
|
+
affiliate_id: coupon.affiliate_id,
|
|
604
|
+
code: coupon.code,
|
|
605
|
+
lifecycle_status: coupon.lifecycle_status,
|
|
606
|
+
provisioning_status: coupon.provisioning_status,
|
|
607
|
+
promotion_id: coupon.promotion_id,
|
|
608
|
+
updated_at: coupon.updated_at,
|
|
609
|
+
};
|
|
610
|
+
}
|
|
611
|
+
async readRestorableCouponIds(receipts, context) {
|
|
612
|
+
if (!receipts.length) {
|
|
613
|
+
return new Set();
|
|
614
|
+
}
|
|
615
|
+
const coupons = await this.store.listAffiliateCoupons({ id: receipts.map(({ id }) => id) }, undefined, context);
|
|
616
|
+
const byId = new Map(coupons.map((coupon) => [coupon.id, coupon]));
|
|
617
|
+
return new Set(receipts
|
|
618
|
+
.filter((receipt) => {
|
|
619
|
+
const coupon = byId.get(receipt.id);
|
|
620
|
+
return (coupon?.affiliate_id === receipt.affiliate_id &&
|
|
621
|
+
coupon.code === receipt.code &&
|
|
622
|
+
coupon.lifecycle_status === "enabled" &&
|
|
623
|
+
coupon.provisioning_status === "ready" &&
|
|
624
|
+
coupon.promotion_id === receipt.promotion_id &&
|
|
625
|
+
Boolean(coupon.updated_at &&
|
|
626
|
+
toDate(coupon.updated_at).getTime() ===
|
|
627
|
+
toDate(receipt.updated_at).getTime()));
|
|
628
|
+
})
|
|
629
|
+
.map(({ id }) => id));
|
|
630
|
+
}
|
|
631
|
+
async resolveActiveReferrer(affiliate, context) {
|
|
632
|
+
if (!affiliate.referred_by_affiliate_id)
|
|
633
|
+
return null;
|
|
634
|
+
const referrer = await this.store.retrieveAffiliate(affiliate.referred_by_affiliate_id, context);
|
|
635
|
+
return referrer.status === "active" ? referrer : null;
|
|
636
|
+
}
|
|
637
|
+
assertActiveAffiliate(affiliate) {
|
|
638
|
+
if (affiliate.status !== "active") {
|
|
639
|
+
throw new utils_1.MedusaError(utils_1.MedusaError.Types.NOT_ALLOWED, "The affiliate is inactive.");
|
|
640
|
+
}
|
|
641
|
+
}
|
|
642
|
+
async lockKeysInOrder(keys, context) {
|
|
643
|
+
const manager = context.transactionManager;
|
|
644
|
+
if (!manager) {
|
|
645
|
+
throw new utils_1.MedusaError(utils_1.MedusaError.Types.UNEXPECTED_STATE, "Affiliate order attribution requires a database transaction.");
|
|
646
|
+
}
|
|
647
|
+
for (const key of keys) {
|
|
648
|
+
await manager.execute("select pg_advisory_xact_lock(hashtext(?))", [key], "all");
|
|
649
|
+
}
|
|
650
|
+
}
|
|
651
|
+
collectAffectedAffiliateIds(input) {
|
|
652
|
+
return [
|
|
653
|
+
...(input.affected_affiliate_ids ?? []),
|
|
654
|
+
...(input.assignment_mutations ?? []).flatMap(({ previous, marker }) => previous
|
|
655
|
+
? [previous.affiliate_id, marker.affiliate_id]
|
|
656
|
+
: [marker.affiliate_id]),
|
|
657
|
+
...(input.expired_assignments ?? []).flatMap(({ previous, marker }) => [
|
|
658
|
+
previous.affiliate_id,
|
|
659
|
+
marker.affiliate_id,
|
|
660
|
+
]),
|
|
661
|
+
...(input.expired_referral
|
|
662
|
+
? [
|
|
663
|
+
input.expired_referral.previous.affiliate_id,
|
|
664
|
+
input.expired_referral.marker.affiliate_id,
|
|
665
|
+
]
|
|
666
|
+
: []),
|
|
667
|
+
...(input.previous_referrals ?? []).map(({ affiliate_id }) => affiliate_id),
|
|
668
|
+
...(input.previous_sessions ?? []).map(({ affiliate_id }) => affiliate_id),
|
|
669
|
+
]
|
|
670
|
+
.filter((id, index, ids) => Boolean(id) && ids.indexOf(id) === index)
|
|
671
|
+
.sort();
|
|
672
|
+
}
|
|
673
|
+
async readActiveAffiliateIds(affiliateIds, context) {
|
|
674
|
+
if (!affiliateIds.length)
|
|
675
|
+
return new Set();
|
|
676
|
+
const affiliates = await this.store.listAffiliates({ id: affiliateIds }, undefined, context);
|
|
677
|
+
return new Set(affiliates.filter(({ status }) => status === "active").map(({ id }) => id));
|
|
678
|
+
}
|
|
679
|
+
async hardDeleteOwnedRow(table, id, orderId, context) {
|
|
680
|
+
await context.transactionManager.execute(`delete from "${table}" where "id" = ? and "order_id" = ?`, [id, orderId], "run");
|
|
681
|
+
}
|
|
682
|
+
async readRawOwnedOrderRow(table, id, context) {
|
|
683
|
+
const rows = await context.transactionManager.execute(`select "id", "order_id" from "${table}" where "id" = ? limit 1`, [id], "all");
|
|
684
|
+
return rows[0] ?? null;
|
|
685
|
+
}
|
|
686
|
+
assignmentExpiryState(assignment) {
|
|
687
|
+
return {
|
|
688
|
+
id: assignment.id,
|
|
689
|
+
affiliate_id: assignment.affiliate_id,
|
|
690
|
+
active: assignment.active,
|
|
691
|
+
ended_at: assignment.ended_at,
|
|
692
|
+
ended_reason: assignment.ended_reason,
|
|
693
|
+
updated_at: assignment.updated_at,
|
|
694
|
+
};
|
|
695
|
+
}
|
|
696
|
+
assignmentCompensationState(assignment) {
|
|
697
|
+
return {
|
|
698
|
+
id: assignment.id,
|
|
699
|
+
customer_id: assignment.customer_id,
|
|
700
|
+
normalized_email: assignment.normalized_email,
|
|
701
|
+
affiliate_id: assignment.affiliate_id,
|
|
702
|
+
source: assignment.source,
|
|
703
|
+
active: assignment.active,
|
|
704
|
+
assigned_at: assignment.assigned_at,
|
|
705
|
+
customer_assignment_mode: assignment.customer_assignment_mode,
|
|
706
|
+
assignment_duration_days: assignment.assignment_duration_days,
|
|
707
|
+
valid_until: assignment.valid_until,
|
|
708
|
+
ended_at: assignment.ended_at,
|
|
709
|
+
ended_reason: assignment.ended_reason,
|
|
710
|
+
metadata: assignment.metadata ?? null,
|
|
711
|
+
updated_at: assignment.updated_at,
|
|
712
|
+
};
|
|
713
|
+
}
|
|
714
|
+
async collectAssignmentMutations(previousStates, createdAssignmentId, context) {
|
|
715
|
+
const receipts = [];
|
|
716
|
+
for (const previous of previousStates) {
|
|
717
|
+
const marker = await this.readRawAssignmentState(previous.id, context);
|
|
718
|
+
if (!marker) {
|
|
719
|
+
throw new utils_1.MedusaError(utils_1.MedusaError.Types.UNEXPECTED_STATE, "The selected Affiliate assignment has no mutation version.");
|
|
720
|
+
}
|
|
721
|
+
receipts.push({
|
|
722
|
+
previous,
|
|
723
|
+
marker,
|
|
724
|
+
checkout_mutated: marker.updated_at !== previous.updated_at,
|
|
725
|
+
});
|
|
726
|
+
}
|
|
727
|
+
if (createdAssignmentId &&
|
|
728
|
+
!previousStates.some(({ id }) => id === createdAssignmentId)) {
|
|
729
|
+
const marker = await this.readRawAssignmentState(createdAssignmentId, context);
|
|
730
|
+
if (!marker) {
|
|
731
|
+
throw new utils_1.MedusaError(utils_1.MedusaError.Types.UNEXPECTED_STATE, "The created Affiliate assignment has no mutation version.");
|
|
732
|
+
}
|
|
733
|
+
receipts.push({ previous: null, marker, checkout_mutated: true });
|
|
734
|
+
}
|
|
735
|
+
return receipts;
|
|
736
|
+
}
|
|
737
|
+
referralExpiryState(referral) {
|
|
738
|
+
return {
|
|
739
|
+
id: referral.id,
|
|
740
|
+
affiliate_id: referral.affiliate_id,
|
|
741
|
+
status: referral.status,
|
|
742
|
+
source: referral.source,
|
|
743
|
+
source_affiliate_coupon_id: referral.source_affiliate_coupon_id,
|
|
744
|
+
applied_affiliate_coupon_id: referral.applied_affiliate_coupon_id,
|
|
745
|
+
applied_promotion_id: referral.applied_promotion_id,
|
|
746
|
+
source_value_snapshot: referral.source_value_snapshot,
|
|
747
|
+
invalidated_reason: referral.invalidated_reason,
|
|
748
|
+
updated_at: referral.updated_at,
|
|
749
|
+
};
|
|
750
|
+
}
|
|
751
|
+
async readLockedAssignmentsByIdentity(identity, context) {
|
|
752
|
+
const predicates = [];
|
|
753
|
+
const params = [];
|
|
754
|
+
if (identity.customer_id) {
|
|
755
|
+
predicates.push('"customer_id" = ?');
|
|
756
|
+
params.push(identity.customer_id);
|
|
757
|
+
}
|
|
758
|
+
if (identity.normalized_email) {
|
|
759
|
+
predicates.push('"normalized_email" = ?');
|
|
760
|
+
params.push(identity.normalized_email);
|
|
761
|
+
}
|
|
762
|
+
if (!predicates.length)
|
|
763
|
+
return [];
|
|
764
|
+
const query = `select "id", "customer_id", "normalized_email", "affiliate_id",
|
|
765
|
+
"source", "active", "assigned_at", "customer_assignment_mode",
|
|
766
|
+
"assignment_duration_days", "valid_until", "ended_at",
|
|
767
|
+
"ended_reason", "metadata", "updated_at"::text as "updated_at"
|
|
768
|
+
from "customer_affiliate_assignment"
|
|
769
|
+
where "deleted_at" is null and "active" = true
|
|
770
|
+
and (${predicates.join(" or ")})
|
|
771
|
+
order by "id" for update`;
|
|
772
|
+
const lockCurrentRows = () => context.transactionManager.execute(query, params, "all");
|
|
773
|
+
// If a row waited behind a replacement transaction, PostgreSQL can drop
|
|
774
|
+
// the now-inactive tuple during EvalPlanQual without adding the newly
|
|
775
|
+
// inserted replacement to that statement's snapshot. The second locked
|
|
776
|
+
// read sees the committed replacement while retaining every first-pass lock.
|
|
777
|
+
await lockCurrentRows();
|
|
778
|
+
const rows = await lockCurrentRows();
|
|
779
|
+
return rows;
|
|
780
|
+
}
|
|
781
|
+
async listAssignmentsByIdentity(identity, context) {
|
|
782
|
+
const [byCustomer, byEmail] = await Promise.all([
|
|
783
|
+
identity.customer_id
|
|
784
|
+
? this.store.listCustomerAffiliateAssignments({ customer_id: identity.customer_id, active: true }, undefined, context)
|
|
785
|
+
: Promise.resolve([]),
|
|
786
|
+
identity.normalized_email
|
|
787
|
+
? this.store.listCustomerAffiliateAssignments({ normalized_email: identity.normalized_email, active: true }, undefined, context)
|
|
788
|
+
: Promise.resolve([]),
|
|
789
|
+
]);
|
|
790
|
+
return Array.from(new Map([...byCustomer, ...byEmail].map((assignment) => [
|
|
791
|
+
assignment.id,
|
|
792
|
+
assignment,
|
|
793
|
+
])).values());
|
|
794
|
+
}
|
|
795
|
+
chooseLockedValidAssignment(candidates, identity) {
|
|
796
|
+
const newest = (rows) => [...rows].sort((left, right) => {
|
|
797
|
+
const assignedAtDifference = toDate(right.assigned_at).getTime() -
|
|
798
|
+
toDate(left.assigned_at).getTime();
|
|
799
|
+
return assignedAtDifference || left.id.localeCompare(right.id);
|
|
800
|
+
})[0];
|
|
801
|
+
const customerAssignment = identity.customer_id
|
|
802
|
+
? newest(candidates.filter(({ customer_id }) => customer_id === identity.customer_id))
|
|
803
|
+
: undefined;
|
|
804
|
+
const emailAssignment = identity.normalized_email
|
|
805
|
+
? newest(candidates.filter(({ normalized_email }) => normalized_email === identity.normalized_email))
|
|
806
|
+
: undefined;
|
|
807
|
+
if (customerAssignment &&
|
|
808
|
+
emailAssignment &&
|
|
809
|
+
customerAssignment.affiliate_id !== emailAssignment.affiliate_id) {
|
|
810
|
+
throw new utils_1.MedusaError(utils_1.MedusaError.Types.CONFLICT, "Customer and email are assigned to different affiliates.");
|
|
811
|
+
}
|
|
812
|
+
return customerAssignment ?? emailAssignment ?? null;
|
|
813
|
+
}
|
|
814
|
+
async readLockedActiveReferralByCart(cartId, context) {
|
|
815
|
+
const query = `select "id", "cart_id", "referral_session_id", "affiliate_id",
|
|
816
|
+
"affiliate_slug_id", "source_affiliate_coupon_id",
|
|
817
|
+
"applied_affiliate_coupon_id", "applied_promotion_id",
|
|
818
|
+
"source", "status",
|
|
819
|
+
"source_value_snapshot", "captured_at", "expires_at",
|
|
820
|
+
"replaced_by_referral_id", "consumed_order_id",
|
|
821
|
+
"invalidated_reason", "updated_at"::text as "updated_at"
|
|
822
|
+
from "affiliate_cart_referral"
|
|
823
|
+
where "deleted_at" is null and "cart_id" = ? and "status" = 'active'
|
|
824
|
+
order by "id" for update`;
|
|
825
|
+
const lockCurrentRows = () => context.transactionManager.execute(query, [cartId], "all");
|
|
826
|
+
// Re-read after acquiring candidate locks so a replacement committed while
|
|
827
|
+
// the first statement waited is visible in this READ COMMITTED transaction.
|
|
828
|
+
await lockCurrentRows();
|
|
829
|
+
const rows = await lockCurrentRows();
|
|
830
|
+
return rows[0] ?? null;
|
|
831
|
+
}
|
|
832
|
+
async readRawAssignmentExpiryState(id, context) {
|
|
833
|
+
const rows = await context.transactionManager.execute(`select "id", "affiliate_id", "active", "ended_at", "ended_reason",
|
|
834
|
+
"updated_at"::text as "updated_at"
|
|
835
|
+
from "customer_affiliate_assignment" where "id" = ? limit 1 for update`, [id], "all");
|
|
836
|
+
return rows[0] ?? null;
|
|
837
|
+
}
|
|
838
|
+
async readRawAssignmentState(id, context) {
|
|
839
|
+
const rows = await context.transactionManager.execute(`select "id", "customer_id", "normalized_email", "affiliate_id", "source",
|
|
840
|
+
"active", "assigned_at", "customer_assignment_mode",
|
|
841
|
+
"assignment_duration_days", "valid_until", "ended_at",
|
|
842
|
+
"ended_reason", "metadata", "updated_at"::text as "updated_at"
|
|
843
|
+
from "customer_affiliate_assignment" where "id" = ? limit 1 for update`, [id], "all");
|
|
844
|
+
return rows[0] ?? null;
|
|
845
|
+
}
|
|
846
|
+
async restoreAssignmentMutations(receipts, restorableAffiliateIds, context) {
|
|
847
|
+
const previousReceipts = receipts.filter((receipt) => receipt.previous !== null);
|
|
848
|
+
const safe = await this.canRestoreAssignmentReceiptGroup(receipts, context);
|
|
849
|
+
if (!safe)
|
|
850
|
+
return;
|
|
851
|
+
const createdReceipts = receipts.filter((receipt) => receipt.previous === null);
|
|
852
|
+
for (const receipt of createdReceipts) {
|
|
853
|
+
if (!(await this.deleteCreatedAssignmentIfUnchanged(receipt, context))) {
|
|
854
|
+
return;
|
|
855
|
+
}
|
|
856
|
+
}
|
|
857
|
+
const ordered = previousReceipts
|
|
858
|
+
.filter(({ checkout_mutated, previous }) => checkout_mutated && restorableAffiliateIds.has(previous.affiliate_id))
|
|
859
|
+
.sort((left, right) => {
|
|
860
|
+
const leftInPlace = left.previous.active && left.marker.active ? 0 : 1;
|
|
861
|
+
const rightInPlace = right.previous.active && right.marker.active ? 0 : 1;
|
|
862
|
+
return leftInPlace - rightInPlace;
|
|
863
|
+
});
|
|
864
|
+
for (const { previous, marker } of ordered) {
|
|
865
|
+
await context.transactionManager.execute(`update "customer_affiliate_assignment"
|
|
866
|
+
set "customer_id" = ?, "normalized_email" = ?, "affiliate_id" = ?,
|
|
867
|
+
"source" = ?, "active" = ?, "assigned_at" = ?,
|
|
868
|
+
"customer_assignment_mode" = ?, "assignment_duration_days" = ?,
|
|
869
|
+
"valid_until" = ?, "ended_at" = ?, "ended_reason" = ?,
|
|
870
|
+
"metadata" = ?, "updated_at" = ?
|
|
871
|
+
where "id" = ? and "updated_at"::text = ?`, [
|
|
872
|
+
previous.customer_id,
|
|
873
|
+
previous.normalized_email,
|
|
874
|
+
previous.affiliate_id,
|
|
875
|
+
previous.source,
|
|
876
|
+
previous.active,
|
|
877
|
+
previous.assigned_at,
|
|
878
|
+
previous.customer_assignment_mode,
|
|
879
|
+
previous.assignment_duration_days,
|
|
880
|
+
previous.valid_until,
|
|
881
|
+
previous.ended_at,
|
|
882
|
+
previous.ended_reason,
|
|
883
|
+
previous.metadata,
|
|
884
|
+
previous.updated_at,
|
|
885
|
+
previous.id,
|
|
886
|
+
marker.updated_at,
|
|
887
|
+
], "run");
|
|
888
|
+
}
|
|
889
|
+
}
|
|
890
|
+
async canRestoreAssignmentReceiptGroup(receipts, context) {
|
|
891
|
+
for (const receipt of receipts) {
|
|
892
|
+
const current = await this.readRawAssignmentState(receipt.marker.id, context);
|
|
893
|
+
if (!current || current.updated_at !== receipt.marker.updated_at) {
|
|
894
|
+
return false;
|
|
895
|
+
}
|
|
896
|
+
if ((receipt.previous === null || receipt.checkout_mutated) &&
|
|
897
|
+
(await this.hasRawAssignmentAttribution(receipt.marker.id, context))) {
|
|
898
|
+
return false;
|
|
899
|
+
}
|
|
900
|
+
}
|
|
901
|
+
const currentCandidates = await this.readLockedActiveAssignmentsByReceiptIdentities(receipts, context);
|
|
902
|
+
const receiptIds = new Set(receipts.map(({ marker }) => marker.id));
|
|
903
|
+
if (currentCandidates.some(({ id }) => !receiptIds.has(id))) {
|
|
904
|
+
return false;
|
|
905
|
+
}
|
|
906
|
+
return true;
|
|
907
|
+
}
|
|
908
|
+
async readLockedActiveAssignmentsByReceiptIdentities(receipts, context) {
|
|
909
|
+
const states = receipts.flatMap(({ previous, marker }) => previous ? [previous, marker] : [marker]);
|
|
910
|
+
const customerIds = Array.from(new Set(states
|
|
911
|
+
.map(({ customer_id }) => customer_id)
|
|
912
|
+
.filter((value) => value !== null)));
|
|
913
|
+
const normalizedEmails = Array.from(new Set(states
|
|
914
|
+
.map(({ normalized_email }) => normalized_email)
|
|
915
|
+
.filter((value) => value !== null)));
|
|
916
|
+
const predicates = [
|
|
917
|
+
...customerIds.map(() => '"customer_id" = ?'),
|
|
918
|
+
...normalizedEmails.map(() => '"normalized_email" = ?'),
|
|
919
|
+
];
|
|
920
|
+
if (!predicates.length)
|
|
921
|
+
return [];
|
|
922
|
+
return await context.transactionManager.execute(`select "id" from "customer_affiliate_assignment"
|
|
923
|
+
where "deleted_at" is null and "active" = true
|
|
924
|
+
and (${predicates.join(" or ")})
|
|
925
|
+
order by "id" for update`, [...customerIds, ...normalizedEmails], "all");
|
|
926
|
+
}
|
|
927
|
+
async deleteCreatedAssignmentIfUnchanged(receipt, context) {
|
|
928
|
+
const deleted = await context.transactionManager.execute(`delete from "customer_affiliate_assignment"
|
|
929
|
+
where "id" = ? and "updated_at"::text = ? returning "id"`, [receipt.marker.id, receipt.marker.updated_at], "all");
|
|
930
|
+
return deleted.length === 1 && deleted[0].id === receipt.marker.id;
|
|
931
|
+
}
|
|
932
|
+
async readRawReferralExpiryState(id, context) {
|
|
933
|
+
const rows = await context.transactionManager.execute(`select "id", "affiliate_id", "status", "source",
|
|
934
|
+
"source_affiliate_coupon_id", "applied_affiliate_coupon_id",
|
|
935
|
+
"applied_promotion_id", "source_value_snapshot",
|
|
936
|
+
"invalidated_reason",
|
|
937
|
+
"updated_at"::text as "updated_at"
|
|
938
|
+
from "affiliate_cart_referral" where "id" = ? limit 1 for update`, [id], "all");
|
|
939
|
+
return rows[0] ?? null;
|
|
940
|
+
}
|
|
941
|
+
async hasRawAssignmentAttribution(assignmentId, context) {
|
|
942
|
+
const rows = await context.transactionManager.execute(`select "id" from "affiliate_order_attribution"
|
|
943
|
+
where "customer_affiliate_assignment_id" = ? limit 1`, [assignmentId], "all");
|
|
944
|
+
return rows.length > 0;
|
|
945
|
+
}
|
|
946
|
+
async restoreExpiredAssignment(expiry, context) {
|
|
947
|
+
await context.transactionManager.execute(`update "customer_affiliate_assignment"
|
|
948
|
+
set "active" = ?, "ended_at" = ?, "ended_reason" = ?, "updated_at" = ?
|
|
949
|
+
where "id" = ?
|
|
950
|
+
and "active" = ?
|
|
951
|
+
and "ended_at" is not distinct from ?
|
|
952
|
+
and "ended_reason" is not distinct from ?
|
|
953
|
+
and "updated_at"::text = ?`, [
|
|
954
|
+
expiry.previous.active,
|
|
955
|
+
expiry.previous.ended_at,
|
|
956
|
+
expiry.previous.ended_reason,
|
|
957
|
+
expiry.previous.updated_at,
|
|
958
|
+
expiry.previous.id,
|
|
959
|
+
expiry.marker.active,
|
|
960
|
+
expiry.marker.ended_at,
|
|
961
|
+
expiry.marker.ended_reason,
|
|
962
|
+
expiry.marker.updated_at,
|
|
963
|
+
], "run");
|
|
964
|
+
}
|
|
965
|
+
async restoreExpiredReferral(expiry, restorableCouponIds, context) {
|
|
966
|
+
if (expiry.previous.source === "coupon" &&
|
|
967
|
+
(!expiry.previous.source_affiliate_coupon_id ||
|
|
968
|
+
!restorableCouponIds.has(expiry.previous.source_affiliate_coupon_id))) {
|
|
969
|
+
return;
|
|
970
|
+
}
|
|
971
|
+
const restoreApplied = Boolean(expiry.previous.applied_affiliate_coupon_id &&
|
|
972
|
+
restorableCouponIds.has(expiry.previous.applied_affiliate_coupon_id));
|
|
973
|
+
await context.transactionManager.execute(`update "affiliate_cart_referral"
|
|
974
|
+
set "status" = ?, "applied_affiliate_coupon_id" = ?,
|
|
975
|
+
"applied_promotion_id" = ?, "invalidated_reason" = ?,
|
|
976
|
+
"updated_at" = ?
|
|
977
|
+
where "id" = ?
|
|
978
|
+
and "status" = ?
|
|
979
|
+
and "source" = ?
|
|
980
|
+
and "source_affiliate_coupon_id" is not distinct from ?
|
|
981
|
+
and "applied_affiliate_coupon_id" is not distinct from ?
|
|
982
|
+
and "applied_promotion_id" is not distinct from ?
|
|
983
|
+
and "source_value_snapshot" = ?
|
|
984
|
+
and "invalidated_reason" is not distinct from ?
|
|
985
|
+
and "updated_at"::text = ?`, [
|
|
986
|
+
expiry.previous.status,
|
|
987
|
+
restoreApplied ? expiry.previous.applied_affiliate_coupon_id : null,
|
|
988
|
+
restoreApplied ? expiry.previous.applied_promotion_id : null,
|
|
989
|
+
expiry.previous.invalidated_reason,
|
|
990
|
+
expiry.previous.updated_at,
|
|
991
|
+
expiry.previous.id,
|
|
992
|
+
expiry.marker.status,
|
|
993
|
+
expiry.marker.source,
|
|
994
|
+
expiry.marker.source_affiliate_coupon_id,
|
|
995
|
+
expiry.marker.applied_affiliate_coupon_id,
|
|
996
|
+
expiry.marker.applied_promotion_id,
|
|
997
|
+
expiry.marker.source_value_snapshot,
|
|
998
|
+
expiry.marker.invalidated_reason,
|
|
999
|
+
expiry.marker.updated_at,
|
|
1000
|
+
], "run");
|
|
1001
|
+
}
|
|
1002
|
+
async restoreReferral(previous, restorableCouponIds, context) {
|
|
1003
|
+
if (previous.source === "coupon" &&
|
|
1004
|
+
(!previous.source_affiliate_coupon_id ||
|
|
1005
|
+
!restorableCouponIds.has(previous.source_affiliate_coupon_id))) {
|
|
1006
|
+
return;
|
|
1007
|
+
}
|
|
1008
|
+
const restoreApplied = Boolean(previous.applied_affiliate_coupon_id &&
|
|
1009
|
+
restorableCouponIds.has(previous.applied_affiliate_coupon_id));
|
|
1010
|
+
await this.store.updateAffiliateCartReferrals({
|
|
1011
|
+
id: previous.id,
|
|
1012
|
+
cart_id: previous.cart_id,
|
|
1013
|
+
referral_session_id: previous.referral_session_id,
|
|
1014
|
+
affiliate_id: previous.affiliate_id,
|
|
1015
|
+
affiliate_slug_id: previous.affiliate_slug_id,
|
|
1016
|
+
source_affiliate_coupon_id: previous.source_affiliate_coupon_id,
|
|
1017
|
+
applied_affiliate_coupon_id: restoreApplied
|
|
1018
|
+
? previous.applied_affiliate_coupon_id
|
|
1019
|
+
: null,
|
|
1020
|
+
applied_promotion_id: restoreApplied
|
|
1021
|
+
? previous.applied_promotion_id
|
|
1022
|
+
: null,
|
|
1023
|
+
source: previous.source,
|
|
1024
|
+
status: previous.status,
|
|
1025
|
+
source_value_snapshot: previous.source_value_snapshot,
|
|
1026
|
+
captured_at: toDate(previous.captured_at),
|
|
1027
|
+
expires_at: toDate(previous.expires_at),
|
|
1028
|
+
replaced_by_referral_id: previous.replaced_by_referral_id,
|
|
1029
|
+
consumed_order_id: previous.consumed_order_id,
|
|
1030
|
+
invalidated_reason: previous.invalidated_reason,
|
|
1031
|
+
}, context);
|
|
1032
|
+
}
|
|
1033
|
+
async restoreSession(previous, context) {
|
|
1034
|
+
await this.store.updateAffiliateReferralSessions({
|
|
1035
|
+
id: previous.id,
|
|
1036
|
+
token_hash: previous.token_hash,
|
|
1037
|
+
affiliate_id: previous.affiliate_id,
|
|
1038
|
+
affiliate_slug_id: previous.affiliate_slug_id,
|
|
1039
|
+
slug_snapshot: previous.slug_snapshot,
|
|
1040
|
+
status: previous.status,
|
|
1041
|
+
expires_at: toDate(previous.expires_at),
|
|
1042
|
+
consumed_at: previous.consumed_at ? toDate(previous.consumed_at) : null,
|
|
1043
|
+
invalidated_at: previous.invalidated_at
|
|
1044
|
+
? toDate(previous.invalidated_at)
|
|
1045
|
+
: null,
|
|
1046
|
+
replaced_by_session_id: previous.replaced_by_session_id,
|
|
1047
|
+
}, context);
|
|
1048
|
+
}
|
|
1049
|
+
}
|
|
1050
|
+
exports.OrderAttributionManager = OrderAttributionManager;
|
|
1051
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoib3JkZXItYXR0cmlidXRpb24tbWFuYWdlci5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uLy4uLy4uLy4uL3NyYy9tb2R1bGVzL2FmZmlsaWF0ZS9zZXJ2aWNlcy9vcmRlci1hdHRyaWJ1dGlvbi1tYW5hZ2VyLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7OztBQUNBLHFEQUF1RDtBQW1GdkQsTUFBTSxNQUFNLEdBQUcsQ0FBQyxLQUFvQixFQUFRLEVBQUUsQ0FDNUMsS0FBSyxZQUFZLElBQUksQ0FBQyxDQUFDLENBQUMsS0FBSyxDQUFDLENBQUMsQ0FBQyxJQUFJLElBQUksQ0FBQyxLQUFLLENBQUMsQ0FBQTtBQUVqRCxNQUFhLHVCQUF1QjtJQUNsQyxZQUNtQixLQUEyQixFQUMzQixpQkFBcUQ7UUFEckQsVUFBSyxHQUFMLEtBQUssQ0FBc0I7UUFDM0Isc0JBQWlCLEdBQWpCLGlCQUFpQixDQUFvQztJQUNyRSxDQUFDO0lBRUosS0FBSyxDQUFDLHdCQUF3QixDQUM1QixLQUE2QyxFQUM3QyxVQUE4QixFQUFFO1FBRWhDLE1BQU0sSUFBSSxDQUFDLGVBQWUsQ0FDeEI7WUFDRSx3QkFBd0IsS0FBSyxDQUFDLE9BQU8sRUFBRTtZQUN2QyxHQUFHO2dCQUNELEtBQUssQ0FBQyxXQUFXO29CQUNmLENBQUMsQ0FBQyxLQUFLLENBQUMsZ0JBQWdCO3dCQUN0QixDQUFDLENBQUMsc0NBQXNDLEtBQUssQ0FBQyxXQUFXLEVBQUU7d0JBQzNELENBQUMsQ0FBQyxJQUFJO29CQUNSLENBQUMsQ0FBQyxJQUFJO2dCQUNSLEtBQUssQ0FBQyxXQUFXLENBQUMsQ0FBQyxDQUFDLHNCQUFzQixLQUFLLENBQUMsV0FBVyxFQUFFLENBQUMsQ0FBQyxDQUFDLElBQUk7Z0JBQ3BFLEtBQUssQ0FBQyxnQkFBZ0I7b0JBQ3BCLENBQUMsQ0FBQyxLQUFLLENBQUMsZ0JBQWdCO3dCQUN0QixDQUFDLENBQUMsbUNBQW1DLEtBQUssQ0FBQyxnQkFBZ0IsRUFBRTt3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
|