@wtree/payload-ecommerce-coupon 3.77.0 → 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 +192 -60
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +192 -61
- 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,7 +236,13 @@ const createReferralCodesCollection = (pluginConfig) => {
|
|
|
175
236
|
type: "relationship",
|
|
176
237
|
relationTo: "users",
|
|
177
238
|
required: true,
|
|
178
|
-
filterOptions: {
|
|
239
|
+
filterOptions: ({ req, user }) => {
|
|
240
|
+
if (isAdminUser({
|
|
241
|
+
user: user || req?.user,
|
|
242
|
+
roleConfig
|
|
243
|
+
}) || access.isAdmin?.({ req })) return true;
|
|
244
|
+
return buildPartnerUserFilterWhere({ roleConfig });
|
|
245
|
+
},
|
|
179
246
|
admin: { description: "The partner who owns this referral code" }
|
|
180
247
|
},
|
|
181
248
|
{
|
|
@@ -252,7 +319,10 @@ const createReferralCodesCollection = (pluginConfig) => {
|
|
|
252
319
|
if (operation === "create" && !data.code && data.partner) data.code = `REF-${Date.now().toString(36)}-${Math.random().toString(36).substring(2, 8)}`.toUpperCase();
|
|
253
320
|
if (operation === "create" && req.user) {
|
|
254
321
|
const user = req.user;
|
|
255
|
-
if (
|
|
322
|
+
if (isPartnerUser({
|
|
323
|
+
user,
|
|
324
|
+
roleConfig
|
|
325
|
+
})) data.partner = user.id;
|
|
256
326
|
}
|
|
257
327
|
return data;
|
|
258
328
|
}] },
|
|
@@ -274,6 +344,7 @@ const deriveCustomerSplit = (partnerSplit) => {
|
|
|
274
344
|
};
|
|
275
345
|
const createReferralProgramsCollection = (pluginConfig) => {
|
|
276
346
|
const { collections, access, defaultCurrency, adminGroups, referralConfig } = pluginConfig;
|
|
347
|
+
const allowedTotalCommissionTypes = referralConfig.allowedTotalCommissionTypes;
|
|
277
348
|
return {
|
|
278
349
|
slug: collections.referralProgramsSlug,
|
|
279
350
|
admin: {
|
|
@@ -296,7 +367,7 @@ const createReferralProgramsCollection = (pluginConfig) => {
|
|
|
296
367
|
data.commissionRules = data.commissionRules.map((rule, index) => {
|
|
297
368
|
const r = rule;
|
|
298
369
|
if (!r.totalCommission) throw new Error(`Commission rule ${index + 1}: Total Commission is required`);
|
|
299
|
-
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(", ")}`);
|
|
300
371
|
const totalValue = toNumber(r.totalCommission.value);
|
|
301
372
|
if (totalValue == null || totalValue < 0) throw new Error(`Commission rule ${index + 1}: Total Commission value must be a non-negative number`);
|
|
302
373
|
if (r.totalCommission.type === "percentage" && totalValue > 100) throw new Error(`Commission rule ${index + 1}: Percentage Total Commission cannot exceed 100`);
|
|
@@ -308,6 +379,8 @@ const createReferralProgramsCollection = (pluginConfig) => {
|
|
|
308
379
|
const partnerSplit = toNumber(r.partnerSplit);
|
|
309
380
|
if (partnerSplit == null || partnerSplit < 0 || partnerSplit > 100) throw new Error(`Commission rule ${index + 1}: Partner Split must be between 0 and 100`);
|
|
310
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`);
|
|
311
384
|
return {
|
|
312
385
|
...rule,
|
|
313
386
|
appliesTo: appliesTo === "categories" ? "segments" : appliesTo,
|
|
@@ -317,7 +390,8 @@ const createReferralProgramsCollection = (pluginConfig) => {
|
|
|
317
390
|
maxAmount: maxAmount ?? null
|
|
318
391
|
},
|
|
319
392
|
partnerSplit,
|
|
320
|
-
customerSplit
|
|
393
|
+
customerSplit,
|
|
394
|
+
minOrderAmount: minOrderAmount ?? null
|
|
321
395
|
};
|
|
322
396
|
});
|
|
323
397
|
return data;
|
|
@@ -407,14 +481,11 @@ const createReferralProgramsCollection = (pluginConfig) => {
|
|
|
407
481
|
name: "type",
|
|
408
482
|
type: "select",
|
|
409
483
|
required: true,
|
|
410
|
-
options:
|
|
411
|
-
label: "Fixed Amount",
|
|
412
|
-
value
|
|
413
|
-
},
|
|
414
|
-
|
|
415
|
-
value: "percentage"
|
|
416
|
-
}],
|
|
417
|
-
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"
|
|
418
489
|
},
|
|
419
490
|
{
|
|
420
491
|
name: "value",
|
|
@@ -440,6 +511,12 @@ const createReferralProgramsCollection = (pluginConfig) => {
|
|
|
440
511
|
defaultValue: referralConfig.defaultPartnerSplit,
|
|
441
512
|
admin: { description: "Percentage of total commission given to Partner (0-100)" }
|
|
442
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
|
+
},
|
|
443
520
|
{
|
|
444
521
|
name: "customerSplit",
|
|
445
522
|
type: "number",
|
|
@@ -526,6 +603,7 @@ function relationId(value) {
|
|
|
526
603
|
if (typeof value === "object" && (typeof value.id === "string" || typeof value.id === "number")) return value.id;
|
|
527
604
|
return null;
|
|
528
605
|
}
|
|
606
|
+
const allowedCommissionTypesSet = (allowed) => new Set((allowed && allowed.length ? allowed : ["fixed", "percentage"]).map((v) => v));
|
|
529
607
|
function normalizeIds(values) {
|
|
530
608
|
if (!Array.isArray(values)) return [];
|
|
531
609
|
return values.map(relationId).filter((v) => v != null);
|
|
@@ -538,8 +616,10 @@ function getRuleSplits(rule) {
|
|
|
538
616
|
customerSplit: typeof rule.customerSplit === "number" ? rule.customerSplit : typeof rule.refereeSplit === "number" ? rule.refereeSplit : 100 - partnerRaw
|
|
539
617
|
};
|
|
540
618
|
}
|
|
541
|
-
function calculateItemRewardByRule({ rule, itemTotal, quantity }) {
|
|
619
|
+
function calculateItemRewardByRule({ rule, itemTotal, quantity, allowedTotalCommissionTypes }) {
|
|
620
|
+
const allowedTypes = allowedCommissionTypesSet(allowedTotalCommissionTypes);
|
|
542
621
|
if (rule.totalCommission) {
|
|
622
|
+
if (!allowedTypes.has(rule.totalCommission.type)) return null;
|
|
543
623
|
const splits = getRuleSplits(rule);
|
|
544
624
|
if (!splits) return null;
|
|
545
625
|
let totalPot = 0;
|
|
@@ -578,21 +658,27 @@ function getItemCategoryIds(item) {
|
|
|
578
658
|
function getItemTagIds(item) {
|
|
579
659
|
return Array.isArray(item?.product?.tags) ? normalizeIds(item.product.tags) : [];
|
|
580
660
|
}
|
|
581
|
-
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
|
+
});
|
|
582
668
|
const productId = relationId(item.product);
|
|
583
669
|
const itemCategoryIds = new Set(getItemCategoryIds(item));
|
|
584
670
|
const itemTagIds = new Set(getItemTagIds(item));
|
|
585
671
|
const candidates = [
|
|
586
|
-
|
|
587
|
-
|
|
672
|
+
eligibleRules.filter((r) => r.appliesTo === "products" && normalizeIds(r.products).some((id) => productId != null && id === productId)),
|
|
673
|
+
eligibleRules.filter((r) => {
|
|
588
674
|
if (!(r.appliesTo === "segments" || r.appliesTo === "categories")) return false;
|
|
589
675
|
return normalizeIds(r.categories).some((id) => itemCategoryIds.has(id));
|
|
590
676
|
}),
|
|
591
|
-
|
|
677
|
+
eligibleRules.filter((r) => {
|
|
592
678
|
if (r.appliesTo !== "segments") return false;
|
|
593
679
|
return normalizeIds(r.tags).some((id) => itemTagIds.has(id));
|
|
594
680
|
}),
|
|
595
|
-
|
|
681
|
+
eligibleRules.filter((r) => r.appliesTo === "all")
|
|
596
682
|
].find((level) => level.length > 0) ?? [];
|
|
597
683
|
if (!candidates.length) return null;
|
|
598
684
|
let best = null;
|
|
@@ -600,7 +686,8 @@ function selectBestRuleForItem({ rules, item, itemTotal, quantity }) {
|
|
|
600
686
|
const reward = calculateItemRewardByRule({
|
|
601
687
|
rule,
|
|
602
688
|
itemTotal,
|
|
603
|
-
quantity
|
|
689
|
+
quantity,
|
|
690
|
+
allowedTotalCommissionTypes
|
|
604
691
|
});
|
|
605
692
|
if (!reward) continue;
|
|
606
693
|
if (!best) {
|
|
@@ -624,7 +711,18 @@ function selectBestRuleForItem({ rules, item, itemTotal, quantity }) {
|
|
|
624
711
|
}
|
|
625
712
|
return best;
|
|
626
713
|
}
|
|
627
|
-
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 }) {
|
|
628
726
|
const rules = Array.isArray(program?.commissionRules) ? program.commissionRules : [];
|
|
629
727
|
if (!rules.length) return {
|
|
630
728
|
partnerCommission: 0,
|
|
@@ -649,7 +747,9 @@ function calculateCommissionAndDiscount({ cartItems, program, currencyCode = "AE
|
|
|
649
747
|
product
|
|
650
748
|
},
|
|
651
749
|
itemTotal,
|
|
652
|
-
quantity
|
|
750
|
+
quantity,
|
|
751
|
+
cartTotal,
|
|
752
|
+
allowedTotalCommissionTypes
|
|
653
753
|
});
|
|
654
754
|
if (!bestMatch) continue;
|
|
655
755
|
totalPartnerCommission += bestMatch.reward.partner;
|
|
@@ -877,10 +977,20 @@ async function handleReferralCode({ payload, code, cartID, cart, customerEmail:
|
|
|
877
977
|
error: "Referral code already applied to this cart"
|
|
878
978
|
}, { status: 400 });
|
|
879
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 });
|
|
880
988
|
const { partnerCommission, customerDiscount } = calculateCommissionAndDiscount({
|
|
881
989
|
cartItems: cart.items || [],
|
|
882
990
|
program,
|
|
883
|
-
currencyCode: pluginConfig.defaultCurrency
|
|
991
|
+
currencyCode: pluginConfig.defaultCurrency,
|
|
992
|
+
cartTotal,
|
|
993
|
+
allowedTotalCommissionTypes: pluginConfig.referralConfig.allowedTotalCommissionTypes
|
|
884
994
|
});
|
|
885
995
|
const roundedPartnerCommission = roundTo2(partnerCommission);
|
|
886
996
|
const roundedCustomerDiscount = roundTo2(customerDiscount);
|
|
@@ -920,8 +1030,14 @@ const partnerStatsHandler = ({ pluginConfig }) => async (req) => {
|
|
|
920
1030
|
error: "Authentication required"
|
|
921
1031
|
}, { status: 401 });
|
|
922
1032
|
const typedUser = user;
|
|
923
|
-
const isPartner =
|
|
924
|
-
|
|
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 });
|
|
925
1041
|
if (!isPartner && !isAdmin) return Response.json({
|
|
926
1042
|
success: false,
|
|
927
1043
|
error: "Partner access required"
|
|
@@ -1201,12 +1317,22 @@ async function validateReferralCode({ payload, code, cartID, pluginConfig }) {
|
|
|
1201
1317
|
id: cartID,
|
|
1202
1318
|
depth: 2
|
|
1203
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 });
|
|
1204
1329
|
const { partnerCommission, customerDiscount } = calculateCommissionAndDiscount({
|
|
1205
1330
|
cartItems: cart?.items || [],
|
|
1206
1331
|
program,
|
|
1207
|
-
currencyCode: pluginConfig.defaultCurrency
|
|
1332
|
+
currencyCode: pluginConfig.defaultCurrency,
|
|
1333
|
+
cartTotal,
|
|
1334
|
+
allowedTotalCommissionTypes: pluginConfig.referralConfig.allowedTotalCommissionTypes
|
|
1208
1335
|
});
|
|
1209
|
-
const cartTotal = cart ? cart.subtotal || cart.total || 0 : 0;
|
|
1210
1336
|
const cappedCustomerDiscount = cartTotal > 0 ? Math.min(customerDiscount, cartTotal) : customerDiscount;
|
|
1211
1337
|
const roundedPartnerCommission = roundTo2(partnerCommission);
|
|
1212
1338
|
const roundedCustomerDiscount = roundTo2(cappedCustomerDiscount);
|
|
@@ -1232,12 +1358,6 @@ const validateCouponEndpoint = ({ pluginConfig }) => ({
|
|
|
1232
1358
|
const recalculateCartHook = (pluginConfig) => async ({ data, req, originalDoc }) => {
|
|
1233
1359
|
if (!req.payload) return data;
|
|
1234
1360
|
const effectiveItems = data.items || originalDoc?.items || [];
|
|
1235
|
-
console.log("[RecalculateCart] Hook triggered", {
|
|
1236
|
-
hasDataItems: !!data.items,
|
|
1237
|
-
dataItemsCount: data.items?.length,
|
|
1238
|
-
originalItemsCount: originalDoc?.items?.length,
|
|
1239
|
-
effectiveItemsCount: effectiveItems.length
|
|
1240
|
-
});
|
|
1241
1361
|
if (!effectiveItems.length) return {
|
|
1242
1362
|
...data,
|
|
1243
1363
|
partnerCommission: 0,
|
|
@@ -1284,12 +1404,6 @@ const recalculateCartHook = (pluginConfig) => async ({ data, req, originalDoc })
|
|
|
1284
1404
|
currencyCode: pluginConfig.defaultCurrency
|
|
1285
1405
|
});
|
|
1286
1406
|
calculatedSubtotal += itemPrice * (item.quantity ?? 1);
|
|
1287
|
-
console.log("[RecalculateCart] Item processed", {
|
|
1288
|
-
productId,
|
|
1289
|
-
quantity: item.quantity,
|
|
1290
|
-
priceUsed: itemPrice,
|
|
1291
|
-
currentSubtotal: calculatedSubtotal
|
|
1292
|
-
});
|
|
1293
1407
|
return {
|
|
1294
1408
|
...item,
|
|
1295
1409
|
product,
|
|
@@ -1318,16 +1432,30 @@ const recalculateCartHook = (pluginConfig) => async ({ data, req, originalDoc })
|
|
|
1318
1432
|
id: programId
|
|
1319
1433
|
}) : null;
|
|
1320
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
|
+
}
|
|
1321
1446
|
const { partnerCommission, customerDiscount } = calculateCommissionAndDiscount({
|
|
1322
1447
|
cartItems: enrichedItems,
|
|
1323
1448
|
program,
|
|
1324
|
-
currencyCode: pluginConfig.defaultCurrency
|
|
1449
|
+
currencyCode: pluginConfig.defaultCurrency,
|
|
1450
|
+
cartTotal: calculatedSubtotal,
|
|
1451
|
+
allowedTotalCommissionTypes: pluginConfig.referralConfig.allowedTotalCommissionTypes
|
|
1325
1452
|
});
|
|
1326
1453
|
const roundedCustomerDiscount = roundTo2(customerDiscount);
|
|
1327
1454
|
data.partnerCommission = roundTo2(partnerCommission);
|
|
1328
1455
|
data.customerDiscount = roundedCustomerDiscount;
|
|
1329
1456
|
data.total = Math.max(0, calculatedSubtotal - roundedCustomerDiscount);
|
|
1330
1457
|
} else {
|
|
1458
|
+
data.appliedReferralCode = null;
|
|
1331
1459
|
data.partnerCommission = 0;
|
|
1332
1460
|
data.customerDiscount = 0;
|
|
1333
1461
|
data.total = calculatedSubtotal;
|
|
@@ -1348,12 +1476,6 @@ const recalculateCartHook = (pluginConfig) => async ({ data, req, originalDoc })
|
|
|
1348
1476
|
coupon,
|
|
1349
1477
|
cartTotal: calculatedSubtotal
|
|
1350
1478
|
});
|
|
1351
|
-
console.log("[RecalculateCart] Coupon Logic", {
|
|
1352
|
-
appliedCoupon,
|
|
1353
|
-
couponId: coupon.id,
|
|
1354
|
-
cartTotal: calculatedSubtotal,
|
|
1355
|
-
discountAmount
|
|
1356
|
-
});
|
|
1357
1479
|
data.discountAmount = discountAmount;
|
|
1358
1480
|
const currentDiscount = data.customerDiscount || 0;
|
|
1359
1481
|
data.total = Math.max(0, calculatedSubtotal - currentDiscount - discountAmount);
|
|
@@ -1365,6 +1487,13 @@ const recalculateCartHook = (pluginConfig) => async ({ data, req, originalDoc })
|
|
|
1365
1487
|
//#endregion
|
|
1366
1488
|
//#region src/utilities/sanitizePluginConfig.ts
|
|
1367
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"))] : [];
|
|
1368
1497
|
return {
|
|
1369
1498
|
enabled: !(pluginConfig?.enabled === false || typeof pluginConfig?.enabled === "string" && pluginConfig.enabled === "false"),
|
|
1370
1499
|
enableReferrals: !!pluginConfig?.enableReferrals && (typeof pluginConfig?.enableReferrals !== "string" || pluginConfig.enableReferrals !== "false"),
|
|
@@ -1386,20 +1515,21 @@ const sanitizePluginConfig = ({ pluginConfig }) => {
|
|
|
1386
1515
|
access: {
|
|
1387
1516
|
canUseCoupons: typeof pluginConfig?.access?.canUseCoupons === "function" ? pluginConfig.access.canUseCoupons : () => true,
|
|
1388
1517
|
canUseReferrals: typeof pluginConfig?.access?.canUseReferrals === "function" ? pluginConfig.access.canUseReferrals : () => false,
|
|
1389
|
-
isAdmin: typeof pluginConfig?.access?.isAdmin === "function" ? pluginConfig.access.isAdmin : () =>
|
|
1390
|
-
|
|
1391
|
-
|
|
1392
|
-
|
|
1393
|
-
|
|
1394
|
-
|
|
1395
|
-
|
|
1396
|
-
}
|
|
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
|
+
})
|
|
1397
1526
|
},
|
|
1398
1527
|
referralConfig: {
|
|
1399
1528
|
allowBothSystems: pluginConfig?.referralConfig?.allowBothSystems ?? false,
|
|
1400
1529
|
singleCodePerCart: pluginConfig?.referralConfig?.singleCodePerCart ?? true,
|
|
1401
1530
|
defaultPartnerSplit: pluginConfig?.referralConfig?.defaultPartnerSplit ?? 70,
|
|
1402
|
-
defaultCustomerSplit: pluginConfig?.referralConfig?.defaultCustomerSplit ?? 30
|
|
1531
|
+
defaultCustomerSplit: pluginConfig?.referralConfig?.defaultCustomerSplit ?? 30,
|
|
1532
|
+
allowedTotalCommissionTypes: normalizedAllowedTotalCommissionTypes.length > 0 ? normalizedAllowedTotalCommissionTypes : ["fixed", "percentage"]
|
|
1403
1533
|
},
|
|
1404
1534
|
adminGroups: {
|
|
1405
1535
|
couponsGroup: pluginConfig?.adminGroups?.couponsGroup ?? "Coupons",
|
|
@@ -1417,7 +1547,8 @@ const sanitizePluginConfig = ({ pluginConfig }) => {
|
|
|
1417
1547
|
orderCustomerEmailField: typeof pluginConfig?.orderIntegration?.orderCustomerEmailField === "string" && pluginConfig.orderIntegration.orderCustomerEmailField.trim().length > 0 ? pluginConfig.orderIntegration.orderCustomerEmailField : "customerEmail",
|
|
1418
1548
|
orderPaymentStatusField: typeof pluginConfig?.orderIntegration?.orderPaymentStatusField === "string" && pluginConfig.orderIntegration.orderPaymentStatusField.trim().length > 0 ? pluginConfig.orderIntegration.orderPaymentStatusField : "paymentStatus",
|
|
1419
1549
|
orderPaidStatusValue: typeof pluginConfig?.orderIntegration?.orderPaidStatusValue === "string" ? pluginConfig.orderIntegration.orderPaidStatusValue : "paid"
|
|
1420
|
-
}
|
|
1550
|
+
},
|
|
1551
|
+
roleConfig
|
|
1421
1552
|
};
|
|
1422
1553
|
};
|
|
1423
1554
|
|
|
@@ -1809,6 +1940,7 @@ exports.createCouponsCollection = createCouponsCollection;
|
|
|
1809
1940
|
exports.createReferralCodesCollection = createReferralCodesCollection;
|
|
1810
1941
|
exports.createReferralProgramsCollection = createReferralProgramsCollection;
|
|
1811
1942
|
exports.getCartTotalWithDiscounts = getCartTotalWithDiscounts;
|
|
1943
|
+
exports.getProgramMinimumOrderAmount = getProgramMinimumOrderAmount;
|
|
1812
1944
|
exports.payloadEcommerceCoupon = payloadEcommerceCouponPlugin;
|
|
1813
1945
|
exports.recordCouponUsageForOrder = recordCouponUsageForOrder;
|
|
1814
1946
|
exports.useCouponCode = useCouponCode;
|