@wtree/payload-ecommerce-coupon 3.77.2 → 3.77.3
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/README.md +22 -1
- package/dist/collections/createReferralCodesCollection.d.ts.map +1 -1
- package/dist/collections/createReferralProgramsCollection.d.ts.map +1 -1
- package/dist/endpoints/applyCoupon.d.ts.map +1 -1
- package/dist/endpoints/partnerStats.d.ts.map +1 -1
- package/dist/endpoints/validateCoupon.d.ts.map +1 -1
- package/dist/hooks/recalculateCart.d.ts.map +1 -1
- package/dist/index.d.ts +2 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +191 -64
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +191 -65
- package/dist/index.mjs.map +1 -1
- package/dist/types.d.ts +20 -0
- package/dist/types.d.ts.map +1 -1
- package/dist/utilities/calculateValues.d.ts +7 -1
- package/dist/utilities/calculateValues.d.ts.map +1 -1
- package/dist/utilities/sanitizePluginConfig.d.ts.map +1 -1
- package/dist/utilities/userRoles.d.ts +25 -0
- package/dist/utilities/userRoles.d.ts.map +1 -0
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -27,6 +27,8 @@ Production-ready coupon and referral system plugin for **Payload CMS** with seam
|
|
|
27
27
|
- ✅ **Commission Rules** – **Required.** At least one rule per program. Each rule supports:
|
|
28
28
|
- **Direct Basis**: Separate Reward (Partner) and Referee Reward (Customer).
|
|
29
29
|
- **Shared Basis**: Define a total "pot" (e.g., 20% of order) and split it (e.g., 50/50) between partner and customer.
|
|
30
|
+
- ✅ **Rule-level Minimum Order** – Optional `minOrderAmount` per commission rule, validated on apply/validate/recalculate
|
|
31
|
+
- ✅ **Fixed-only Mode** – Restrict `totalCommission.type` to fixed only via `referralConfig.allowedTotalCommissionTypes: ['fixed']`
|
|
30
32
|
- ✅ **Referrer/Referee inside each rule** – Partner gets commission, customer gets discount; type (percentage/fixed), value, and optional max cap per rule.
|
|
31
33
|
- ✅ **Partner Tracking** – Commission earnings and referral performance (credited when order is placed)
|
|
32
34
|
- ✅ **Auto-Generated Codes** – Unique referral codes for each partner
|
|
@@ -85,6 +87,8 @@ export default buildConfig({
|
|
|
85
87
|
singleCodePerCart: true, // Only one code per order
|
|
86
88
|
defaultPartnerSplit: 70, // 70% to partner
|
|
87
89
|
defaultCustomerSplit: 30, // 30% discount to customer
|
|
90
|
+
// Set fixed-only mode for production partner programs
|
|
91
|
+
allowedTotalCommissionTypes: ["fixed"], // Default: ["fixed", "percentage"]
|
|
88
92
|
},
|
|
89
93
|
|
|
90
94
|
// Custom admin panel groups
|
|
@@ -110,6 +114,13 @@ export default buildConfig({
|
|
|
110
114
|
isPartner: ({ req }) => req.user?.role === "partner",
|
|
111
115
|
},
|
|
112
116
|
|
|
117
|
+
// Optional: role resolver for custom user schemas
|
|
118
|
+
// roleConfig: {
|
|
119
|
+
// roleFieldPaths: ["role", "roles", "account.roles"],
|
|
120
|
+
// adminRoleValues: ["admin"],
|
|
121
|
+
// partnerRoleValues: ["partner", "affiliate"],
|
|
122
|
+
// },
|
|
123
|
+
|
|
113
124
|
// Optional: for per-customer coupon limit (defaults shown)
|
|
114
125
|
// orderIntegration: {
|
|
115
126
|
// ordersSlug: 'orders',
|
|
@@ -138,7 +149,7 @@ This will create collections for:
|
|
|
138
149
|
|
|
139
150
|
### 3. Setting Up Partner Role
|
|
140
151
|
|
|
141
|
-
To enable the partner dashboard and role-based access, add a `role` field to your Users collection:
|
|
152
|
+
To enable the partner dashboard and role-based access, add a `role` or `roles` field to your Users collection (or configure custom paths with `roleConfig`):
|
|
142
153
|
|
|
143
154
|
```typescript
|
|
144
155
|
// collections/Users.ts
|
|
@@ -175,6 +186,16 @@ export const Users: CollectionConfig = {
|
|
|
175
186
|
};
|
|
176
187
|
```
|
|
177
188
|
|
|
189
|
+
If your user schema stores roles in a custom structure, configure:
|
|
190
|
+
|
|
191
|
+
```typescript
|
|
192
|
+
roleConfig: {
|
|
193
|
+
roleFieldPaths: ["role", "roles", "profile.accountRoles"],
|
|
194
|
+
adminRoleValues: ["admin"],
|
|
195
|
+
partnerRoleValues: ["partner", "affiliate"],
|
|
196
|
+
}
|
|
197
|
+
```
|
|
198
|
+
|
|
178
199
|
### 4. Record Usage When Order Is Placed
|
|
179
200
|
|
|
180
201
|
Coupon and referral **usage is not counted when a code is applied** to the cart. It is counted only when an **order is placed successfully** (e.g. paid). You must call the plugin when converting cart to order:
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"createReferralCodesCollection.d.ts","sourceRoot":"","sources":["../../src/collections/createReferralCodesCollection.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,SAAS,CAAA;AAE/C,OAAO,KAAK,EAAE,4BAA4B,EAAE,MAAM,UAAU,CAAA;
|
|
1
|
+
{"version":3,"file":"createReferralCodesCollection.d.ts","sourceRoot":"","sources":["../../src/collections/createReferralCodesCollection.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,SAAS,CAAA;AAE/C,OAAO,KAAK,EAAE,4BAA4B,EAAE,MAAM,UAAU,CAAA;AAG5D,eAAO,MAAM,6BAA6B,GACxC,cAAc,4BAA4B,KACzC,gBA0LF,CAAA"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"createReferralProgramsCollection.d.ts","sourceRoot":"","sources":["../../src/collections/createReferralProgramsCollection.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,SAAS,CAAA;AAE/C,OAAO,KAAK,EAAE,4BAA4B,EAAE,MAAM,UAAU,CAAA;
|
|
1
|
+
{"version":3,"file":"createReferralProgramsCollection.d.ts","sourceRoot":"","sources":["../../src/collections/createReferralProgramsCollection.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,SAAS,CAAA;AAE/C,OAAO,KAAK,EAAE,4BAA4B,EAAE,MAAM,UAAU,CAAA;AAyB5D,eAAO,MAAM,gCAAgC,GAC3C,cAAc,4BAA4B,KACzC,gBAiRF,CAAA"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"applyCoupon.d.ts","sourceRoot":"","sources":["../../src/endpoints/applyCoupon.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAAE,cAAc,EAAE,MAAM,SAAS,CAAA;AACvD,OAAO,KAAK,EAAE,4BAA4B,EAAE,MAAM,UAAU,CAAA;
|
|
1
|
+
{"version":3,"file":"applyCoupon.d.ts","sourceRoot":"","sources":["../../src/endpoints/applyCoupon.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAAE,cAAc,EAAE,MAAM,SAAS,CAAA;AACvD,OAAO,KAAK,EAAE,4BAA4B,EAAE,MAAM,UAAU,CAAA;AAQ5D,KAAK,IAAI,GAAG;IACV,YAAY,EAAE,4BAA4B,CAAA;CAC3C,CAAA;AAcD,eAAO,MAAM,kBAAkB,GAC5B,kBAAkB,IAAI,KAAG,cAyFzB,CAAA;AA4TH,eAAO,MAAM,mBAAmB,GAAI,kBAAkB,IAAI,KAAG,QAI3D,CAAA"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"partnerStats.d.ts","sourceRoot":"","sources":["../../src/endpoints/partnerStats.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAAE,cAAc,EAAE,MAAM,SAAS,CAAA;AAEvD,OAAO,KAAK,EAAsC,4BAA4B,EAAE,MAAM,UAAU,CAAA;
|
|
1
|
+
{"version":3,"file":"partnerStats.d.ts","sourceRoot":"","sources":["../../src/endpoints/partnerStats.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAAE,cAAc,EAAE,MAAM,SAAS,CAAA;AAEvD,OAAO,KAAK,EAAsC,4BAA4B,EAAE,MAAM,UAAU,CAAA;AAGhG,KAAK,IAAI,GAAG;IACV,YAAY,EAAE,4BAA4B,CAAA;CAC3C,CAAA;AAED,eAAO,MAAM,mBAAmB,GAC7B,kBAAkB,IAAI,KAAG,cA6KzB,CAAA;AAEH,eAAO,MAAM,oBAAoB,GAAI,kBAAkB,IAAI,KAAG,QAI5D,CAAA"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"validateCoupon.d.ts","sourceRoot":"","sources":["../../src/endpoints/validateCoupon.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAAE,cAAc,EAAE,MAAM,SAAS,CAAA;AAEvD,OAAO,KAAK,EAAE,4BAA4B,EAAE,MAAM,UAAU,CAAA;
|
|
1
|
+
{"version":3,"file":"validateCoupon.d.ts","sourceRoot":"","sources":["../../src/endpoints/validateCoupon.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAAE,cAAc,EAAE,MAAM,SAAS,CAAA;AAEvD,OAAO,KAAK,EAAE,4BAA4B,EAAE,MAAM,UAAU,CAAA;AAO5D,KAAK,IAAI,GAAG;IACV,YAAY,EAAE,4BAA4B,CAAA;CAC3C,CAAA;AAED,eAAO,MAAM,qBAAqB,GAC/B,kBAAkB,IAAI,KAAG,cAkCzB,CAAA;AA4RH,eAAO,MAAM,sBAAsB,GAAI,kBAAkB,IAAI,KAAG,QAI9D,CAAA"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"recalculateCart.d.ts","sourceRoot":"","sources":["../../src/hooks/recalculateCart.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,0BAA0B,EAAE,MAAM,SAAS,CAAA;AACzD,OAAO,KAAK,EAAE,4BAA4B,EAAE,MAAM,UAAU,CAAA;
|
|
1
|
+
{"version":3,"file":"recalculateCart.d.ts","sourceRoot":"","sources":["../../src/hooks/recalculateCart.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,0BAA0B,EAAE,MAAM,SAAS,CAAA;AACzD,OAAO,KAAK,EAAE,4BAA4B,EAAE,MAAM,UAAU,CAAA;AAS5D,eAAO,MAAM,mBAAmB,GAC7B,cAAc,4BAA4B,KAAG,0BA2N7C,CAAA"}
|
package/dist/index.d.ts
CHANGED
|
@@ -3,10 +3,10 @@ import { createReferralCodesCollection } from './collections/createReferralCodes
|
|
|
3
3
|
import { createReferralProgramsCollection } from './collections/createReferralProgramsCollection';
|
|
4
4
|
import { payloadEcommerceCouponPlugin } from './plugin';
|
|
5
5
|
export { useCouponCode, usePartnerStats, validateCouponCode } from './client/hooks';
|
|
6
|
-
export { calculateCommissionAndDiscount } from './utilities/calculateValues';
|
|
6
|
+
export { calculateCommissionAndDiscount, getProgramMinimumOrderAmount, } from './utilities/calculateValues';
|
|
7
7
|
export { getCartTotalWithDiscounts } from './utilities/getCartTotalWithDiscounts';
|
|
8
8
|
export { recordCouponUsageForOrder } from './utilities/recordCouponUsageForOrder';
|
|
9
9
|
export { createCouponsCollection, createReferralCodesCollection, createReferralProgramsCollection, payloadEcommerceCouponPlugin as payloadEcommerceCoupon, };
|
|
10
|
-
export type { AdminGroupConfig, ApplyCouponHook, ApplyCouponResponse, CouponPluginAccess, CouponPluginCollections, CouponPluginOptions, OrderIntegrationConfig, PartnerDashboardConfig, PartnerDashboardData, PartnerStats, ReferralProgramConfig, } from './types';
|
|
10
|
+
export type { AdminGroupConfig, ApplyCouponHook, ApplyCouponResponse, CouponPluginAccess, CouponPluginCollections, CouponPluginOptions, OrderIntegrationConfig, PartnerDashboardConfig, PartnerDashboardData, PartnerStats, ReferralProgramConfig, RoleConfig, } from './types';
|
|
11
11
|
export type { CartLike } from './utilities/getCartTotalWithDiscounts';
|
|
12
12
|
//# sourceMappingURL=index.d.ts.map
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,uBAAuB,EAAE,MAAM,uCAAuC,CAAA;AAC/E,OAAO,EAAE,6BAA6B,EAAE,MAAM,6CAA6C,CAAA;AAC3F,OAAO,EAAE,gCAAgC,EAAE,MAAM,gDAAgD,CAAA;AACjG,OAAO,EAAE,4BAA4B,EAAE,MAAM,UAAU,CAAA;AAEvD,OAAO,EAAE,aAAa,EAAE,eAAe,EAAE,kBAAkB,EAAE,MAAM,gBAAgB,CAAA;AACnF,OAAO,
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,uBAAuB,EAAE,MAAM,uCAAuC,CAAA;AAC/E,OAAO,EAAE,6BAA6B,EAAE,MAAM,6CAA6C,CAAA;AAC3F,OAAO,EAAE,gCAAgC,EAAE,MAAM,gDAAgD,CAAA;AACjG,OAAO,EAAE,4BAA4B,EAAE,MAAM,UAAU,CAAA;AAEvD,OAAO,EAAE,aAAa,EAAE,eAAe,EAAE,kBAAkB,EAAE,MAAM,gBAAgB,CAAA;AACnF,OAAO,EACL,8BAA8B,EAC9B,4BAA4B,GAC7B,MAAM,6BAA6B,CAAA;AACpC,OAAO,EAAE,yBAAyB,EAAE,MAAM,uCAAuC,CAAA;AACjF,OAAO,EAAE,yBAAyB,EAAE,MAAM,uCAAuC,CAAA;AACjF,OAAO,EACL,uBAAuB,EACvB,6BAA6B,EAC7B,gCAAgC,EAChC,4BAA4B,IAAI,sBAAsB,GACvD,CAAA;AAED,YAAY,EACV,gBAAgB,EAChB,eAAe,EACf,mBAAmB,EACnB,kBAAkB,EAClB,uBAAuB,EACvB,mBAAmB,EACnB,sBAAsB,EACtB,sBAAsB,EACtB,oBAAoB,EACpB,YAAY,EACZ,qBAAqB,EACrB,UAAU,GACX,MAAM,SAAS,CAAA;AAChB,YAAY,EAAE,QAAQ,EAAE,MAAM,uCAAuC,CAAA"}
|
package/dist/index.js
CHANGED
|
@@ -120,10 +120,59 @@ const createCouponsCollection = (pluginConfig) => {
|
|
|
120
120
|
};
|
|
121
121
|
};
|
|
122
122
|
|
|
123
|
+
//#endregion
|
|
124
|
+
//#region src/utilities/userRoles.ts
|
|
125
|
+
function readByPath(input, path) {
|
|
126
|
+
if (!input || typeof input !== "object" || !path) return void 0;
|
|
127
|
+
return path.split(".").reduce((acc, key) => {
|
|
128
|
+
if (!acc || typeof acc !== "object") return void 0;
|
|
129
|
+
return acc[key];
|
|
130
|
+
}, input);
|
|
131
|
+
}
|
|
132
|
+
function toRoleArray(value) {
|
|
133
|
+
if (typeof value === "string" && value.trim().length > 0) return [value];
|
|
134
|
+
if (Array.isArray(value)) return value.filter((item) => typeof item === "string").map((item) => item.trim()).filter(Boolean);
|
|
135
|
+
return [];
|
|
136
|
+
}
|
|
137
|
+
const normalizeRoleValue = (value) => value.trim().toLowerCase();
|
|
138
|
+
const resolveUserRoles = ({ user, roleConfig }) => {
|
|
139
|
+
if (!user) return [];
|
|
140
|
+
if (typeof roleConfig.customRoleResolver === "function") {
|
|
141
|
+
const custom = roleConfig.customRoleResolver(user);
|
|
142
|
+
return Array.isArray(custom) ? custom.map(normalizeRoleValue).filter(Boolean) : [];
|
|
143
|
+
}
|
|
144
|
+
const roles = roleConfig.roleFieldPaths.flatMap((path) => toRoleArray(readByPath(user, path)));
|
|
145
|
+
return [...new Set(roles.map(normalizeRoleValue).filter(Boolean))];
|
|
146
|
+
};
|
|
147
|
+
const userHasAnyRole = ({ user, roleConfig, targetRoles }) => {
|
|
148
|
+
const userRoles = new Set(resolveUserRoles({
|
|
149
|
+
user,
|
|
150
|
+
roleConfig
|
|
151
|
+
}));
|
|
152
|
+
for (const target of targetRoles) if (userRoles.has(normalizeRoleValue(target))) return true;
|
|
153
|
+
return false;
|
|
154
|
+
};
|
|
155
|
+
const isPartnerUser = ({ user, roleConfig }) => userHasAnyRole({
|
|
156
|
+
user,
|
|
157
|
+
roleConfig,
|
|
158
|
+
targetRoles: roleConfig.partnerRoleValues
|
|
159
|
+
});
|
|
160
|
+
const isAdminUser = ({ user, roleConfig }) => userHasAnyRole({
|
|
161
|
+
user,
|
|
162
|
+
roleConfig,
|
|
163
|
+
targetRoles: roleConfig.adminRoleValues
|
|
164
|
+
});
|
|
165
|
+
const buildPartnerUserFilterWhere = ({ roleConfig }) => {
|
|
166
|
+
if (!roleConfig.roleFieldPaths.length || !roleConfig.partnerRoleValues.length) return true;
|
|
167
|
+
const conditions = roleConfig.roleFieldPaths.map((fieldPath) => ({ [fieldPath]: { in: roleConfig.partnerRoleValues } }));
|
|
168
|
+
if (conditions.length === 1) return conditions[0];
|
|
169
|
+
return { or: conditions };
|
|
170
|
+
};
|
|
171
|
+
|
|
123
172
|
//#endregion
|
|
124
173
|
//#region src/collections/createReferralCodesCollection.ts
|
|
125
174
|
const createReferralCodesCollection = (pluginConfig) => {
|
|
126
|
-
const { collections, access, adminGroups, defaultCurrency } = pluginConfig;
|
|
175
|
+
const { collections, access, adminGroups, defaultCurrency, roleConfig } = pluginConfig;
|
|
127
176
|
return {
|
|
128
177
|
slug: collections.referralCodesSlug,
|
|
129
178
|
admin: {
|
|
@@ -141,15 +190,27 @@ const createReferralCodesCollection = (pluginConfig) => {
|
|
|
141
190
|
read: ({ req }) => {
|
|
142
191
|
const user = req?.user;
|
|
143
192
|
if (!user) return false;
|
|
144
|
-
if (
|
|
145
|
-
|
|
193
|
+
if (isAdminUser({
|
|
194
|
+
user,
|
|
195
|
+
roleConfig
|
|
196
|
+
}) || access.isAdmin?.({ req })) return true;
|
|
197
|
+
if (isPartnerUser({
|
|
198
|
+
user,
|
|
199
|
+
roleConfig
|
|
200
|
+
}) || access.isPartner?.({ req })) return { partner: { equals: user.id } };
|
|
146
201
|
return access.canUseReferrals ? access.canUseReferrals({ req }) : false;
|
|
147
202
|
},
|
|
148
203
|
create: ({ req }) => {
|
|
149
204
|
const user = req?.user;
|
|
150
205
|
if (!user) return false;
|
|
151
|
-
if (
|
|
152
|
-
|
|
206
|
+
if (isAdminUser({
|
|
207
|
+
user,
|
|
208
|
+
roleConfig
|
|
209
|
+
}) || access.isAdmin?.({ req })) return true;
|
|
210
|
+
if (isPartnerUser({
|
|
211
|
+
user,
|
|
212
|
+
roleConfig
|
|
213
|
+
}) || access.isPartner?.({ req })) return true;
|
|
153
214
|
return access.isAdmin ? access.isAdmin({ req }) : false;
|
|
154
215
|
},
|
|
155
216
|
update: access.isAdmin || (() => false),
|
|
@@ -175,11 +236,12 @@ const createReferralCodesCollection = (pluginConfig) => {
|
|
|
175
236
|
type: "relationship",
|
|
176
237
|
relationTo: "users",
|
|
177
238
|
required: true,
|
|
178
|
-
filterOptions: ({
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
return
|
|
239
|
+
filterOptions: ({ req, user }) => {
|
|
240
|
+
if (isAdminUser({
|
|
241
|
+
user: user || req?.user,
|
|
242
|
+
roleConfig
|
|
243
|
+
}) || access.isAdmin?.({ req })) return true;
|
|
244
|
+
return buildPartnerUserFilterWhere({ roleConfig });
|
|
183
245
|
},
|
|
184
246
|
admin: { description: "The partner who owns this referral code" }
|
|
185
247
|
},
|
|
@@ -257,7 +319,10 @@ const createReferralCodesCollection = (pluginConfig) => {
|
|
|
257
319
|
if (operation === "create" && !data.code && data.partner) data.code = `REF-${Date.now().toString(36)}-${Math.random().toString(36).substring(2, 8)}`.toUpperCase();
|
|
258
320
|
if (operation === "create" && req.user) {
|
|
259
321
|
const user = req.user;
|
|
260
|
-
if (
|
|
322
|
+
if (isPartnerUser({
|
|
323
|
+
user,
|
|
324
|
+
roleConfig
|
|
325
|
+
})) data.partner = user.id;
|
|
261
326
|
}
|
|
262
327
|
return data;
|
|
263
328
|
}] },
|
|
@@ -279,6 +344,7 @@ const deriveCustomerSplit = (partnerSplit) => {
|
|
|
279
344
|
};
|
|
280
345
|
const createReferralProgramsCollection = (pluginConfig) => {
|
|
281
346
|
const { collections, access, defaultCurrency, adminGroups, referralConfig } = pluginConfig;
|
|
347
|
+
const allowedTotalCommissionTypes = referralConfig.allowedTotalCommissionTypes;
|
|
282
348
|
return {
|
|
283
349
|
slug: collections.referralProgramsSlug,
|
|
284
350
|
admin: {
|
|
@@ -301,7 +367,7 @@ const createReferralProgramsCollection = (pluginConfig) => {
|
|
|
301
367
|
data.commissionRules = data.commissionRules.map((rule, index) => {
|
|
302
368
|
const r = rule;
|
|
303
369
|
if (!r.totalCommission) throw new Error(`Commission rule ${index + 1}: Total Commission is required`);
|
|
304
|
-
if (!r.totalCommission.type || !
|
|
370
|
+
if (!r.totalCommission.type || !allowedTotalCommissionTypes.includes(r.totalCommission.type)) throw new Error(`Commission rule ${index + 1}: Total Commission type must be one of ${allowedTotalCommissionTypes.join(", ")}`);
|
|
305
371
|
const totalValue = toNumber(r.totalCommission.value);
|
|
306
372
|
if (totalValue == null || totalValue < 0) throw new Error(`Commission rule ${index + 1}: Total Commission value must be a non-negative number`);
|
|
307
373
|
if (r.totalCommission.type === "percentage" && totalValue > 100) throw new Error(`Commission rule ${index + 1}: Percentage Total Commission cannot exceed 100`);
|
|
@@ -313,6 +379,8 @@ const createReferralProgramsCollection = (pluginConfig) => {
|
|
|
313
379
|
const partnerSplit = toNumber(r.partnerSplit);
|
|
314
380
|
if (partnerSplit == null || partnerSplit < 0 || partnerSplit > 100) throw new Error(`Commission rule ${index + 1}: Partner Split must be between 0 and 100`);
|
|
315
381
|
const customerSplit = 100 - partnerSplit;
|
|
382
|
+
const minOrderAmount = toNumber(r.minOrderAmount);
|
|
383
|
+
if (minOrderAmount != null && minOrderAmount < 0) throw new Error(`Commission rule ${index + 1}: Minimum Order Amount must be a non-negative number`);
|
|
316
384
|
return {
|
|
317
385
|
...rule,
|
|
318
386
|
appliesTo: appliesTo === "categories" ? "segments" : appliesTo,
|
|
@@ -322,7 +390,8 @@ const createReferralProgramsCollection = (pluginConfig) => {
|
|
|
322
390
|
maxAmount: maxAmount ?? null
|
|
323
391
|
},
|
|
324
392
|
partnerSplit,
|
|
325
|
-
customerSplit
|
|
393
|
+
customerSplit,
|
|
394
|
+
minOrderAmount: minOrderAmount ?? null
|
|
326
395
|
};
|
|
327
396
|
});
|
|
328
397
|
return data;
|
|
@@ -412,14 +481,11 @@ const createReferralProgramsCollection = (pluginConfig) => {
|
|
|
412
481
|
name: "type",
|
|
413
482
|
type: "select",
|
|
414
483
|
required: true,
|
|
415
|
-
options:
|
|
416
|
-
label: "Fixed Amount",
|
|
417
|
-
value
|
|
418
|
-
},
|
|
419
|
-
|
|
420
|
-
value: "percentage"
|
|
421
|
-
}],
|
|
422
|
-
defaultValue: "percentage"
|
|
484
|
+
options: allowedTotalCommissionTypes.map((value) => ({
|
|
485
|
+
label: value === "fixed" ? "Fixed Amount" : "Percentage of Order",
|
|
486
|
+
value
|
|
487
|
+
})),
|
|
488
|
+
defaultValue: allowedTotalCommissionTypes.includes("fixed") ? "fixed" : "percentage"
|
|
423
489
|
},
|
|
424
490
|
{
|
|
425
491
|
name: "value",
|
|
@@ -445,6 +511,12 @@ const createReferralProgramsCollection = (pluginConfig) => {
|
|
|
445
511
|
defaultValue: referralConfig.defaultPartnerSplit,
|
|
446
512
|
admin: { description: "Percentage of total commission given to Partner (0-100)" }
|
|
447
513
|
},
|
|
514
|
+
{
|
|
515
|
+
name: "minOrderAmount",
|
|
516
|
+
type: "number",
|
|
517
|
+
min: 0,
|
|
518
|
+
admin: { description: `Minimum cart subtotal required for this rule in ${defaultCurrency}. Leave empty for no minimum.` }
|
|
519
|
+
},
|
|
448
520
|
{
|
|
449
521
|
name: "customerSplit",
|
|
450
522
|
type: "number",
|
|
@@ -531,6 +603,7 @@ function relationId(value) {
|
|
|
531
603
|
if (typeof value === "object" && (typeof value.id === "string" || typeof value.id === "number")) return value.id;
|
|
532
604
|
return null;
|
|
533
605
|
}
|
|
606
|
+
const allowedCommissionTypesSet = (allowed) => new Set((allowed && allowed.length ? allowed : ["fixed", "percentage"]).map((v) => v));
|
|
534
607
|
function normalizeIds(values) {
|
|
535
608
|
if (!Array.isArray(values)) return [];
|
|
536
609
|
return values.map(relationId).filter((v) => v != null);
|
|
@@ -543,8 +616,10 @@ function getRuleSplits(rule) {
|
|
|
543
616
|
customerSplit: typeof rule.customerSplit === "number" ? rule.customerSplit : typeof rule.refereeSplit === "number" ? rule.refereeSplit : 100 - partnerRaw
|
|
544
617
|
};
|
|
545
618
|
}
|
|
546
|
-
function calculateItemRewardByRule({ rule, itemTotal, quantity }) {
|
|
619
|
+
function calculateItemRewardByRule({ rule, itemTotal, quantity, allowedTotalCommissionTypes }) {
|
|
620
|
+
const allowedTypes = allowedCommissionTypesSet(allowedTotalCommissionTypes);
|
|
547
621
|
if (rule.totalCommission) {
|
|
622
|
+
if (!allowedTypes.has(rule.totalCommission.type)) return null;
|
|
548
623
|
const splits = getRuleSplits(rule);
|
|
549
624
|
if (!splits) return null;
|
|
550
625
|
let totalPot = 0;
|
|
@@ -583,21 +658,27 @@ function getItemCategoryIds(item) {
|
|
|
583
658
|
function getItemTagIds(item) {
|
|
584
659
|
return Array.isArray(item?.product?.tags) ? normalizeIds(item.product.tags) : [];
|
|
585
660
|
}
|
|
586
|
-
function selectBestRuleForItem({ rules, item, itemTotal, quantity }) {
|
|
661
|
+
function selectBestRuleForItem({ rules, item, itemTotal, quantity, cartTotal, allowedTotalCommissionTypes }) {
|
|
662
|
+
const allowedTypes = allowedCommissionTypesSet(allowedTotalCommissionTypes);
|
|
663
|
+
const eligibleRules = rules.filter((rule) => {
|
|
664
|
+
if (!(rule?.totalCommission?.type ? allowedTypes.has(rule.totalCommission.type) : true)) return false;
|
|
665
|
+
if (typeof rule?.minOrderAmount === "number" && Number.isFinite(rule.minOrderAmount)) return cartTotal >= rule.minOrderAmount;
|
|
666
|
+
return true;
|
|
667
|
+
});
|
|
587
668
|
const productId = relationId(item.product);
|
|
588
669
|
const itemCategoryIds = new Set(getItemCategoryIds(item));
|
|
589
670
|
const itemTagIds = new Set(getItemTagIds(item));
|
|
590
671
|
const candidates = [
|
|
591
|
-
|
|
592
|
-
|
|
672
|
+
eligibleRules.filter((r) => r.appliesTo === "products" && normalizeIds(r.products).some((id) => productId != null && id === productId)),
|
|
673
|
+
eligibleRules.filter((r) => {
|
|
593
674
|
if (!(r.appliesTo === "segments" || r.appliesTo === "categories")) return false;
|
|
594
675
|
return normalizeIds(r.categories).some((id) => itemCategoryIds.has(id));
|
|
595
676
|
}),
|
|
596
|
-
|
|
677
|
+
eligibleRules.filter((r) => {
|
|
597
678
|
if (r.appliesTo !== "segments") return false;
|
|
598
679
|
return normalizeIds(r.tags).some((id) => itemTagIds.has(id));
|
|
599
680
|
}),
|
|
600
|
-
|
|
681
|
+
eligibleRules.filter((r) => r.appliesTo === "all")
|
|
601
682
|
].find((level) => level.length > 0) ?? [];
|
|
602
683
|
if (!candidates.length) return null;
|
|
603
684
|
let best = null;
|
|
@@ -605,7 +686,8 @@ function selectBestRuleForItem({ rules, item, itemTotal, quantity }) {
|
|
|
605
686
|
const reward = calculateItemRewardByRule({
|
|
606
687
|
rule,
|
|
607
688
|
itemTotal,
|
|
608
|
-
quantity
|
|
689
|
+
quantity,
|
|
690
|
+
allowedTotalCommissionTypes
|
|
609
691
|
});
|
|
610
692
|
if (!reward) continue;
|
|
611
693
|
if (!best) {
|
|
@@ -629,7 +711,18 @@ function selectBestRuleForItem({ rules, item, itemTotal, quantity }) {
|
|
|
629
711
|
}
|
|
630
712
|
return best;
|
|
631
713
|
}
|
|
632
|
-
function
|
|
714
|
+
function getProgramMinimumOrderAmount({ program, allowedTotalCommissionTypes }) {
|
|
715
|
+
const rules = Array.isArray(program?.commissionRules) ? program.commissionRules : [];
|
|
716
|
+
if (!rules.length) return null;
|
|
717
|
+
const allowedTypes = allowedCommissionTypesSet(allowedTotalCommissionTypes);
|
|
718
|
+
const minValues = rules.filter((rule) => {
|
|
719
|
+
if (rule?.totalCommission?.type) return allowedTypes.has(rule.totalCommission.type);
|
|
720
|
+
return true;
|
|
721
|
+
}).map((rule) => rule?.minOrderAmount).filter((value) => typeof value === "number" && Number.isFinite(value));
|
|
722
|
+
if (!minValues.length) return null;
|
|
723
|
+
return Math.min(...minValues);
|
|
724
|
+
}
|
|
725
|
+
function calculateCommissionAndDiscount({ cartItems, program, currencyCode = "AED", cartTotal = 0, allowedTotalCommissionTypes }) {
|
|
633
726
|
const rules = Array.isArray(program?.commissionRules) ? program.commissionRules : [];
|
|
634
727
|
if (!rules.length) return {
|
|
635
728
|
partnerCommission: 0,
|
|
@@ -654,7 +747,9 @@ function calculateCommissionAndDiscount({ cartItems, program, currencyCode = "AE
|
|
|
654
747
|
product
|
|
655
748
|
},
|
|
656
749
|
itemTotal,
|
|
657
|
-
quantity
|
|
750
|
+
quantity,
|
|
751
|
+
cartTotal,
|
|
752
|
+
allowedTotalCommissionTypes
|
|
658
753
|
});
|
|
659
754
|
if (!bestMatch) continue;
|
|
660
755
|
totalPartnerCommission += bestMatch.reward.partner;
|
|
@@ -882,10 +977,20 @@ async function handleReferralCode({ payload, code, cartID, cart, customerEmail:
|
|
|
882
977
|
error: "Referral code already applied to this cart"
|
|
883
978
|
}, { status: 400 });
|
|
884
979
|
const cartTotal = cart.subtotal || cart.total || 0;
|
|
980
|
+
const minOrderAmount = getProgramMinimumOrderAmount({
|
|
981
|
+
program,
|
|
982
|
+
allowedTotalCommissionTypes: pluginConfig.referralConfig.allowedTotalCommissionTypes
|
|
983
|
+
});
|
|
984
|
+
if (typeof minOrderAmount === "number" && cartTotal < minOrderAmount) return Response.json({
|
|
985
|
+
success: false,
|
|
986
|
+
error: `Minimum order value of ${minOrderAmount} ${pluginConfig.defaultCurrency} required for this referral program`
|
|
987
|
+
}, { status: 400 });
|
|
885
988
|
const { partnerCommission, customerDiscount } = calculateCommissionAndDiscount({
|
|
886
989
|
cartItems: cart.items || [],
|
|
887
990
|
program,
|
|
888
|
-
currencyCode: pluginConfig.defaultCurrency
|
|
991
|
+
currencyCode: pluginConfig.defaultCurrency,
|
|
992
|
+
cartTotal,
|
|
993
|
+
allowedTotalCommissionTypes: pluginConfig.referralConfig.allowedTotalCommissionTypes
|
|
889
994
|
});
|
|
890
995
|
const roundedPartnerCommission = roundTo2(partnerCommission);
|
|
891
996
|
const roundedCustomerDiscount = roundTo2(customerDiscount);
|
|
@@ -925,8 +1030,14 @@ const partnerStatsHandler = ({ pluginConfig }) => async (req) => {
|
|
|
925
1030
|
error: "Authentication required"
|
|
926
1031
|
}, { status: 401 });
|
|
927
1032
|
const typedUser = user;
|
|
928
|
-
const isPartner =
|
|
929
|
-
|
|
1033
|
+
const isPartner = isPartnerUser({
|
|
1034
|
+
user: typedUser,
|
|
1035
|
+
roleConfig: pluginConfig.roleConfig
|
|
1036
|
+
}) || pluginConfig.access.isPartner?.({ req });
|
|
1037
|
+
const isAdmin = isAdminUser({
|
|
1038
|
+
user: typedUser,
|
|
1039
|
+
roleConfig: pluginConfig.roleConfig
|
|
1040
|
+
}) || pluginConfig.access.isAdmin?.({ req });
|
|
930
1041
|
if (!isPartner && !isAdmin) return Response.json({
|
|
931
1042
|
success: false,
|
|
932
1043
|
error: "Partner access required"
|
|
@@ -1206,12 +1317,22 @@ async function validateReferralCode({ payload, code, cartID, pluginConfig }) {
|
|
|
1206
1317
|
id: cartID,
|
|
1207
1318
|
depth: 2
|
|
1208
1319
|
}) : null;
|
|
1320
|
+
const cartTotal = cart ? cart.subtotal || cart.total || 0 : 0;
|
|
1321
|
+
const minOrderAmount = getProgramMinimumOrderAmount({
|
|
1322
|
+
program,
|
|
1323
|
+
allowedTotalCommissionTypes: pluginConfig.referralConfig.allowedTotalCommissionTypes
|
|
1324
|
+
});
|
|
1325
|
+
if (typeof minOrderAmount === "number" && cartTotal < minOrderAmount) return Response.json({
|
|
1326
|
+
success: false,
|
|
1327
|
+
error: `Minimum order value of ${minOrderAmount} ${pluginConfig.defaultCurrency} required for this referral program`
|
|
1328
|
+
}, { status: 400 });
|
|
1209
1329
|
const { partnerCommission, customerDiscount } = calculateCommissionAndDiscount({
|
|
1210
1330
|
cartItems: cart?.items || [],
|
|
1211
1331
|
program,
|
|
1212
|
-
currencyCode: pluginConfig.defaultCurrency
|
|
1332
|
+
currencyCode: pluginConfig.defaultCurrency,
|
|
1333
|
+
cartTotal,
|
|
1334
|
+
allowedTotalCommissionTypes: pluginConfig.referralConfig.allowedTotalCommissionTypes
|
|
1213
1335
|
});
|
|
1214
|
-
const cartTotal = cart ? cart.subtotal || cart.total || 0 : 0;
|
|
1215
1336
|
const cappedCustomerDiscount = cartTotal > 0 ? Math.min(customerDiscount, cartTotal) : customerDiscount;
|
|
1216
1337
|
const roundedPartnerCommission = roundTo2(partnerCommission);
|
|
1217
1338
|
const roundedCustomerDiscount = roundTo2(cappedCustomerDiscount);
|
|
@@ -1237,12 +1358,6 @@ const validateCouponEndpoint = ({ pluginConfig }) => ({
|
|
|
1237
1358
|
const recalculateCartHook = (pluginConfig) => async ({ data, req, originalDoc }) => {
|
|
1238
1359
|
if (!req.payload) return data;
|
|
1239
1360
|
const effectiveItems = data.items || originalDoc?.items || [];
|
|
1240
|
-
console.log("[RecalculateCart] Hook triggered", {
|
|
1241
|
-
hasDataItems: !!data.items,
|
|
1242
|
-
dataItemsCount: data.items?.length,
|
|
1243
|
-
originalItemsCount: originalDoc?.items?.length,
|
|
1244
|
-
effectiveItemsCount: effectiveItems.length
|
|
1245
|
-
});
|
|
1246
1361
|
if (!effectiveItems.length) return {
|
|
1247
1362
|
...data,
|
|
1248
1363
|
partnerCommission: 0,
|
|
@@ -1289,12 +1404,6 @@ const recalculateCartHook = (pluginConfig) => async ({ data, req, originalDoc })
|
|
|
1289
1404
|
currencyCode: pluginConfig.defaultCurrency
|
|
1290
1405
|
});
|
|
1291
1406
|
calculatedSubtotal += itemPrice * (item.quantity ?? 1);
|
|
1292
|
-
console.log("[RecalculateCart] Item processed", {
|
|
1293
|
-
productId,
|
|
1294
|
-
quantity: item.quantity,
|
|
1295
|
-
priceUsed: itemPrice,
|
|
1296
|
-
currentSubtotal: calculatedSubtotal
|
|
1297
|
-
});
|
|
1298
1407
|
return {
|
|
1299
1408
|
...item,
|
|
1300
1409
|
product,
|
|
@@ -1323,16 +1432,30 @@ const recalculateCartHook = (pluginConfig) => async ({ data, req, originalDoc })
|
|
|
1323
1432
|
id: programId
|
|
1324
1433
|
}) : null;
|
|
1325
1434
|
if (program) {
|
|
1435
|
+
const minOrderAmount = getProgramMinimumOrderAmount({
|
|
1436
|
+
program,
|
|
1437
|
+
allowedTotalCommissionTypes: pluginConfig.referralConfig.allowedTotalCommissionTypes
|
|
1438
|
+
});
|
|
1439
|
+
if (typeof minOrderAmount === "number" && calculatedSubtotal < minOrderAmount) {
|
|
1440
|
+
data.appliedReferralCode = null;
|
|
1441
|
+
data.partnerCommission = 0;
|
|
1442
|
+
data.customerDiscount = 0;
|
|
1443
|
+
data.total = calculatedSubtotal;
|
|
1444
|
+
return data;
|
|
1445
|
+
}
|
|
1326
1446
|
const { partnerCommission, customerDiscount } = calculateCommissionAndDiscount({
|
|
1327
1447
|
cartItems: enrichedItems,
|
|
1328
1448
|
program,
|
|
1329
|
-
currencyCode: pluginConfig.defaultCurrency
|
|
1449
|
+
currencyCode: pluginConfig.defaultCurrency,
|
|
1450
|
+
cartTotal: calculatedSubtotal,
|
|
1451
|
+
allowedTotalCommissionTypes: pluginConfig.referralConfig.allowedTotalCommissionTypes
|
|
1330
1452
|
});
|
|
1331
1453
|
const roundedCustomerDiscount = roundTo2(customerDiscount);
|
|
1332
1454
|
data.partnerCommission = roundTo2(partnerCommission);
|
|
1333
1455
|
data.customerDiscount = roundedCustomerDiscount;
|
|
1334
1456
|
data.total = Math.max(0, calculatedSubtotal - roundedCustomerDiscount);
|
|
1335
1457
|
} else {
|
|
1458
|
+
data.appliedReferralCode = null;
|
|
1336
1459
|
data.partnerCommission = 0;
|
|
1337
1460
|
data.customerDiscount = 0;
|
|
1338
1461
|
data.total = calculatedSubtotal;
|
|
@@ -1353,12 +1476,6 @@ const recalculateCartHook = (pluginConfig) => async ({ data, req, originalDoc })
|
|
|
1353
1476
|
coupon,
|
|
1354
1477
|
cartTotal: calculatedSubtotal
|
|
1355
1478
|
});
|
|
1356
|
-
console.log("[RecalculateCart] Coupon Logic", {
|
|
1357
|
-
appliedCoupon,
|
|
1358
|
-
couponId: coupon.id,
|
|
1359
|
-
cartTotal: calculatedSubtotal,
|
|
1360
|
-
discountAmount
|
|
1361
|
-
});
|
|
1362
1479
|
data.discountAmount = discountAmount;
|
|
1363
1480
|
const currentDiscount = data.customerDiscount || 0;
|
|
1364
1481
|
data.total = Math.max(0, calculatedSubtotal - currentDiscount - discountAmount);
|
|
@@ -1370,6 +1487,13 @@ const recalculateCartHook = (pluginConfig) => async ({ data, req, originalDoc })
|
|
|
1370
1487
|
//#endregion
|
|
1371
1488
|
//#region src/utilities/sanitizePluginConfig.ts
|
|
1372
1489
|
const sanitizePluginConfig = ({ pluginConfig }) => {
|
|
1490
|
+
const roleConfig = {
|
|
1491
|
+
roleFieldPaths: Array.isArray(pluginConfig?.roleConfig?.roleFieldPaths) && pluginConfig.roleConfig.roleFieldPaths.length > 0 ? pluginConfig.roleConfig.roleFieldPaths.filter((value) => typeof value === "string").map((value) => value.trim()).filter(Boolean) : ["role", "roles"],
|
|
1492
|
+
adminRoleValues: Array.isArray(pluginConfig?.roleConfig?.adminRoleValues) && pluginConfig.roleConfig.adminRoleValues.length > 0 ? pluginConfig.roleConfig.adminRoleValues.filter((value) => typeof value === "string").map((value) => value.trim()).filter(Boolean) : ["admin"],
|
|
1493
|
+
partnerRoleValues: Array.isArray(pluginConfig?.roleConfig?.partnerRoleValues) && pluginConfig.roleConfig.partnerRoleValues.length > 0 ? pluginConfig.roleConfig.partnerRoleValues.filter((value) => typeof value === "string").map((value) => value.trim()).filter(Boolean) : ["partner"],
|
|
1494
|
+
customRoleResolver: typeof pluginConfig?.roleConfig?.customRoleResolver === "function" ? pluginConfig.roleConfig.customRoleResolver : void 0
|
|
1495
|
+
};
|
|
1496
|
+
const normalizedAllowedTotalCommissionTypes = Array.isArray(pluginConfig?.referralConfig?.allowedTotalCommissionTypes) ? [...new Set(pluginConfig.referralConfig.allowedTotalCommissionTypes.filter((value) => value === "fixed" || value === "percentage"))] : [];
|
|
1373
1497
|
return {
|
|
1374
1498
|
enabled: !(pluginConfig?.enabled === false || typeof pluginConfig?.enabled === "string" && pluginConfig.enabled === "false"),
|
|
1375
1499
|
enableReferrals: !!pluginConfig?.enableReferrals && (typeof pluginConfig?.enableReferrals !== "string" || pluginConfig.enableReferrals !== "false"),
|
|
@@ -1391,20 +1515,21 @@ const sanitizePluginConfig = ({ pluginConfig }) => {
|
|
|
1391
1515
|
access: {
|
|
1392
1516
|
canUseCoupons: typeof pluginConfig?.access?.canUseCoupons === "function" ? pluginConfig.access.canUseCoupons : () => true,
|
|
1393
1517
|
canUseReferrals: typeof pluginConfig?.access?.canUseReferrals === "function" ? pluginConfig.access.canUseReferrals : () => false,
|
|
1394
|
-
isAdmin: typeof pluginConfig?.access?.isAdmin === "function" ? pluginConfig.access.isAdmin : () =>
|
|
1395
|
-
|
|
1396
|
-
|
|
1397
|
-
|
|
1398
|
-
|
|
1399
|
-
|
|
1400
|
-
|
|
1401
|
-
}
|
|
1518
|
+
isAdmin: typeof pluginConfig?.access?.isAdmin === "function" ? pluginConfig.access.isAdmin : ({ req }) => isAdminUser({
|
|
1519
|
+
user: req?.user,
|
|
1520
|
+
roleConfig
|
|
1521
|
+
}),
|
|
1522
|
+
isPartner: typeof pluginConfig?.access?.isPartner === "function" ? pluginConfig.access.isPartner : ({ req }) => isPartnerUser({
|
|
1523
|
+
user: req?.user,
|
|
1524
|
+
roleConfig
|
|
1525
|
+
})
|
|
1402
1526
|
},
|
|
1403
1527
|
referralConfig: {
|
|
1404
1528
|
allowBothSystems: pluginConfig?.referralConfig?.allowBothSystems ?? false,
|
|
1405
1529
|
singleCodePerCart: pluginConfig?.referralConfig?.singleCodePerCart ?? true,
|
|
1406
1530
|
defaultPartnerSplit: pluginConfig?.referralConfig?.defaultPartnerSplit ?? 70,
|
|
1407
|
-
defaultCustomerSplit: pluginConfig?.referralConfig?.defaultCustomerSplit ?? 30
|
|
1531
|
+
defaultCustomerSplit: pluginConfig?.referralConfig?.defaultCustomerSplit ?? 30,
|
|
1532
|
+
allowedTotalCommissionTypes: normalizedAllowedTotalCommissionTypes.length > 0 ? normalizedAllowedTotalCommissionTypes : ["fixed", "percentage"]
|
|
1408
1533
|
},
|
|
1409
1534
|
adminGroups: {
|
|
1410
1535
|
couponsGroup: pluginConfig?.adminGroups?.couponsGroup ?? "Coupons",
|
|
@@ -1422,7 +1547,8 @@ const sanitizePluginConfig = ({ pluginConfig }) => {
|
|
|
1422
1547
|
orderCustomerEmailField: typeof pluginConfig?.orderIntegration?.orderCustomerEmailField === "string" && pluginConfig.orderIntegration.orderCustomerEmailField.trim().length > 0 ? pluginConfig.orderIntegration.orderCustomerEmailField : "customerEmail",
|
|
1423
1548
|
orderPaymentStatusField: typeof pluginConfig?.orderIntegration?.orderPaymentStatusField === "string" && pluginConfig.orderIntegration.orderPaymentStatusField.trim().length > 0 ? pluginConfig.orderIntegration.orderPaymentStatusField : "paymentStatus",
|
|
1424
1549
|
orderPaidStatusValue: typeof pluginConfig?.orderIntegration?.orderPaidStatusValue === "string" ? pluginConfig.orderIntegration.orderPaidStatusValue : "paid"
|
|
1425
|
-
}
|
|
1550
|
+
},
|
|
1551
|
+
roleConfig
|
|
1426
1552
|
};
|
|
1427
1553
|
};
|
|
1428
1554
|
|
|
@@ -1814,6 +1940,7 @@ exports.createCouponsCollection = createCouponsCollection;
|
|
|
1814
1940
|
exports.createReferralCodesCollection = createReferralCodesCollection;
|
|
1815
1941
|
exports.createReferralProgramsCollection = createReferralProgramsCollection;
|
|
1816
1942
|
exports.getCartTotalWithDiscounts = getCartTotalWithDiscounts;
|
|
1943
|
+
exports.getProgramMinimumOrderAmount = getProgramMinimumOrderAmount;
|
|
1817
1944
|
exports.payloadEcommerceCoupon = payloadEcommerceCouponPlugin;
|
|
1818
1945
|
exports.recordCouponUsageForOrder = recordCouponUsageForOrder;
|
|
1819
1946
|
exports.useCouponCode = useCouponCode;
|