@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,350 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.CustomerAffiliateAssignmentManager = void 0;
4
+ const utils_1 = require("@medusajs/framework/utils");
5
+ const affiliate_attribution_policy_1 = require("../domain/affiliate-attribution-policy");
6
+ class CustomerAffiliateAssignmentManager {
7
+ constructor(store, affiliateService, slugService) {
8
+ this.store = store;
9
+ this.affiliateService = affiliateService;
10
+ this.slugService = slugService;
11
+ }
12
+ async getActiveAssignment(customerId, context) {
13
+ return await this.getValidAssignmentByIdentity({ customer_id: customerId }, new Date(), context);
14
+ }
15
+ async getActiveAssignmentByIdentity(input, context) {
16
+ return await this.getValidAssignmentByIdentity(input, new Date(), context);
17
+ }
18
+ async getValidAssignmentByIdentity(input, now = new Date(), context) {
19
+ const assignment = await this.findActiveAssignmentByIdentity(input, context, now);
20
+ return assignment ? await this.attachAffiliate(assignment, context) : null;
21
+ }
22
+ async findActiveAssignmentByIdentity(input, context, now = new Date()) {
23
+ const [customerAssignments, emailAssignments] = await Promise.all([
24
+ input.customer_id
25
+ ? this.store.listCustomerAffiliateAssignments({ customer_id: input.customer_id, active: true }, { order: { assigned_at: "DESC" } }, context)
26
+ : Promise.resolve([]),
27
+ input.normalized_email
28
+ ? this.store.listCustomerAffiliateAssignments({ normalized_email: input.normalized_email, active: true }, { order: { assigned_at: "DESC" } }, context)
29
+ : Promise.resolve([]),
30
+ ]);
31
+ const candidates = Array.from(new Map([...customerAssignments, ...emailAssignments].map((assignment) => [
32
+ assignment.id,
33
+ assignment,
34
+ ])).values());
35
+ const expiredCandidates = candidates.filter((assignment) => this.isExpired(assignment, now));
36
+ for (const assignment of expiredCandidates) {
37
+ await this.endAssignment(assignment.id, "expired", context, now);
38
+ }
39
+ if (expiredCandidates.length) {
40
+ await this.store.flush(context);
41
+ }
42
+ const validCandidates = candidates.filter((assignment) => !this.isExpired(assignment, now));
43
+ const newest = (assignments) => [...assignments].sort((left, right) => {
44
+ const assignedAtDifference = new Date(right.assigned_at).getTime() -
45
+ new Date(left.assigned_at).getTime();
46
+ return assignedAtDifference || left.id.localeCompare(right.id);
47
+ })[0];
48
+ const customerAssignment = input.customer_id
49
+ ? newest(validCandidates.filter((assignment) => assignment.customer_id === input.customer_id))
50
+ : undefined;
51
+ const emailAssignment = input.normalized_email
52
+ ? newest(validCandidates.filter((assignment) => assignment.normalized_email === input.normalized_email))
53
+ : undefined;
54
+ if (customerAssignment &&
55
+ emailAssignment &&
56
+ customerAssignment.affiliate_id !== emailAssignment.affiliate_id) {
57
+ throw new utils_1.MedusaError(utils_1.MedusaError.Types.CONFLICT, "Customer and email are assigned to different affiliates.");
58
+ }
59
+ if (customerAssignment &&
60
+ emailAssignment &&
61
+ customerAssignment.id !== emailAssignment.id) {
62
+ // Preserve the customer-precedence row as the identity's live record.
63
+ // The email-only row remains historical so attribution/redemption FKs
64
+ // continue to reference the exact row that existed at the time.
65
+ await this.endAssignment(emailAssignment.id, "same_affiliate_identity_consolidated", context, now);
66
+ await this.store.flush(context);
67
+ }
68
+ return customerAssignment ?? emailAssignment ?? null;
69
+ }
70
+ /**
71
+ * Order ingestion is the authoritative point for linking a guest
72
+ * email-assignment to the now known Customer ID. It never changes the
73
+ * affiliate and therefore cannot be used as a reassignment path.
74
+ */
75
+ async resolveAssignmentForOrderIdentity(input, context) {
76
+ const assignment = await this.getValidAssignmentByIdentity(input, new Date(), context);
77
+ return assignment
78
+ ? await this.attachMissingIdentity(assignment, input, context)
79
+ : null;
80
+ }
81
+ /**
82
+ * Checkout identity attachment is deliberately non-reassigning. Only the
83
+ * Admin-facing assignCustomer path below may end and replace an assignment.
84
+ */
85
+ async assignIdentity(input, context) {
86
+ if (!input.customer_id && !input.normalized_email) {
87
+ throw new utils_1.MedusaError(utils_1.MedusaError.Types.INVALID_DATA, "A customer ID or normalized email is required.");
88
+ }
89
+ if (input.customer_id) {
90
+ await this.assertCustomerIsNotAffiliate(input.customer_id, context);
91
+ }
92
+ const affiliate = await this.store.retrieveAffiliate(input.affiliate_id, context);
93
+ this.affiliateService.assertAffiliateIsActive(affiliate);
94
+ return await this.createAssignmentFromAffiliate({ ...input, affiliate }, context);
95
+ }
96
+ async createAssignmentFromAffiliate(input, context) {
97
+ this.affiliateService.assertAffiliateIsActive(input.affiliate);
98
+ const now = input.assigned_at ?? new Date();
99
+ const activeAssignment = await this.getValidAssignmentByIdentity(input, now, context);
100
+ if (activeAssignment) {
101
+ if (activeAssignment.affiliate_id !== input.affiliate.id) {
102
+ throw new utils_1.MedusaError(utils_1.MedusaError.Types.NOT_ALLOWED, "This customer identity is already assigned to another affiliate.");
103
+ }
104
+ return {
105
+ assignment: await this.attachMissingIdentity(activeAssignment, input, context),
106
+ created: false,
107
+ };
108
+ }
109
+ if (input.affiliate.customer_assignment_mode === "order_only") {
110
+ return { assignment: null, created: false };
111
+ }
112
+ const validUntil = (0, affiliate_attribution_policy_1.calculateAssignmentValidUntil)({
113
+ customer_assignment_mode: input.affiliate.customer_assignment_mode,
114
+ assignment_duration_days: input.affiliate.assignment_duration_days,
115
+ assigned_at: now,
116
+ existing_assignment: null,
117
+ });
118
+ const created = await this.store.createCustomerAffiliateAssignments({
119
+ customer_id: input.customer_id ?? null,
120
+ normalized_email: input.normalized_email ?? null,
121
+ affiliate_id: input.affiliate.id,
122
+ source: input.source,
123
+ active: true,
124
+ assigned_at: now,
125
+ customer_assignment_mode: input.affiliate.customer_assignment_mode,
126
+ assignment_duration_days: input.affiliate.assignment_duration_days,
127
+ valid_until: validUntil ?? null,
128
+ ended_at: null,
129
+ ended_reason: null,
130
+ metadata: input.metadata ?? null,
131
+ }, context);
132
+ return {
133
+ assignment: await this.attachAffiliate(created, context),
134
+ created: true,
135
+ };
136
+ }
137
+ async assignCustomer(input, context) {
138
+ await this.assertCustomerIsNotAffiliate(input.customer_id, context);
139
+ const affiliate = await this.store.retrieveAffiliate(input.affiliate_id, context);
140
+ this.affiliateService.assertAffiliateIsActive(affiliate);
141
+ if (affiliate.customer_assignment_mode === "order_only") {
142
+ throw new utils_1.MedusaError(utils_1.MedusaError.Types.INVALID_DATA, "An order_only affiliate cannot be assigned manually.");
143
+ }
144
+ const assignedAt = new Date();
145
+ const candidates = await this.listActiveAssignmentsByIdentity(input, context);
146
+ const validAffiliates = new Set(candidates
147
+ .filter((candidate) => !this.isExpired(candidate, assignedAt))
148
+ .map((candidate) => candidate.affiliate_id));
149
+ if (validAffiliates.size > 1) {
150
+ for (const candidate of candidates) {
151
+ await this.endAssignment(candidate.id, "reassigned", context, assignedAt);
152
+ }
153
+ await this.store.flush(context);
154
+ }
155
+ const activeAssignment = await this.getValidAssignmentByIdentity({
156
+ customer_id: input.customer_id,
157
+ normalized_email: input.normalized_email,
158
+ }, assignedAt, context);
159
+ if (activeAssignment?.affiliate_id === affiliate.id) {
160
+ return await this.attachMissingIdentity(activeAssignment, input, context);
161
+ }
162
+ if (activeAssignment) {
163
+ await this.endAssignment(activeAssignment.id, "reassigned", context, assignedAt);
164
+ }
165
+ let created;
166
+ try {
167
+ const result = await this.createAssignmentFromAffiliate({
168
+ ...input,
169
+ affiliate,
170
+ assigned_at: assignedAt,
171
+ }, context);
172
+ if (!result.assignment) {
173
+ throw new utils_1.MedusaError(utils_1.MedusaError.Types.UNEXPECTED_STATE, "A manual assignment unexpectedly produced no persistent assignment.");
174
+ }
175
+ created = result.assignment;
176
+ }
177
+ catch (error) {
178
+ // The facade owns a transaction for every Admin mutation. Once an
179
+ // INSERT fails, PostgreSQL rejects any recovery read in that same
180
+ // transaction; rethrow so the transaction rolls the prior end back.
181
+ if (context?.transactionManager) {
182
+ throw error;
183
+ }
184
+ // Two concurrent requests can both pass the activeAssignment check
185
+ // above; the DB's partial unique index on (customer_id) where
186
+ // active = true then lets only one insert through. Resolve the race
187
+ // instead of surfacing the loser's constraint-violation error as-is.
188
+ const concurrentAssignment = await this.getActiveAssignment(input.customer_id, context);
189
+ if (!concurrentAssignment) {
190
+ throw error;
191
+ }
192
+ if (concurrentAssignment.affiliate_id === affiliate.id) {
193
+ return concurrentAssignment;
194
+ }
195
+ throw new utils_1.MedusaError(utils_1.MedusaError.Types.INVALID_DATA, "Customer was concurrently assigned to a different affiliate. Please retry.");
196
+ }
197
+ return await this.attachAffiliate(created, context);
198
+ }
199
+ async removeActiveAssignment(input, context) {
200
+ const candidates = await this.listActiveAssignmentsByIdentity(input, context);
201
+ const activeAffiliates = new Set(candidates.map((candidate) => candidate.affiliate_id));
202
+ if (activeAffiliates.size > 1) {
203
+ const ended = await Promise.all(candidates.map((candidate) => this.endAssignment(candidate.id, input.ended_reason, context)));
204
+ await this.store.flush(context);
205
+ return ended[0] ?? null;
206
+ }
207
+ const activeAssignment = await this.getValidAssignmentByIdentity(input, new Date(), context);
208
+ if (!activeAssignment) {
209
+ return null;
210
+ }
211
+ return await this.endAssignment(activeAssignment.id, input.ended_reason, context);
212
+ }
213
+ async listAssignmentHistory(customerId, context) {
214
+ const now = new Date();
215
+ const assignments = await this.store.listCustomerAffiliateAssignments({ customer_id: customerId }, { order: { assigned_at: "DESC" } }, context);
216
+ return await Promise.all(assignments.map((assignment) => assignment.active && this.isExpired(assignment, now)
217
+ ? this.endAssignment(assignment.id, "expired", context, now)
218
+ : this.attachAffiliate(assignment, context)));
219
+ }
220
+ async expireAssignmentsBatch(input = {}, context) {
221
+ const now = input.now ?? new Date();
222
+ const assignments = await this.store.listCustomerAffiliateAssignments({ active: true, valid_until: { $lte: now } }, { take: input.limit ?? 100, order: { assigned_at: "ASC" } }, context);
223
+ return await Promise.all(assignments.map((assignment) => this.endAssignment(assignment.id, "expired", context, now)));
224
+ }
225
+ async expireOpenAssignmentsBatch(now, limit, context) {
226
+ const assignments = await this.store.listCustomerAffiliateAssignments({ active: true, valid_until: { $lte: now } }, { take: limit + 1, order: { assigned_at: "ASC" } }, context);
227
+ const due = assignments.slice(0, limit);
228
+ let processed = 0;
229
+ for (const assignment of due) {
230
+ const updated = await this.store.updateCustomerAffiliateAssignments({
231
+ selector: {
232
+ id: assignment.id,
233
+ active: true,
234
+ valid_until: { $lte: now },
235
+ },
236
+ data: {
237
+ active: false,
238
+ ended_at: now,
239
+ ended_reason: "expired",
240
+ },
241
+ }, context);
242
+ processed += Array.isArray(updated)
243
+ ? updated.length
244
+ : Number(Boolean(updated));
245
+ }
246
+ return { processed, has_more: assignments.length > limit };
247
+ }
248
+ /**
249
+ * Ends every active assignment when a customer becomes an affiliate.
250
+ * Historical attribution remains auditable.
251
+ */
252
+ async deleteAssignmentsForCustomer(customerId, context) {
253
+ const assignments = await this.store.listCustomerAffiliateAssignments({
254
+ customer_id: customerId,
255
+ active: true,
256
+ }, undefined, context);
257
+ if (assignments.length) {
258
+ for (const assignment of assignments) {
259
+ await this.endAssignment(assignment.id, "customer_became_affiliate", context);
260
+ }
261
+ }
262
+ }
263
+ async removeAssignmentsForAffiliate(affiliateId, reason = "affiliate_inactive", context, now = new Date()) {
264
+ const activeAssignments = await this.store.listCustomerAffiliateAssignments({
265
+ affiliate_id: affiliateId,
266
+ active: true,
267
+ }, undefined, context);
268
+ const endedAssignments = [];
269
+ for (const assignment of activeAssignments) {
270
+ const updated = await this.store.updateCustomerAffiliateAssignments({
271
+ selector: { id: assignment.id, active: true },
272
+ data: { active: false, ended_at: now, ended_reason: reason },
273
+ }, context);
274
+ const ended = Array.isArray(updated) ? updated[0] : updated;
275
+ if (ended) {
276
+ endedAssignments.push(await this.attachAffiliate(ended, context));
277
+ }
278
+ }
279
+ return endedAssignments;
280
+ }
281
+ async isCustomerAffiliate(customerId) {
282
+ const affiliates = await this.store.listAffiliates({
283
+ customer_id: customerId,
284
+ });
285
+ return affiliates.some((affiliate) => affiliate.status !== "rejected");
286
+ }
287
+ async assertCustomerIsNotAffiliate(customerId, context) {
288
+ const affiliates = await this.store.listAffiliates({ customer_id: customerId }, undefined, context);
289
+ if (affiliates.some((affiliate) => affiliate.status !== "rejected")) {
290
+ throw new utils_1.MedusaError(utils_1.MedusaError.Types.NOT_ALLOWED, "This customer is a registered affiliate and cannot be assigned a referring affiliate.");
291
+ }
292
+ }
293
+ async endAssignment(assignmentId, reason, context, endedAt = new Date()) {
294
+ const updated = (await this.store.updateCustomerAffiliateAssignments({
295
+ id: assignmentId,
296
+ active: false,
297
+ ended_at: endedAt,
298
+ ended_reason: reason,
299
+ }, context));
300
+ return await this.attachAffiliate(updated, context);
301
+ }
302
+ async listActiveAssignmentsByIdentity(input, context) {
303
+ const [customerAssignments, emailAssignments] = await Promise.all([
304
+ input.customer_id
305
+ ? this.store.listCustomerAffiliateAssignments({ customer_id: input.customer_id, active: true }, undefined, context)
306
+ : Promise.resolve([]),
307
+ input.normalized_email
308
+ ? this.store.listCustomerAffiliateAssignments({ normalized_email: input.normalized_email, active: true }, undefined, context)
309
+ : Promise.resolve([]),
310
+ ]);
311
+ return Array.from(new Map([...customerAssignments, ...emailAssignments].map((assignment) => [
312
+ assignment.id,
313
+ assignment,
314
+ ])).values());
315
+ }
316
+ isExpired(assignment, now) {
317
+ return (assignment.valid_until !== null &&
318
+ new Date(assignment.valid_until).getTime() <= now.getTime());
319
+ }
320
+ async attachMissingIdentity(assignment, input, context) {
321
+ if ((input.customer_id &&
322
+ assignment.customer_id &&
323
+ input.customer_id !== assignment.customer_id) ||
324
+ (input.normalized_email &&
325
+ assignment.normalized_email &&
326
+ input.normalized_email !== assignment.normalized_email)) {
327
+ throw new utils_1.MedusaError(utils_1.MedusaError.Types.CONFLICT, "Customer identity does not match its existing affiliate assignment.");
328
+ }
329
+ const missingCustomerId = input.customer_id && !assignment.customer_id;
330
+ const missingEmail = input.normalized_email && !assignment.normalized_email;
331
+ if (!missingCustomerId && !missingEmail) {
332
+ return assignment;
333
+ }
334
+ const updated = (await this.store.updateCustomerAffiliateAssignments({
335
+ id: assignment.id,
336
+ ...(missingCustomerId ? { customer_id: input.customer_id } : {}),
337
+ ...(missingEmail ? { normalized_email: input.normalized_email } : {}),
338
+ }, context));
339
+ return await this.attachAffiliate(updated, context);
340
+ }
341
+ async attachAffiliate(assignment, context) {
342
+ const affiliate = await this.affiliateService.retrieveAffiliateWithSlugs(assignment.affiliate_id, context);
343
+ return {
344
+ ...assignment,
345
+ affiliate,
346
+ };
347
+ }
348
+ }
349
+ exports.CustomerAffiliateAssignmentManager = CustomerAffiliateAssignmentManager;
350
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiY3VzdG9tZXItYWZmaWxpYXRlLWFzc2lnbm1lbnQtbWFuYWdlci5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uLy4uLy4uLy4uL3NyYy9tb2R1bGVzL2FmZmlsaWF0ZS9zZXJ2aWNlcy9jdXN0b21lci1hZmZpbGlhdGUtYXNzaWdubWVudC1tYW5hZ2VyLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7OztBQUFBLHFEQUF1RDtBQWdCdkQseUZBQXNGO0FBRXRGLE1BQWEsa0NBQWtDO0lBQzdDLFlBQ21CLEtBQTJCLEVBQzNCLGdCQUFrQyxFQUNsQyxXQUFpQztRQUZqQyxVQUFLLEdBQUwsS0FBSyxDQUFzQjtRQUMzQixxQkFBZ0IsR0FBaEIsZ0JBQWdCLENBQWtCO1FBQ2xDLGdCQUFXLEdBQVgsV0FBVyxDQUFzQjtJQUNqRCxDQUFDO0lBRUosS0FBSyxDQUFDLG1CQUFtQixDQUN2QixVQUFrQixFQUNsQixPQUFpQjtRQUVqQixPQUFPLE1BQU0sSUFBSSxDQUFDLDRCQUE0QixDQUM1QyxFQUFFLFdBQVcsRUFBRSxVQUFVLEVBQUUsRUFDM0IsSUFBSSxJQUFJLEVBQUUsRUFDVixPQUFPLENBQ1IsQ0FBQTtJQUNILENBQUM7SUFFRCxLQUFLLENBQUMsNkJBQTZCLENBQ2pDLEtBQTZCLEVBQzdCLE9BQWlCO1FBRWpCLE9BQU8sTUFBTSxJQUFJLENBQUMsNEJBQTRCLENBQUMsS0FBSyxFQUFFLElBQUksSUFBSSxFQUFFLEVBQUUsT0FBTyxDQUFDLENBQUE7SUFDNUUsQ0FBQztJQUVELEtBQUssQ0FBQyw0QkFBNEIsQ0FDaEMsS0FBNkIsRUFDN0IsR0FBRyxHQUFHLElBQUksSUFBSSxFQUFFLEVBQ2hCLE9BQWlCO1FBRWpCLE1BQU0sVUFBVSxHQUFHLE1BQU0sSUFBSSxDQUFDLDhCQUE4QixDQUMxRCxLQUFLLEVBQ0wsT0FBTyxFQUNQLEdBQUcsQ0FDSixDQUFBO1FBQ0QsT0FBTyxVQUFVLENBQUMsQ0FBQyxDQUFDLE1BQU0sSUFBSSxDQUFD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