@hartl-services/medusa-affiliate 0.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.medusa/server/src/admin/index.js +3739 -0
- package/.medusa/server/src/admin/index.mjs +3738 -0
- package/.medusa/server/src/api/admin/affiliate-applications/[id]/approve/route.js +28 -0
- package/.medusa/server/src/api/admin/affiliate-applications/[id]/reject/route.js +19 -0
- package/.medusa/server/src/api/admin/affiliate-applications/route.js +23 -0
- package/.medusa/server/src/api/admin/affiliate-distribution-reports/query.js +171 -0
- package/.medusa/server/src/api/admin/affiliate-distribution-reports/route.js +13 -0
- package/.medusa/server/src/api/admin/affiliate-program-settings/route.js +27 -0
- package/.medusa/server/src/api/admin/affiliate-reports/[id]/route.js +45 -0
- package/.medusa/server/src/api/admin/affiliate-reports/route.js +27 -0
- package/.medusa/server/src/api/admin/affiliates/[id]/consignment-reminders/route.js +31 -0
- package/.medusa/server/src/api/admin/affiliates/[id]/consignment-transfers/route.js +41 -0
- package/.medusa/server/src/api/admin/affiliates/[id]/coupon-codes/[coupon_id]/reconcile/route.js +34 -0
- package/.medusa/server/src/api/admin/affiliates/[id]/coupon-codes/[coupon_id]/revoke/route.js +36 -0
- package/.medusa/server/src/api/admin/affiliates/[id]/coupon-codes/[coupon_id]/rotate/route.js +40 -0
- package/.medusa/server/src/api/admin/affiliates/[id]/coupon-codes/route.js +56 -0
- package/.medusa/server/src/api/admin/affiliates/[id]/distribution/route.js +45 -0
- package/.medusa/server/src/api/admin/affiliates/[id]/inactive/route.js +20 -0
- package/.medusa/server/src/api/admin/affiliates/[id]/route.js +50 -0
- package/.medusa/server/src/api/admin/affiliates/[id]/slugs/[slug_id]/route.js +19 -0
- package/.medusa/server/src/api/admin/affiliates/[id]/slugs/route.js +26 -0
- package/.medusa/server/src/api/admin/affiliates/route.js +43 -0
- package/.medusa/server/src/api/admin/consignment-report-response.js +36 -0
- package/.medusa/server/src/api/admin/consignment-reports/[id]/approve/route.js +25 -0
- package/.medusa/server/src/api/admin/consignment-reports/[id]/correct/route.js +18 -0
- package/.medusa/server/src/api/admin/consignment-reports/[id]/reject/route.js +15 -0
- package/.medusa/server/src/api/admin/consignment-reports/[id]/route.js +11 -0
- package/.medusa/server/src/api/admin/consignment-reports/route.js +27 -0
- package/.medusa/server/src/api/admin/customers/[id]/affiliate/route.js +50 -0
- package/.medusa/server/src/api/admin/orders/[id]/affiliate-attribution/route.js +30 -0
- package/.medusa/server/src/api/affiliate-coupon-http.js +152 -0
- package/.medusa/server/src/api/affiliate-referral-cookie.js +34 -0
- package/.medusa/server/src/api/affiliate-self-service-http.js +37 -0
- package/.medusa/server/src/api/middlewares.js +786 -0
- package/.medusa/server/src/api/store/affiliate-referrals/apply-coupon/route.js +47 -0
- package/.medusa/server/src/api/store/affiliate-referrals/capture/route.js +76 -0
- package/.medusa/server/src/api/store/affiliate-referrals/carts/[cart_id]/route.js +20 -0
- package/.medusa/server/src/api/store/affiliates/consignment-inventory/route.js +53 -0
- package/.medusa/server/src/api/store/affiliates/consignment-report-response.js +31 -0
- package/.medusa/server/src/api/store/affiliates/consignment-reports/[id]/submit/route.js +40 -0
- package/.medusa/server/src/api/store/affiliates/consignment-reports/route.js +43 -0
- package/.medusa/server/src/api/store/affiliates/coupon-labels/route.js +14 -0
- package/.medusa/server/src/api/store/affiliates/me/commissions/route.js +35 -0
- package/.medusa/server/src/api/store/affiliates/me/coupon-codes/[coupon_id]/revoke/route.js +36 -0
- package/.medusa/server/src/api/store/affiliates/me/coupon-codes/[coupon_id]/rotate/route.js +40 -0
- package/.medusa/server/src/api/store/affiliates/me/coupon-codes/route.js +55 -0
- package/.medusa/server/src/api/store/affiliates/me/dashboard/route.js +15 -0
- package/.medusa/server/src/api/store/affiliates/me/route.js +85 -0
- package/.medusa/server/src/api/store/affiliates/me/slugs/[slug_id]/route.js +29 -0
- package/.medusa/server/src/api/store/affiliates/me/slugs/route.js +34 -0
- package/.medusa/server/src/api/store/affiliates/own-order-discount/route.js +22 -0
- package/.medusa/server/src/api/store/affiliates/own-order-promotion/route.js +30 -0
- package/.medusa/server/src/api/store/affiliates/register/route.js +27 -0
- package/.medusa/server/src/api/store/affiliates/resolve-referral/route.js +34 -0
- package/.medusa/server/src/api/validators.js +52 -0
- package/.medusa/server/src/api/wire-response.js +10 -0
- package/.medusa/server/src/integration/email-events.js +51 -0
- package/.medusa/server/src/integrations/inventory-transfer/batch-management-transfer-adapter.js +36 -0
- package/.medusa/server/src/integrations/inventory-transfer/native-inventory-transfer-adapter.js +30 -0
- package/.medusa/server/src/integrations/inventory-transfer/resolve-inventory-transfer-adapter.js +46 -0
- package/.medusa/server/src/integrations/inventory-transfer/types.js +3 -0
- package/.medusa/server/src/jobs/affiliate-attribution-expiry.js +20 -0
- package/.medusa/server/src/jobs/affiliate-consignment-report-reminders.js +15 -0
- package/.medusa/server/src/jobs/affiliate-promotion-freshness.js +24 -0
- package/.medusa/server/src/lib/query-string.js +15 -0
- package/.medusa/server/src/modules/affiliate/domain/affiliate-attribution-policy.js +81 -0
- package/.medusa/server/src/modules/affiliate/domain/affiliate-coupon-policy.js +61 -0
- package/.medusa/server/src/modules/affiliate/domain/commission-policy.js +33 -0
- package/.medusa/server/src/modules/affiliate/domain/consignment-reminder-rules.js +74 -0
- package/.medusa/server/src/modules/affiliate/domain/email-normalization.js +20 -0
- package/.medusa/server/src/modules/affiliate/domain/own-order-coupon-code.js +37 -0
- package/.medusa/server/src/modules/affiliate/domain/plugin-options.js +40 -0
- package/.medusa/server/src/modules/affiliate/index.js +13 -0
- package/.medusa/server/src/modules/affiliate/migrations/Migration20260827085154.js +423 -0
- package/.medusa/server/src/modules/affiliate/models/affiliate-application.js +38 -0
- package/.medusa/server/src/modules/affiliate/models/affiliate-cart-referral.js +65 -0
- package/.medusa/server/src/modules/affiliate/models/affiliate-code-redemption.js +41 -0
- package/.medusa/server/src/modules/affiliate/models/affiliate-coupon.js +55 -0
- package/.medusa/server/src/modules/affiliate/models/affiliate-distribution-settings.js +22 -0
- package/.medusa/server/src/modules/affiliate/models/affiliate-order-attribution.js +49 -0
- package/.medusa/server/src/modules/affiliate/models/affiliate-program-settings.js +28 -0
- package/.medusa/server/src/modules/affiliate/models/affiliate-referral-session.js +34 -0
- package/.medusa/server/src/modules/affiliate/models/affiliate-slug.js +27 -0
- package/.medusa/server/src/modules/affiliate/models/affiliate.js +49 -0
- package/.medusa/server/src/modules/affiliate/models/commission-entry.js +62 -0
- package/.medusa/server/src/modules/affiliate/models/consignment-report-line.js +21 -0
- package/.medusa/server/src/modules/affiliate/models/consignment-report.js +31 -0
- package/.medusa/server/src/modules/affiliate/models/consignment-transfer-line.js +16 -0
- package/.medusa/server/src/modules/affiliate/models/consignment-transfer.js +20 -0
- package/.medusa/server/src/modules/affiliate/models/customer-affiliate-assignment.js +58 -0
- package/.medusa/server/src/modules/affiliate/service.js +2321 -0
- package/.medusa/server/src/modules/affiliate/services/affiliate-application-manager.js +171 -0
- package/.medusa/server/src/modules/affiliate/services/affiliate-coupon-manager.js +441 -0
- package/.medusa/server/src/modules/affiliate/services/affiliate-discount.service.js +55 -0
- package/.medusa/server/src/modules/affiliate/services/affiliate-manager.js +242 -0
- package/.medusa/server/src/modules/affiliate/services/affiliate-partner-portal.service.js +138 -0
- package/.medusa/server/src/modules/affiliate/services/affiliate-report.service.js +436 -0
- package/.medusa/server/src/modules/affiliate/services/affiliate-slug-manager.js +163 -0
- package/.medusa/server/src/modules/affiliate/services/commission-ledger.service.js +729 -0
- package/.medusa/server/src/modules/affiliate/services/customer-affiliate-assignment-manager.js +350 -0
- package/.medusa/server/src/modules/affiliate/services/order-attribution-manager.js +1051 -0
- package/.medusa/server/src/modules/affiliate/services/referral-lifecycle-manager.js +1420 -0
- package/.medusa/server/src/modules/affiliate/services/utils.js +49 -0
- package/.medusa/server/src/modules/affiliate/types/internal.js +3 -0
- package/.medusa/server/src/paths/affiliate.js +7 -0
- package/.medusa/server/src/paths/index.js +18 -0
- package/.medusa/server/src/schemas/index.js +18 -0
- package/.medusa/server/src/schemas/store.js +24 -0
- package/.medusa/server/src/subscribers/affiliate-cart-updated.js +92 -0
- package/.medusa/server/src/subscribers/affiliate-order-canceled.js +70 -0
- package/.medusa/server/src/subscribers/affiliate-order-placed.js +63 -0
- package/.medusa/server/src/subscribers/affiliate-order-return-received.js +67 -0
- package/.medusa/server/src/subscribers/affiliate-product-eligibility-updated.js +87 -0
- package/.medusa/server/src/types/admin-api.js +3 -0
- package/.medusa/server/src/types/enums.js +53 -0
- package/.medusa/server/src/types/index.js +32 -0
- package/.medusa/server/src/types/public.js +3 -0
- package/.medusa/server/src/types/store-api.js +3 -0
- package/.medusa/server/src/utils/affiliate-cart-operation-lock.js +316 -0
- package/.medusa/server/src/utils/affiliate-promotion-mutation-authorization.js +49 -0
- package/.medusa/server/src/utils/cart-promotions.js +9 -0
- package/.medusa/server/src/utils/money.js +79 -0
- package/.medusa/server/src/utils/promotion-code-availability.js +34 -0
- package/.medusa/server/src/utils/registered-email-checkout.js +101 -0
- package/.medusa/server/src/utils/resolve-services.js +7 -0
- package/.medusa/server/src/utils/settle-cart-promotions.js +44 -0
- package/.medusa/server/src/workflows/affiliate/affiliate-coupon-cart.js +215 -0
- package/.medusa/server/src/workflows/affiliate/affiliate-coupon-command-authorization.js +20 -0
- package/.medusa/server/src/workflows/affiliate/apply-affiliate-coupon.js +174 -0
- package/.medusa/server/src/workflows/affiliate/apply-own-order-promotion.js +89 -0
- package/.medusa/server/src/workflows/affiliate/approve-consignment-report.js +186 -0
- package/.medusa/server/src/workflows/affiliate/correct-approved-consignment-report.js +263 -0
- package/.medusa/server/src/workflows/affiliate/create-affiliate-coupon.js +35 -0
- package/.medusa/server/src/workflows/affiliate/create-commission-correction-for-cancellation.js +21 -0
- package/.medusa/server/src/workflows/affiliate/create-commission-correction-for-refund.js +24 -0
- package/.medusa/server/src/workflows/affiliate/create-commission-for-order.js +17 -0
- package/.medusa/server/src/workflows/affiliate/deactivate-affiliate.js +89 -0
- package/.medusa/server/src/workflows/affiliate/enable-distribution.js +120 -0
- package/.medusa/server/src/workflows/affiliate/enrich-affiliate-report.js +75 -0
- package/.medusa/server/src/workflows/affiliate/ensure-affiliate-coupon-promotion.js +410 -0
- package/.medusa/server/src/workflows/affiliate/ensure-affiliate-own-order-promotion.js +240 -0
- package/.medusa/server/src/workflows/affiliate/ensure-default-affiliate-coupon.js +32 -0
- package/.medusa/server/src/workflows/affiliate/expire-affiliate-attribution-state.js +131 -0
- package/.medusa/server/src/workflows/affiliate/finalize-affiliate-order-attribution.js +82 -0
- package/.medusa/server/src/workflows/affiliate/payment-authorization.js +33 -0
- package/.medusa/server/src/workflows/affiliate/promotion-eligibility.js +179 -0
- package/.medusa/server/src/workflows/affiliate/reconcile-affiliate-cart-referral.js +219 -0
- package/.medusa/server/src/workflows/affiliate/reconcile-affiliate-coupon.js +388 -0
- package/.medusa/server/src/workflows/affiliate/refresh-affiliate-promotions.js +114 -0
- package/.medusa/server/src/workflows/affiliate/resolve-coupon-labels.js +40 -0
- package/.medusa/server/src/workflows/affiliate/revoke-affiliate-coupon.js +29 -0
- package/.medusa/server/src/workflows/affiliate/rotate-affiliate-coupon.js +36 -0
- package/.medusa/server/src/workflows/affiliate/run-consignment-report-reminders.js +58 -0
- package/.medusa/server/src/workflows/affiliate/submit-consignment-report.js +279 -0
- package/.medusa/server/src/workflows/affiliate/transfer-batch-aware-inventory.js +172 -0
- package/.medusa/server/src/workflows/affiliate/transfer-consignment-stock.js +106 -0
- package/.medusa/server/src/workflows/affiliate/update-affiliate-coupon-discounts.js +129 -0
- package/.medusa/server/src/workflows/affiliate/utils.js +118 -0
- package/.medusa/server/src/workflows/hooks/complete-cart-affiliate-attribution.js +57 -0
- package/.medusa/server/src/workflows/hooks/complete-cart-order-created-composition.js +111 -0
- package/.medusa/server/src/workflows/hooks/complete-cart-own-order-discount.js +75 -0
- package/.medusa/server/src/workflows/hooks/enforce-unique-promotion-codes.js +33 -0
- package/.medusa/server/src/workflows/hooks/validate-affiliate-customer-code.js +239 -0
- package/.medusa/server/src/workflows/hooks/validate-complete-cart-affiliate-referral.js +137 -0
- package/LICENSE +21 -0
- package/README.md +799 -0
- package/dist/integration/email-events.d.ts +20 -0
- package/dist/integration/email-events.js +50 -0
- package/package.json +84 -0
|
@@ -0,0 +1,436 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.AffiliateReportService = void 0;
|
|
4
|
+
const money_1 = require("../../../utils/money");
|
|
5
|
+
const utils_1 = require("./utils");
|
|
6
|
+
class AffiliateReportService {
|
|
7
|
+
constructor(store) {
|
|
8
|
+
this.store = store;
|
|
9
|
+
/**
|
|
10
|
+
* Commission entries for a date range are fetched a page at a time and
|
|
11
|
+
* folded into the running totals map instead of loading the whole range
|
|
12
|
+
* into memory at once, so peak memory is bounded by the batch size and the
|
|
13
|
+
* number of distinct affiliate/currency groups, not by entry count.
|
|
14
|
+
*/
|
|
15
|
+
this.overviewBatchSize = 500;
|
|
16
|
+
}
|
|
17
|
+
/**
|
|
18
|
+
* Portal-only aggregation over the immutable ledger. The Admin report keeps
|
|
19
|
+
* its existing accumulator below; both paths share the same bounded scanner.
|
|
20
|
+
*/
|
|
21
|
+
async getPortalLedgerTotals(input) {
|
|
22
|
+
const from = (0, utils_1.startOfUtcDate)(input.from);
|
|
23
|
+
const to = (0, utils_1.endOfUtcDate)(input.to);
|
|
24
|
+
const totals = new Map();
|
|
25
|
+
await this.forEachAttributionInRange({ from, to, affiliate_id: input.affiliate_id }, (batch) => {
|
|
26
|
+
for (const attribution of batch) {
|
|
27
|
+
const current = this.getPortalGroup(totals, attribution.currency_code);
|
|
28
|
+
// order_id is permanently unique on the immutable attribution model,
|
|
29
|
+
// so every live row is one distinct attributed order.
|
|
30
|
+
current.attributed_order_count += 1;
|
|
31
|
+
}
|
|
32
|
+
});
|
|
33
|
+
await this.forEachEntryInRange({ from, to, affiliate_id: input.affiliate_id }, (batch) => {
|
|
34
|
+
for (const entry of batch) {
|
|
35
|
+
const current = this.getPortalGroup(totals, entry.currency_code);
|
|
36
|
+
const amount = money_1.Money.of(entry.commission_amount);
|
|
37
|
+
if (entry.type === "order_commission") {
|
|
38
|
+
current.direct = current.direct.add(amount);
|
|
39
|
+
current.base = current.base.add(money_1.Money.of(entry.base_amount_net));
|
|
40
|
+
}
|
|
41
|
+
else if (entry.type === "affiliate_referral_bonus" ||
|
|
42
|
+
entry.type === "affiliate_own_order_referrer_bonus") {
|
|
43
|
+
current.referral = current.referral.add(amount);
|
|
44
|
+
}
|
|
45
|
+
else if (entry.type === "refund_correction" ||
|
|
46
|
+
entry.type === "cancellation_correction" ||
|
|
47
|
+
entry.type === "manual_correction") {
|
|
48
|
+
current.correction = current.correction.add(amount);
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
});
|
|
52
|
+
await this.forEachDirectCommissionOrderInRange({ from, to, affiliate_id: input.affiliate_id }, (batch) => {
|
|
53
|
+
for (const entry of batch) {
|
|
54
|
+
if (entry.commission_amount <= 0)
|
|
55
|
+
continue;
|
|
56
|
+
const current = this.getPortalGroup(totals, entry.currency_code);
|
|
57
|
+
current.commissioned_order_count += 1;
|
|
58
|
+
}
|
|
59
|
+
});
|
|
60
|
+
return Array.from(totals.values())
|
|
61
|
+
.map((total) => {
|
|
62
|
+
const decimals = (0, money_1.getCurrencyDecimals)(total.currency_code);
|
|
63
|
+
return {
|
|
64
|
+
currency_code: total.currency_code,
|
|
65
|
+
direct_commission_amount: total.direct.toRoundedNumber(decimals),
|
|
66
|
+
referral_commission_amount: total.referral.toRoundedNumber(decimals),
|
|
67
|
+
correction_amount: total.correction.toRoundedNumber(decimals),
|
|
68
|
+
net_commission_amount: total.direct
|
|
69
|
+
.add(total.referral)
|
|
70
|
+
.add(total.correction)
|
|
71
|
+
.toRoundedNumber(decimals),
|
|
72
|
+
commission_base_amount: total.base.toRoundedNumber(decimals),
|
|
73
|
+
attributed_order_count: total.attributed_order_count,
|
|
74
|
+
commissioned_order_count: total.commissioned_order_count
|
|
75
|
+
};
|
|
76
|
+
})
|
|
77
|
+
.sort((a, b) => a.currency_code.localeCompare(b.currency_code));
|
|
78
|
+
}
|
|
79
|
+
async getPortalLedgerPage(input) {
|
|
80
|
+
const from = (0, utils_1.startOfUtcDate)(input.from);
|
|
81
|
+
const to = (0, utils_1.endOfUtcDate)(input.to);
|
|
82
|
+
let count = 0;
|
|
83
|
+
await this.forEachEntryInRange({ from, to, affiliate_id: input.affiliate_id }, (batch) => {
|
|
84
|
+
count += batch.length;
|
|
85
|
+
});
|
|
86
|
+
const [totals, entries] = await Promise.all([
|
|
87
|
+
this.getPortalLedgerTotals(input),
|
|
88
|
+
this.store.listCommissionEntries({
|
|
89
|
+
affiliate_id: input.affiliate_id,
|
|
90
|
+
occurred_at: { $gte: from, $lte: to }
|
|
91
|
+
}, {
|
|
92
|
+
order: { occurred_at: "DESC", id: "DESC" },
|
|
93
|
+
skip: input.offset,
|
|
94
|
+
take: input.limit
|
|
95
|
+
})
|
|
96
|
+
]);
|
|
97
|
+
return { entries, count, totals };
|
|
98
|
+
}
|
|
99
|
+
async getOverview(input) {
|
|
100
|
+
const from = (0, utils_1.startOfUtcDate)(input.from);
|
|
101
|
+
const to = (0, utils_1.endOfUtcDate)(input.to);
|
|
102
|
+
const totals = new Map();
|
|
103
|
+
const affiliateIds = new Set();
|
|
104
|
+
await this.forEachAttributionInRange({ from, to }, (batch) => {
|
|
105
|
+
for (const attribution of batch) {
|
|
106
|
+
affiliateIds.add(attribution.affiliate_id);
|
|
107
|
+
const current = this.getReportGroup(totals, {
|
|
108
|
+
affiliate_id: attribution.affiliate_id,
|
|
109
|
+
currency_code: attribution.currency_code
|
|
110
|
+
}, this.reportGroupKey(attribution.affiliate_id, attribution.currency_code));
|
|
111
|
+
// The storage model enforces one live immutable attribution per order.
|
|
112
|
+
current.attributed_order_count += 1;
|
|
113
|
+
}
|
|
114
|
+
});
|
|
115
|
+
await this.forEachDirectCommissionOrderInRange({ from, to }, (batch) => {
|
|
116
|
+
for (const entry of batch) {
|
|
117
|
+
if (entry.commission_amount <= 0)
|
|
118
|
+
continue;
|
|
119
|
+
const current = this.getReportGroup(totals, {
|
|
120
|
+
affiliate_id: entry.affiliate_id,
|
|
121
|
+
currency_code: entry.currency_code
|
|
122
|
+
}, this.reportGroupKey(entry.affiliate_id, entry.currency_code));
|
|
123
|
+
current.commissioned_order_count += 1;
|
|
124
|
+
current.order_count += 1;
|
|
125
|
+
}
|
|
126
|
+
});
|
|
127
|
+
await this.forEachBonusOnlyOrderInRange({ from, to }, (batch) => {
|
|
128
|
+
for (const entry of batch) {
|
|
129
|
+
if (entry.commission_amount <= 0)
|
|
130
|
+
continue;
|
|
131
|
+
const current = this.getReportGroup(totals, {
|
|
132
|
+
affiliate_id: entry.affiliate_id,
|
|
133
|
+
currency_code: entry.currency_code
|
|
134
|
+
}, this.reportGroupKey(entry.affiliate_id, entry.currency_code));
|
|
135
|
+
current.order_count += 1;
|
|
136
|
+
}
|
|
137
|
+
});
|
|
138
|
+
await this.forEachEntryInRange({ from, to }, (batch) => {
|
|
139
|
+
this.accumulateEntriesInto(totals, batch, (entry) => {
|
|
140
|
+
affiliateIds.add(entry.affiliate_id);
|
|
141
|
+
return {
|
|
142
|
+
affiliate_id: entry.affiliate_id,
|
|
143
|
+
currency_code: entry.currency_code
|
|
144
|
+
};
|
|
145
|
+
});
|
|
146
|
+
});
|
|
147
|
+
const affiliates = affiliateIds.size
|
|
148
|
+
? await this.store.listAffiliates({ id: Array.from(affiliateIds) })
|
|
149
|
+
: [];
|
|
150
|
+
const affiliatesById = new Map(affiliates.map((affiliate) => [affiliate.id, affiliate]));
|
|
151
|
+
const overviewItems = this.finalizeTotals(totals).map((total) => ({
|
|
152
|
+
...total,
|
|
153
|
+
display_name: affiliatesById.get(total.affiliate_id)?.display_name ??
|
|
154
|
+
total.affiliate_id,
|
|
155
|
+
status: affiliatesById.get(total.affiliate_id)?.status ?? "inactive"
|
|
156
|
+
}));
|
|
157
|
+
return {
|
|
158
|
+
from: from.toISOString().slice(0, 10),
|
|
159
|
+
to: to.toISOString().slice(0, 10),
|
|
160
|
+
affiliates: overviewItems.sort((a, b) => a.display_name.localeCompare(b.display_name))
|
|
161
|
+
};
|
|
162
|
+
}
|
|
163
|
+
async getDetail(input) {
|
|
164
|
+
const from = (0, utils_1.startOfUtcDate)(input.from);
|
|
165
|
+
const to = (0, utils_1.endOfUtcDate)(input.to);
|
|
166
|
+
const affiliate = await this.store.retrieveAffiliate(input.affiliate_id);
|
|
167
|
+
// Totals are accumulated over the whole range in bounded batches so they
|
|
168
|
+
// stay correct even though only one page of entries is loaded for display.
|
|
169
|
+
const totals = new Map();
|
|
170
|
+
let entriesCount = 0;
|
|
171
|
+
await this.forEachAttributionInRange({ from, to, affiliate_id: input.affiliate_id }, (batch) => {
|
|
172
|
+
for (const attribution of batch) {
|
|
173
|
+
const current = this.getReportGroup(totals, {
|
|
174
|
+
currency_code: attribution.currency_code
|
|
175
|
+
}, this.reportGroupKey(attribution.affiliate_id, attribution.currency_code));
|
|
176
|
+
current.attributed_order_count += 1;
|
|
177
|
+
}
|
|
178
|
+
});
|
|
179
|
+
await this.forEachEntryInRange({ from, to, affiliate_id: input.affiliate_id }, (batch) => {
|
|
180
|
+
entriesCount += batch.length;
|
|
181
|
+
this.accumulateEntriesInto(totals, batch, (entry) => ({
|
|
182
|
+
currency_code: entry.currency_code
|
|
183
|
+
}));
|
|
184
|
+
});
|
|
185
|
+
await this.forEachDirectCommissionOrderInRange({ from, to, affiliate_id: input.affiliate_id }, (batch) => {
|
|
186
|
+
for (const entry of batch) {
|
|
187
|
+
if (entry.commission_amount <= 0)
|
|
188
|
+
continue;
|
|
189
|
+
const current = this.getReportGroup(totals, { currency_code: entry.currency_code }, this.reportGroupKey(entry.affiliate_id, entry.currency_code));
|
|
190
|
+
current.commissioned_order_count += 1;
|
|
191
|
+
current.order_count += 1;
|
|
192
|
+
}
|
|
193
|
+
});
|
|
194
|
+
await this.forEachBonusOnlyOrderInRange({ from, to, affiliate_id: input.affiliate_id }, (batch) => {
|
|
195
|
+
for (const entry of batch) {
|
|
196
|
+
if (entry.commission_amount <= 0)
|
|
197
|
+
continue;
|
|
198
|
+
const current = this.getReportGroup(totals, { currency_code: entry.currency_code }, this.reportGroupKey(entry.affiliate_id, entry.currency_code));
|
|
199
|
+
current.order_count += 1;
|
|
200
|
+
}
|
|
201
|
+
});
|
|
202
|
+
const entries = await this.store.listCommissionEntries({
|
|
203
|
+
affiliate_id: input.affiliate_id,
|
|
204
|
+
occurred_at: {
|
|
205
|
+
$gte: from,
|
|
206
|
+
$lte: to
|
|
207
|
+
}
|
|
208
|
+
}, {
|
|
209
|
+
order: {
|
|
210
|
+
occurred_at: "DESC",
|
|
211
|
+
id: "DESC"
|
|
212
|
+
},
|
|
213
|
+
skip: input.offset,
|
|
214
|
+
take: input.limit
|
|
215
|
+
});
|
|
216
|
+
return {
|
|
217
|
+
from: from.toISOString().slice(0, 10),
|
|
218
|
+
to: to.toISOString().slice(0, 10),
|
|
219
|
+
affiliate,
|
|
220
|
+
entries,
|
|
221
|
+
entries_count: entriesCount,
|
|
222
|
+
totals: this.finalizeTotals(totals)
|
|
223
|
+
};
|
|
224
|
+
}
|
|
225
|
+
/**
|
|
226
|
+
* Scans every commission entry in the range in bounded batches using keyset
|
|
227
|
+
* pagination on the unique `id` (stable: no row is skipped or double-counted
|
|
228
|
+
* across batch boundaries the way an occurred_at skip/take would when several
|
|
229
|
+
* entries share a timestamp). The aggregation is order-independent, so a plain
|
|
230
|
+
* `id ASC` cursor is sufficient.
|
|
231
|
+
*/
|
|
232
|
+
async forEachEntryInRange(range, onBatch) {
|
|
233
|
+
let cursor;
|
|
234
|
+
for (;;) {
|
|
235
|
+
const batch = await this.store.listCommissionEntries({
|
|
236
|
+
...(range.affiliate_id ? { affiliate_id: range.affiliate_id } : {}),
|
|
237
|
+
occurred_at: {
|
|
238
|
+
$gte: range.from,
|
|
239
|
+
$lte: range.to
|
|
240
|
+
},
|
|
241
|
+
...(cursor ? { id: { $gt: cursor } } : {})
|
|
242
|
+
}, {
|
|
243
|
+
order: {
|
|
244
|
+
id: "ASC"
|
|
245
|
+
},
|
|
246
|
+
take: this.overviewBatchSize
|
|
247
|
+
});
|
|
248
|
+
if (!batch.length) {
|
|
249
|
+
return;
|
|
250
|
+
}
|
|
251
|
+
onBatch(batch);
|
|
252
|
+
if (batch.length < this.overviewBatchSize) {
|
|
253
|
+
return;
|
|
254
|
+
}
|
|
255
|
+
cursor = batch[batch.length - 1].id;
|
|
256
|
+
}
|
|
257
|
+
}
|
|
258
|
+
/** Scans immutable attribution snapshots with the same bounded keyset rule. */
|
|
259
|
+
async forEachAttributionInRange(range, onBatch) {
|
|
260
|
+
let cursor;
|
|
261
|
+
for (;;) {
|
|
262
|
+
const batch = await this.store.listAffiliateOrderAttributions({
|
|
263
|
+
...(range.affiliate_id ? { affiliate_id: range.affiliate_id } : {}),
|
|
264
|
+
attributed_at: { $gte: range.from, $lte: range.to },
|
|
265
|
+
...(cursor ? { id: { $gt: cursor } } : {})
|
|
266
|
+
}, { order: { id: "ASC" }, take: this.overviewBatchSize });
|
|
267
|
+
if (!batch.length)
|
|
268
|
+
return;
|
|
269
|
+
onBatch(batch);
|
|
270
|
+
if (batch.length < this.overviewBatchSize)
|
|
271
|
+
return;
|
|
272
|
+
cursor = batch[batch.length - 1].id;
|
|
273
|
+
}
|
|
274
|
+
}
|
|
275
|
+
/**
|
|
276
|
+
* Counts positive direct commissions by a bounded `order_id` keyset rather
|
|
277
|
+
* than retaining every order ID. Direct order-commission rows are immutable
|
|
278
|
+
* one-per-order bookings (`oc:<order_id>`); the order keyset also preserves
|
|
279
|
+
* the distinct-order result for legacy duplicate rows without unbounded
|
|
280
|
+
* process memory. Generated service reads exclude soft-deleted history.
|
|
281
|
+
*/
|
|
282
|
+
async forEachDirectCommissionOrderInRange(range, onBatch) {
|
|
283
|
+
let cursor;
|
|
284
|
+
for (;;) {
|
|
285
|
+
const batch = await this.store.listCommissionEntries({
|
|
286
|
+
...(range.affiliate_id ? { affiliate_id: range.affiliate_id } : {}),
|
|
287
|
+
type: "order_commission",
|
|
288
|
+
occurred_at: { $gte: range.from, $lte: range.to },
|
|
289
|
+
...(cursor ? { order_id: { $gt: cursor } } : {})
|
|
290
|
+
}, {
|
|
291
|
+
order: { order_id: "ASC", id: "ASC" },
|
|
292
|
+
take: this.overviewBatchSize
|
|
293
|
+
});
|
|
294
|
+
if (!batch.length)
|
|
295
|
+
return;
|
|
296
|
+
// Rows for the same order are adjacent in this query. Deduplicate only
|
|
297
|
+
// the current bounded batch; the cursor advances by order_id, so later
|
|
298
|
+
// batches cannot reintroduce a completed order.
|
|
299
|
+
const distinctOrders = batch.filter((entry, index) => index === 0 || entry.order_id !== batch[index - 1].order_id);
|
|
300
|
+
onBatch(distinctOrders);
|
|
301
|
+
if (batch.length < this.overviewBatchSize)
|
|
302
|
+
return;
|
|
303
|
+
cursor = batch[batch.length - 1].order_id ?? undefined;
|
|
304
|
+
if (!cursor)
|
|
305
|
+
return;
|
|
306
|
+
}
|
|
307
|
+
}
|
|
308
|
+
/**
|
|
309
|
+
* Same bounded `order_id`-keyset scan as
|
|
310
|
+
* `forEachDirectCommissionOrderInRange`, but over the referral/own-order
|
|
311
|
+
* bonus types instead of `order_commission`. A given order has at most one
|
|
312
|
+
* row in this type set system-wide (the own-order-bonus path short-circuits
|
|
313
|
+
* the normal attribution flow entirely, and a regular referral bonus is
|
|
314
|
+
* bound to a single `referrer_affiliate_id`), so the same order-only,
|
|
315
|
+
* cross-affiliate-agnostic adjacent dedup stays correct: whenever both a
|
|
316
|
+
* direct and a bonus row exist for one order, they belong to two different
|
|
317
|
+
* affiliates (buyer vs. referrer), never the same one.
|
|
318
|
+
*/
|
|
319
|
+
async forEachBonusOnlyOrderInRange(range, onBatch) {
|
|
320
|
+
let cursor;
|
|
321
|
+
for (;;) {
|
|
322
|
+
const batch = await this.store.listCommissionEntries({
|
|
323
|
+
...(range.affiliate_id ? { affiliate_id: range.affiliate_id } : {}),
|
|
324
|
+
type: ["affiliate_referral_bonus", "affiliate_own_order_referrer_bonus"],
|
|
325
|
+
occurred_at: { $gte: range.from, $lte: range.to },
|
|
326
|
+
...(cursor ? { order_id: { $gt: cursor } } : {})
|
|
327
|
+
}, {
|
|
328
|
+
order: { order_id: "ASC", id: "ASC" },
|
|
329
|
+
take: this.overviewBatchSize
|
|
330
|
+
});
|
|
331
|
+
if (!batch.length)
|
|
332
|
+
return;
|
|
333
|
+
const distinctOrders = batch.filter((entry, index) => index === 0 || entry.order_id !== batch[index - 1].order_id);
|
|
334
|
+
onBatch(distinctOrders);
|
|
335
|
+
if (batch.length < this.overviewBatchSize)
|
|
336
|
+
return;
|
|
337
|
+
cursor = batch[batch.length - 1].order_id ?? undefined;
|
|
338
|
+
if (!cursor)
|
|
339
|
+
return;
|
|
340
|
+
}
|
|
341
|
+
}
|
|
342
|
+
/**
|
|
343
|
+
* Sums commission_amount by immutable affiliate/currency snapshot into the
|
|
344
|
+
* given map. Callers can feed entries in as many batches as needed.
|
|
345
|
+
*/
|
|
346
|
+
accumulateEntriesInto(totals, entries, seed) {
|
|
347
|
+
for (const entry of entries) {
|
|
348
|
+
const current = this.getReportGroup(totals, seed(entry), this.reportGroupKey(entry.affiliate_id, entry.currency_code));
|
|
349
|
+
const commissionAmount = money_1.Money.of(entry.commission_amount);
|
|
350
|
+
current.total_commission_amount =
|
|
351
|
+
current.total_commission_amount.add(commissionAmount);
|
|
352
|
+
current.entry_count += 1;
|
|
353
|
+
if (!commissionAmount.isNegative()) {
|
|
354
|
+
current.positive_commission_amount =
|
|
355
|
+
current.positive_commission_amount.add(commissionAmount);
|
|
356
|
+
}
|
|
357
|
+
else {
|
|
358
|
+
current.negative_correction_amount =
|
|
359
|
+
current.negative_correction_amount.add(commissionAmount);
|
|
360
|
+
}
|
|
361
|
+
// "Bestellungswert": the net basis behind every entry that actually
|
|
362
|
+
// paid out, so it stays a meaningful denominator next to the
|
|
363
|
+
// commission total (see affiliate-report.service.ts's own module
|
|
364
|
+
// docs). Zero-amount entries don't count as "earned from".
|
|
365
|
+
if (entry.commission_amount > 0) {
|
|
366
|
+
current.order_value_amount = current.order_value_amount.add(money_1.Money.of(entry.base_amount_net));
|
|
367
|
+
}
|
|
368
|
+
if (entry.type === "affiliate_referral_bonus" ||
|
|
369
|
+
entry.type === "affiliate_own_order_referrer_bonus") {
|
|
370
|
+
current.referral_bonus_amount =
|
|
371
|
+
current.referral_bonus_amount.add(commissionAmount);
|
|
372
|
+
}
|
|
373
|
+
}
|
|
374
|
+
}
|
|
375
|
+
/**
|
|
376
|
+
* Keeps the running totals as Money values, then applies the exact decimal
|
|
377
|
+
* precision of the group's currency only at the response boundary.
|
|
378
|
+
*/
|
|
379
|
+
finalizeTotals(totals) {
|
|
380
|
+
return Array.from(totals.values()).map((total) => {
|
|
381
|
+
const decimalPlaces = (0, money_1.getCurrencyDecimals)(total.currency_code);
|
|
382
|
+
return {
|
|
383
|
+
...total,
|
|
384
|
+
total_commission_amount: total.total_commission_amount.toRoundedNumber(decimalPlaces),
|
|
385
|
+
positive_commission_amount: total.positive_commission_amount.toRoundedNumber(decimalPlaces),
|
|
386
|
+
negative_correction_amount: total.negative_correction_amount.toRoundedNumber(decimalPlaces),
|
|
387
|
+
referral_bonus_amount: total.referral_bonus_amount.toRoundedNumber(decimalPlaces),
|
|
388
|
+
order_value_amount: total.order_value_amount.toRoundedNumber(decimalPlaces),
|
|
389
|
+
attributed_order_count: total.attributed_order_count,
|
|
390
|
+
commissioned_order_count: total.commissioned_order_count,
|
|
391
|
+
order_count: total.order_count
|
|
392
|
+
};
|
|
393
|
+
});
|
|
394
|
+
}
|
|
395
|
+
getReportGroup(totals, seed, key) {
|
|
396
|
+
const current = totals.get(key);
|
|
397
|
+
if (current)
|
|
398
|
+
return current;
|
|
399
|
+
const created = {
|
|
400
|
+
...seed,
|
|
401
|
+
total_commission_amount: money_1.Money.zero(),
|
|
402
|
+
positive_commission_amount: money_1.Money.zero(),
|
|
403
|
+
negative_correction_amount: money_1.Money.zero(),
|
|
404
|
+
referral_bonus_amount: money_1.Money.zero(),
|
|
405
|
+
order_value_amount: money_1.Money.zero(),
|
|
406
|
+
entry_count: 0,
|
|
407
|
+
attributed_order_count: 0,
|
|
408
|
+
commissioned_order_count: 0,
|
|
409
|
+
order_count: 0
|
|
410
|
+
};
|
|
411
|
+
totals.set(key, created);
|
|
412
|
+
return created;
|
|
413
|
+
}
|
|
414
|
+
/** A reversible tuple encoding prevents delimiter collisions in report maps. */
|
|
415
|
+
reportGroupKey(affiliateId, currencyCode) {
|
|
416
|
+
return JSON.stringify([affiliateId, currencyCode]);
|
|
417
|
+
}
|
|
418
|
+
getPortalGroup(totals, currencyCode) {
|
|
419
|
+
const current = totals.get(currencyCode);
|
|
420
|
+
if (current)
|
|
421
|
+
return current;
|
|
422
|
+
const created = {
|
|
423
|
+
currency_code: currencyCode,
|
|
424
|
+
direct: money_1.Money.zero(),
|
|
425
|
+
referral: money_1.Money.zero(),
|
|
426
|
+
correction: money_1.Money.zero(),
|
|
427
|
+
base: money_1.Money.zero(),
|
|
428
|
+
attributed_order_count: 0,
|
|
429
|
+
commissioned_order_count: 0
|
|
430
|
+
};
|
|
431
|
+
totals.set(currencyCode, created);
|
|
432
|
+
return created;
|
|
433
|
+
}
|
|
434
|
+
}
|
|
435
|
+
exports.AffiliateReportService = AffiliateReportService;
|
|
436
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiYWZmaWxpYXRlLXJlcG9ydC5zZXJ2aWNlLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vLi4vLi4vLi4vc3JjL21vZHVsZXMvYWZmaWxpYXRlL3NlcnZpY2VzL2FmZmlsaWF0ZS1yZXBvcnQuc2VydmljZS50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiOzs7QUFLQSxnREFBaUU7QUFNakUsbUNBQXNEO0FBK0J0RCxNQUFhLHNCQUFzQjtJQVNqQyxZQUE2QixLQUEyQjtRQUEzQixVQUFLLEdBQUwsS0FBSyxDQUFzQjtRQVJ4RDs7Ozs7V0FLRztRQUNjLHNCQUFpQixHQUFHLEdBQUcsQ0FBQTtJQUVtQixDQUFDO0lBRTVEOzs7T0FHRztJQUNILEtBQUssQ0FBQyxxQkFBcUIsQ0FBQyxLQUkzQjtRQUNDLE1BQU0sSUFBSSxHQUFHLElBQUEsc0JBQWMsRUFBQyxLQUFLLENBQUMsSUFBSSxDQUFDLENBQUE7UUFDdkMsTUFBTSxFQUFFLEdBQUcsSUFBQSxvQkFBWSxFQUFDLEtBQUssQ0FBQyxFQUFFLENBQUMsQ0FBQTtRQUNqQyxNQUFNLE1BQU0sR0FBRyxJQUFJLEdBQUcsRUFXbkIsQ0FBQTtRQUVILE1BQU0sSUFBSSxDQUFDLHlCQUF5QixDQUNsQyxFQUFFLElBQUksRUFBRSxFQUFFLEVBQUUsWUFBWSxFQUFFLEtBQUssQ0FBQyxZQUFZLEVBQUUsRUFDOUMsQ0FBQyxLQUFLLEVBQUUsRUFBRTtZQUNSLEtBQUssTUFBTSxXQUFXLElBQUksS0FBSyxFQUFFLENBQUM7Z0JBQ2hDLE1BQU0sT0FBTyxHQUFHLElBQUksQ0FBQyxjQUFjLENBQUMsTUFBTSxFQUFFLFdBQVcsQ0FBQyxhQUFhLENBQUMsQ0FBQTtnQkFDdEUscUVBQXFFO2dCQUNyRSxzREFBc0Q7Z0JBQ3RELE9BQU8sQ0FBQyxzQkFBc0IsSUFBSSxDQUFDLENBQUE7WUFDckMsQ0FBQztRQUNILENBQUMsQ0FDRixDQUFBO1FBRUQsTUFBTSxJQUFJLENBQUMsbUJBQW1CLENBQzVCLEVB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
|
|
@@ -0,0 +1,163 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.AffiliateSlugManager = void 0;
|
|
4
|
+
const utils_1 = require("@medusajs/framework/utils");
|
|
5
|
+
class AffiliateSlugManager {
|
|
6
|
+
constructor(store) {
|
|
7
|
+
this.store = store;
|
|
8
|
+
}
|
|
9
|
+
normalizeSlug(value) {
|
|
10
|
+
const slug = value
|
|
11
|
+
.trim()
|
|
12
|
+
.toLowerCase()
|
|
13
|
+
.replace(/['"]/g, "")
|
|
14
|
+
.replace(/[^a-z0-9]+/g, "-")
|
|
15
|
+
.replace(/^-+|-+$/g, "")
|
|
16
|
+
.replace(/-{2,}/g, "-");
|
|
17
|
+
if (!slug) {
|
|
18
|
+
throw new utils_1.MedusaError(utils_1.MedusaError.Types.INVALID_DATA, "Affiliate slug is required.");
|
|
19
|
+
}
|
|
20
|
+
return slug;
|
|
21
|
+
}
|
|
22
|
+
async createSlug(input, context) {
|
|
23
|
+
const slug = this.normalizeSlug(input.slug);
|
|
24
|
+
// When called right after the affiliate was created in the same
|
|
25
|
+
// transaction, flush so the existence check below sees it. A filtered
|
|
26
|
+
// `list` is used rather than `retrieve` because, within an open
|
|
27
|
+
// transaction, the generated `retrieve` does not observe a row created
|
|
28
|
+
// (and flushed) earlier in the same transaction, whereas `list` does.
|
|
29
|
+
await this.store.flush(context);
|
|
30
|
+
await this.assertSlugIsAvailable(slug, undefined, context);
|
|
31
|
+
const [affiliate] = await this.store.listAffiliates({ id: input.affiliate_id }, { take: 1 }, context);
|
|
32
|
+
if (!affiliate) {
|
|
33
|
+
throw new utils_1.MedusaError(utils_1.MedusaError.Types.NOT_FOUND, `Affiliate with id "${input.affiliate_id}" was not found.`);
|
|
34
|
+
}
|
|
35
|
+
const existingSlugs = await this.store.listAffiliateSlugs({
|
|
36
|
+
affiliate_id: input.affiliate_id,
|
|
37
|
+
}, undefined, context);
|
|
38
|
+
const makePrimary = existingSlugs.length === 0 || (input.is_primary ?? false);
|
|
39
|
+
const active = input.active ?? true;
|
|
40
|
+
if (makePrimary && !active) {
|
|
41
|
+
throw new utils_1.MedusaError(utils_1.MedusaError.Types.INVALID_DATA, "A primary affiliate slug must be active.");
|
|
42
|
+
}
|
|
43
|
+
const created = await this.store.createAffiliateSlugs({
|
|
44
|
+
affiliate_id: input.affiliate_id,
|
|
45
|
+
slug,
|
|
46
|
+
active,
|
|
47
|
+
is_primary: false,
|
|
48
|
+
}, context);
|
|
49
|
+
if (makePrimary) {
|
|
50
|
+
return await this.setPrimarySlug({ affiliate_id: input.affiliate_id, slug_id: created.id }, context);
|
|
51
|
+
}
|
|
52
|
+
return created;
|
|
53
|
+
}
|
|
54
|
+
async updateSlug(input, context) {
|
|
55
|
+
const [existing] = await this.store.listAffiliateSlugs({ id: input.id, affiliate_id: input.affiliate_id }, { take: 1 }, context);
|
|
56
|
+
if (!existing) {
|
|
57
|
+
throw new utils_1.MedusaError(utils_1.MedusaError.Types.NOT_FOUND, "Affiliate slug was not found for this affiliate.");
|
|
58
|
+
}
|
|
59
|
+
const nextSlug = input.slug !== undefined ? this.normalizeSlug(input.slug) : existing.slug;
|
|
60
|
+
if (nextSlug !== existing.slug) {
|
|
61
|
+
await this.assertSlugIsAvailable(nextSlug, existing.id, context);
|
|
62
|
+
}
|
|
63
|
+
const nextActive = input.active ?? existing.active;
|
|
64
|
+
const nextPrimary = input.is_primary ?? existing.is_primary;
|
|
65
|
+
if (existing.is_primary && (!nextActive || !nextPrimary)) {
|
|
66
|
+
throw new utils_1.MedusaError(utils_1.MedusaError.Types.INVALID_DATA, "A primary affiliate slug must remain active and primary.");
|
|
67
|
+
}
|
|
68
|
+
if (nextPrimary && !nextActive) {
|
|
69
|
+
throw new utils_1.MedusaError(utils_1.MedusaError.Types.INVALID_DATA, "A primary affiliate slug must be active.");
|
|
70
|
+
}
|
|
71
|
+
const updated = (await this.store.updateAffiliateSlugs({
|
|
72
|
+
id: input.id,
|
|
73
|
+
slug: nextSlug,
|
|
74
|
+
active: nextActive,
|
|
75
|
+
is_primary: existing.is_primary,
|
|
76
|
+
}, context));
|
|
77
|
+
if (nextPrimary && !existing.is_primary) {
|
|
78
|
+
return await this.setPrimarySlug({ affiliate_id: input.affiliate_id, slug_id: updated.id }, context);
|
|
79
|
+
}
|
|
80
|
+
return updated;
|
|
81
|
+
}
|
|
82
|
+
async setPrimarySlug(input, context) {
|
|
83
|
+
await this.store.flush(context);
|
|
84
|
+
const [target] = await this.store.listAffiliateSlugs({ id: input.slug_id, affiliate_id: input.affiliate_id }, { take: 1 }, context);
|
|
85
|
+
if (!target) {
|
|
86
|
+
throw new utils_1.MedusaError(utils_1.MedusaError.Types.NOT_FOUND, "Affiliate slug was not found for this affiliate.");
|
|
87
|
+
}
|
|
88
|
+
if (!target.active) {
|
|
89
|
+
throw new utils_1.MedusaError(utils_1.MedusaError.Types.INVALID_DATA, "An inactive affiliate slug cannot be primary.");
|
|
90
|
+
}
|
|
91
|
+
await this.clearPrimarySlug(input.affiliate_id, context);
|
|
92
|
+
const updated = (await this.store.updateAffiliateSlugs({
|
|
93
|
+
id: target.id,
|
|
94
|
+
active: true,
|
|
95
|
+
is_primary: true,
|
|
96
|
+
}, context));
|
|
97
|
+
await this.store.updateAffiliates({
|
|
98
|
+
id: input.affiliate_id,
|
|
99
|
+
primary_slug_id: updated.id,
|
|
100
|
+
}, context);
|
|
101
|
+
return updated;
|
|
102
|
+
}
|
|
103
|
+
async listSlugs(affiliateId, context) {
|
|
104
|
+
return await this.store.listAffiliateSlugs({
|
|
105
|
+
affiliate_id: affiliateId,
|
|
106
|
+
}, {
|
|
107
|
+
order: {
|
|
108
|
+
created_at: "ASC",
|
|
109
|
+
},
|
|
110
|
+
}, context);
|
|
111
|
+
}
|
|
112
|
+
/**
|
|
113
|
+
* Normalizes and asserts a slug is free before a caller commits to a
|
|
114
|
+
* multi-row write (H3), so an affiliate row is never inserted only to have
|
|
115
|
+
* its primary slug rejected by the global unique index afterwards.
|
|
116
|
+
*/
|
|
117
|
+
async assertSlugAvailable(slug, context) {
|
|
118
|
+
const normalized = this.normalizeSlug(slug);
|
|
119
|
+
await this.assertSlugIsAvailable(normalized, undefined, context);
|
|
120
|
+
return normalized;
|
|
121
|
+
}
|
|
122
|
+
async resolveActiveSlug(slugValue) {
|
|
123
|
+
const slug = this.normalizeSlug(slugValue);
|
|
124
|
+
const slugs = await this.store.listAffiliateSlugs({
|
|
125
|
+
slug,
|
|
126
|
+
active: true,
|
|
127
|
+
});
|
|
128
|
+
return slugs[0] ?? null;
|
|
129
|
+
}
|
|
130
|
+
async generateAvailableSlug(displayName, context) {
|
|
131
|
+
const base = this.normalizeSlug(displayName);
|
|
132
|
+
let candidate = base;
|
|
133
|
+
let suffix = 2;
|
|
134
|
+
while (!(await this.isSlugAvailable(candidate, undefined, context))) {
|
|
135
|
+
candidate = `${base}-${suffix}`;
|
|
136
|
+
suffix += 1;
|
|
137
|
+
}
|
|
138
|
+
return candidate;
|
|
139
|
+
}
|
|
140
|
+
async clearPrimarySlug(affiliateId, context) {
|
|
141
|
+
await this.store.updateAffiliateSlugs({
|
|
142
|
+
selector: {
|
|
143
|
+
affiliate_id: affiliateId,
|
|
144
|
+
is_primary: true,
|
|
145
|
+
},
|
|
146
|
+
data: {
|
|
147
|
+
is_primary: false,
|
|
148
|
+
},
|
|
149
|
+
}, context);
|
|
150
|
+
}
|
|
151
|
+
async isSlugAvailable(slug, currentSlugId, context) {
|
|
152
|
+
const existing = await this.store.listAffiliateSlugs({ slug }, undefined, context);
|
|
153
|
+
return existing.every((existingSlug) => existingSlug.id === currentSlugId);
|
|
154
|
+
}
|
|
155
|
+
async assertSlugIsAvailable(slug, currentSlugId, context) {
|
|
156
|
+
if (await this.isSlugAvailable(slug, currentSlugId, context)) {
|
|
157
|
+
return;
|
|
158
|
+
}
|
|
159
|
+
throw new utils_1.MedusaError(utils_1.MedusaError.Types.DUPLICATE_ERROR, `Affiliate slug "${slug}" is already in use.`);
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
exports.AffiliateSlugManager = AffiliateSlugManager;
|
|
163
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiYWZmaWxpYXRlLXNsdWctbWFuYWdlci5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uLy4uLy4uLy4uL3NyYy9tb2R1bGVzL2FmZmlsaWF0ZS9zZXJ2aWNlcy9hZmZpbGlhdGUtc2x1Zy1tYW5hZ2VyLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7OztBQUFBLHFEQUF1RDtBQVV2RCxNQUFhLG9CQUFvQjtJQUMvQixZQUE2QixLQUEyQjtRQUEzQixVQUFLLEdBQUwsS0FBSyxDQUFzQjtJQUFHLENBQUM7SUFFNUQsYUFBYSxDQUFDLEtBQWE7UUFDekIsTUFBTSxJQUFJLEdBQUcsS0FBSzthQUNmLElBQUksRUFBRTthQUNOLFdBQVcsRUFBRTthQUNiLE9BQU8sQ0FBQyxPQUFPLEVBQUUsRUFBRSxDQUFDO2FBQ3BCLE9BQU8sQ0FBQyxhQUFhLEVBQUUsR0FBRyxDQUFDO2FBQzNCLE9BQU8sQ0FBQyxVQUFVLEVBQUUsRUFBRSxDQUFDO2FBQ3ZCLE9BQU8sQ0FBQyxRQUFRLEVBQUUsR0FBRyxDQUFDLENBQUE7UUFFekIsSUFBSSxDQUFDLElBQUksRUFBRSxDQUFDO1lBQ1YsTUFBTSxJQUFJLG1CQUFXLENBQ25CLG1CQUFXLENBQUMsS0FBSyxDQUFDLFlBQVksRUFDOUIsNkJBQTZCLENBQzlCLENBQUE7UUFDSCxDQUFDO1FBRUQsT0FBTyxJQUFJLENBQUE7SUFDYixDQUFDO0lBRUQsS0FBSyxDQUFDLFVBQVUsQ0FDZCxLQUErQixFQUMvQixPQUFpQjtRQUVqQixNQUFNLElBQUksR0FBRyxJQUFJLENBQUMsYUFBYSxDQUFDLEtBQUssQ0FBQyxJQUFJLENBQUMsQ0FBQTtRQUUzQyxnRUFBZ0U7UUFDaEUsc0VBQXNFO1FBQ3RFLGdFQUFnRTtRQUNoRSx1RUFBdUU7UUFDdkUsc0VBQXNFO1FBQ3RFLE1BQU0sSUFBSSxDQUFDLEtBQUssQ0FBQyxLQUFLLENBQUMsT0FBTyxDQUFDLENBQUE7UUFDL0IsTUFBTSxJQUFJLENBQUMscUJBQXFCLENBQUMs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
|