@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.
Files changed (169) hide show
  1. package/.medusa/server/src/admin/index.js +3739 -0
  2. package/.medusa/server/src/admin/index.mjs +3738 -0
  3. package/.medusa/server/src/api/admin/affiliate-applications/[id]/approve/route.js +28 -0
  4. package/.medusa/server/src/api/admin/affiliate-applications/[id]/reject/route.js +19 -0
  5. package/.medusa/server/src/api/admin/affiliate-applications/route.js +23 -0
  6. package/.medusa/server/src/api/admin/affiliate-distribution-reports/query.js +171 -0
  7. package/.medusa/server/src/api/admin/affiliate-distribution-reports/route.js +13 -0
  8. package/.medusa/server/src/api/admin/affiliate-program-settings/route.js +27 -0
  9. package/.medusa/server/src/api/admin/affiliate-reports/[id]/route.js +45 -0
  10. package/.medusa/server/src/api/admin/affiliate-reports/route.js +27 -0
  11. package/.medusa/server/src/api/admin/affiliates/[id]/consignment-reminders/route.js +31 -0
  12. package/.medusa/server/src/api/admin/affiliates/[id]/consignment-transfers/route.js +41 -0
  13. package/.medusa/server/src/api/admin/affiliates/[id]/coupon-codes/[coupon_id]/reconcile/route.js +34 -0
  14. package/.medusa/server/src/api/admin/affiliates/[id]/coupon-codes/[coupon_id]/revoke/route.js +36 -0
  15. package/.medusa/server/src/api/admin/affiliates/[id]/coupon-codes/[coupon_id]/rotate/route.js +40 -0
  16. package/.medusa/server/src/api/admin/affiliates/[id]/coupon-codes/route.js +56 -0
  17. package/.medusa/server/src/api/admin/affiliates/[id]/distribution/route.js +45 -0
  18. package/.medusa/server/src/api/admin/affiliates/[id]/inactive/route.js +20 -0
  19. package/.medusa/server/src/api/admin/affiliates/[id]/route.js +50 -0
  20. package/.medusa/server/src/api/admin/affiliates/[id]/slugs/[slug_id]/route.js +19 -0
  21. package/.medusa/server/src/api/admin/affiliates/[id]/slugs/route.js +26 -0
  22. package/.medusa/server/src/api/admin/affiliates/route.js +43 -0
  23. package/.medusa/server/src/api/admin/consignment-report-response.js +36 -0
  24. package/.medusa/server/src/api/admin/consignment-reports/[id]/approve/route.js +25 -0
  25. package/.medusa/server/src/api/admin/consignment-reports/[id]/correct/route.js +18 -0
  26. package/.medusa/server/src/api/admin/consignment-reports/[id]/reject/route.js +15 -0
  27. package/.medusa/server/src/api/admin/consignment-reports/[id]/route.js +11 -0
  28. package/.medusa/server/src/api/admin/consignment-reports/route.js +27 -0
  29. package/.medusa/server/src/api/admin/customers/[id]/affiliate/route.js +50 -0
  30. package/.medusa/server/src/api/admin/orders/[id]/affiliate-attribution/route.js +30 -0
  31. package/.medusa/server/src/api/affiliate-coupon-http.js +152 -0
  32. package/.medusa/server/src/api/affiliate-referral-cookie.js +34 -0
  33. package/.medusa/server/src/api/affiliate-self-service-http.js +37 -0
  34. package/.medusa/server/src/api/middlewares.js +786 -0
  35. package/.medusa/server/src/api/store/affiliate-referrals/apply-coupon/route.js +47 -0
  36. package/.medusa/server/src/api/store/affiliate-referrals/capture/route.js +76 -0
  37. package/.medusa/server/src/api/store/affiliate-referrals/carts/[cart_id]/route.js +20 -0
  38. package/.medusa/server/src/api/store/affiliates/consignment-inventory/route.js +53 -0
  39. package/.medusa/server/src/api/store/affiliates/consignment-report-response.js +31 -0
  40. package/.medusa/server/src/api/store/affiliates/consignment-reports/[id]/submit/route.js +40 -0
  41. package/.medusa/server/src/api/store/affiliates/consignment-reports/route.js +43 -0
  42. package/.medusa/server/src/api/store/affiliates/coupon-labels/route.js +14 -0
  43. package/.medusa/server/src/api/store/affiliates/me/commissions/route.js +35 -0
  44. package/.medusa/server/src/api/store/affiliates/me/coupon-codes/[coupon_id]/revoke/route.js +36 -0
  45. package/.medusa/server/src/api/store/affiliates/me/coupon-codes/[coupon_id]/rotate/route.js +40 -0
  46. package/.medusa/server/src/api/store/affiliates/me/coupon-codes/route.js +55 -0
  47. package/.medusa/server/src/api/store/affiliates/me/dashboard/route.js +15 -0
  48. package/.medusa/server/src/api/store/affiliates/me/route.js +85 -0
  49. package/.medusa/server/src/api/store/affiliates/me/slugs/[slug_id]/route.js +29 -0
  50. package/.medusa/server/src/api/store/affiliates/me/slugs/route.js +34 -0
  51. package/.medusa/server/src/api/store/affiliates/own-order-discount/route.js +22 -0
  52. package/.medusa/server/src/api/store/affiliates/own-order-promotion/route.js +30 -0
  53. package/.medusa/server/src/api/store/affiliates/register/route.js +27 -0
  54. package/.medusa/server/src/api/store/affiliates/resolve-referral/route.js +34 -0
  55. package/.medusa/server/src/api/validators.js +52 -0
  56. package/.medusa/server/src/api/wire-response.js +10 -0
  57. package/.medusa/server/src/integration/email-events.js +51 -0
  58. package/.medusa/server/src/integrations/inventory-transfer/batch-management-transfer-adapter.js +36 -0
  59. package/.medusa/server/src/integrations/inventory-transfer/native-inventory-transfer-adapter.js +30 -0
  60. package/.medusa/server/src/integrations/inventory-transfer/resolve-inventory-transfer-adapter.js +46 -0
  61. package/.medusa/server/src/integrations/inventory-transfer/types.js +3 -0
  62. package/.medusa/server/src/jobs/affiliate-attribution-expiry.js +20 -0
  63. package/.medusa/server/src/jobs/affiliate-consignment-report-reminders.js +15 -0
  64. package/.medusa/server/src/jobs/affiliate-promotion-freshness.js +24 -0
  65. package/.medusa/server/src/lib/query-string.js +15 -0
  66. package/.medusa/server/src/modules/affiliate/domain/affiliate-attribution-policy.js +81 -0
  67. package/.medusa/server/src/modules/affiliate/domain/affiliate-coupon-policy.js +61 -0
  68. package/.medusa/server/src/modules/affiliate/domain/commission-policy.js +33 -0
  69. package/.medusa/server/src/modules/affiliate/domain/consignment-reminder-rules.js +74 -0
  70. package/.medusa/server/src/modules/affiliate/domain/email-normalization.js +20 -0
  71. package/.medusa/server/src/modules/affiliate/domain/own-order-coupon-code.js +37 -0
  72. package/.medusa/server/src/modules/affiliate/domain/plugin-options.js +40 -0
  73. package/.medusa/server/src/modules/affiliate/index.js +13 -0
  74. package/.medusa/server/src/modules/affiliate/migrations/Migration20260827085154.js +423 -0
  75. package/.medusa/server/src/modules/affiliate/models/affiliate-application.js +38 -0
  76. package/.medusa/server/src/modules/affiliate/models/affiliate-cart-referral.js +65 -0
  77. package/.medusa/server/src/modules/affiliate/models/affiliate-code-redemption.js +41 -0
  78. package/.medusa/server/src/modules/affiliate/models/affiliate-coupon.js +55 -0
  79. package/.medusa/server/src/modules/affiliate/models/affiliate-distribution-settings.js +22 -0
  80. package/.medusa/server/src/modules/affiliate/models/affiliate-order-attribution.js +49 -0
  81. package/.medusa/server/src/modules/affiliate/models/affiliate-program-settings.js +28 -0
  82. package/.medusa/server/src/modules/affiliate/models/affiliate-referral-session.js +34 -0
  83. package/.medusa/server/src/modules/affiliate/models/affiliate-slug.js +27 -0
  84. package/.medusa/server/src/modules/affiliate/models/affiliate.js +49 -0
  85. package/.medusa/server/src/modules/affiliate/models/commission-entry.js +62 -0
  86. package/.medusa/server/src/modules/affiliate/models/consignment-report-line.js +21 -0
  87. package/.medusa/server/src/modules/affiliate/models/consignment-report.js +31 -0
  88. package/.medusa/server/src/modules/affiliate/models/consignment-transfer-line.js +16 -0
  89. package/.medusa/server/src/modules/affiliate/models/consignment-transfer.js +20 -0
  90. package/.medusa/server/src/modules/affiliate/models/customer-affiliate-assignment.js +58 -0
  91. package/.medusa/server/src/modules/affiliate/service.js +2321 -0
  92. package/.medusa/server/src/modules/affiliate/services/affiliate-application-manager.js +171 -0
  93. package/.medusa/server/src/modules/affiliate/services/affiliate-coupon-manager.js +441 -0
  94. package/.medusa/server/src/modules/affiliate/services/affiliate-discount.service.js +55 -0
  95. package/.medusa/server/src/modules/affiliate/services/affiliate-manager.js +242 -0
  96. package/.medusa/server/src/modules/affiliate/services/affiliate-partner-portal.service.js +138 -0
  97. package/.medusa/server/src/modules/affiliate/services/affiliate-report.service.js +436 -0
  98. package/.medusa/server/src/modules/affiliate/services/affiliate-slug-manager.js +163 -0
  99. package/.medusa/server/src/modules/affiliate/services/commission-ledger.service.js +729 -0
  100. package/.medusa/server/src/modules/affiliate/services/customer-affiliate-assignment-manager.js +350 -0
  101. package/.medusa/server/src/modules/affiliate/services/order-attribution-manager.js +1051 -0
  102. package/.medusa/server/src/modules/affiliate/services/referral-lifecycle-manager.js +1420 -0
  103. package/.medusa/server/src/modules/affiliate/services/utils.js +49 -0
  104. package/.medusa/server/src/modules/affiliate/types/internal.js +3 -0
  105. package/.medusa/server/src/paths/affiliate.js +7 -0
  106. package/.medusa/server/src/paths/index.js +18 -0
  107. package/.medusa/server/src/schemas/index.js +18 -0
  108. package/.medusa/server/src/schemas/store.js +24 -0
  109. package/.medusa/server/src/subscribers/affiliate-cart-updated.js +92 -0
  110. package/.medusa/server/src/subscribers/affiliate-order-canceled.js +70 -0
  111. package/.medusa/server/src/subscribers/affiliate-order-placed.js +63 -0
  112. package/.medusa/server/src/subscribers/affiliate-order-return-received.js +67 -0
  113. package/.medusa/server/src/subscribers/affiliate-product-eligibility-updated.js +87 -0
  114. package/.medusa/server/src/types/admin-api.js +3 -0
  115. package/.medusa/server/src/types/enums.js +53 -0
  116. package/.medusa/server/src/types/index.js +32 -0
  117. package/.medusa/server/src/types/public.js +3 -0
  118. package/.medusa/server/src/types/store-api.js +3 -0
  119. package/.medusa/server/src/utils/affiliate-cart-operation-lock.js +316 -0
  120. package/.medusa/server/src/utils/affiliate-promotion-mutation-authorization.js +49 -0
  121. package/.medusa/server/src/utils/cart-promotions.js +9 -0
  122. package/.medusa/server/src/utils/money.js +79 -0
  123. package/.medusa/server/src/utils/promotion-code-availability.js +34 -0
  124. package/.medusa/server/src/utils/registered-email-checkout.js +101 -0
  125. package/.medusa/server/src/utils/resolve-services.js +7 -0
  126. package/.medusa/server/src/utils/settle-cart-promotions.js +44 -0
  127. package/.medusa/server/src/workflows/affiliate/affiliate-coupon-cart.js +215 -0
  128. package/.medusa/server/src/workflows/affiliate/affiliate-coupon-command-authorization.js +20 -0
  129. package/.medusa/server/src/workflows/affiliate/apply-affiliate-coupon.js +174 -0
  130. package/.medusa/server/src/workflows/affiliate/apply-own-order-promotion.js +89 -0
  131. package/.medusa/server/src/workflows/affiliate/approve-consignment-report.js +186 -0
  132. package/.medusa/server/src/workflows/affiliate/correct-approved-consignment-report.js +263 -0
  133. package/.medusa/server/src/workflows/affiliate/create-affiliate-coupon.js +35 -0
  134. package/.medusa/server/src/workflows/affiliate/create-commission-correction-for-cancellation.js +21 -0
  135. package/.medusa/server/src/workflows/affiliate/create-commission-correction-for-refund.js +24 -0
  136. package/.medusa/server/src/workflows/affiliate/create-commission-for-order.js +17 -0
  137. package/.medusa/server/src/workflows/affiliate/deactivate-affiliate.js +89 -0
  138. package/.medusa/server/src/workflows/affiliate/enable-distribution.js +120 -0
  139. package/.medusa/server/src/workflows/affiliate/enrich-affiliate-report.js +75 -0
  140. package/.medusa/server/src/workflows/affiliate/ensure-affiliate-coupon-promotion.js +410 -0
  141. package/.medusa/server/src/workflows/affiliate/ensure-affiliate-own-order-promotion.js +240 -0
  142. package/.medusa/server/src/workflows/affiliate/ensure-default-affiliate-coupon.js +32 -0
  143. package/.medusa/server/src/workflows/affiliate/expire-affiliate-attribution-state.js +131 -0
  144. package/.medusa/server/src/workflows/affiliate/finalize-affiliate-order-attribution.js +82 -0
  145. package/.medusa/server/src/workflows/affiliate/payment-authorization.js +33 -0
  146. package/.medusa/server/src/workflows/affiliate/promotion-eligibility.js +179 -0
  147. package/.medusa/server/src/workflows/affiliate/reconcile-affiliate-cart-referral.js +219 -0
  148. package/.medusa/server/src/workflows/affiliate/reconcile-affiliate-coupon.js +388 -0
  149. package/.medusa/server/src/workflows/affiliate/refresh-affiliate-promotions.js +114 -0
  150. package/.medusa/server/src/workflows/affiliate/resolve-coupon-labels.js +40 -0
  151. package/.medusa/server/src/workflows/affiliate/revoke-affiliate-coupon.js +29 -0
  152. package/.medusa/server/src/workflows/affiliate/rotate-affiliate-coupon.js +36 -0
  153. package/.medusa/server/src/workflows/affiliate/run-consignment-report-reminders.js +58 -0
  154. package/.medusa/server/src/workflows/affiliate/submit-consignment-report.js +279 -0
  155. package/.medusa/server/src/workflows/affiliate/transfer-batch-aware-inventory.js +172 -0
  156. package/.medusa/server/src/workflows/affiliate/transfer-consignment-stock.js +106 -0
  157. package/.medusa/server/src/workflows/affiliate/update-affiliate-coupon-discounts.js +129 -0
  158. package/.medusa/server/src/workflows/affiliate/utils.js +118 -0
  159. package/.medusa/server/src/workflows/hooks/complete-cart-affiliate-attribution.js +57 -0
  160. package/.medusa/server/src/workflows/hooks/complete-cart-order-created-composition.js +111 -0
  161. package/.medusa/server/src/workflows/hooks/complete-cart-own-order-discount.js +75 -0
  162. package/.medusa/server/src/workflows/hooks/enforce-unique-promotion-codes.js +33 -0
  163. package/.medusa/server/src/workflows/hooks/validate-affiliate-customer-code.js +239 -0
  164. package/.medusa/server/src/workflows/hooks/validate-complete-cart-affiliate-referral.js +137 -0
  165. package/LICENSE +21 -0
  166. package/README.md +799 -0
  167. package/dist/integration/email-events.d.ts +20 -0
  168. package/dist/integration/email-events.js +50 -0
  169. 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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