@wtree/payload-ecommerce-coupon 3.72.2 → 3.76.1

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.
@@ -1 +1 @@
1
- {"version":3,"file":"index.mjs","names":["validateCouponCode"],"sources":["../src/collections/createCouponsCollection.ts","../src/collections/createReferralCodesCollection.ts","../src/collections/createReferralProgramsCollection.ts","../src/utilities/roundTo2.ts","../src/endpoints/applyCoupon.ts","../src/endpoints/partnerStats.ts","../src/endpoints/validateCoupon.ts","../src/utilities/sanitizePluginConfig.ts","../src/plugin.ts","../src/client/hooks.ts","../src/utilities/getCartTotalWithDiscounts.ts","../src/utilities/recordCouponUsageForOrder.ts"],"sourcesContent":["import type { CollectionConfig } from 'payload'\n\nimport type { SanitizedCouponPluginOptions } from '../types'\n\nexport const createCouponsCollection = (\n pluginConfig: SanitizedCouponPluginOptions,\n): CollectionConfig => {\n const { collections, access, defaultCurrency, adminGroups } = pluginConfig\n\n return {\n slug: collections.couponsSlug,\n admin: {\n useAsTitle: 'code',\n defaultColumns: ['code', 'type', 'value', 'activeFrom', 'activeUntil'],\n group: adminGroups.couponsGroup,\n },\n access: {\n read: access.canUseCoupons || (() => true),\n create: access.isAdmin || (() => false),\n update: access.isAdmin || (() => false),\n delete: access.isAdmin || (() => false),\n },\n fields: [\n {\n name: 'code',\n type: 'text',\n required: true,\n unique: true,\n admin: {\n description: 'The coupon code that customers will enter',\n },\n },\n {\n name: 'description',\n type: 'text',\n admin: {\n description: 'Optional description for admin reference',\n },\n },\n {\n name: 'type',\n type: 'select',\n required: true,\n options: [\n { label: 'Percentage', value: 'percentage' },\n { label: 'Fixed Amount', value: 'fixed' },\n ],\n defaultValue: 'percentage',\n admin: {\n description: 'Whether this is a percentage or fixed amount discount',\n },\n },\n {\n name: 'value',\n type: 'number',\n required: true,\n admin: {\n description: `If percentage, 10 = 10%. If fixed, interpreted in ${defaultCurrency} (smallest currency units)`,\n step: 0.01,\n },\n },\n {\n name: 'maxDiscountAmount',\n type: 'number',\n admin: {\n description: `Maximum discount amount in ${defaultCurrency} (smallest currency unit). Leave empty for no cap.`,\n },\n },\n {\n name: 'usageLimit',\n type: 'number',\n admin: {\n description:\n 'Total times this coupon can be used across all customers. Empty = unlimited.',\n },\n },\n {\n name: 'perCustomerLimit',\n type: 'number',\n admin: {\n description: 'Times a single customer can use this coupon. Empty = unlimited.',\n },\n },\n {\n name: 'activeFrom',\n type: 'date',\n admin: {\n description:\n 'Coupon becomes active from this date. Leave empty for immediate activation.',\n },\n },\n {\n name: 'activeUntil',\n type: 'date',\n admin: {\n description: 'Coupon expires after this date. Leave empty for no expiration.',\n },\n },\n {\n name: 'minOrderValue',\n type: 'number',\n admin: {\n description: `Minimum order value required in ${defaultCurrency} (smallest currency units)`,\n },\n },\n {\n name: 'maxOrderValue',\n type: 'number',\n admin: {\n description: `Maximum order value allowed in ${defaultCurrency} (smallest currency units)`,\n },\n },\n {\n name: 'usageCount',\n type: 'number',\n defaultValue: 0,\n admin: {\n description: 'How many times this coupon has been used',\n readOnly: true,\n },\n },\n {\n name: 'createdBy',\n type: 'relationship',\n relationTo: 'users',\n admin: {\n readOnly: true,\n position: 'sidebar',\n },\n },\n ],\n hooks: {\n beforeChange: [\n ({ operation, req, data }) => {\n if (operation === 'create' && req.user) {\n data.createdBy = req.user.id\n }\n return data\n },\n ],\n },\n timestamps: true,\n }\n}\n","import type { CollectionConfig } from 'payload'\n\nimport type { SanitizedCouponPluginOptions } from '../types'\n\nexport const createReferralCodesCollection = (\n pluginConfig: SanitizedCouponPluginOptions,\n): CollectionConfig => {\n const { collections, access, adminGroups, defaultCurrency } = pluginConfig\n\n return {\n slug: collections.referralCodesSlug,\n admin: {\n useAsTitle: 'code',\n defaultColumns: ['code', 'referrer', 'program', 'usageCount', 'isActive'],\n group: adminGroups.referralsGroup,\n },\n access: {\n read: ({ req }) => {\n // Partners can read their own codes, admins can read all\n const user = req?.user as { id?: string; role?: string; roles?: string[] } | undefined\n if (!user) return false\n\n // Admin access\n if (user.role === 'admin' || (Array.isArray(user.roles) && user.roles.includes('admin'))) {\n return true\n }\n\n // Partner access - only their own codes\n if (\n user.role === 'partner' ||\n (Array.isArray(user.roles) && user.roles.includes('partner'))\n ) {\n return {\n referrer: {\n equals: user.id,\n },\n }\n }\n\n // Default access from config\n return access.canUseReferrals ? access.canUseReferrals({ req } as any) : false\n },\n create: ({ req }) => {\n // Partners can create their own codes, admins can create any\n const user = req?.user as { role?: string; roles?: string[] } | undefined\n if (!user) return false\n\n if (user.role === 'admin' || (Array.isArray(user.roles) && user.roles.includes('admin'))) {\n return true\n }\n\n if (\n user.role === 'partner' ||\n (Array.isArray(user.roles) && user.roles.includes('partner'))\n ) {\n return true\n }\n\n return access.isAdmin ? access.isAdmin({ req } as any) : false\n },\n update: access.isAdmin || (() => false),\n delete: access.isAdmin || (() => false),\n },\n fields: [\n {\n name: 'code',\n type: 'text',\n required: true,\n unique: true,\n admin: {\n description: 'The referral code that customers will enter',\n },\n },\n {\n name: 'program',\n type: 'relationship',\n relationTo: collections.referralProgramsSlug,\n required: true,\n admin: {\n description: 'The referral program this code belongs to',\n },\n },\n {\n name: 'referrer',\n type: 'relationship',\n relationTo: 'users',\n required: true,\n admin: {\n description: 'The partner who owns this referral code',\n },\n },\n {\n name: 'isActive',\n type: 'checkbox',\n defaultValue: true,\n admin: {\n description: 'Whether this referral code is currently active',\n },\n },\n {\n name: 'usageCount',\n type: 'number',\n defaultValue: 0,\n admin: {\n description: 'How many times this referral code has been used',\n readOnly: true,\n },\n },\n {\n name: 'usageLimit',\n type: 'number',\n admin: {\n description: 'Maximum times this code can be used. Empty = unlimited.',\n },\n },\n {\n name: 'expiresAt',\n type: 'date',\n admin: {\n description: 'When this referral code expires',\n },\n },\n {\n name: 'successfulReferralsCount',\n type: 'number',\n defaultValue: 0,\n admin: {\n description: 'Total count of successful referrals using this code',\n readOnly: true,\n },\n },\n {\n name: 'totalEarnings',\n type: 'number',\n defaultValue: 0,\n admin: {\n description: `Total earnings generated by this code in ${defaultCurrency}`,\n readOnly: true,\n },\n },\n {\n name: 'pendingEarnings',\n type: 'number',\n defaultValue: 0,\n admin: {\n description: `Pending earnings awaiting payout in ${defaultCurrency}`,\n readOnly: true,\n },\n },\n {\n name: 'paidEarnings',\n type: 'number',\n defaultValue: 0,\n admin: {\n description: `Total earnings paid out in ${defaultCurrency}`,\n readOnly: true,\n },\n },\n {\n name: 'metadata',\n type: 'json',\n admin: {\n description: 'Additional metadata for the referral code',\n position: 'sidebar',\n },\n },\n ],\n hooks: {\n beforeChange: [\n ({ operation, req, data }) => {\n // Auto-generate code if not provided\n if (operation === 'create' && !data.code && data.referrer) {\n const timestamp = Date.now().toString(36)\n const random = Math.random().toString(36).substring(2, 8)\n data.code = `REF-${timestamp}-${random}`.toUpperCase()\n }\n\n // Auto-assign referrer to current user if partner\n if (operation === 'create' && req.user) {\n const user = req.user as { id?: string; role?: string; roles?: string[] }\n if (\n user.role === 'partner' ||\n (Array.isArray(user.roles) && user.roles.includes('partner'))\n ) {\n data.referrer = user.id\n }\n }\n\n return data\n },\n ],\n },\n timestamps: true,\n }\n}\n","import type { CollectionConfig } from 'payload'\n\nimport type { SanitizedCouponPluginOptions } from '../types'\n\nexport const createReferralProgramsCollection = (\n pluginConfig: SanitizedCouponPluginOptions,\n): CollectionConfig => {\n const { collections, access, defaultCurrency, adminGroups, referralConfig } = pluginConfig\n\n const beforeChange: NonNullable<CollectionConfig['hooks']>['beforeChange'] = [\n ({ data }: { data: Record<string, unknown> }) => {\n // Commission rules are required; each rule must have referrerReward and refereeReward\n if (\n !data.commissionRules ||\n !Array.isArray(data.commissionRules) ||\n data.commissionRules.length === 0\n ) {\n throw new Error('At least one commission rule is required')\n }\n data.commissionRules.forEach((rule: Record<string, unknown>, index: number) => {\n const r = rule as {\n basis?: 'direct' | 'shared'\n referrerReward?: { type?: string; value?: number }\n refereeReward?: { type?: string; value?: number }\n totalCommission?: { type?: string; value?: number }\n referrerSplit?: number\n refereeSplit?: number\n }\n\n // Shared Basis Validation\n if (r.basis === 'shared') {\n if (!r.totalCommission || r.totalCommission.value == null) {\n throw new Error(\n `Commission rule ${index + 1}: Total Commission is required for Shared Basis`,\n )\n }\n if (r.referrerSplit == null) {\n throw new Error(\n `Commission rule ${index + 1}: Referrer Split is required for Shared Basis`,\n )\n }\n if (r.refereeSplit == null) {\n throw new Error(\n `Commission rule ${index + 1}: Referee Split is required for Shared Basis`,\n )\n }\n if ((r.referrerSplit || 0) + (r.refereeSplit || 0) > 100) {\n throw new Error(\n `Commission rule ${index + 1}: Referrer + Referee split cannot exceed 100%`,\n )\n }\n }\n // Direct Basis Validation (Legacy)\n else {\n if (!r.referrerReward || r.referrerReward.value == null) {\n throw new Error(`Commission rule ${index + 1}: Referrer Reward is required`)\n }\n if (!r.refereeReward || r.refereeReward.value == null) {\n throw new Error(`Commission rule ${index + 1}: Referee Reward is required`)\n }\n if (r.referrerReward?.type === 'percentage' && r.refereeReward?.type === 'percentage') {\n const total = (r.referrerReward.value || 0) + (r.refereeReward.value || 0)\n if (total > 100) {\n throw new Error(\n `Commission rule ${index + 1}: Referrer + Referee percentage cannot exceed 100%`,\n )\n }\n }\n }\n })\n return data\n },\n ]\n\n return {\n slug: collections.referralProgramsSlug,\n admin: {\n useAsTitle: 'name',\n defaultColumns: ['name', 'commissionRules', 'isActive'],\n group: adminGroups.referralsGroup,\n },\n access: {\n read: access.canUseReferrals || (() => true),\n create: access.isAdmin || (() => false),\n update: access.isAdmin || (() => false),\n delete: access.isAdmin || (() => false),\n },\n hooks: {\n beforeChange,\n },\n fields: [\n {\n name: 'name',\n type: 'text',\n required: true,\n admin: {\n description: 'Name of the referral program for admin reference',\n },\n },\n {\n name: 'description',\n type: 'textarea',\n admin: {\n description: 'Description of the referral program',\n },\n },\n {\n name: 'isActive',\n type: 'checkbox',\n defaultValue: true,\n admin: {\n description: 'Whether this referral program is currently active',\n },\n },\n {\n name: 'commissionRules',\n type: 'array',\n required: true,\n minRows: 1,\n admin: {\n description:\n 'Commission rules: each rule defines who it applies to and Referrer Reward + Referee Reward inside the rule.',\n },\n fields: [\n {\n name: 'name',\n type: 'text',\n required: true,\n admin: { description: 'Name of this rule' },\n },\n {\n name: 'appliesTo',\n type: 'select',\n required: true,\n options: [\n { label: 'All Products', value: 'all' },\n { label: 'Specific Categories', value: 'categories' },\n { label: 'Specific Products', value: 'products' },\n ],\n defaultValue: 'all',\n },\n {\n name: 'categories',\n type: 'relationship',\n relationTo: 'categories',\n hasMany: true,\n admin: {\n condition: (_: unknown, siblingData: { appliesTo?: string }) =>\n siblingData?.appliesTo === 'categories',\n description: 'Categories this rule applies to',\n },\n },\n {\n name: 'products',\n type: 'relationship',\n relationTo: 'products',\n hasMany: true,\n admin: {\n condition: (_: unknown, siblingData: { appliesTo?: string }) =>\n siblingData?.appliesTo === 'products',\n description: 'Products this rule applies to',\n },\n },\n {\n name: 'basis',\n type: 'select',\n required: true,\n defaultValue: 'direct',\n options: [\n { label: 'Direct Values', value: 'direct' },\n { label: 'Shared Commission', value: 'shared' },\n ],\n admin: {\n description:\n 'Direct: Set specific reward/discount for each. Shared: Set a total commission and split it.',\n },\n },\n {\n name: 'totalCommission',\n type: 'group',\n admin: {\n condition: (_: unknown, siblingData: { basis?: string }) =>\n siblingData?.basis === 'shared',\n description: 'Total commission available to be split between partner and customer',\n },\n fields: [\n {\n name: 'type',\n type: 'select',\n required: true,\n options: [\n { label: 'Fixed Amount', value: 'fixed' },\n { label: 'Percentage of Order', value: 'percentage' },\n ],\n defaultValue: 'percentage',\n },\n {\n name: 'value',\n type: 'number',\n required: true,\n admin: {\n description: `Total commission value`,\n },\n },\n {\n name: 'maxAmount',\n type: 'number',\n admin: {\n description: `Max commission cap per item in ${defaultCurrency}`,\n },\n },\n ],\n },\n {\n name: 'referrerSplit',\n type: 'number',\n min: 0,\n max: 100,\n admin: {\n condition: (_: unknown, siblingData: { basis?: string }) =>\n siblingData?.basis === 'shared',\n description: 'Percentage of total commission given to the Partner (0-100)',\n },\n },\n {\n name: 'refereeSplit',\n type: 'number',\n min: 0,\n max: 100,\n admin: {\n condition: (_: unknown, siblingData: { basis?: string }) =>\n siblingData?.basis === 'shared',\n description: 'Percentage of total commission given as Discount to Customer (0-100)',\n },\n },\n {\n name: 'referrerReward',\n type: 'group',\n admin: {\n condition: (_: unknown, siblingData: { basis?: string }) =>\n siblingData?.basis !== 'shared',\n description: 'Reward given to the partner who refers others',\n },\n fields: [\n {\n name: 'type',\n type: 'select',\n required: true,\n options: [\n { label: 'Fixed Amount', value: 'fixed' },\n { label: 'Percentage of Order', value: 'percentage' },\n ],\n defaultValue: 'percentage',\n },\n {\n name: 'value',\n type: 'number',\n required: true,\n defaultValue: referralConfig.defaultPartnerSplit,\n admin: {\n description: `For percentage: 10 = 10% of order value. For fixed: amount in ${defaultCurrency}`,\n },\n },\n {\n name: 'maxReward',\n type: 'number',\n admin: {\n description: `Max reward in ${defaultCurrency}. Leave empty for no cap.`,\n },\n },\n ],\n },\n {\n name: 'refereeReward',\n type: 'group',\n admin: {\n condition: (_: unknown, siblingData: { basis?: string }) =>\n siblingData?.basis !== 'shared',\n description: 'Discount given to the customer who was referred',\n },\n fields: [\n {\n name: 'type',\n type: 'select',\n required: true,\n options: [\n { label: 'Fixed Amount', value: 'fixed' },\n { label: 'Percentage Discount', value: 'percentage' },\n ],\n defaultValue: 'percentage',\n },\n {\n name: 'value',\n type: 'number',\n required: true,\n defaultValue: referralConfig.defaultCustomerSplit,\n admin: {\n description: `For percentage: 10 = 10% discount. For fixed: amount in ${defaultCurrency}`,\n },\n },\n {\n name: 'maxReward',\n type: 'number',\n admin: {\n description: `Max discount in ${defaultCurrency}. Leave empty for no cap.`,\n },\n },\n ],\n },\n ],\n },\n {\n name: 'minOrderValue',\n type: 'number',\n admin: {\n description: `Minimum order value required for referral in ${defaultCurrency}`,\n },\n },\n {\n name: 'maxReferralsPerUser',\n type: 'number',\n admin: {\n description: 'Maximum number of referrals a partner can make. Empty = unlimited.',\n },\n },\n {\n name: 'referralCodePrefix',\n type: 'text',\n admin: {\n description: 'Prefix for generated referral codes (e.g., \"REF\" will create REF123)',\n },\n },\n {\n name: 'activeFrom',\n type: 'date',\n admin: {\n description: 'Program becomes active from this date',\n },\n },\n {\n name: 'activeUntil',\n type: 'date',\n admin: {\n description: 'Program expires after this date',\n },\n },\n {\n name: 'totalReferrals',\n type: 'number',\n defaultValue: 0,\n admin: {\n description: 'Total number of successful referrals through this program',\n readOnly: true,\n },\n },\n {\n name: 'totalRewardsPaid',\n type: 'number',\n defaultValue: 0,\n admin: {\n description: `Total rewards paid out in ${defaultCurrency}`,\n readOnly: true,\n },\n },\n ],\n timestamps: true,\n }\n}\n","/**\n * Rounds a number to 2 decimal places (standard for monetary values).\n */\nexport function roundTo2(value: number): number {\n return Math.round(value * 100) / 100\n}\n","import type { Endpoint, PayloadHandler } from 'payload'\n\nimport type { SanitizedCouponPluginOptions } from '../types'\nimport { roundTo2 } from '../utilities/roundTo2'\n\ntype Args = {\n pluginConfig: SanitizedCouponPluginOptions\n}\n\nexport const applyCouponHandler =\n ({ pluginConfig }: Args): PayloadHandler =>\n async (req) => {\n const { payload } = req\n const { code, cartID, customerEmail } = req.data || {}\n\n if (!code || !cartID) {\n return Response.json(\n {\n success: false,\n error: `${pluginConfig.enableReferrals ? 'Referral code' : 'Coupon code'} and cart ID are required`,\n },\n { status: 400 },\n )\n }\n\n try {\n // Find the cart first to check for existing codes\n const cartQuery = await payload.findByID({\n collection: 'carts',\n id: cartID,\n })\n\n if (!cartQuery) {\n return Response.json({ success: false, error: 'Cart not found' }, { status: 404 })\n }\n\n // Check if single code per cart is enforced\n if (pluginConfig.referralConfig.singleCodePerCart) {\n const hasExistingCoupon = cartQuery.appliedCoupon\n const hasExistingReferral = cartQuery.appliedReferralCode\n\n if (hasExistingCoupon || hasExistingReferral) {\n return Response.json(\n {\n success: false,\n error:\n 'A code has already been applied to this cart. Only one code can be used per order.',\n },\n { status: 400 },\n )\n }\n }\n\n if (pluginConfig.enableReferrals) {\n // Try referral code first\n const referralResult = await handleReferralCode({\n payload,\n code,\n cartID,\n cart: cartQuery,\n customerEmail,\n pluginConfig,\n })\n\n // If referral code not found and both systems allowed, try coupon\n if (\n !referralResult.ok &&\n referralResult.status === 404 &&\n pluginConfig.referralConfig.allowBothSystems\n ) {\n return await handleCouponCode({\n payload,\n code,\n cartID,\n cart: cartQuery,\n customerEmail,\n pluginConfig,\n })\n }\n\n return referralResult\n } else {\n // Coupon mode: handle coupons\n return await handleCouponCode({\n payload,\n code,\n cartID,\n cart: cartQuery,\n customerEmail,\n pluginConfig,\n })\n }\n } catch (error) {\n console.error('Code application error:', error)\n return Response.json({ success: false, error: 'Internal server error' }, { status: 500 })\n }\n }\n\n// Handle coupon application\nasync function handleCouponCode({\n payload,\n code,\n cartID,\n cart,\n customerEmail,\n pluginConfig,\n}: {\n payload: any\n code: string\n cartID: string\n cart: any\n customerEmail?: string\n pluginConfig: SanitizedCouponPluginOptions\n}) {\n // Find the coupon\n const couponQuery = await payload.find({\n collection: pluginConfig.collections.couponsSlug,\n where: {\n code: { equals: code },\n },\n limit: 1,\n })\n\n if (!couponQuery.docs.length) {\n return Response.json({ success: false, error: 'Invalid coupon code' }, { status: 404 })\n }\n\n const coupon = couponQuery.docs[0]\n\n // Check if coupon is active\n const now = new Date()\n const activeFrom = coupon.activeFrom ? new Date(coupon.activeFrom) : null\n const activeUntil = coupon.activeUntil ? new Date(coupon.activeUntil) : null\n\n if (activeFrom && now < activeFrom) {\n return Response.json({ success: false, error: 'Coupon is not yet active' }, { status: 400 })\n }\n\n if (activeUntil && now > activeUntil) {\n return Response.json({ success: false, error: 'Coupon has expired' }, { status: 400 })\n }\n\n // Check usage limits\n if (coupon.usageLimit && coupon.usageCount >= coupon.usageLimit) {\n return Response.json({ success: false, error: 'Coupon usage limit exceeded' }, { status: 400 })\n }\n\n // Per-customer limit: require customer email and count paid orders with this coupon for this customer\n if (coupon.perCustomerLimit != null && coupon.perCustomerLimit > 0) {\n const email = typeof customerEmail === 'string' ? customerEmail.trim() : ''\n if (!email) {\n return Response.json(\n { success: false, error: 'Customer email is required for this coupon.' },\n { status: 400 },\n )\n }\n const { ordersSlug, orderCustomerEmailField, orderPaymentStatusField, orderPaidStatusValue } =\n pluginConfig.orderIntegration\n const ordersQuery = await payload.find({\n collection: ordersSlug,\n where: {\n and: [\n { appliedCoupon: { equals: coupon.id } },\n { [orderCustomerEmailField]: { equals: email } },\n { [orderPaymentStatusField]: { equals: orderPaidStatusValue } },\n ],\n },\n limit: 0,\n })\n if (ordersQuery.totalDocs >= coupon.perCustomerLimit) {\n return Response.json(\n { success: false, error: 'You have reached the maximum uses for this coupon.' },\n { status: 400 },\n )\n }\n }\n\n // Check if coupon already applied to this cart\n if (cart.appliedCoupon === coupon.id) {\n return Response.json(\n { success: false, error: 'Coupon already applied to this cart' },\n { status: 400 },\n )\n }\n\n // Calculate discount based on cart total\n const cartTotal = cart.subtotal || cart.total || 0\n\n // Check minimum order value\n if (coupon.minOrderValue && cartTotal < coupon.minOrderValue) {\n return Response.json(\n {\n success: false,\n error: `Minimum order value of ${coupon.minOrderValue} ${pluginConfig.defaultCurrency} required`,\n },\n { status: 400 },\n )\n }\n\n // Check maximum order value\n if (coupon.maxOrderValue && cartTotal > coupon.maxOrderValue) {\n return Response.json(\n {\n success: false,\n error: `Maximum order value of ${coupon.maxOrderValue} ${pluginConfig.defaultCurrency} exceeded`,\n },\n { status: 400 },\n )\n }\n\n let discount = 0\n\n if (coupon.type === 'percentage') {\n // Calculate percentage discount\n discount = roundTo2((cartTotal * coupon.value) / 100)\n // Apply max discount cap if set\n if (coupon.maxDiscountAmount != null && discount > coupon.maxDiscountAmount) {\n discount = roundTo2(coupon.maxDiscountAmount)\n }\n } else if (coupon.type === 'fixed') {\n discount = roundTo2(coupon.value)\n // Ensure discount doesn't exceed cart total\n if (discount > cartTotal) {\n discount = roundTo2(cartTotal)\n }\n }\n\n const discountAmount = roundTo2(discount)\n const total = roundTo2(Math.max(0, cartTotal - discountAmount))\n\n // Apply coupon to cart (usage is counted when order is placed via recordCouponUsageForOrder)\n await payload.update({\n collection: 'carts',\n id: cartID,\n data: {\n appliedCoupon: coupon.id,\n discountAmount,\n total,\n },\n })\n\n return Response.json({\n success: true,\n message: 'Coupon applied successfully',\n coupon: {\n code: coupon.code,\n type: coupon.type,\n value: coupon.value,\n },\n discount: discountAmount,\n currency: pluginConfig.defaultCurrency,\n })\n}\n\n// Handle referral code application\nasync function handleReferralCode({\n payload,\n code,\n cartID,\n cart,\n customerEmail: _customerEmail,\n pluginConfig,\n}: {\n payload: any\n code: string\n cartID: string\n cart: any\n customerEmail?: string\n pluginConfig: SanitizedCouponPluginOptions\n}) {\n // Find the referral code\n const referralQuery = await payload.find({\n collection: pluginConfig.collections.referralCodesSlug,\n where: {\n code: { equals: code },\n },\n limit: 1,\n depth: 1, // Include program data\n })\n\n if (!referralQuery.docs.length) {\n return Response.json({ success: false, error: 'Invalid referral code' }, { status: 404 })\n }\n\n const referralCode = referralQuery.docs[0]\n\n // Check if referral code is active\n if (!referralCode.isActive) {\n return Response.json({ success: false, error: 'Referral code is not active' }, { status: 400 })\n }\n\n // Check expiration\n if (referralCode.expiresAt && new Date() > new Date(referralCode.expiresAt)) {\n return Response.json({ success: false, error: 'Referral code has expired' }, { status: 400 })\n }\n\n // Check usage limit\n if (referralCode.usageLimit && referralCode.usageCount >= referralCode.usageLimit) {\n return Response.json(\n { success: false, error: 'Referral code usage limit exceeded' },\n { status: 400 },\n )\n }\n\n // Get the referral program\n const programId =\n typeof referralCode.program === 'string' ? referralCode.program : referralCode.program?.id\n\n const program = await payload.findByID({\n collection: pluginConfig.collections.referralProgramsSlug,\n id: programId,\n })\n\n if (!program || !program.isActive) {\n return Response.json(\n { success: false, error: 'Referral program is not active' },\n { status: 400 },\n )\n }\n\n // Check program dates\n const now = new Date()\n if (program.activeFrom && now < new Date(program.activeFrom)) {\n return Response.json(\n { success: false, error: 'Referral program is not yet active' },\n { status: 400 },\n )\n }\n\n if (program.activeUntil && now > new Date(program.activeUntil)) {\n return Response.json({ success: false, error: 'Referral program has expired' }, { status: 400 })\n }\n\n // Check if referral code already applied to this cart\n if (cart.appliedReferralCode === referralCode.id) {\n return Response.json(\n { success: false, error: 'Referral code already applied to this cart' },\n { status: 400 },\n )\n }\n\n // Calculate commission and discount\n const cartTotal = cart.subtotal || cart.total || 0\n\n // Check minimum order value\n if (program.minOrderValue && cartTotal < program.minOrderValue) {\n return Response.json(\n {\n success: false,\n error: `Minimum order value of ${program.minOrderValue} ${pluginConfig.defaultCurrency} required`,\n },\n { status: 400 },\n )\n }\n\n // Calculate based on commission rules or default program rewards\n const { partnerCommission, customerDiscount } = calculateCommissionAndDiscount({\n cart,\n program,\n pluginConfig,\n payload,\n })\n\n const roundedPartnerCommission = roundTo2(partnerCommission)\n const roundedCustomerDiscount = roundTo2(customerDiscount)\n const total = roundTo2(Math.max(0, cartTotal - roundedCustomerDiscount))\n\n // Apply referral to cart (usage and partner earnings are recorded when order is placed via recordCouponUsageForOrder)\n await payload.update({\n collection: 'carts',\n id: cartID,\n data: {\n appliedReferralCode: referralCode.id,\n partnerCommission: roundedPartnerCommission,\n customerDiscount: roundedCustomerDiscount,\n total,\n },\n })\n\n return Response.json({\n success: true,\n message: 'Referral code applied successfully',\n referralCode: {\n code: referralCode.code,\n },\n partnerCommission: roundedPartnerCommission,\n customerDiscount: roundedCustomerDiscount,\n currency: pluginConfig.defaultCurrency,\n })\n}\n\n// Calculate commission and discount from program commission rules (each rule has referrerReward + refereeReward)\nfunction calculateCommissionAndDiscount({\n cart,\n program,\n pluginConfig: _pluginConfig,\n payload: _payload,\n}: {\n cart: any\n program: any\n pluginConfig: SanitizedCouponPluginOptions\n payload: any\n}): { partnerCommission: number; customerDiscount: number } {\n const cartTotal = cart.subtotal || cart.total || 0\n const cartItems = cart.items || []\n const rules = program.commissionRules || []\n\n if (rules.length === 0) {\n return { partnerCommission: 0, customerDiscount: 0 }\n }\n\n let totalPartnerCommission = 0\n let totalCustomerDiscount = 0\n\n for (const item of cartItems) {\n const rule = findApplicableCommissionRule(rules, item)\n if (!rule) continue\n\n const itemPrice = item.price ?? item.unitPrice ?? 0\n const quantity = item.quantity ?? 1\n const itemTotal = itemPrice * quantity\n\n console.log('Calculating Item:', {\n id: item.id,\n itemPrice,\n quantity,\n itemTotal,\n ruleBasis: rule.basis,\n })\n\n let itemPartner = 0\n let itemCustomer = 0\n\n // Shared Basis Calculation\n if (rule.basis === 'shared') {\n if (!rule.totalCommission || rule.referrerSplit == null || rule.refereeSplit == null) {\n console.error('Missing shared commission fields', rule)\n continue\n }\n\n let totalPot = 0\n if (rule.totalCommission.type === 'percentage') {\n totalPot = (itemTotal * rule.totalCommission.value) / 100\n } else {\n totalPot = rule.totalCommission.value * quantity\n }\n\n console.log('Shared Commission Pot:', {\n type: rule.totalCommission.type,\n value: rule.totalCommission.value,\n totalPot,\n })\n\n if (rule.totalCommission.maxAmount != null && totalPot > rule.totalCommission.maxAmount) {\n totalPot = rule.totalCommission.maxAmount\n console.log('Total pot capped at:', totalPot)\n }\n\n itemPartner = (totalPot * rule.referrerSplit) / 100\n itemCustomer = (totalPot * rule.refereeSplit) / 100\n console.log('Shared Splits:', {\n referrerSplit: rule.referrerSplit,\n refereeSplit: rule.refereeSplit,\n itemPartner,\n itemCustomer,\n })\n }\n // Direct Basis Calculation (Legacy)\n else {\n if (!rule.referrerReward || !rule.refereeReward) continue\n\n // Partner commission from this rule's referrerReward\n if (rule.referrerReward.type === 'percentage') {\n itemPartner = (itemTotal * rule.referrerReward.value) / 100\n } else {\n itemPartner = rule.referrerReward.value * quantity\n }\n if (rule.referrerReward.maxReward != null && itemPartner > rule.referrerReward.maxReward) {\n itemPartner = rule.referrerReward.maxReward\n }\n\n // Customer discount from this rule's refereeReward\n if (rule.refereeReward.type === 'percentage') {\n itemCustomer = (itemTotal * rule.refereeReward.value) / 100\n } else {\n itemCustomer = rule.refereeReward.value * quantity\n }\n if (rule.refereeReward.maxReward != null && itemCustomer > rule.refereeReward.maxReward) {\n itemCustomer = rule.refereeReward.maxReward\n }\n }\n\n totalPartnerCommission += itemPartner\n totalCustomerDiscount += itemCustomer\n }\n\n if (totalCustomerDiscount > cartTotal) {\n totalCustomerDiscount = cartTotal\n }\n\n return { partnerCommission: totalPartnerCommission, customerDiscount: totalCustomerDiscount }\n}\n\nfunction findApplicableCommissionRule(rules: any[], item: any) {\n const productId = typeof item.product === 'string' ? item.product : item.product?.id\n const categoryId = item.category ?? item.product?.category\n\n const productRule = rules.find(\n (r) =>\n r.appliesTo === 'products' &&\n r.products?.some((p: any) => (typeof p === 'string' ? p : p?.id) === productId),\n )\n if (productRule) return productRule\n\n if (categoryId) {\n const categoryRule = rules.find(\n (r) =>\n r.appliesTo === 'categories' &&\n r.categories?.some((c: any) => (typeof c === 'string' ? c : c?.id) === categoryId),\n )\n if (categoryRule) return categoryRule\n }\n\n return rules.find((r) => r.appliesTo === 'all') ?? null\n}\n\nexport const applyCouponEndpoint = ({ pluginConfig }: Args): Endpoint => ({\n path: pluginConfig.endpoints.applyCoupon,\n method: 'post',\n handler: applyCouponHandler({ pluginConfig }),\n})\n","import type { Endpoint, PayloadHandler } from 'payload'\n\nimport type { PartnerDashboardData, PartnerStats, SanitizedCouponPluginOptions } from '../types'\n\ntype Args = {\n pluginConfig: SanitizedCouponPluginOptions\n}\n\nexport const partnerStatsHandler =\n ({ pluginConfig }: Args): PayloadHandler =>\n async (req) => {\n const { payload, user } = req\n\n if (!user) {\n return Response.json({ success: false, error: 'Authentication required' }, { status: 401 })\n }\n\n const typedUser = user as { id: string; role?: string; roles?: string[] }\n\n // Check if user is a partner\n const isPartner =\n typedUser.role === 'partner' ||\n (Array.isArray(typedUser.roles) && typedUser.roles.includes('partner'))\n\n const isAdmin =\n typedUser.role === 'admin' ||\n (Array.isArray(typedUser.roles) && typedUser.roles.includes('admin'))\n\n if (!isPartner && !isAdmin) {\n return Response.json({ success: false, error: 'Partner access required' }, { status: 403 })\n }\n\n try {\n // Get partner's referral codes\n const referralCodesQuery = await payload.find({\n collection: pluginConfig.collections.referralCodesSlug,\n where: {\n referrer: { equals: typedUser.id },\n },\n limit: 100,\n })\n\n const referralCodes = referralCodesQuery.docs\n\n // Calculate stats\n let totalEarnings = 0\n let pendingEarnings = 0\n let paidEarnings = 0\n let totalReferrals = 0\n let successfulReferrals = 0\n\n const referralCodeData = referralCodes.map((code: any) => {\n totalEarnings += code.totalEarnings || 0\n pendingEarnings += code.pendingEarnings || 0\n paidEarnings += code.paidEarnings || 0\n totalReferrals += code.usageCount || 0\n successfulReferrals += code.successfulReferralsCount || 0\n\n return {\n id: code.id,\n code: code.code,\n usageCount: code.usageCount || 0,\n totalEarnings: code.totalEarnings || 0,\n isActive: code.isActive,\n }\n })\n\n // Calculate conversion rate\n const conversionRate = totalReferrals > 0 ? (successfulReferrals / totalReferrals) * 100 : 0\n\n // Get recent referrals (from orders with this partner's referral codes)\n const recentReferrals: PartnerStats['recentReferrals'] = []\n\n // Try to get orders with applied referral codes\n try {\n const ordersQuery = await payload.find({\n collection: 'orders',\n where: {\n appliedReferralCode: {\n in: referralCodes.map((c: any) => c.id),\n },\n },\n limit: 10,\n sort: '-createdAt',\n })\n\n for (const order of ordersQuery.docs as any[]) {\n recentReferrals.push({\n id: order.id,\n code: referralCodes.find((c: any) => c.id === order.appliedReferralCode)?.code || '',\n orderValue: order.total || 0,\n commission: order.partnerCommission || 0,\n date: order.createdAt,\n status: order.paymentStatus === 'paid' ? 'paid' : 'pending',\n })\n }\n } catch {\n // Orders collection might not exist or have different structure\n }\n\n // Calculate monthly earnings (last 6 months)\n const monthlyEarnings: PartnerStats['monthlyEarnings'] = []\n const now = new Date()\n\n for (let i = 5; i >= 0; i--) {\n const monthDate = new Date(now.getFullYear(), now.getMonth() - i, 1)\n const monthName = monthDate.toLocaleString('default', { month: 'short', year: 'numeric' })\n\n // This would need actual order data to calculate properly\n // For now, we'll provide placeholder structure\n monthlyEarnings.push({\n month: monthName,\n earnings: 0,\n referrals: 0,\n })\n }\n\n // Get the partner's active program\n let program: PartnerDashboardData['program'] = null\n\n if (referralCodes.length > 0) {\n const firstCode = referralCodes[0] as any\n if (firstCode.program) {\n try {\n const programData = await payload.findByID({\n collection: pluginConfig.collections.referralProgramsSlug,\n id: typeof firstCode.program === 'string' ? firstCode.program : firstCode.program.id,\n })\n\n if (programData) {\n const typedProgram = programData as any\n const firstRule = typedProgram.commissionRules?.[0]\n program = {\n name: typedProgram.name,\n description: typedProgram.description,\n commissionRate: firstRule?.referrerReward?.value ?? 0,\n customerDiscount: firstRule?.refereeReward?.value ?? 0,\n }\n }\n } catch {\n // Program might not exist\n }\n }\n }\n\n const stats: PartnerStats = {\n totalEarnings,\n pendingEarnings,\n paidEarnings,\n totalReferrals,\n successfulReferrals,\n conversionRate: Math.round(conversionRate * 100) / 100,\n recentReferrals,\n monthlyEarnings,\n }\n\n const dashboardData: PartnerDashboardData = {\n stats,\n referralCodes: referralCodeData,\n program,\n }\n\n return Response.json({\n success: true,\n data: dashboardData,\n currency: pluginConfig.defaultCurrency,\n })\n } catch (error) {\n console.error('Partner stats error:', error)\n return Response.json(\n { success: false, error: 'Failed to fetch partner stats' },\n { status: 500 },\n )\n }\n }\n\nexport const partnerStatsEndpoint = ({ pluginConfig }: Args): Endpoint => ({\n path: pluginConfig.endpoints.partnerStats,\n method: 'get',\n handler: partnerStatsHandler({ pluginConfig }),\n})\n","import type { Endpoint, PayloadHandler } from 'payload'\n\nimport type { SanitizedCouponPluginOptions } from '../types'\nimport { roundTo2 } from '../utilities/roundTo2'\n\ntype Args = {\n pluginConfig: SanitizedCouponPluginOptions\n}\n\nexport const validateCouponHandler =\n ({ pluginConfig }: Args): PayloadHandler =>\n async (req) => {\n const { payload } = req\n const { code, cartValue, cartID, customerEmail } = req.data || {}\n\n if (!code) {\n return Response.json(\n {\n success: false,\n error: 'Code is required',\n },\n { status: 400 },\n )\n }\n\n try {\n if (pluginConfig.enableReferrals) {\n // Referral mode: validate referral codes\n return await validateReferralCode({ payload, code, cartID, pluginConfig })\n } else {\n // Coupon mode: validate coupons\n return await validateCouponCode({\n payload,\n code,\n cartValue,\n customerEmail,\n pluginConfig,\n })\n }\n } catch (error) {\n console.error('Code validation error:', error)\n return Response.json({ success: false, error: 'Internal server error' }, { status: 500 })\n }\n }\n\n// Validate coupon code (existing logic)\nasync function validateCouponCode({\n payload,\n code,\n cartValue,\n customerEmail,\n pluginConfig,\n}: {\n payload: any\n code: string\n cartValue?: number\n customerEmail?: string\n pluginConfig: SanitizedCouponPluginOptions\n}) {\n // Find the coupon\n const coupon = await payload.find({\n collection: pluginConfig.collections.couponsSlug,\n where: {\n code: { equals: code },\n },\n limit: 1,\n })\n\n if (!coupon.docs.length) {\n return Response.json({ success: false, error: 'Invalid coupon code' }, { status: 404 })\n }\n\n const couponData = coupon.docs[0]\n\n // Check if coupon is active\n const now = new Date()\n const activeFrom = couponData.activeFrom ? new Date(couponData.activeFrom) : null\n const activeUntil = couponData.activeUntil ? new Date(couponData.activeUntil) : null\n\n if (activeFrom && now < activeFrom) {\n return Response.json({ success: false, error: 'Coupon is not yet active' }, { status: 400 })\n }\n\n if (activeUntil && now > activeUntil) {\n return Response.json({ success: false, error: 'Coupon has expired' }, { status: 400 })\n }\n\n // Check usage limits\n if (couponData.usageLimit && couponData.usageCount >= couponData.usageLimit) {\n return Response.json({ success: false, error: 'Coupon usage limit exceeded' }, { status: 400 })\n }\n\n // Optional: per-customer limit (when customer identifier provided)\n if (\n couponData.perCustomerLimit != null &&\n couponData.perCustomerLimit > 0 &&\n typeof customerEmail === 'string' &&\n customerEmail.trim().length > 0\n ) {\n const email = customerEmail.trim()\n const { ordersSlug, orderCustomerEmailField, orderPaymentStatusField, orderPaidStatusValue } =\n pluginConfig.orderIntegration\n const ordersQuery = await payload.find({\n collection: ordersSlug,\n where: {\n and: [\n { appliedCoupon: { equals: couponData.id } },\n { [orderCustomerEmailField]: { equals: email } },\n { [orderPaymentStatusField]: { equals: orderPaidStatusValue } },\n ],\n },\n limit: 0,\n })\n if (ordersQuery.totalDocs >= couponData.perCustomerLimit) {\n return Response.json(\n { success: false, error: 'You have reached the maximum uses for this coupon.' },\n { status: 400 },\n )\n }\n }\n\n // Check minimum/maximum order value (top-level fields, same as apply endpoint)\n if (cartValue !== undefined) {\n const minOrderValue = couponData.minOrderValue\n const maxOrderValue = couponData.maxOrderValue\n\n if (minOrderValue && cartValue < minOrderValue) {\n return Response.json(\n {\n success: false,\n error: `Minimum order value of ${minOrderValue} ${pluginConfig.defaultCurrency} required`,\n },\n { status: 400 },\n )\n }\n\n if (maxOrderValue && cartValue > maxOrderValue) {\n return Response.json(\n {\n success: false,\n error: `Maximum order value of ${maxOrderValue} ${pluginConfig.defaultCurrency} exceeded`,\n },\n { status: 400 },\n )\n }\n }\n\n // Calculate discount preview (2 decimal standard)\n let discount = 0\n if (cartValue !== undefined) {\n if (couponData.type === 'percentage') {\n discount = roundTo2((cartValue * couponData.value) / 100)\n if (couponData.maxDiscountAmount != null && discount > couponData.maxDiscountAmount) {\n discount = roundTo2(couponData.maxDiscountAmount)\n }\n } else if (couponData.type === 'fixed') {\n discount = roundTo2(couponData.value)\n if (discount > cartValue) discount = roundTo2(cartValue)\n }\n }\n\n return Response.json({\n success: true,\n coupon: {\n code: couponData.code,\n type: couponData.type,\n value: couponData.value,\n description: couponData.description,\n },\n discount,\n currency: pluginConfig.defaultCurrency,\n })\n}\n\n// Validate referral code (new logic)\nasync function validateReferralCode({\n payload,\n code,\n cartID,\n pluginConfig,\n}: {\n payload: any\n code: string\n cartID?: string\n pluginConfig: SanitizedCouponPluginOptions\n}) {\n // Find the referral code\n const referral = await payload.find({\n collection: pluginConfig.collections.referralCodesSlug,\n where: {\n code: { equals: code },\n },\n limit: 1,\n })\n\n if (!referral.docs.length) {\n return Response.json({ success: false, error: 'Referral code not found' }, { status: 404 })\n }\n\n const referralData = referral.docs[0]\n\n // Check if referral code is active\n if (!referralData.isActive) {\n return Response.json({ success: false, error: 'Referral code is not active' }, { status: 400 })\n }\n\n // Check expiration\n if (referralData.expiresAt && new Date() > new Date(referralData.expiresAt)) {\n return Response.json({ success: false, error: 'Referral code has expired' }, { status: 400 })\n }\n\n // Check usage limit\n if (referralData.usageLimit && referralData.usageCount >= referralData.usageLimit) {\n return Response.json(\n { success: false, error: 'Referral code usage limit exceeded' },\n { status: 400 },\n )\n }\n\n // Get the referral program\n const program = await payload.findByID({\n collection: pluginConfig.collections.referralProgramsSlug,\n id: referralData.program,\n })\n\n if (!program || !program.isActive) {\n return Response.json(\n { success: false, error: 'Referral program is not active' },\n { status: 400 },\n )\n }\n\n // Calculate from commission rules (each rule has referrerReward + refereeReward)\n let totalPartnerCommission = 0\n let totalCustomerDiscount = 0\n const rules = (program as any).commissionRules || []\n\n if (cartID && rules.length > 0) {\n const cart = await payload.findByID({\n collection: 'carts',\n id: cartID,\n })\n const cartTotal = cart ? cart.subtotal || cart.total || 0 : 0\n const items = cart?.items || []\n\n for (const item of items) {\n const rule = findApplicableReferralRule(rules, item)\n if (!rule?.referrerReward || !rule?.refereeReward) continue\n\n const itemPrice = item.price ?? item.unitPrice ?? 0\n const quantity = item.quantity ?? 1\n const itemTotal = itemPrice * quantity\n\n let itemPartner = 0\n if (rule.referrerReward.type === 'percentage') {\n itemPartner = (itemTotal * rule.referrerReward.value) / 100\n } else {\n itemPartner = rule.referrerReward.value * quantity\n }\n if (rule.referrerReward.maxReward != null && itemPartner > rule.referrerReward.maxReward) {\n itemPartner = rule.referrerReward.maxReward\n }\n totalPartnerCommission += itemPartner\n\n let itemCustomer = 0\n if (rule.refereeReward.type === 'percentage') {\n itemCustomer = (itemTotal * rule.refereeReward.value) / 100\n } else {\n itemCustomer = rule.refereeReward.value * quantity\n }\n if (rule.refereeReward.maxReward != null && itemCustomer > rule.refereeReward.maxReward) {\n itemCustomer = rule.refereeReward.maxReward\n }\n totalCustomerDiscount += itemCustomer\n }\n\n if (totalCustomerDiscount > cartTotal) totalCustomerDiscount = cartTotal\n }\n\n const roundedPartnerCommission = roundTo2(totalPartnerCommission)\n const roundedCustomerDiscount = roundTo2(totalCustomerDiscount)\n\n return Response.json({\n success: true,\n referralCode: {\n code: referralData.code,\n description: `Get ${roundedCustomerDiscount.toFixed(2)} discount with this referral code`,\n },\n partnerCommission: roundedPartnerCommission,\n customerDiscount: roundedCustomerDiscount,\n currency: pluginConfig.defaultCurrency,\n })\n}\n\nfunction findApplicableReferralRule(rules: any[], item: any) {\n const productId = typeof item.product === 'string' ? item.product : item.product?.id\n const categoryId = item.category ?? item.product?.category\n\n const productRule = rules.find(\n (r) =>\n r.appliesTo === 'products' &&\n r.products?.some((p: any) => (typeof p === 'string' ? p : p?.id) === productId),\n )\n if (productRule) return productRule\n\n if (categoryId) {\n const categoryRule = rules.find(\n (r) =>\n r.appliesTo === 'categories' &&\n r.categories?.some((c: any) => (typeof c === 'string' ? c : c?.id) === categoryId),\n )\n if (categoryRule) return categoryRule\n }\n\n return rules.find((r) => r.appliesTo === 'all') ?? null\n}\n\nexport const validateCouponEndpoint = ({ pluginConfig }: Args): Endpoint => ({\n path: pluginConfig.endpoints.validateCoupon,\n method: 'post',\n handler: validateCouponHandler({ pluginConfig }),\n})\n","import type { CouponPluginOptions, SanitizedCouponPluginOptions } from '../types'\n\nexport const sanitizePluginConfig = ({\n pluginConfig,\n}: {\n pluginConfig: CouponPluginOptions\n}): SanitizedCouponPluginOptions => {\n // Apply defaults for each property when missing or invalid\n return {\n enabled: !(\n pluginConfig?.enabled === false ||\n (typeof pluginConfig?.enabled === 'string' && pluginConfig.enabled === 'false')\n ),\n enableReferrals:\n !!pluginConfig?.enableReferrals &&\n (typeof pluginConfig?.enableReferrals !== 'string' ||\n pluginConfig.enableReferrals !== 'false'),\n allowStackWithOtherCoupons:\n !!pluginConfig?.allowStackWithOtherCoupons &&\n (typeof pluginConfig?.allowStackWithOtherCoupons !== 'string' ||\n pluginConfig.allowStackWithOtherCoupons !== 'false'),\n defaultCurrency:\n typeof pluginConfig?.defaultCurrency === 'string' &&\n pluginConfig.defaultCurrency.length > 0 &&\n pluginConfig.defaultCurrency.length <= 3\n ? pluginConfig.defaultCurrency\n : 'USD',\n collections: {\n couponsSlug:\n typeof pluginConfig?.collections?.couponsSlug === 'string' &&\n pluginConfig.collections.couponsSlug.trim().length > 0 &&\n pluginConfig.collections.couponsSlug.length <= 100\n ? pluginConfig.collections.couponsSlug\n : 'coupons',\n referralProgramsSlug:\n typeof pluginConfig?.collections?.referralProgramsSlug === 'string' &&\n pluginConfig.collections.referralProgramsSlug.trim().length > 0 &&\n pluginConfig.collections.referralProgramsSlug.length <= 100\n ? pluginConfig.collections.referralProgramsSlug\n : 'referral-programs',\n referralCodesSlug:\n typeof pluginConfig?.collections?.referralCodesSlug === 'string' &&\n pluginConfig.collections.referralCodesSlug.trim().length > 0 &&\n pluginConfig.collections.referralCodesSlug.length <= 100\n ? pluginConfig.collections.referralCodesSlug\n : 'referral-codes',\n referralPartnersSlug:\n typeof pluginConfig?.collections?.referralPartnersSlug === 'string' &&\n pluginConfig.collections.referralPartnersSlug.trim().length > 0 &&\n pluginConfig.collections.referralPartnersSlug.length <= 100\n ? pluginConfig.collections.referralPartnersSlug\n : 'referral-partners',\n },\n endpoints: {\n applyCoupon:\n typeof pluginConfig?.endpoints?.applyCoupon === 'string' &&\n pluginConfig.endpoints.applyCoupon.trim().length > 0\n ? pluginConfig.endpoints.applyCoupon\n : '/coupons/apply',\n validateCoupon:\n typeof pluginConfig?.endpoints?.validateCoupon === 'string' &&\n pluginConfig.endpoints.validateCoupon.trim().length > 0\n ? pluginConfig.endpoints.validateCoupon\n : '/coupons/validate',\n partnerStats:\n typeof pluginConfig?.endpoints?.partnerStats === 'string' &&\n pluginConfig.endpoints.partnerStats.trim().length > 0\n ? pluginConfig.endpoints.partnerStats\n : '/referrals/partner-stats',\n recordOrderUsage:\n typeof pluginConfig?.endpoints?.recordOrderUsage === 'string' &&\n pluginConfig.endpoints.recordOrderUsage.trim().length > 0\n ? pluginConfig.endpoints.recordOrderUsage\n : '/coupons/record-order-usage',\n },\n autoIntegrate: pluginConfig?.autoIntegrate !== false,\n access: {\n canUseCoupons:\n typeof pluginConfig?.access?.canUseCoupons === 'function'\n ? pluginConfig.access.canUseCoupons\n : () => true,\n canUseReferrals:\n typeof pluginConfig?.access?.canUseReferrals === 'function'\n ? pluginConfig.access.canUseReferrals\n : () => false,\n isAdmin:\n typeof pluginConfig?.access?.isAdmin === 'function'\n ? pluginConfig.access.isAdmin\n : () => false,\n isPartner:\n typeof pluginConfig?.access?.isPartner === 'function'\n ? pluginConfig.access.isPartner\n : ({ req }) => {\n // Default: check if user has partner role\n const user = req?.user as { role?: string; roles?: string[] } | undefined\n if (!user) return false\n if (user.role === 'partner') return true\n if (Array.isArray(user.roles) && user.roles.includes('partner')) return true\n return false\n },\n },\n referralConfig: {\n allowBothSystems: pluginConfig?.referralConfig?.allowBothSystems ?? false,\n singleCodePerCart: pluginConfig?.referralConfig?.singleCodePerCart ?? true,\n defaultPartnerSplit: pluginConfig?.referralConfig?.defaultPartnerSplit ?? 70,\n defaultCustomerSplit: pluginConfig?.referralConfig?.defaultCustomerSplit ?? 30,\n },\n adminGroups: {\n couponsGroup: pluginConfig?.adminGroups?.couponsGroup ?? 'Coupons',\n referralsGroup: pluginConfig?.adminGroups?.referralsGroup ?? 'Referrals',\n },\n partnerDashboard: {\n enabled: pluginConfig?.partnerDashboard?.enabled ?? true,\n showEarningsSummary: pluginConfig?.partnerDashboard?.showEarningsSummary ?? true,\n showReferralPerformance: pluginConfig?.partnerDashboard?.showReferralPerformance ?? true,\n showRecentReferrals: pluginConfig?.partnerDashboard?.showRecentReferrals ?? true,\n showCommissionBreakdown: pluginConfig?.partnerDashboard?.showCommissionBreakdown ?? true,\n },\n orderIntegration: {\n ordersSlug:\n typeof pluginConfig?.orderIntegration?.ordersSlug === 'string' &&\n pluginConfig.orderIntegration.ordersSlug.trim().length > 0\n ? pluginConfig.orderIntegration.ordersSlug\n : 'orders',\n orderCustomerEmailField:\n typeof pluginConfig?.orderIntegration?.orderCustomerEmailField === 'string' &&\n pluginConfig.orderIntegration.orderCustomerEmailField.trim().length > 0\n ? pluginConfig.orderIntegration.orderCustomerEmailField\n : 'customerEmail',\n orderPaymentStatusField:\n typeof pluginConfig?.orderIntegration?.orderPaymentStatusField === 'string' &&\n pluginConfig.orderIntegration.orderPaymentStatusField.trim().length > 0\n ? pluginConfig.orderIntegration.orderPaymentStatusField\n : 'paymentStatus',\n orderPaidStatusValue:\n typeof pluginConfig?.orderIntegration?.orderPaidStatusValue === 'string'\n ? pluginConfig.orderIntegration.orderPaidStatusValue\n : 'paid',\n },\n }\n}\n","import type { Config } from 'payload'\n\nimport { createCouponsCollection } from './collections/createCouponsCollection'\nimport { createReferralCodesCollection } from './collections/createReferralCodesCollection'\nimport { createReferralProgramsCollection } from './collections/createReferralProgramsCollection'\nimport { applyCouponEndpoint } from './endpoints/applyCoupon'\nimport { partnerStatsEndpoint } from './endpoints/partnerStats'\nimport { validateCouponEndpoint } from './endpoints/validateCoupon'\nimport type { CouponPluginOptions } from './types'\nimport { sanitizePluginConfig } from './utilities/sanitizePluginConfig'\n\nexport const payloadEcommerceCouponPlugin =\n (pluginOptions: CouponPluginOptions = {}) =>\n async (incomingConfig: Config): Promise<Config> => {\n const pluginConfig = sanitizePluginConfig({ pluginConfig: pluginOptions })\n\n if (!pluginConfig.enabled) return incomingConfig || {}\n\n // Handle null or undefined incoming config\n if (!incomingConfig) {\n incomingConfig = { collections: [], endpoints: [] } as any\n }\n if (!incomingConfig.collections) {\n incomingConfig.collections = []\n }\n\n const collectionsToAdd = []\n\n // When enableReferrals is true, both coupon and referral collections are created\n // The referralConfig.allowBothSystems determines if both can be used simultaneously\n if (pluginConfig.enableReferrals) {\n // Referral mode: create referral collections\n let referralProgramsCollection = createReferralProgramsCollection(pluginConfig)\n let referralCodesCollection = createReferralCodesCollection(pluginConfig)\n\n // Apply collection overrides if provided\n if (pluginOptions.collections?.referralProgramsCollectionOverride) {\n referralProgramsCollection =\n await pluginOptions.collections.referralProgramsCollectionOverride({\n defaultCollection: referralProgramsCollection,\n })\n }\n\n if (pluginOptions.collections?.referralCodesCollectionOverride) {\n referralCodesCollection = await pluginOptions.collections.referralCodesCollectionOverride({\n defaultCollection: referralCodesCollection,\n })\n }\n\n collectionsToAdd.push(referralProgramsCollection, referralCodesCollection)\n\n // If allowBothSystems is true, also create coupon collection\n if (pluginConfig.referralConfig.allowBothSystems) {\n let couponsCollection = createCouponsCollection(pluginConfig)\n if (pluginOptions.collections?.couponsCollectionOverride) {\n couponsCollection = await pluginOptions.collections.couponsCollectionOverride({\n defaultCollection: couponsCollection,\n })\n }\n collectionsToAdd.push(couponsCollection)\n }\n } else {\n // Coupon mode: create coupon collections only\n let couponsCollection = createCouponsCollection(pluginConfig)\n if (pluginOptions.collections?.couponsCollectionOverride) {\n couponsCollection = await pluginOptions.collections.couponsCollectionOverride({\n defaultCollection: couponsCollection,\n })\n }\n collectionsToAdd.push(couponsCollection)\n }\n\n // Add collections to config (avoid duplicates)\n const existingSlugs = new Set(incomingConfig.collections.map((c: any) => c.slug))\n const collectionsToAddFiltered = collectionsToAdd.filter((c: any) => !existingSlugs.has(c.slug))\n incomingConfig.collections = [...incomingConfig.collections, ...collectionsToAddFiltered]\n\n // Add endpoints\n if (!incomingConfig.endpoints) {\n incomingConfig.endpoints = []\n }\n\n incomingConfig.endpoints = [\n ...incomingConfig.endpoints,\n validateCouponEndpoint({ pluginConfig }),\n applyCouponEndpoint({ pluginConfig }),\n ]\n\n // Add partner stats endpoint if referrals are enabled\n if (pluginConfig.enableReferrals) {\n incomingConfig.endpoints.push(partnerStatsEndpoint({ pluginConfig }))\n }\n\n // Safe autoIntegrate implementation — ensure referral collection exists before injecting relationships\n if (pluginConfig.autoIntegrate) {\n // Ensure collections array exists\n incomingConfig.collections = incomingConfig.collections || []\n\n // After we already appended the plugin collections above, recompute slug set\n const allSlugs = new Set<string>(incomingConfig.collections.map((c: any) => c.slug))\n\n // Helper that adds a field group to an existing collection (by slug) if not already present\n const addFieldsToCollection = (targetSlug: string, newFields: any[]) => {\n const idx = incomingConfig.collections!.findIndex((c: any) => c.slug === targetSlug)\n if (idx === -1) return\n const collection = incomingConfig.collections![idx]\n collection.fields = collection.fields || []\n\n // Avoid adding duplicate fields (by name)\n const existingFieldNames = new Set(collection.fields.map((f: any) => f.name))\n for (const f of newFields) {\n if (!existingFieldNames.has(f.name)) {\n collection.fields.push(f)\n }\n }\n\n // Replace the collection entry (mutation is OK here)\n incomingConfig.collections![idx] = collection\n }\n\n // Only inject referral integration if the referral collection slug is actually present\n if (\n pluginConfig.enableReferrals &&\n allSlugs.has(pluginConfig.collections.referralCodesSlug)\n ) {\n // Fields to append to carts (referral mode)\n const cartReferralFields = [\n {\n name: 'appliedReferralCode',\n type: 'relationship',\n relationTo: pluginConfig.collections.referralCodesSlug,\n admin: { description: 'Referral code applied to this cart' },\n },\n {\n name: 'partnerCommission',\n type: 'number',\n admin: { description: 'Partner commission amount for this cart' },\n },\n {\n name: 'customerDiscount',\n type: 'number',\n admin: { description: 'Customer discount amount for this cart' },\n },\n ]\n\n // If both systems allowed, also add coupon field\n if (\n pluginConfig.referralConfig.allowBothSystems &&\n allSlugs.has(pluginConfig.collections.couponsSlug)\n ) {\n cartReferralFields.push({\n name: 'appliedCoupon',\n type: 'relationship',\n relationTo: pluginConfig.collections.couponsSlug,\n admin: { description: 'Coupon applied to this cart' },\n })\n cartReferralFields.push({\n name: 'discountAmount',\n type: 'number',\n admin: { description: 'Discount amount from coupon' },\n })\n }\n\n addFieldsToCollection('carts', cartReferralFields)\n\n // Fields to append to orders (referral mode)\n const orderReferralFields = [\n {\n name: 'appliedReferralCode',\n type: 'relationship',\n relationTo: pluginConfig.collections.referralCodesSlug,\n admin: { description: 'Referral code applied to this order', readOnly: true },\n },\n {\n name: 'partnerCommission',\n type: 'number',\n admin: { description: 'Partner commission amount for this order', readOnly: true },\n },\n {\n name: 'customerDiscount',\n type: 'number',\n admin: { description: 'Customer discount amount for this order', readOnly: true },\n },\n ]\n\n // If both systems allowed, also add coupon field to orders\n if (\n pluginConfig.referralConfig.allowBothSystems &&\n allSlugs.has(pluginConfig.collections.couponsSlug)\n ) {\n orderReferralFields.push({\n name: 'appliedCoupon',\n type: 'relationship',\n relationTo: pluginConfig.collections.couponsSlug,\n admin: { description: 'Coupon applied to this order', readOnly: true },\n })\n orderReferralFields.push({\n name: 'discountAmount',\n type: 'number',\n admin: { description: 'Discount amount from coupon', readOnly: true },\n })\n }\n\n addFieldsToCollection('orders', orderReferralFields)\n } else if (\n !pluginConfig.enableReferrals &&\n allSlugs.has(pluginConfig.collections.couponsSlug)\n ) {\n // coupon mode — similar safe injection for appliedCoupons\n const cartCouponFields = [\n {\n name: 'appliedCoupon',\n type: 'relationship',\n relationTo: pluginConfig.collections.couponsSlug,\n admin: { description: 'Coupon applied to this cart' },\n },\n {\n name: 'discountAmount',\n type: 'number',\n admin: { description: 'Discount amount from coupon' },\n },\n ]\n addFieldsToCollection('carts', cartCouponFields)\n\n const orderCouponFields = [\n {\n name: 'appliedCoupon',\n type: 'relationship',\n relationTo: pluginConfig.collections.couponsSlug,\n admin: { description: 'Coupon applied to this order', readOnly: true },\n },\n {\n name: 'discountAmount',\n type: 'number',\n admin: { description: 'Discount amount from coupon', readOnly: true },\n },\n ]\n addFieldsToCollection('orders', orderCouponFields)\n }\n }\n\n return incomingConfig\n }\n","import type { ApplyCouponHook, ApplyCouponResponse, PartnerDashboardData } from '../types'\n\n/**\n * Apply a coupon code to a cart\n * @param options - Coupon code, cart ID, and customer email\n * @returns Response with success status, discount amount, and coupon details\n */\nexport async function useCouponCode(options: ApplyCouponHook): Promise<ApplyCouponResponse> {\n const { code, cartID, customerEmail } = options\n\n if (!code) {\n return {\n success: false,\n message: 'Coupon code is required',\n error: 'Code is missing',\n }\n }\n\n try {\n const response = await fetch('/api/coupons/apply', {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify({ code, cartID, customerEmail }),\n })\n\n const data = (await response.json()) as Record<string, unknown>\n\n if (!response.ok) {\n return {\n success: false,\n message: (data.error as string) || 'Failed to apply coupon',\n error: data.error as string,\n }\n }\n\n const couponData = data.coupon as Record<string, unknown> | undefined\n const referralData = data.referralCode as Record<string, unknown> | undefined\n\n return {\n success: data.success as boolean,\n message: data.message as string,\n discount: (data.discount as number) || (data.customerDiscount as number),\n partnerCommission: data.partnerCommission as number,\n customerDiscount: data.customerDiscount as number,\n coupon: couponData\n ? {\n code: (couponData.code as string) || '',\n type: (couponData.type as 'percentage' | 'fixed') || 'percentage',\n value: (couponData.value as number) || 0,\n }\n : undefined,\n referralCode: referralData\n ? {\n code: (referralData.code as string) || '',\n }\n : undefined,\n }\n } catch (error) {\n const message = error instanceof Error ? error.message : 'Network error'\n return { success: false, message, error: message }\n }\n}\n\n/**\n * Validate a coupon code without applying it\n * @param code - Coupon code to validate\n * @param cartValue - Optional cart value in smallest currency unit\n * @returns Response with validation result and coupon details\n */\nexport async function validateCouponCode(\n code: string,\n cartValue?: number,\n cartID?: string,\n): Promise<ApplyCouponResponse> {\n if (!code) {\n return {\n success: false,\n message: 'Code required',\n error: 'Code missing',\n }\n }\n\n try {\n const response = await fetch('/api/coupons/validate', {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify({ code, cartValue, cartID }),\n })\n\n const data = (await response.json()) as Record<string, unknown>\n\n if (!response.ok) {\n return {\n success: false,\n message: (data.error as string) || 'Invalid coupon',\n error: data.error as string,\n }\n }\n\n const couponData = data.coupon as Record<string, unknown> | undefined\n const referralData = data.referralCode as Record<string, unknown> | undefined\n\n return {\n success: data.success as boolean,\n message: data.message as string,\n coupon: couponData\n ? {\n code: (couponData.code as string) || '',\n type: (couponData.type as 'percentage' | 'fixed') || 'percentage',\n value: (couponData.value as number) || 0,\n }\n : undefined,\n referralCode: referralData\n ? {\n code: (referralData.code as string) || '',\n }\n : undefined,\n discount: data.discount as number,\n partnerCommission: data.partnerCommission as number,\n customerDiscount: data.customerDiscount as number,\n currency: data.currency as string,\n }\n } catch (error) {\n const message = error instanceof Error ? error.message : 'Network error'\n return { success: false, message, error: message }\n }\n}\n\nexport type PartnerStatsResponse = {\n success: boolean\n data?: PartnerDashboardData\n currency?: string\n error?: string\n}\n\n/**\n * Fetch partner dashboard statistics\n * @param apiEndpoint - Optional custom API endpoint (default: /api/referrals/partner-stats)\n * @returns Response with partner stats, referral codes, and program info\n */\nexport async function usePartnerStats(\n apiEndpoint: string = '/api/referrals/partner-stats',\n): Promise<PartnerStatsResponse> {\n try {\n const response = await fetch(apiEndpoint, {\n method: 'GET',\n headers: { 'Content-Type': 'application/json' },\n credentials: 'include',\n })\n\n const data = (await response.json()) as Record<string, unknown>\n\n if (!response.ok) {\n return {\n success: false,\n error: (data.error as string) || 'Failed to fetch partner stats',\n }\n }\n\n return {\n success: data.success as boolean,\n data: data.data as PartnerDashboardData,\n currency: data.currency as string,\n }\n } catch (error) {\n const message = error instanceof Error ? error.message : 'Network error'\n return { success: false, error: message }\n }\n}\n","import { roundTo2 } from './roundTo2'\n\nexport type CartLike = {\n subtotal?: number\n total?: number\n discountAmount?: number\n customerDiscount?: number\n}\n\n/**\n * Computes the cart total after applying plugin discounts.\n * Use this in your host app's cart beforeChange (or wherever you compute total)\n * so the amount always reflects coupon/referral discounts and is not overwritten incorrectly.\n *\n * Formula: subtotal - discountAmount - customerDiscount (each defaulting to 0).\n */\nexport function getCartTotalWithDiscounts(cart: CartLike): number {\n const subtotal = cart.subtotal ?? cart.total ?? 0\n const discountAmount = cart.discountAmount ?? 0\n const customerDiscount = cart.customerDiscount ?? 0\n return roundTo2(Math.max(0, subtotal - discountAmount - customerDiscount))\n}\n","import type { Payload } from 'payload'\n\nimport type { SanitizedCouponPluginOptions } from '../types'\n\nexport type OrderWithCouponFields = {\n id?: string\n appliedCoupon?: string | { id: string }\n appliedReferralCode?: string | { id: string }\n partnerCommission?: number\n customerDiscount?: number\n discountAmount?: number\n}\n\nexport type RecordCouponUsageResult = {\n recordedCoupon: boolean\n recordedReferral: boolean\n}\n\n/**\n * Record coupon and referral usage when an order is placed successfully.\n * Call this once when the order is created/paid (e.g. from Orders collection afterChange hook).\n *\n * - Coupon: increments the coupon's usageCount.\n * - Referral: increments the referral code's usageCount and successfulReferralsCount,\n * and adds order.partnerCommission to totalEarnings and pendingEarnings (referrer gets commission;\n * referee discount is already on the order).\n */\nexport async function recordCouponUsageForOrder(\n payload: Payload,\n order: OrderWithCouponFields,\n pluginConfig: SanitizedCouponPluginOptions,\n): Promise<RecordCouponUsageResult> {\n const result: RecordCouponUsageResult = { recordedCoupon: false, recordedReferral: false }\n\n const couponId =\n order.appliedCoupon == null\n ? null\n : typeof order.appliedCoupon === 'string'\n ? order.appliedCoupon\n : order.appliedCoupon?.id\n\n const referralCodeId =\n order.appliedReferralCode == null\n ? null\n : typeof order.appliedReferralCode === 'string'\n ? order.appliedReferralCode\n : order.appliedReferralCode?.id\n\n if (couponId) {\n const coupon = await payload.findByID({\n collection: pluginConfig.collections.couponsSlug,\n id: couponId,\n })\n if (coupon) {\n await payload.update({\n collection: pluginConfig.collections.couponsSlug,\n id: couponId,\n data: {\n usageCount: (coupon.usageCount ?? 0) + 1,\n },\n })\n result.recordedCoupon = true\n }\n }\n\n if (referralCodeId) {\n const referralCode = await payload.findByID({\n collection: pluginConfig.collections.referralCodesSlug,\n id: referralCodeId,\n })\n if (referralCode) {\n const commission = Number(order.partnerCommission) || 0\n const currentTotal = Number((referralCode as any).totalEarnings) || 0\n const currentPending = Number((referralCode as any).pendingEarnings) || 0\n const currentUsageCount = Number((referralCode as any).usageCount) || 0\n const currentSuccessful = Number((referralCode as any).successfulReferralsCount) || 0\n\n await payload.update({\n collection: pluginConfig.collections.referralCodesSlug,\n id: referralCodeId,\n data: {\n usageCount: currentUsageCount + 1,\n successfulReferralsCount: currentSuccessful + 1,\n totalEarnings: currentTotal + commission,\n pendingEarnings: currentPending + commission,\n },\n })\n result.recordedReferral = true\n }\n }\n\n return result\n}\n"],"mappings":"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U;OACzB,aAAa;OACd;MACF;KACD;MACE,MAAM;MACN,MAAM;MACN,KAAK;MACL,KAAK;MACL,OAAO;OACL,YAAY,GAAY,gBACtB,aAAa,UAAU;OACzB,aAAa;OACd;MACF;KACD;MACE,MAAM;MACN,MAAM;MACN,OAAO;OACL,YAAY,GAAY,gBACtB,aAAa,UAAU;OACzB,aAAa;OACd;MACD,QAAQ;OACN;QACE,MAAM;QACN,MAAM;QACN,UAAU;QACV,SAAS,CACP;SAAE,OAAO;SAAgB,OAAO;SAAS,EACzC;SAAE,OAAO;SAAuB,OAAO;SAAc,CACtD;QACD,cAAc;QACf;OACD;QACE,MAAM;QACN,MAAM;QACN,UAAU;QACV,cAAc,eAAe;QAC7B,OAAO,EACL,aAAa,iEAAiE,mBAC/E;QACF;OACD;QACE,MAAM;QACN,MAAM;QACN,OAAO,EACL,aAAa,iBAAiB,gBAAgB,4BAC/C;QACF;OACF;MACF;KACD;MACE,MAAM;MACN,MAAM;MACN,OAAO;OACL,YAAY,GAAY,gBACtB,aAAa,UAAU;OACzB,aAAa;OACd;MACD,QAAQ;OACN;QACE,MAAM;QACN,MAAM;QACN,UAAU;QACV,SAAS,CACP;SAAE,OAAO;SAAgB,OAAO;SAAS,EACzC;SAAE,OAAO;SAAuB,OAAO;SAAc,CACtD;QACD,cAAc;QACf;OACD;QACE,MAAM;QACN,MAAM;QACN,UAAU;QACV,cAAc,eAAe;QAC7B,OAAO,EACL,aAAa,2DAA2D,mBACzE;QACF;OACD;QACE,MAAM;QACN,MAAM;QACN,OAAO,EACL,aAAa,mBAAmB,gBAAgB,4BACjD;QACF;OACF;MACF;KACF;IACF;GACD;IACE,MAAM;IACN,MAAM;IACN,OAAO,EACL,aAAa,gDAAgD,mBAC9D;IACF;GACD;IACE,MAAM;IACN,MAAM;IACN,OAAO,EACL,aAAa,sEACd;IACF;GACD;IACE,MAAM;IACN,MAAM;IACN,OAAO,EACL,aAAa,0EACd;IACF;GACD;IACE,MAAM;IACN,MAAM;IACN,OAAO,EACL,aAAa,yCACd;IACF;GACD;IACE,MAAM;IACN,MAAM;IACN,OAAO,EACL,a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"}
1
+ {"version":3,"file":"index.mjs","names":["validateCouponCode"],"sources":["../src/collections/createCouponsCollection.ts","../src/collections/createReferralCodesCollection.ts","../src/collections/createReferralProgramsCollection.ts","../src/utilities/roundTo2.ts","../src/utilities/pricing.ts","../src/utilities/calculateValues.ts","../src/endpoints/applyCoupon.ts","../src/endpoints/partnerStats.ts","../src/endpoints/validateCoupon.ts","../src/hooks/recalculateCart.ts","../src/utilities/sanitizePluginConfig.ts","../src/plugin.ts","../src/client/hooks.ts","../src/utilities/getCartTotalWithDiscounts.ts","../src/utilities/recordCouponUsageForOrder.ts"],"sourcesContent":["import type { CollectionConfig } from 'payload'\n\nimport type { SanitizedCouponPluginOptions } from '../types'\n\nexport const createCouponsCollection = (\n pluginConfig: SanitizedCouponPluginOptions,\n): CollectionConfig => {\n const { collections, access, defaultCurrency, adminGroups } = pluginConfig\n\n return {\n slug: collections.couponsSlug,\n admin: {\n useAsTitle: 'code',\n defaultColumns: ['code', 'type', 'value', 'activeFrom', 'activeUntil'],\n group: adminGroups.couponsGroup,\n },\n access: {\n read: access.canUseCoupons || (() => true),\n create: access.isAdmin || (() => false),\n update: access.isAdmin || (() => false),\n delete: access.isAdmin || (() => false),\n },\n fields: [\n {\n name: 'code',\n type: 'text',\n required: true,\n unique: true,\n admin: {\n description: 'The coupon code that customers will enter',\n },\n },\n {\n name: 'description',\n type: 'text',\n admin: {\n description: 'Optional description for admin reference',\n },\n },\n {\n name: 'type',\n type: 'select',\n required: true,\n options: [\n { label: 'Percentage', value: 'percentage' },\n { label: 'Fixed Amount', value: 'fixed' },\n ],\n defaultValue: 'percentage',\n admin: {\n description: 'Whether this is a percentage or fixed amount discount',\n },\n },\n {\n name: 'value',\n type: 'number',\n required: true,\n admin: {\n description: `If percentage, 10 = 10%. If fixed, interpreted in ${defaultCurrency} (smallest currency units)`,\n step: 0.01,\n },\n },\n {\n name: 'maxDiscountAmount',\n type: 'number',\n admin: {\n description: `Maximum discount amount in ${defaultCurrency} (smallest currency unit). Leave empty for no cap.`,\n },\n },\n {\n name: 'usageLimit',\n type: 'number',\n admin: {\n description:\n 'Total times this coupon can be used across all customers. Empty = unlimited.',\n },\n },\n {\n name: 'perCustomerLimit',\n type: 'number',\n admin: {\n description: 'Times a single customer can use this coupon. Empty = unlimited.',\n },\n },\n {\n name: 'activeFrom',\n type: 'date',\n admin: {\n description:\n 'Coupon becomes active from this date. Leave empty for immediate activation.',\n },\n },\n {\n name: 'activeUntil',\n type: 'date',\n admin: {\n description: 'Coupon expires after this date. Leave empty for no expiration.',\n },\n },\n {\n name: 'minOrderValue',\n type: 'number',\n admin: {\n description: `Minimum order value required in ${defaultCurrency} (smallest currency units)`,\n },\n },\n {\n name: 'maxOrderValue',\n type: 'number',\n admin: {\n description: `Maximum order value allowed in ${defaultCurrency} (smallest currency units)`,\n },\n },\n {\n name: 'usageCount',\n type: 'number',\n defaultValue: 0,\n admin: {\n description: 'How many times this coupon has been used',\n readOnly: true,\n },\n },\n {\n name: 'createdBy',\n type: 'relationship',\n relationTo: 'users',\n admin: {\n readOnly: true,\n position: 'sidebar',\n },\n },\n ],\n hooks: {\n beforeChange: [\n ({ operation, req, data }) => {\n if (operation === 'create' && req.user) {\n data.createdBy = req.user.id\n }\n return data\n },\n ],\n },\n timestamps: true,\n }\n}\n","import type { CollectionConfig } from 'payload'\n\nimport type { SanitizedCouponPluginOptions } from '../types'\n\nexport const createReferralCodesCollection = (\n pluginConfig: SanitizedCouponPluginOptions,\n): CollectionConfig => {\n const { collections, access, adminGroups, defaultCurrency } = pluginConfig\n\n return {\n slug: collections.referralCodesSlug,\n admin: {\n useAsTitle: 'code',\n defaultColumns: ['code', 'referrer', 'program', 'usageCount', 'isActive'],\n group: adminGroups.referralsGroup,\n },\n access: {\n read: ({ req }) => {\n // Partners can read their own codes, admins can read all\n const user = req?.user as { id?: string; role?: string; roles?: string[] } | undefined\n if (!user) return false\n\n // Admin access\n if (user.role === 'admin' || (Array.isArray(user.roles) && user.roles.includes('admin'))) {\n return true\n }\n\n // Partner access - only their own codes\n if (\n user.role === 'partner' ||\n (Array.isArray(user.roles) && user.roles.includes('partner'))\n ) {\n return {\n referrer: {\n equals: user.id,\n },\n }\n }\n\n // Default access from config\n return access.canUseReferrals ? access.canUseReferrals({ req } as any) : false\n },\n create: ({ req }) => {\n // Partners can create their own codes, admins can create any\n const user = req?.user as { role?: string; roles?: string[] } | undefined\n if (!user) return false\n\n if (user.role === 'admin' || (Array.isArray(user.roles) && user.roles.includes('admin'))) {\n return true\n }\n\n if (\n user.role === 'partner' ||\n (Array.isArray(user.roles) && user.roles.includes('partner'))\n ) {\n return true\n }\n\n return access.isAdmin ? access.isAdmin({ req } as any) : false\n },\n update: access.isAdmin || (() => false),\n delete: access.isAdmin || (() => false),\n },\n fields: [\n {\n name: 'code',\n type: 'text',\n required: true,\n unique: true,\n admin: {\n description: 'The referral code that customers will enter',\n },\n },\n {\n name: 'program',\n type: 'relationship',\n relationTo: collections.referralProgramsSlug,\n required: true,\n admin: {\n description: 'The referral program this code belongs to',\n },\n },\n {\n name: 'referrer',\n type: 'relationship',\n relationTo: 'users',\n required: true,\n admin: {\n description: 'The partner who owns this referral code',\n },\n },\n {\n name: 'isActive',\n type: 'checkbox',\n defaultValue: true,\n admin: {\n description: 'Whether this referral code is currently active',\n },\n },\n {\n name: 'usageCount',\n type: 'number',\n defaultValue: 0,\n admin: {\n description: 'How many times this referral code has been used',\n readOnly: true,\n },\n },\n {\n name: 'usageLimit',\n type: 'number',\n admin: {\n description: 'Maximum times this code can be used. Empty = unlimited.',\n },\n },\n {\n name: 'expiresAt',\n type: 'date',\n admin: {\n description: 'When this referral code expires',\n },\n },\n {\n name: 'successfulReferralsCount',\n type: 'number',\n defaultValue: 0,\n admin: {\n description: 'Total count of successful referrals using this code',\n readOnly: true,\n },\n },\n {\n name: 'totalEarnings',\n type: 'number',\n defaultValue: 0,\n admin: {\n description: `Total earnings generated by this code in ${defaultCurrency}`,\n readOnly: true,\n },\n },\n {\n name: 'pendingEarnings',\n type: 'number',\n defaultValue: 0,\n admin: {\n description: `Pending earnings awaiting payout in ${defaultCurrency}`,\n readOnly: true,\n },\n },\n {\n name: 'paidEarnings',\n type: 'number',\n defaultValue: 0,\n admin: {\n description: `Total earnings paid out in ${defaultCurrency}`,\n readOnly: true,\n },\n },\n {\n name: 'metadata',\n type: 'json',\n admin: {\n description: 'Additional metadata for the referral code',\n position: 'sidebar',\n },\n },\n ],\n hooks: {\n beforeChange: [\n ({ operation, req, data }) => {\n // Auto-generate code if not provided\n if (operation === 'create' && !data.code && data.referrer) {\n const timestamp = Date.now().toString(36)\n const random = Math.random().toString(36).substring(2, 8)\n data.code = `REF-${timestamp}-${random}`.toUpperCase()\n }\n\n // Auto-assign referrer to current user if partner\n if (operation === 'create' && req.user) {\n const user = req.user as { id?: string; role?: string; roles?: string[] }\n if (\n user.role === 'partner' ||\n (Array.isArray(user.roles) && user.roles.includes('partner'))\n ) {\n data.referrer = user.id\n }\n }\n\n return data\n },\n ],\n },\n timestamps: true,\n }\n}\n","import type { CollectionConfig } from 'payload'\n\nimport type { SanitizedCouponPluginOptions } from '../types'\n\nexport const createReferralProgramsCollection = (\n pluginConfig: SanitizedCouponPluginOptions,\n): CollectionConfig => {\n const { collections, access, defaultCurrency, adminGroups, referralConfig } = pluginConfig\n\n const beforeChange: NonNullable<CollectionConfig['hooks']>['beforeChange'] = [\n ({ data }: { data: Record<string, unknown> }) => {\n // Commission rules are required; each rule must have referrerReward and refereeReward\n if (\n !data.commissionRules ||\n !Array.isArray(data.commissionRules) ||\n data.commissionRules.length === 0\n ) {\n throw new Error('At least one commission rule is required')\n }\n data.commissionRules.forEach((rule: Record<string, unknown>, index: number) => {\n const r = rule as {\n basis?: 'direct' | 'shared'\n referrerReward?: { type?: string; value?: number }\n refereeReward?: { type?: string; value?: number }\n totalCommission?: { type?: string; value?: number }\n referrerSplit?: number\n refereeSplit?: number\n }\n\n // Shared Basis Validation\n if (r.basis === 'shared') {\n if (!r.totalCommission || r.totalCommission.value == null) {\n throw new Error(\n `Commission rule ${index + 1}: Total Commission is required for Shared Basis`,\n )\n }\n if (r.referrerSplit == null) {\n throw new Error(\n `Commission rule ${index + 1}: Referrer Split is required for Shared Basis`,\n )\n }\n if (r.refereeSplit == null) {\n throw new Error(\n `Commission rule ${index + 1}: Referee Split is required for Shared Basis`,\n )\n }\n if ((r.referrerSplit || 0) + (r.refereeSplit || 0) > 100) {\n throw new Error(\n `Commission rule ${index + 1}: Referrer + Referee split cannot exceed 100%`,\n )\n }\n }\n // Direct Basis Validation (Legacy)\n else {\n if (!r.referrerReward || r.referrerReward.value == null) {\n throw new Error(`Commission rule ${index + 1}: Referrer Reward is required`)\n }\n if (!r.refereeReward || r.refereeReward.value == null) {\n throw new Error(`Commission rule ${index + 1}: Referee Reward is required`)\n }\n if (r.referrerReward?.type === 'percentage' && r.refereeReward?.type === 'percentage') {\n const total = (r.referrerReward.value || 0) + (r.refereeReward.value || 0)\n if (total > 100) {\n throw new Error(\n `Commission rule ${index + 1}: Referrer + Referee percentage cannot exceed 100%`,\n )\n }\n }\n }\n })\n return data\n },\n ]\n\n return {\n slug: collections.referralProgramsSlug,\n admin: {\n useAsTitle: 'name',\n defaultColumns: ['name', 'commissionRules', 'isActive'],\n group: adminGroups.referralsGroup,\n },\n access: {\n read: access.canUseReferrals || (() => true),\n create: access.isAdmin || (() => false),\n update: access.isAdmin || (() => false),\n delete: access.isAdmin || (() => false),\n },\n hooks: {\n beforeChange,\n },\n fields: [\n {\n name: 'name',\n type: 'text',\n required: true,\n admin: {\n description: 'Name of the referral program for admin reference',\n },\n },\n {\n name: 'description',\n type: 'textarea',\n admin: {\n description: 'Description of the referral program',\n },\n },\n {\n name: 'isActive',\n type: 'checkbox',\n defaultValue: true,\n admin: {\n description: 'Whether this referral program is currently active',\n },\n },\n {\n name: 'commissionRules',\n type: 'array',\n required: true,\n minRows: 1,\n admin: {\n description:\n 'Commission rules: each rule defines who it applies to and Referrer Reward + Referee Reward inside the rule.',\n },\n fields: [\n {\n name: 'name',\n type: 'text',\n required: true,\n admin: { description: 'Name of this rule' },\n },\n {\n name: 'appliesTo',\n type: 'select',\n required: true,\n options: [\n { label: 'All Products', value: 'all' },\n { label: 'Specific Categories', value: 'categories' },\n { label: 'Specific Products', value: 'products' },\n ],\n defaultValue: 'all',\n },\n {\n name: 'categories',\n type: 'relationship',\n relationTo: 'categories',\n hasMany: true,\n admin: {\n condition: (_: unknown, siblingData: { appliesTo?: string }) =>\n siblingData?.appliesTo === 'categories',\n description: 'Categories this rule applies to',\n },\n },\n {\n name: 'products',\n type: 'relationship',\n relationTo: 'products',\n hasMany: true,\n admin: {\n condition: (_: unknown, siblingData: { appliesTo?: string }) =>\n siblingData?.appliesTo === 'products',\n description: 'Products this rule applies to',\n },\n },\n {\n name: 'basis',\n type: 'select',\n required: true,\n defaultValue: 'direct',\n options: [\n { label: 'Direct Values', value: 'direct' },\n { label: 'Shared Commission', value: 'shared' },\n ],\n admin: {\n description:\n 'Direct: Set specific reward/discount for each. Shared: Set a total commission and split it.',\n },\n },\n {\n name: 'totalCommission',\n type: 'group',\n admin: {\n condition: (_: unknown, siblingData: { basis?: string }) =>\n siblingData?.basis === 'shared',\n description: 'Total commission available to be split between partner and customer',\n },\n fields: [\n {\n name: 'type',\n type: 'select',\n required: true,\n options: [\n { label: 'Fixed Amount', value: 'fixed' },\n { label: 'Percentage of Order', value: 'percentage' },\n ],\n defaultValue: 'percentage',\n },\n {\n name: 'value',\n type: 'number',\n required: true,\n admin: {\n description: `Total commission value`,\n },\n },\n {\n name: 'maxAmount',\n type: 'number',\n admin: {\n description: `Max commission cap per item in ${defaultCurrency}`,\n },\n },\n ],\n },\n {\n name: 'referrerSplit',\n type: 'number',\n min: 0,\n max: 100,\n admin: {\n condition: (_: unknown, siblingData: { basis?: string }) =>\n siblingData?.basis === 'shared',\n description: 'Percentage of total commission given to the Partner (0-100)',\n },\n },\n {\n name: 'refereeSplit',\n type: 'number',\n min: 0,\n max: 100,\n admin: {\n condition: (_: unknown, siblingData: { basis?: string }) =>\n siblingData?.basis === 'shared',\n description: 'Percentage of total commission given as Discount to Customer (0-100)',\n },\n },\n {\n name: 'referrerReward',\n type: 'group',\n admin: {\n condition: (_: unknown, siblingData: { basis?: string }) =>\n siblingData?.basis !== 'shared',\n description: 'Reward given to the partner who refers others',\n },\n fields: [\n {\n name: 'type',\n type: 'select',\n required: true,\n options: [\n { label: 'Fixed Amount', value: 'fixed' },\n { label: 'Percentage of Order', value: 'percentage' },\n ],\n defaultValue: 'percentage',\n },\n {\n name: 'value',\n type: 'number',\n required: true,\n defaultValue: referralConfig.defaultPartnerSplit,\n admin: {\n description: `For percentage: 10 = 10% of order value. For fixed: amount in ${defaultCurrency}`,\n },\n },\n {\n name: 'maxReward',\n type: 'number',\n admin: {\n description: `Max reward in ${defaultCurrency}. Leave empty for no cap.`,\n },\n },\n ],\n },\n {\n name: 'refereeReward',\n type: 'group',\n admin: {\n condition: (_: unknown, siblingData: { basis?: string }) =>\n siblingData?.basis !== 'shared',\n description: 'Discount given to the customer who was referred',\n },\n fields: [\n {\n name: 'type',\n type: 'select',\n required: true,\n options: [\n { label: 'Fixed Amount', value: 'fixed' },\n { label: 'Percentage Discount', value: 'percentage' },\n ],\n defaultValue: 'percentage',\n },\n {\n name: 'value',\n type: 'number',\n required: true,\n defaultValue: referralConfig.defaultCustomerSplit,\n admin: {\n description: `For percentage: 10 = 10% discount. For fixed: amount in ${defaultCurrency}`,\n },\n },\n {\n name: 'maxReward',\n type: 'number',\n admin: {\n description: `Max discount in ${defaultCurrency}. Leave empty for no cap.`,\n },\n },\n ],\n },\n ],\n },\n {\n name: 'minOrderValue',\n type: 'number',\n admin: {\n description: `Minimum order value required for referral in ${defaultCurrency}`,\n },\n },\n {\n name: 'maxReferralsPerUser',\n type: 'number',\n admin: {\n description: 'Maximum number of referrals a partner can make. Empty = unlimited.',\n },\n },\n {\n name: 'referralCodePrefix',\n type: 'text',\n admin: {\n description: 'Prefix for generated referral codes (e.g., \"REF\" will create REF123)',\n },\n },\n {\n name: 'activeFrom',\n type: 'date',\n admin: {\n description: 'Program becomes active from this date',\n },\n },\n {\n name: 'activeUntil',\n type: 'date',\n admin: {\n description: 'Program expires after this date',\n },\n },\n {\n name: 'totalReferrals',\n type: 'number',\n defaultValue: 0,\n admin: {\n description: 'Total number of successful referrals through this program',\n readOnly: true,\n },\n },\n {\n name: 'totalRewardsPaid',\n type: 'number',\n defaultValue: 0,\n admin: {\n description: `Total rewards paid out in ${defaultCurrency}`,\n readOnly: true,\n },\n },\n ],\n timestamps: true,\n }\n}\n","/**\n * Rounds a number to 2 decimal places (standard for monetary values).\n */\nexport function roundTo2(value: number): number {\n return Math.round(value * 100) / 100\n}\n","export const DEFAULT_PRICE_CURRENCY = 'AED'\n\ntype PriceEntity = {\n price?: number | null\n} & Record<string, unknown>\n\nfunction normalizeCurrencyCode(currencyCode?: string): string {\n if (!currencyCode) return DEFAULT_PRICE_CURRENCY\n return currencyCode.toUpperCase()\n}\n\nfunction readNumberField(entity: unknown, key: string): number | undefined {\n if (!entity || typeof entity !== 'object') return undefined\n const value = (entity as Record<string, unknown>)[key]\n return typeof value === 'number' ? value : undefined\n}\n\nexport function getPriceFieldKey(currencyCode: string): string {\n return `priceIn${normalizeCurrencyCode(currencyCode)}`\n}\n\nexport function readMoneyField(\n entity: PriceEntity | null | undefined,\n currencyCode: string,\n defaultCurrencyCode = DEFAULT_PRICE_CURRENCY,\n): number | undefined {\n if (!entity) return undefined\n\n const primaryField = getPriceFieldKey(currencyCode)\n const primary = readNumberField(entity, primaryField)\n if (typeof primary === 'number') return primary\n\n const fallbackField = getPriceFieldKey(defaultCurrencyCode)\n if (fallbackField !== primaryField) {\n const fallback = readNumberField(entity, fallbackField)\n if (typeof fallback === 'number') return fallback\n }\n\n return typeof entity.price === 'number' ? entity.price : undefined\n}\n\nexport function resolveMoneyField(\n entity: PriceEntity | null | undefined,\n currencyCode: string,\n defaultCurrencyCode = DEFAULT_PRICE_CURRENCY,\n): number {\n return readMoneyField(entity, currencyCode, defaultCurrencyCode) ?? 0\n}\n\nexport function getCartItemUnitPrice({\n item,\n product,\n variant,\n currencyCode,\n defaultCurrencyCode = DEFAULT_PRICE_CURRENCY,\n}: {\n item?: {\n price?: number | null\n unitPrice?: number | null\n } | null\n product?: PriceEntity | null\n variant?: PriceEntity | null\n currencyCode: string\n defaultCurrencyCode?: string\n}): number {\n if (typeof item?.price === 'number') return item.price\n if (typeof item?.unitPrice === 'number') return item.unitPrice\n if (variant) return resolveMoneyField(variant, currencyCode, defaultCurrencyCode)\n return resolveMoneyField(product, currencyCode, defaultCurrencyCode)\n}\n","import { roundTo2 } from './roundTo2'\nimport { getCartItemUnitPrice } from './pricing'\n\nexport function calculateCouponDiscount({ coupon, cartTotal }: { coupon: any; cartTotal: number }) {\n let discount = 0\n\n if (coupon.type === 'percentage') {\n discount = roundTo2((cartTotal * coupon.value) / 100)\n // Apply max discount cap if set\n if (coupon.maxDiscountAmount != null && discount > coupon.maxDiscountAmount) {\n discount = roundTo2(coupon.maxDiscountAmount)\n }\n } else if (coupon.type === 'fixed') {\n discount = roundTo2(coupon.value)\n // Ensure discount doesn't exceed cart total\n if (discount > cartTotal) {\n discount = roundTo2(cartTotal)\n }\n }\n\n return roundTo2(discount)\n}\n\nexport function calculateCommissionAndDiscount({\n cartItems,\n program,\n currencyCode = 'AED',\n}: {\n cartItems: any[]\n program: any\n currencyCode?: string\n}): { partnerCommission: number; customerDiscount: number } {\n const rules = program.commissionRules || []\n\n if (rules.length === 0) {\n return { partnerCommission: 0, customerDiscount: 0 }\n }\n\n let totalPartnerCommission = 0\n let totalCustomerDiscount = 0\n\n for (const item of cartItems) {\n const rule = findApplicableCommissionRule(rules, item)\n if (!rule) continue\n\n const product = typeof item.product === 'object' ? item.product : {}\n const variant = typeof item.variant === 'object' ? item.variant : {}\n\n const itemPrice = getCartItemUnitPrice({\n item,\n product,\n variant,\n currencyCode,\n })\n\n const quantity = item.quantity ?? 1\n const itemTotal = itemPrice * quantity\n\n let itemPartner\n let itemCustomer\n\n // Shared Basis Calculation\n if (rule.basis === 'shared') {\n if (!rule.totalCommission || rule.referrerSplit == null || rule.refereeSplit == null) {\n continue\n }\n\n let totalPot\n if (rule.totalCommission.type === 'percentage') {\n totalPot = (itemTotal * rule.totalCommission.value) / 100\n } else {\n totalPot = rule.totalCommission.value * quantity\n }\n\n if (rule.totalCommission.maxAmount != null && totalPot > rule.totalCommission.maxAmount) {\n totalPot = rule.totalCommission.maxAmount\n }\n\n // Using Math.floor as per customer requirement (e.g. 2499.5 -> 2499)\n itemPartner = Math.floor((totalPot * (rule.referrerSplit || 0)) / 100)\n itemCustomer = Math.floor((totalPot * (rule.refereeSplit || 0)) / 100)\n }\n // Direct Basis Calculation (Legacy)\n else {\n if (!rule.referrerReward || !rule.refereeReward) continue\n\n // Partner commission from this rule's referrerReward\n if (rule.referrerReward.type === 'percentage') {\n itemPartner = (itemTotal * rule.referrerReward.value) / 100\n } else {\n itemPartner = rule.referrerReward.value * quantity\n }\n if (rule.referrerReward.maxReward != null && itemPartner > rule.referrerReward.maxReward) {\n itemPartner = rule.referrerReward.maxReward\n }\n\n // Customer discount from this rule's refereeReward\n if (rule.refereeReward.type === 'percentage') {\n itemCustomer = (itemTotal * rule.refereeReward.value) / 100\n } else {\n itemCustomer = rule.refereeReward.value * quantity\n }\n if (rule.refereeReward.maxReward != null && itemCustomer > rule.refereeReward.maxReward) {\n itemCustomer = rule.refereeReward.maxReward\n }\n }\n\n totalPartnerCommission += itemPartner\n totalCustomerDiscount += itemCustomer\n }\n\n return { partnerCommission: totalPartnerCommission, customerDiscount: totalCustomerDiscount }\n}\n\nfunction findApplicableCommissionRule(rules: any[], item: any) {\n const productId = typeof item.product === 'string' ? item.product : item.product?.id\n const categoryId = item.category ?? item.product?.category\n\n const productRule = rules.find(\n (r: any) =>\n r.appliesTo === 'products' &&\n r.products?.some((p: any) => (typeof p === 'string' ? p : p?.id) === productId),\n )\n if (productRule) return productRule\n\n if (categoryId) {\n const categoryRule = rules.find(\n (r: any) =>\n r.appliesTo === 'categories' &&\n r.categories?.some((c: any) => (typeof c === 'string' ? c : c?.id) === categoryId),\n )\n if (categoryRule) return categoryRule\n }\n\n return rules.find((r: any) => r.appliesTo === 'all') ?? null\n}\n","import type { Endpoint, PayloadHandler } from 'payload'\nimport type { SanitizedCouponPluginOptions } from '../types'\nimport {\n calculateCommissionAndDiscount,\n calculateCouponDiscount,\n} from '../utilities/calculateValues'\nimport { roundTo2 } from '../utilities/roundTo2'\n\ntype Args = {\n pluginConfig: SanitizedCouponPluginOptions\n}\n\n// Debug Capture\nconst globalDebugLogs: string[] = []\n\nexport const applyCouponHandler =\n ({ pluginConfig }: Args): PayloadHandler =>\n async (req) => {\n globalDebugLogs.length = 0 // Reset logs\n const { payload } = req\n const { code, cartID, customerEmail } = req.data || {}\n\n if (!code || !cartID) {\n return Response.json(\n {\n success: false,\n error: `${pluginConfig.enableReferrals ? 'Referral code' : 'Coupon code'} and cart ID are required`,\n },\n { status: 400 },\n )\n }\n\n try {\n // Find the cart first to check for existing codes\n const cartQuery = await payload.findByID({\n collection: 'carts',\n id: cartID,\n depth: 2,\n })\n\n if (!cartQuery) {\n return Response.json({ success: false, error: 'Cart not found' }, { status: 404 })\n }\n\n // Check if single code per cart is enforced\n if (pluginConfig.referralConfig.singleCodePerCart) {\n const hasExistingCoupon = cartQuery.appliedCoupon\n const hasExistingReferral = cartQuery.appliedReferralCode\n\n if (hasExistingCoupon || hasExistingReferral) {\n return Response.json(\n {\n success: false,\n error:\n 'A code has already been applied to this cart. Only one code can be used per order.',\n },\n { status: 400 },\n )\n }\n }\n\n if (pluginConfig.enableReferrals) {\n // Try referral code first\n const referralResult = await handleReferralCode({\n payload,\n code,\n cartID,\n cart: cartQuery,\n customerEmail,\n pluginConfig,\n })\n\n // If referral code not found and both systems allowed, try coupon\n if (\n !referralResult.ok &&\n referralResult.status === 404 &&\n pluginConfig.referralConfig.allowBothSystems\n ) {\n return await handleCouponCode({\n payload,\n code,\n cartID,\n cart: cartQuery,\n customerEmail,\n pluginConfig,\n })\n }\n\n return referralResult\n } else {\n // Coupon mode: handle coupons\n return await handleCouponCode({\n payload,\n code,\n cartID,\n cart: cartQuery,\n customerEmail,\n pluginConfig,\n })\n }\n } catch (error) {\n console.error('Code application error:', error)\n return Response.json({ success: false, error: 'Internal server error' }, { status: 500 })\n }\n }\n\n// Handle coupon application\nasync function handleCouponCode({\n payload,\n code,\n cartID,\n cart,\n customerEmail,\n pluginConfig,\n}: {\n payload: any\n code: string\n cartID: string\n cart: any\n customerEmail?: string\n pluginConfig: SanitizedCouponPluginOptions\n}) {\n // Find the coupon\n // Find the coupon (Case insensitive check: Exact -> Lower -> Upper)\n let couponQuery = await payload.find({\n collection: pluginConfig.collections.couponsSlug,\n where: {\n code: { equals: code },\n },\n limit: 1,\n })\n\n if (!couponQuery.docs.length) {\n couponQuery = await payload.find({\n collection: pluginConfig.collections.couponsSlug,\n where: {\n code: { equals: code.toLowerCase() },\n },\n limit: 1,\n })\n }\n\n if (!couponQuery.docs.length) {\n couponQuery = await payload.find({\n collection: pluginConfig.collections.couponsSlug,\n where: {\n code: { equals: code.toUpperCase() },\n },\n limit: 1,\n })\n }\n\n if (!couponQuery.docs.length) {\n return Response.json({ success: false, error: 'Invalid coupon code' }, { status: 404 })\n }\n\n const coupon = couponQuery.docs[0]\n\n // Check if coupon is active\n const now = new Date()\n const activeFrom = coupon.activeFrom ? new Date(coupon.activeFrom) : null\n const activeUntil = coupon.activeUntil ? new Date(coupon.activeUntil) : null\n\n if (activeFrom && now < activeFrom) {\n return Response.json({ success: false, error: 'Coupon is not yet active' }, { status: 400 })\n }\n\n if (activeUntil && now > activeUntil) {\n return Response.json({ success: false, error: 'Coupon has expired' }, { status: 400 })\n }\n\n // Check usage limits\n if (coupon.usageLimit && coupon.usageCount >= coupon.usageLimit) {\n return Response.json({ success: false, error: 'Coupon usage limit exceeded' }, { status: 400 })\n }\n\n // Per-customer limit: require customer email and count paid orders with this coupon for this customer\n if (coupon.perCustomerLimit != null && coupon.perCustomerLimit > 0) {\n const email = typeof customerEmail === 'string' ? customerEmail.trim() : ''\n if (!email) {\n return Response.json(\n { success: false, error: 'Customer email is required for this coupon.' },\n { status: 400 },\n )\n }\n const { ordersSlug, orderCustomerEmailField, orderPaymentStatusField, orderPaidStatusValue } =\n pluginConfig.orderIntegration\n const ordersQuery = await payload.find({\n collection: ordersSlug,\n where: {\n and: [\n { appliedCoupon: { equals: coupon.id } },\n { [orderCustomerEmailField]: { equals: email } },\n { [orderPaymentStatusField]: { equals: orderPaidStatusValue } },\n ],\n },\n limit: 0,\n })\n if (ordersQuery.totalDocs >= coupon.perCustomerLimit) {\n return Response.json(\n { success: false, error: 'You have reached the maximum uses for this coupon.' },\n { status: 400 },\n )\n }\n }\n\n // Check if coupon already applied to this cart\n if (cart.appliedCoupon === coupon.id) {\n return Response.json(\n { success: false, error: 'Coupon already applied to this cart' },\n { status: 400 },\n )\n }\n\n // Calculate discount based on cart total\n const cartTotal = cart.subtotal || cart.total || 0\n\n // Check minimum order value\n if (coupon.minOrderValue && cartTotal < coupon.minOrderValue) {\n return Response.json(\n {\n success: false,\n error: `Minimum order value of ${coupon.minOrderValue} ${pluginConfig.defaultCurrency} required`,\n },\n { status: 400 },\n )\n }\n\n // Check maximum order value\n if (coupon.maxOrderValue && cartTotal > coupon.maxOrderValue) {\n return Response.json(\n {\n success: false,\n error: `Maximum order value of ${coupon.maxOrderValue} ${pluginConfig.defaultCurrency} exceeded`,\n },\n { status: 400 },\n )\n }\n\n const discountAmount = calculateCouponDiscount({ coupon, cartTotal })\n const total = roundTo2(Math.max(0, cartTotal - discountAmount))\n\n // Apply coupon to cart (usage is counted when order is placed via recordCouponUsageForOrder)\n await payload.update({\n collection: 'carts',\n id: cartID,\n data: {\n appliedCoupon: coupon.id,\n discountAmount,\n total,\n },\n })\n\n return Response.json({\n success: true,\n message: 'Coupon applied successfully',\n coupon: {\n code: coupon.code,\n type: coupon.type,\n value: coupon.value,\n },\n discount: discountAmount,\n currency: pluginConfig.defaultCurrency,\n debug: globalDebugLogs,\n })\n}\n\n// Handle referral code application\nasync function handleReferralCode({\n payload,\n code,\n cartID,\n cart,\n customerEmail: _customerEmail,\n pluginConfig,\n}: {\n payload: any\n code: string\n cartID: string\n cart: any\n customerEmail?: string\n pluginConfig: SanitizedCouponPluginOptions\n}) {\n // Find the referral code\n // Find the referral code (Case insensitive check: Exact -> Lower -> Upper)\n let referralQuery = await payload.find({\n collection: pluginConfig.collections.referralCodesSlug,\n where: {\n code: { equals: code },\n },\n limit: 1,\n depth: 1,\n })\n\n if (!referralQuery.docs.length) {\n referralQuery = await payload.find({\n collection: pluginConfig.collections.referralCodesSlug,\n where: {\n code: { equals: code.toLowerCase() },\n },\n limit: 1,\n depth: 1,\n })\n }\n\n if (!referralQuery.docs.length) {\n referralQuery = await payload.find({\n collection: pluginConfig.collections.referralCodesSlug,\n where: {\n code: { equals: code.toUpperCase() },\n },\n limit: 1,\n depth: 1,\n })\n }\n\n if (!referralQuery.docs.length) {\n return Response.json({ success: false, error: 'Invalid referral code' }, { status: 404 })\n }\n\n const referralCode = referralQuery.docs[0]\n\n // Check if referral code is active\n if (!referralCode.isActive) {\n return Response.json({ success: false, error: 'Referral code is not active' }, { status: 400 })\n }\n\n // Check expiration\n if (referralCode.expiresAt && new Date() > new Date(referralCode.expiresAt)) {\n return Response.json({ success: false, error: 'Referral code has expired' }, { status: 400 })\n }\n\n // Check usage limit\n if (referralCode.usageLimit && referralCode.usageCount >= referralCode.usageLimit) {\n return Response.json(\n { success: false, error: 'Referral code usage limit exceeded' },\n { status: 400 },\n )\n }\n\n // Get the referral program\n const programId =\n typeof referralCode.program === 'string' ? referralCode.program : referralCode.program?.id\n\n const program = await payload.findByID({\n collection: pluginConfig.collections.referralProgramsSlug,\n id: programId,\n })\n\n if (!program || !program.isActive) {\n return Response.json(\n { success: false, error: 'Referral program is not active' },\n { status: 400 },\n )\n }\n\n // Check program dates\n const now = new Date()\n if (program.activeFrom && now < new Date(program.activeFrom)) {\n return Response.json(\n { success: false, error: 'Referral program is not yet active' },\n { status: 400 },\n )\n }\n\n if (program.activeUntil && now > new Date(program.activeUntil)) {\n return Response.json({ success: false, error: 'Referral program has expired' }, { status: 400 })\n }\n\n // Check if referral code already applied to this cart\n if (cart.appliedReferralCode === referralCode.id) {\n return Response.json(\n { success: false, error: 'Referral code already applied to this cart' },\n { status: 400 },\n )\n }\n\n // Calculate commission and discount\n const cartTotal = cart.subtotal || cart.total || 0\n\n // Check minimum order value\n if (program.minOrderValue && cartTotal < program.minOrderValue) {\n return Response.json(\n {\n success: false,\n error: `Minimum order value of ${program.minOrderValue} ${pluginConfig.defaultCurrency} required`,\n },\n { status: 400 },\n )\n }\n\n // Calculate based on commission rules\n const { partnerCommission, customerDiscount } = calculateCommissionAndDiscount({\n cartItems: cart.items || [],\n program,\n })\n\n // Round commission and discount\n const roundedPartnerCommission = roundTo2(partnerCommission)\n const roundedCustomerDiscount = roundTo2(customerDiscount)\n const total = roundTo2(Math.max(0, cartTotal - roundedCustomerDiscount))\n\n // Apply referral to cart\n await payload.update({\n collection: 'carts',\n id: cartID,\n data: {\n appliedReferralCode: referralCode.id,\n partnerCommission: roundedPartnerCommission,\n customerDiscount: roundedCustomerDiscount,\n total,\n },\n })\n\n return Response.json({\n success: true,\n message: 'Referral code applied successfully',\n referralCode: {\n code: referralCode.code,\n },\n partnerCommission: roundedPartnerCommission,\n customerDiscount: roundedCustomerDiscount,\n currency: pluginConfig.defaultCurrency,\n debug: globalDebugLogs,\n })\n}\n\nexport const applyCouponEndpoint = ({ pluginConfig }: Args): Endpoint => ({\n path: pluginConfig.endpoints.applyCoupon,\n method: 'post',\n handler: applyCouponHandler({ pluginConfig }),\n})\n","import type { Endpoint, PayloadHandler } from 'payload'\n\nimport type { PartnerDashboardData, PartnerStats, SanitizedCouponPluginOptions } from '../types'\n\ntype Args = {\n pluginConfig: SanitizedCouponPluginOptions\n}\n\nexport const partnerStatsHandler =\n ({ pluginConfig }: Args): PayloadHandler =>\n async (req) => {\n const { payload, user } = req\n\n if (!user) {\n return Response.json({ success: false, error: 'Authentication required' }, { status: 401 })\n }\n\n const typedUser = user as { id: string; role?: string; roles?: string[] }\n\n // Check if user is a partner\n const isPartner =\n typedUser.role === 'partner' ||\n (Array.isArray(typedUser.roles) && typedUser.roles.includes('partner'))\n\n const isAdmin =\n typedUser.role === 'admin' ||\n (Array.isArray(typedUser.roles) && typedUser.roles.includes('admin'))\n\n if (!isPartner && !isAdmin) {\n return Response.json({ success: false, error: 'Partner access required' }, { status: 403 })\n }\n\n try {\n // Get partner's referral codes\n const referralCodesQuery = await payload.find({\n collection: pluginConfig.collections.referralCodesSlug,\n where: {\n referrer: { equals: typedUser.id },\n },\n limit: 100,\n })\n\n const referralCodes = referralCodesQuery.docs\n\n // Calculate stats\n let totalEarnings = 0\n let pendingEarnings = 0\n let paidEarnings = 0\n let totalReferrals = 0\n let successfulReferrals = 0\n\n const referralCodeData = referralCodes.map((code: any) => {\n totalEarnings += code.totalEarnings || 0\n pendingEarnings += code.pendingEarnings || 0\n paidEarnings += code.paidEarnings || 0\n totalReferrals += code.usageCount || 0\n successfulReferrals += code.successfulReferralsCount || 0\n\n return {\n id: code.id,\n code: code.code,\n usageCount: code.usageCount || 0,\n totalEarnings: code.totalEarnings || 0,\n isActive: code.isActive,\n }\n })\n\n // Calculate conversion rate\n const conversionRate = totalReferrals > 0 ? (successfulReferrals / totalReferrals) * 100 : 0\n\n // Get recent referrals (from orders with this partner's referral codes)\n const recentReferrals: PartnerStats['recentReferrals'] = []\n\n // Try to get orders with applied referral codes\n try {\n const ordersQuery = await payload.find({\n collection: 'orders',\n where: {\n appliedReferralCode: {\n in: referralCodes.map((c: any) => c.id),\n },\n },\n limit: 10,\n sort: '-createdAt',\n })\n\n for (const order of ordersQuery.docs as any[]) {\n recentReferrals.push({\n id: order.id,\n code: referralCodes.find((c: any) => c.id === order.appliedReferralCode)?.code || '',\n orderValue: order.total || 0,\n commission: order.partnerCommission || 0,\n date: order.createdAt,\n status: order.paymentStatus === 'paid' ? 'paid' : 'pending',\n })\n }\n } catch {\n // Orders collection might not exist or have different structure\n }\n\n // Calculate monthly earnings (last 6 months)\n const monthlyEarnings: PartnerStats['monthlyEarnings'] = []\n const now = new Date()\n\n for (let i = 5; i >= 0; i--) {\n const monthDate = new Date(now.getFullYear(), now.getMonth() - i, 1)\n const monthName = monthDate.toLocaleString('default', { month: 'short', year: 'numeric' })\n\n // This would need actual order data to calculate properly\n // For now, we'll provide placeholder structure\n monthlyEarnings.push({\n month: monthName,\n earnings: 0,\n referrals: 0,\n })\n }\n\n // Get the partner's active program\n let program: PartnerDashboardData['program'] = null\n\n if (referralCodes.length > 0) {\n const firstCode = referralCodes[0] as any\n if (firstCode.program) {\n try {\n const programData = await payload.findByID({\n collection: pluginConfig.collections.referralProgramsSlug,\n id: typeof firstCode.program === 'string' ? firstCode.program : firstCode.program.id,\n })\n\n if (programData) {\n const typedProgram = programData as any\n const firstRule = typedProgram.commissionRules?.[0]\n program = {\n name: typedProgram.name,\n description: typedProgram.description,\n commissionRate: firstRule?.referrerReward?.value ?? 0,\n customerDiscount: firstRule?.refereeReward?.value ?? 0,\n }\n }\n } catch {\n // Program might not exist\n }\n }\n }\n\n const stats: PartnerStats = {\n totalEarnings,\n pendingEarnings,\n paidEarnings,\n totalReferrals,\n successfulReferrals,\n conversionRate: Math.round(conversionRate * 100) / 100,\n recentReferrals,\n monthlyEarnings,\n }\n\n const dashboardData: PartnerDashboardData = {\n stats,\n referralCodes: referralCodeData,\n program,\n }\n\n return Response.json({\n success: true,\n data: dashboardData,\n currency: pluginConfig.defaultCurrency,\n })\n } catch (error) {\n console.error('Partner stats error:', error)\n return Response.json(\n { success: false, error: 'Failed to fetch partner stats' },\n { status: 500 },\n )\n }\n }\n\nexport const partnerStatsEndpoint = ({ pluginConfig }: Args): Endpoint => ({\n path: pluginConfig.endpoints.partnerStats,\n method: 'get',\n handler: partnerStatsHandler({ pluginConfig }),\n})\n","import type { Endpoint, PayloadHandler } from 'payload'\n\nimport type { SanitizedCouponPluginOptions } from '../types'\nimport { roundTo2 } from '../utilities/roundTo2'\n\ntype Args = {\n pluginConfig: SanitizedCouponPluginOptions\n}\n\nexport const validateCouponHandler =\n ({ pluginConfig }: Args): PayloadHandler =>\n async (req) => {\n const { payload } = req\n const { code, cartValue, cartID, customerEmail } = req.data || {}\n\n if (!code) {\n return Response.json(\n {\n success: false,\n error: 'Code is required',\n },\n { status: 400 },\n )\n }\n\n try {\n if (pluginConfig.enableReferrals) {\n // Referral mode: validate referral codes\n return await validateReferralCode({ payload, code, cartID, pluginConfig })\n } else {\n // Coupon mode: validate coupons\n return await validateCouponCode({\n payload,\n code,\n cartValue,\n customerEmail,\n pluginConfig,\n })\n }\n } catch (error) {\n console.error('Code validation error:', error)\n return Response.json({ success: false, error: 'Internal server error' }, { status: 500 })\n }\n }\n\n// Validate coupon code (existing logic)\nasync function validateCouponCode({\n payload,\n code,\n cartValue,\n customerEmail,\n pluginConfig,\n}: {\n payload: any\n code: string\n cartValue?: number\n customerEmail?: string\n pluginConfig: SanitizedCouponPluginOptions\n}) {\n // Find the coupon\n // Find the coupon (Case insensitive check: Exact -> Lower -> Upper)\n let coupon = await payload.find({\n collection: pluginConfig.collections.couponsSlug,\n where: {\n code: { equals: code },\n },\n limit: 1,\n })\n\n if (!coupon.docs.length) {\n coupon = await payload.find({\n collection: pluginConfig.collections.couponsSlug,\n where: {\n code: { equals: code.toLowerCase() },\n },\n limit: 1,\n })\n }\n\n if (!coupon.docs.length) {\n coupon = await payload.find({\n collection: pluginConfig.collections.couponsSlug,\n where: {\n code: { equals: code.toUpperCase() },\n },\n limit: 1,\n })\n }\n\n if (!coupon.docs.length) {\n return Response.json({ success: false, error: 'Invalid coupon code' }, { status: 404 })\n }\n\n const couponData = coupon.docs[0]\n\n // Check if coupon is active\n const now = new Date()\n const activeFrom = couponData.activeFrom ? new Date(couponData.activeFrom) : null\n const activeUntil = couponData.activeUntil ? new Date(couponData.activeUntil) : null\n\n if (activeFrom && now < activeFrom) {\n return Response.json({ success: false, error: 'Coupon is not yet active' }, { status: 400 })\n }\n\n if (activeUntil && now > activeUntil) {\n return Response.json({ success: false, error: 'Coupon has expired' }, { status: 400 })\n }\n\n // Check usage limits\n if (couponData.usageLimit && couponData.usageCount >= couponData.usageLimit) {\n return Response.json({ success: false, error: 'Coupon usage limit exceeded' }, { status: 400 })\n }\n\n // Optional: per-customer limit (when customer identifier provided)\n if (\n couponData.perCustomerLimit != null &&\n couponData.perCustomerLimit > 0 &&\n typeof customerEmail === 'string' &&\n customerEmail.trim().length > 0\n ) {\n const email = customerEmail.trim()\n const { ordersSlug, orderCustomerEmailField, orderPaymentStatusField, orderPaidStatusValue } =\n pluginConfig.orderIntegration\n const ordersQuery = await payload.find({\n collection: ordersSlug,\n where: {\n and: [\n { appliedCoupon: { equals: couponData.id } },\n { [orderCustomerEmailField]: { equals: email } },\n { [orderPaymentStatusField]: { equals: orderPaidStatusValue } },\n ],\n },\n limit: 0,\n })\n if (ordersQuery.totalDocs >= couponData.perCustomerLimit) {\n return Response.json(\n { success: false, error: 'You have reached the maximum uses for this coupon.' },\n { status: 400 },\n )\n }\n }\n\n // Check minimum/maximum order value (top-level fields, same as apply endpoint)\n if (cartValue !== undefined) {\n const minOrderValue = couponData.minOrderValue\n const maxOrderValue = couponData.maxOrderValue\n\n if (minOrderValue && cartValue < minOrderValue) {\n return Response.json(\n {\n success: false,\n error: `Minimum order value of ${minOrderValue} ${pluginConfig.defaultCurrency} required`,\n },\n { status: 400 },\n )\n }\n\n if (maxOrderValue && cartValue > maxOrderValue) {\n return Response.json(\n {\n success: false,\n error: `Maximum order value of ${maxOrderValue} ${pluginConfig.defaultCurrency} exceeded`,\n },\n { status: 400 },\n )\n }\n }\n\n // Calculate discount preview (2 decimal standard)\n let discount = 0\n if (cartValue !== undefined) {\n if (couponData.type === 'percentage') {\n discount = roundTo2((cartValue * couponData.value) / 100)\n if (couponData.maxDiscountAmount != null && discount > couponData.maxDiscountAmount) {\n discount = roundTo2(couponData.maxDiscountAmount)\n }\n } else if (couponData.type === 'fixed') {\n discount = roundTo2(couponData.value)\n if (discount > cartValue) discount = roundTo2(cartValue)\n }\n }\n\n return Response.json({\n success: true,\n coupon: {\n code: couponData.code,\n type: couponData.type,\n value: couponData.value,\n description: couponData.description,\n },\n discount,\n currency: pluginConfig.defaultCurrency,\n })\n}\n\n// Validate referral code (new logic)\nasync function validateReferralCode({\n payload,\n code,\n cartID,\n pluginConfig,\n}: {\n payload: any\n code: string\n cartID?: string\n pluginConfig: SanitizedCouponPluginOptions\n}) {\n // Find the referral code\n // Find the referral code (Case insensitive check: Exact -> Lower -> Upper)\n let referral = await payload.find({\n collection: pluginConfig.collections.referralCodesSlug,\n where: {\n code: { equals: code },\n },\n limit: 1,\n })\n\n if (!referral.docs.length) {\n referral = await payload.find({\n collection: pluginConfig.collections.referralCodesSlug,\n where: {\n code: { equals: code.toLowerCase() },\n },\n limit: 1,\n })\n }\n\n if (!referral.docs.length) {\n referral = await payload.find({\n collection: pluginConfig.collections.referralCodesSlug,\n where: {\n code: { equals: code.toUpperCase() },\n },\n limit: 1,\n })\n }\n\n if (!referral.docs.length) {\n return Response.json({ success: false, error: 'Referral code not found' }, { status: 404 })\n }\n\n const referralData = referral.docs[0]\n\n // Check if referral code is active\n if (!referralData.isActive) {\n return Response.json({ success: false, error: 'Referral code is not active' }, { status: 400 })\n }\n\n // Check expiration\n if (referralData.expiresAt && new Date() > new Date(referralData.expiresAt)) {\n return Response.json({ success: false, error: 'Referral code has expired' }, { status: 400 })\n }\n\n // Check usage limit\n if (referralData.usageLimit && referralData.usageCount >= referralData.usageLimit) {\n return Response.json(\n { success: false, error: 'Referral code usage limit exceeded' },\n { status: 400 },\n )\n }\n\n // Get the referral program\n const program = await payload.findByID({\n collection: pluginConfig.collections.referralProgramsSlug,\n id: referralData.program,\n })\n\n if (!program || !program.isActive) {\n return Response.json(\n { success: false, error: 'Referral program is not active' },\n { status: 400 },\n )\n }\n\n // Calculate from commission rules (each rule has referrerReward + refereeReward)\n let totalPartnerCommission = 0\n let totalCustomerDiscount = 0\n const rules = (program as any).commissionRules || []\n\n if (cartID && rules.length > 0) {\n const cart = await payload.findByID({\n collection: 'carts',\n id: cartID,\n })\n const cartTotal = cart ? cart.subtotal || cart.total || 0 : 0\n const items = cart?.items || []\n\n for (const item of items) {\n const rule = findApplicableReferralRule(rules, item)\n if (!rule?.referrerReward || !rule?.refereeReward) continue\n\n const itemPrice = item.price ?? item.unitPrice ?? 0\n const quantity = item.quantity ?? 1\n const itemTotal = itemPrice * quantity\n\n let itemPartner\n if (rule.referrerReward.type === 'percentage') {\n itemPartner = (itemTotal * rule.referrerReward.value) / 100\n } else {\n itemPartner = rule.referrerReward.value * quantity\n }\n if (rule.referrerReward.maxReward != null && itemPartner > rule.referrerReward.maxReward) {\n itemPartner = rule.referrerReward.maxReward\n }\n totalPartnerCommission += itemPartner\n\n let itemCustomer\n if (rule.refereeReward.type === 'percentage') {\n itemCustomer = (itemTotal * rule.refereeReward.value) / 100\n } else {\n itemCustomer = rule.refereeReward.value * quantity\n }\n if (rule.refereeReward.maxReward != null && itemCustomer > rule.refereeReward.maxReward) {\n itemCustomer = rule.refereeReward.maxReward\n }\n totalCustomerDiscount += itemCustomer\n }\n\n if (totalCustomerDiscount > cartTotal) totalCustomerDiscount = cartTotal\n }\n\n const roundedPartnerCommission = roundTo2(totalPartnerCommission)\n const roundedCustomerDiscount = roundTo2(totalCustomerDiscount)\n\n return Response.json({\n success: true,\n referralCode: {\n code: referralData.code,\n description: `Get ${roundedCustomerDiscount.toFixed(2)} discount with this referral code`,\n },\n partnerCommission: roundedPartnerCommission,\n customerDiscount: roundedCustomerDiscount,\n currency: pluginConfig.defaultCurrency,\n })\n}\n\nfunction findApplicableReferralRule(rules: any[], item: any) {\n const productId = typeof item.product === 'string' ? item.product : item.product?.id\n const categoryId = item.category ?? item.product?.category\n\n const productRule = rules.find(\n (r) =>\n r.appliesTo === 'products' &&\n r.products?.some((p: any) => (typeof p === 'string' ? p : p?.id) === productId),\n )\n if (productRule) return productRule\n\n if (categoryId) {\n const categoryRule = rules.find(\n (r) =>\n r.appliesTo === 'categories' &&\n r.categories?.some((c: any) => (typeof c === 'string' ? c : c?.id) === categoryId),\n )\n if (categoryRule) return categoryRule\n }\n\n return rules.find((r) => r.appliesTo === 'all') ?? null\n}\n\nexport const validateCouponEndpoint = ({ pluginConfig }: Args): Endpoint => ({\n path: pluginConfig.endpoints.validateCoupon,\n method: 'post',\n handler: validateCouponHandler({ pluginConfig }),\n})\n","import type { CollectionBeforeChangeHook } from 'payload'\nimport type { SanitizedCouponPluginOptions } from '../types'\nimport {\n calculateCommissionAndDiscount,\n calculateCouponDiscount,\n} from '../utilities/calculateValues'\nimport { getCartItemUnitPrice } from '../utilities/pricing'\nimport { roundTo2 } from '../utilities/roundTo2'\n\nexport const recalculateCartHook =\n (pluginConfig: SanitizedCouponPluginOptions): CollectionBeforeChangeHook =>\n async ({ data, req, originalDoc }) => {\n // If no Payload, can't fetch relations\n if (!req.payload) return data\n\n // Determine effective state\n // data.items might be replacing or merging. In standard ecommerce, usually it replaces.\n // We need to calculate based on the *final* state of items.\n // If data.items is present, use it. If not, use originalDoc.items.\n const effectiveItems = data.items || originalDoc?.items || []\n\n console.log('[RecalculateCart] Hook triggered', {\n hasDataItems: !!data.items,\n dataItemsCount: data.items?.length,\n originalItemsCount: originalDoc?.items?.length,\n effectiveItemsCount: effectiveItems.length,\n })\n\n // If no items, ensure totals are 0\n if (!effectiveItems.length) {\n return {\n ...data,\n partnerCommission: 0,\n customerDiscount: 0,\n discountAmount: 0,\n total: 0,\n }\n }\n\n // Determine effective codes\n const appliedReferralCode = data.appliedReferralCode ?? originalDoc?.appliedReferralCode\n const appliedCoupon = data.appliedCoupon ?? originalDoc?.appliedCoupon\n\n if (!appliedReferralCode && !appliedCoupon) {\n // No codes applied, just return data (cleanup done by other logic if needed, or we explicitly clear?)\n // Use case: user removed code. data.appliedCoupon would be null.\n // If we are just updating items, and code was removed, these should be 0.\n // But if code was removed, data.appliedCoupon is null.\n if (data.appliedReferralCode === null || data.appliedCoupon === null) {\n return {\n ...data,\n partnerCommission: 0,\n customerDiscount: 0,\n discountAmount: 0,\n // Recalc total ?? Standard ecommerce will handle total if we don't mess with it.\n }\n }\n return data\n }\n\n // We need fully hydrated items to calculate prices\n // Optimized: Only fetch if we really need to recalculate.\n // Standard ecommerce recalculates 'total' and 'subtotal' in its hooks.\n // We need to know the *new* subtotal.\n // Since we don't know the order of hooks, we can't rely on data.subtotal being correct yet if we run before ecommerce.\n // SAFEST: We calculate our own subtotal based on current prices.\n\n const productIds = effectiveItems\n .map((item: any) => (typeof item.product === 'string' ? item.product : item.product?.id))\n .filter(Boolean)\n\n if (!productIds.length) return data\n\n // Fetch products to get prices\n const productsQuery = await req.payload.find({\n collection: 'products', // Assumption: standard shops have products\n where: {\n id: { in: productIds },\n },\n limit: productIds.length,\n })\n\n const productsMap = new Map(productsQuery.docs.map((p) => [p.id, p]))\n\n let calculatedSubtotal = 0\n const enrichedItems = effectiveItems.map((item: any) => {\n const productId = typeof item.product === 'string' ? item.product : item.product?.id\n const product: any = productsMap.get(productId) || {}\n\n // We might need variants logic too, keeping it simple for now based on available info\n // Ideally we should replicate the price finding logic fully.\n // For now, let's map what we have.\n\n const itemPrice = getCartItemUnitPrice({\n item,\n product,\n variant: typeof item.variant === 'object' ? item.variant : undefined,\n currencyCode: pluginConfig.defaultCurrency,\n })\n\n calculatedSubtotal += itemPrice * (item.quantity ?? 1)\n\n console.log('[RecalculateCart] Item processed', {\n productId,\n quantity: item.quantity,\n priceUsed: itemPrice,\n currentSubtotal: calculatedSubtotal,\n })\n\n return {\n ...item,\n product, // Attach full product for rules\n price: itemPrice, // Normalized price\n }\n })\n\n // 1. Handle Referral\n if (appliedReferralCode && pluginConfig.enableReferrals) {\n // Fetch referral code & program\n const referralQuery = await req.payload.find({\n collection: pluginConfig.collections.referralCodesSlug,\n where: {\n id: {\n equals:\n typeof appliedReferralCode === 'string'\n ? appliedReferralCode\n : appliedReferralCode.id,\n },\n },\n limit: 1,\n depth: 1,\n })\n\n if (referralQuery.docs.length) {\n const referralCode = referralQuery.docs[0]\n const program = typeof referralCode.program === 'object' ? referralCode.program : null\n\n // If program is not populated or valid, we skip\n if (program) {\n const { partnerCommission, customerDiscount } = calculateCommissionAndDiscount({\n cartItems: enrichedItems,\n program,\n currencyCode: pluginConfig.defaultCurrency,\n })\n\n const roundedCustomerDiscount = roundTo2(customerDiscount)\n data.partnerCommission = roundTo2(partnerCommission)\n data.customerDiscount = roundedCustomerDiscount\n\n // Update total\n // Use calculated subtotal or trust data.subtotal if present?\n // Best to use our calculated subtotal to be safely independent.\n data.total = Math.max(0, calculatedSubtotal - roundedCustomerDiscount)\n }\n }\n }\n\n // 2. Handle Coupon\n if (appliedCoupon && (!appliedReferralCode || pluginConfig.referralConfig.allowBothSystems)) {\n const couponQuery = await req.payload.find({\n collection: pluginConfig.collections.couponsSlug,\n where: {\n id: { equals: typeof appliedCoupon === 'string' ? appliedCoupon : appliedCoupon.id },\n },\n limit: 1,\n })\n\n if (couponQuery.docs.length) {\n const coupon = couponQuery.docs[0]\n const discountAmount = calculateCouponDiscount({\n coupon,\n cartTotal: calculatedSubtotal,\n })\n\n console.log('[RecalculateCart] Coupon Logic', {\n appliedCoupon,\n couponId: coupon.id,\n cartTotal: calculatedSubtotal,\n discountAmount,\n })\n\n data.discountAmount = discountAmount\n\n // If referral also applied, subtract from the already reduced total?\n // Usually discounts stack or are applied to subtotal.\n // Let's assume applied to subtotal for simplicity unless logic dictates otherwise.\n // But wait, referral discount reduces total. Coupon reduces total.\n // Standard approach: Total = Subtotal - ReferralDiscount - CouponDiscount\n\n const currentDiscount = data.customerDiscount || 0\n data.total = Math.max(0, calculatedSubtotal - currentDiscount - discountAmount)\n }\n }\n\n return data\n }\n","import type { CouponPluginOptions, SanitizedCouponPluginOptions } from '../types'\n\nexport const sanitizePluginConfig = ({\n pluginConfig,\n}: {\n pluginConfig: CouponPluginOptions\n}): SanitizedCouponPluginOptions => {\n // Apply defaults for each property when missing or invalid\n return {\n enabled: !(\n pluginConfig?.enabled === false ||\n (typeof pluginConfig?.enabled === 'string' && pluginConfig.enabled === 'false')\n ),\n enableReferrals:\n !!pluginConfig?.enableReferrals &&\n (typeof pluginConfig?.enableReferrals !== 'string' ||\n pluginConfig.enableReferrals !== 'false'),\n allowStackWithOtherCoupons:\n !!pluginConfig?.allowStackWithOtherCoupons &&\n (typeof pluginConfig?.allowStackWithOtherCoupons !== 'string' ||\n pluginConfig.allowStackWithOtherCoupons !== 'false'),\n defaultCurrency:\n typeof pluginConfig?.defaultCurrency === 'string' &&\n pluginConfig.defaultCurrency.length > 0 &&\n pluginConfig.defaultCurrency.length <= 3\n ? pluginConfig.defaultCurrency\n : 'USD',\n collections: {\n couponsSlug:\n typeof pluginConfig?.collections?.couponsSlug === 'string' &&\n pluginConfig.collections.couponsSlug.trim().length > 0 &&\n pluginConfig.collections.couponsSlug.length <= 100\n ? pluginConfig.collections.couponsSlug\n : 'coupons',\n referralProgramsSlug:\n typeof pluginConfig?.collections?.referralProgramsSlug === 'string' &&\n pluginConfig.collections.referralProgramsSlug.trim().length > 0 &&\n pluginConfig.collections.referralProgramsSlug.length <= 100\n ? pluginConfig.collections.referralProgramsSlug\n : 'referral-programs',\n referralCodesSlug:\n typeof pluginConfig?.collections?.referralCodesSlug === 'string' &&\n pluginConfig.collections.referralCodesSlug.trim().length > 0 &&\n pluginConfig.collections.referralCodesSlug.length <= 100\n ? pluginConfig.collections.referralCodesSlug\n : 'referral-codes',\n referralPartnersSlug:\n typeof pluginConfig?.collections?.referralPartnersSlug === 'string' &&\n pluginConfig.collections.referralPartnersSlug.trim().length > 0 &&\n pluginConfig.collections.referralPartnersSlug.length <= 100\n ? pluginConfig.collections.referralPartnersSlug\n : 'referral-partners',\n },\n endpoints: {\n applyCoupon:\n typeof pluginConfig?.endpoints?.applyCoupon === 'string' &&\n pluginConfig.endpoints.applyCoupon.trim().length > 0\n ? pluginConfig.endpoints.applyCoupon\n : '/coupons/apply',\n validateCoupon:\n typeof pluginConfig?.endpoints?.validateCoupon === 'string' &&\n pluginConfig.endpoints.validateCoupon.trim().length > 0\n ? pluginConfig.endpoints.validateCoupon\n : '/coupons/validate',\n partnerStats:\n typeof pluginConfig?.endpoints?.partnerStats === 'string' &&\n pluginConfig.endpoints.partnerStats.trim().length > 0\n ? pluginConfig.endpoints.partnerStats\n : '/referrals/partner-stats',\n recordOrderUsage:\n typeof pluginConfig?.endpoints?.recordOrderUsage === 'string' &&\n pluginConfig.endpoints.recordOrderUsage.trim().length > 0\n ? pluginConfig.endpoints.recordOrderUsage\n : '/coupons/record-order-usage',\n },\n autoIntegrate: pluginConfig?.autoIntegrate !== false,\n access: {\n canUseCoupons:\n typeof pluginConfig?.access?.canUseCoupons === 'function'\n ? pluginConfig.access.canUseCoupons\n : () => true,\n canUseReferrals:\n typeof pluginConfig?.access?.canUseReferrals === 'function'\n ? pluginConfig.access.canUseReferrals\n : () => false,\n isAdmin:\n typeof pluginConfig?.access?.isAdmin === 'function'\n ? pluginConfig.access.isAdmin\n : () => false,\n isPartner:\n typeof pluginConfig?.access?.isPartner === 'function'\n ? pluginConfig.access.isPartner\n : ({ req }) => {\n // Default: check if user has partner role\n const user = req?.user as { role?: string; roles?: string[] } | undefined\n if (!user) return false\n if (user.role === 'partner') return true\n if (Array.isArray(user.roles) && user.roles.includes('partner')) return true\n return false\n },\n },\n referralConfig: {\n allowBothSystems: pluginConfig?.referralConfig?.allowBothSystems ?? false,\n singleCodePerCart: pluginConfig?.referralConfig?.singleCodePerCart ?? true,\n defaultPartnerSplit: pluginConfig?.referralConfig?.defaultPartnerSplit ?? 70,\n defaultCustomerSplit: pluginConfig?.referralConfig?.defaultCustomerSplit ?? 30,\n },\n adminGroups: {\n couponsGroup: pluginConfig?.adminGroups?.couponsGroup ?? 'Coupons',\n referralsGroup: pluginConfig?.adminGroups?.referralsGroup ?? 'Referrals',\n },\n partnerDashboard: {\n enabled: pluginConfig?.partnerDashboard?.enabled ?? true,\n showEarningsSummary: pluginConfig?.partnerDashboard?.showEarningsSummary ?? true,\n showReferralPerformance: pluginConfig?.partnerDashboard?.showReferralPerformance ?? true,\n showRecentReferrals: pluginConfig?.partnerDashboard?.showRecentReferrals ?? true,\n showCommissionBreakdown: pluginConfig?.partnerDashboard?.showCommissionBreakdown ?? true,\n },\n orderIntegration: {\n ordersSlug:\n typeof pluginConfig?.orderIntegration?.ordersSlug === 'string' &&\n pluginConfig.orderIntegration.ordersSlug.trim().length > 0\n ? pluginConfig.orderIntegration.ordersSlug\n : 'orders',\n orderCustomerEmailField:\n typeof pluginConfig?.orderIntegration?.orderCustomerEmailField === 'string' &&\n pluginConfig.orderIntegration.orderCustomerEmailField.trim().length > 0\n ? pluginConfig.orderIntegration.orderCustomerEmailField\n : 'customerEmail',\n orderPaymentStatusField:\n typeof pluginConfig?.orderIntegration?.orderPaymentStatusField === 'string' &&\n pluginConfig.orderIntegration.orderPaymentStatusField.trim().length > 0\n ? pluginConfig.orderIntegration.orderPaymentStatusField\n : 'paymentStatus',\n orderPaidStatusValue:\n typeof pluginConfig?.orderIntegration?.orderPaidStatusValue === 'string'\n ? pluginConfig.orderIntegration.orderPaidStatusValue\n : 'paid',\n },\n }\n}\n","import type { Config } from 'payload'\n\nimport { createCouponsCollection } from './collections/createCouponsCollection'\nimport { createReferralCodesCollection } from './collections/createReferralCodesCollection'\nimport { createReferralProgramsCollection } from './collections/createReferralProgramsCollection'\nimport { applyCouponEndpoint } from './endpoints/applyCoupon'\nimport { partnerStatsEndpoint } from './endpoints/partnerStats'\nimport { validateCouponEndpoint } from './endpoints/validateCoupon'\nimport { recalculateCartHook } from './hooks/recalculateCart'\nimport { CouponPluginOptions } from './types'\nimport { sanitizePluginConfig } from './utilities/sanitizePluginConfig'\n\n// Fields to append to orders (referral mode)\n\nexport const payloadEcommerceCouponPlugin =\n (pluginOptions: CouponPluginOptions = {}) =>\n async (incomingConfig: Config): Promise<Config> => {\n const pluginConfig = sanitizePluginConfig({ pluginConfig: pluginOptions })\n\n if (!pluginConfig.enabled) return incomingConfig || {}\n\n // Handle null or undefined incoming config\n if (!incomingConfig) {\n incomingConfig = { collections: [], endpoints: [] } as any\n }\n if (!incomingConfig.collections) {\n incomingConfig.collections = []\n }\n\n const collectionsToAdd = []\n\n // When enableReferrals is true, both coupon and referral collections are created\n // The referralConfig.allowBothSystems determines if both can be used simultaneously\n if (pluginConfig.enableReferrals) {\n // Referral mode: create referral collections\n let referralProgramsCollection = createReferralProgramsCollection(pluginConfig)\n let referralCodesCollection = createReferralCodesCollection(pluginConfig)\n\n // Apply collection overrides if provided\n if (pluginOptions.collections?.referralProgramsCollectionOverride) {\n referralProgramsCollection =\n await pluginOptions.collections.referralProgramsCollectionOverride({\n defaultCollection: referralProgramsCollection,\n })\n }\n\n if (pluginOptions.collections?.referralCodesCollectionOverride) {\n referralCodesCollection = await pluginOptions.collections.referralCodesCollectionOverride({\n defaultCollection: referralCodesCollection,\n })\n }\n\n collectionsToAdd.push(referralProgramsCollection, referralCodesCollection)\n\n // If allowBothSystems is true, also create coupon collection\n if (pluginConfig.referralConfig.allowBothSystems) {\n let couponsCollection = createCouponsCollection(pluginConfig)\n if (pluginOptions.collections?.couponsCollectionOverride) {\n couponsCollection = await pluginOptions.collections.couponsCollectionOverride({\n defaultCollection: couponsCollection,\n })\n }\n collectionsToAdd.push(couponsCollection)\n }\n } else {\n // Coupon mode: create coupon collections only\n let couponsCollection = createCouponsCollection(pluginConfig)\n if (pluginOptions.collections?.couponsCollectionOverride) {\n couponsCollection = await pluginOptions.collections.couponsCollectionOverride({\n defaultCollection: couponsCollection,\n })\n }\n collectionsToAdd.push(couponsCollection)\n }\n\n // Add collections to config (avoid duplicates)\n const existingSlugs = new Set(incomingConfig.collections.map((c: any) => c.slug))\n const collectionsToAddFiltered = collectionsToAdd.filter((c: any) => !existingSlugs.has(c.slug))\n incomingConfig.collections = [...incomingConfig.collections, ...collectionsToAddFiltered]\n\n // Add endpoints\n if (!incomingConfig.endpoints) {\n incomingConfig.endpoints = []\n }\n\n incomingConfig.endpoints = [\n ...incomingConfig.endpoints,\n validateCouponEndpoint({ pluginConfig }),\n applyCouponEndpoint({ pluginConfig }),\n ]\n\n // Add partner stats endpoint if referrals are enabled\n if (pluginConfig.enableReferrals) {\n incomingConfig.endpoints.push(partnerStatsEndpoint({ pluginConfig }))\n }\n\n // Safe autoIntegrate implementation — ensure referral collection exists before injecting relationships\n if (pluginConfig.autoIntegrate) {\n // Ensure collections array exists\n incomingConfig.collections = incomingConfig.collections || []\n\n // After we already appended the plugin collections above, recompute slug set\n const allSlugs = new Set<string>(incomingConfig.collections.map((c: any) => c.slug))\n\n // Helper that adds a field group to an existing collection (by slug) if not already present\n const addFieldsToCollection = (targetSlug: string, newFields: any[]) => {\n const idx = incomingConfig.collections!.findIndex((c: any) => c.slug === targetSlug)\n if (idx === -1) return\n const collection = incomingConfig.collections![idx]\n collection.fields = collection.fields || []\n\n // Avoid adding duplicate fields (by name)\n const existingFieldNames = new Set(collection.fields.map((f: any) => f.name))\n for (const f of newFields) {\n if (!existingFieldNames.has(f.name)) {\n collection.fields.push(f)\n }\n }\n\n // Replace the collection entry (mutation is OK here)\n incomingConfig.collections![idx] = collection\n }\n\n // Only inject referral integration if the referral collection slug is actually present\n if (\n pluginConfig.enableReferrals &&\n allSlugs.has(pluginConfig.collections.referralCodesSlug)\n ) {\n // Fields to append to carts (referral mode)\n const cartReferralFields = [\n {\n name: 'appliedReferralCode',\n type: 'relationship',\n relationTo: pluginConfig.collections.referralCodesSlug,\n admin: { description: 'Referral code applied to this cart' },\n },\n {\n name: 'partnerCommission',\n type: 'number',\n admin: { description: 'Partner commission amount for this cart' },\n },\n {\n name: 'customerDiscount',\n type: 'number',\n admin: { description: 'Customer discount amount for this cart' },\n },\n ]\n\n // If both systems allowed, also add coupon field\n if (\n pluginConfig.referralConfig.allowBothSystems &&\n allSlugs.has(pluginConfig.collections.couponsSlug)\n ) {\n cartReferralFields.push({\n name: 'appliedCoupon',\n type: 'relationship',\n relationTo: pluginConfig.collections.couponsSlug,\n admin: { description: 'Coupon applied to this cart' },\n })\n cartReferralFields.push({\n name: 'discountAmount',\n type: 'number',\n admin: { description: 'Discount amount from coupon' },\n })\n }\n\n addFieldsToCollection('carts', cartReferralFields)\n\n // Fields to append to orders (referral mode)\n const orderReferralFields = [\n {\n name: 'appliedReferralCode',\n type: 'relationship',\n relationTo: pluginConfig.collections.referralCodesSlug,\n admin: { description: 'Referral code applied to this order', readOnly: true },\n },\n {\n name: 'partnerCommission',\n type: 'number',\n admin: { description: 'Partner commission amount for this order', readOnly: true },\n },\n {\n name: 'customerDiscount',\n type: 'number',\n admin: { description: 'Customer discount amount for this order', readOnly: true },\n },\n ]\n\n // If both systems allowed, also add coupon field to orders\n if (\n pluginConfig.referralConfig.allowBothSystems &&\n allSlugs.has(pluginConfig.collections.couponsSlug)\n ) {\n orderReferralFields.push({\n name: 'appliedCoupon',\n type: 'relationship',\n relationTo: pluginConfig.collections.couponsSlug,\n admin: { description: 'Coupon applied to this order', readOnly: true },\n })\n orderReferralFields.push({\n name: 'discountAmount',\n type: 'number',\n admin: { description: 'Discount amount from coupon', readOnly: true },\n })\n }\n\n addFieldsToCollection('orders', orderReferralFields)\n } else if (\n !pluginConfig.enableReferrals &&\n allSlugs.has(pluginConfig.collections.couponsSlug)\n ) {\n // coupon mode — similar safe injection for appliedCoupons\n const cartCouponFields = [\n {\n name: 'appliedCoupon',\n type: 'relationship',\n relationTo: pluginConfig.collections.couponsSlug,\n admin: { description: 'Coupon applied to this cart' },\n },\n {\n name: 'discountAmount',\n type: 'number',\n admin: { description: 'Discount amount from coupon' },\n },\n ]\n addFieldsToCollection('carts', cartCouponFields)\n\n const orderCouponFields = [\n {\n name: 'appliedCoupon',\n type: 'relationship',\n relationTo: pluginConfig.collections.couponsSlug,\n admin: { description: 'Coupon applied to this order', readOnly: true },\n },\n {\n name: 'discountAmount',\n type: 'number',\n admin: { description: 'Discount amount from coupon', readOnly: true },\n },\n ]\n addFieldsToCollection('orders', orderCouponFields)\n }\n }\n\n // Add Recalculate Cart Hook\n const cartIndex = incomingConfig.collections!.findIndex((c: any) => c.slug === 'carts')\n if (cartIndex > -1) {\n const collection = incomingConfig.collections![cartIndex]\n collection.hooks = {\n ...collection.hooks,\n beforeChange: [\n ...(collection.hooks?.beforeChange || []),\n recalculateCartHook(pluginConfig),\n ],\n }\n incomingConfig.collections![cartIndex] = collection\n }\n\n return incomingConfig\n }\n","import type { ApplyCouponHook, ApplyCouponResponse, PartnerDashboardData } from '../types'\n\n/**\n * Apply a coupon code to a cart\n * @param options - Coupon code, cart ID, and customer email\n * @returns Response with success status, discount amount, and coupon details\n */\nexport async function useCouponCode(options: ApplyCouponHook): Promise<ApplyCouponResponse> {\n const { code, cartID, customerEmail } = options\n\n if (!code) {\n return {\n success: false,\n message: 'Coupon code is required',\n error: 'Code is missing',\n }\n }\n\n try {\n const response = await fetch('/api/coupons/apply', {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify({ code, cartID, customerEmail }),\n })\n\n const data = (await response.json()) as Record<string, unknown>\n\n if (!response.ok) {\n return {\n success: false,\n message: (data.error as string) || 'Failed to apply coupon',\n error: data.error as string,\n }\n }\n\n const couponData = data.coupon as Record<string, unknown> | undefined\n const referralData = data.referralCode as Record<string, unknown> | undefined\n\n return {\n success: data.success as boolean,\n message: data.message as string,\n discount: (data.discount as number) || (data.customerDiscount as number),\n partnerCommission: data.partnerCommission as number,\n customerDiscount: data.customerDiscount as number,\n coupon: couponData\n ? {\n code: (couponData.code as string) || '',\n type: (couponData.type as 'percentage' | 'fixed') || 'percentage',\n value: (couponData.value as number) || 0,\n }\n : undefined,\n referralCode: referralData\n ? {\n code: (referralData.code as string) || '',\n }\n : undefined,\n }\n } catch (error) {\n const message = error instanceof Error ? error.message : 'Network error'\n return { success: false, message, error: message }\n }\n}\n\n/**\n * Validate a coupon code without applying it\n * @param code - Coupon code to validate\n * @param cartValue - Optional cart value in smallest currency unit\n * @returns Response with validation result and coupon details\n */\nexport async function validateCouponCode(\n code: string,\n cartValue?: number,\n cartID?: string,\n): Promise<ApplyCouponResponse> {\n if (!code) {\n return {\n success: false,\n message: 'Code required',\n error: 'Code missing',\n }\n }\n\n try {\n const response = await fetch('/api/coupons/validate', {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify({ code, cartValue, cartID }),\n })\n\n const data = (await response.json()) as Record<string, unknown>\n\n if (!response.ok) {\n return {\n success: false,\n message: (data.error as string) || 'Invalid coupon',\n error: data.error as string,\n }\n }\n\n const couponData = data.coupon as Record<string, unknown> | undefined\n const referralData = data.referralCode as Record<string, unknown> | undefined\n\n return {\n success: data.success as boolean,\n message: data.message as string,\n coupon: couponData\n ? {\n code: (couponData.code as string) || '',\n type: (couponData.type as 'percentage' | 'fixed') || 'percentage',\n value: (couponData.value as number) || 0,\n }\n : undefined,\n referralCode: referralData\n ? {\n code: (referralData.code as string) || '',\n }\n : undefined,\n discount: data.discount as number,\n partnerCommission: data.partnerCommission as number,\n customerDiscount: data.customerDiscount as number,\n currency: data.currency as string,\n }\n } catch (error) {\n const message = error instanceof Error ? error.message : 'Network error'\n return { success: false, message, error: message }\n }\n}\n\nexport type PartnerStatsResponse = {\n success: boolean\n data?: PartnerDashboardData\n currency?: string\n error?: string\n}\n\n/**\n * Fetch partner dashboard statistics\n * @param apiEndpoint - Optional custom API endpoint (default: /api/referrals/partner-stats)\n * @returns Response with partner stats, referral codes, and program info\n */\nexport async function usePartnerStats(\n apiEndpoint: string = '/api/referrals/partner-stats',\n): Promise<PartnerStatsResponse> {\n try {\n const response = await fetch(apiEndpoint, {\n method: 'GET',\n headers: { 'Content-Type': 'application/json' },\n credentials: 'include',\n })\n\n const data = (await response.json()) as Record<string, unknown>\n\n if (!response.ok) {\n return {\n success: false,\n error: (data.error as string) || 'Failed to fetch partner stats',\n }\n }\n\n return {\n success: data.success as boolean,\n data: data.data as PartnerDashboardData,\n currency: data.currency as string,\n }\n } catch (error) {\n const message = error instanceof Error ? error.message : 'Network error'\n return { success: false, error: message }\n }\n}\n","import { roundTo2 } from './roundTo2'\n\nexport type CartLike = {\n subtotal?: number\n total?: number\n discountAmount?: number\n customerDiscount?: number\n}\n\n/**\n * Computes the cart total after applying plugin discounts.\n * Use this in your host app's cart beforeChange (or wherever you compute total)\n * so the amount always reflects coupon/referral discounts and is not overwritten incorrectly.\n *\n * Formula: subtotal - discountAmount - customerDiscount (each defaulting to 0).\n */\nexport function getCartTotalWithDiscounts(cart: CartLike): number {\n const subtotal = cart.subtotal ?? cart.total ?? 0\n const discountAmount = cart.discountAmount ?? 0\n const customerDiscount = cart.customerDiscount ?? 0\n return roundTo2(Math.max(0, subtotal - discountAmount - customerDiscount))\n}\n","import type { Payload } from 'payload'\n\nimport type { SanitizedCouponPluginOptions } from '../types'\n\nexport type OrderWithCouponFields = {\n id?: string\n appliedCoupon?: string | { id: string }\n appliedReferralCode?: string | { id: string }\n partnerCommission?: number\n customerDiscount?: number\n discountAmount?: number\n}\n\nexport type RecordCouponUsageResult = {\n recordedCoupon: boolean\n recordedReferral: boolean\n}\n\n/**\n * Record coupon and referral usage when an order is placed successfully.\n * Call this once when the order is created/paid (e.g. from Orders collection afterChange hook).\n *\n * - Coupon: increments the coupon's usageCount.\n * - Referral: increments the referral code's usageCount and successfulReferralsCount,\n * and adds order.partnerCommission to totalEarnings and pendingEarnings (referrer gets commission;\n * referee discount is already on the order).\n */\nexport async function recordCouponUsageForOrder(\n payload: Payload,\n order: OrderWithCouponFields,\n pluginConfig: SanitizedCouponPluginOptions,\n): Promise<RecordCouponUsageResult> {\n const result: RecordCouponUsageResult = { recordedCoupon: false, recordedReferral: false }\n\n const couponId =\n order.appliedCoupon == null\n ? null\n : typeof order.appliedCoupon === 'string'\n ? order.appliedCoupon\n : order.appliedCoupon?.id\n\n const referralCodeId =\n order.appliedReferralCode == null\n ? null\n : typeof order.appliedReferralCode === 'string'\n ? order.appliedReferralCode\n : order.appliedReferralCode?.id\n\n if (couponId) {\n const coupon = await payload.findByID({\n collection: pluginConfig.collections.couponsSlug,\n id: couponId,\n })\n if (coupon) {\n await payload.update({\n collection: pluginConfig.collections.couponsSlug,\n id: couponId,\n data: {\n usageCount: (coupon.usageCount ?? 0) + 1,\n },\n })\n result.recordedCoupon = true\n }\n }\n\n if (referralCodeId) {\n const referralCode = await payload.findByID({\n collection: pluginConfig.collections.referralCodesSlug,\n id: referralCodeId,\n })\n if (referralCode) {\n const commission = Number(order.partnerCommission) || 0\n const currentTotal = Number((referralCode as any).totalEarnings) || 0\n const currentPending = Number((referralCode as any).pendingEarnings) || 0\n const currentUsageCount = Number((referralCode as any).usageCount) || 0\n const currentSuccessful = Number((referralCode as any).successfulReferralsCount) || 0\n\n await payload.update({\n collection: pluginConfig.collections.referralCodesSlug,\n id: referralCodeId,\n data: {\n usageCount: currentUsageCount + 1,\n successfulReferralsCount: currentSuccessful + 1,\n totalEarnings: currentTotal + commission,\n pendingEarnings: currentPending + commission,\n },\n })\n result.recordedReferral = true\n }\n }\n\n return result\n}\n"],"mappings":"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U;OACzB,aAAa;OACd;MACF;KACD;MACE,MAAM;MACN,MAAM;MACN,KAAK;MACL,KAAK;MACL,OAAO;OACL,YAAY,GAAY,gBACtB,aAAa,UAAU;OACzB,aAAa;OACd;MACF;KACD;MACE,MAAM;MACN,MAAM;MACN,OAAO;OACL,YAAY,GAAY,gBACtB,aAAa,UAAU;OACzB,aAAa;OACd;MACD,QAAQ;OACN;QACE,MAAM;QACN,MAAM;QACN,UAAU;QACV,SAAS,CACP;SAAE,OAAO;SAAgB,OAAO;SAAS,EACzC;SAAE,OAAO;SAAuB,OAAO;SAAc,CACtD;QACD,cAAc;QACf;OACD;QACE,MAAM;QACN,MAAM;QACN,UAAU;QACV,cAAc,eAAe;QAC7B,OAAO,EACL,aAAa,iEAAiE,mBAC/E;QACF;OACD;QACE,MAAM;QACN,MAAM;QACN,OAAO,EACL,aAAa,iBAAiB,gBAAgB,4BAC/C;QACF;OACF;MACF;KACD;MACE,MAAM;MACN,MAAM;MACN,OAAO;OACL,YAAY,GAAY,gBACtB,aAAa,UAAU;OACzB,aAAa;OACd;MACD,QAAQ;OACN;QACE,MAAM;QACN,MAAM;QACN,UAAU;QACV,SAAS,CACP;SAAE,OAAO;SAAgB,OAAO;SAAS,EACzC;SAAE,OAAO;SAAuB,OAAO;SAAc,CACtD;QACD,cAAc;QACf;OACD;QACE,MAAM;QACN,MAAM;QACN,UAAU;QACV,cAAc,eAAe;QAC7B,OAAO,EACL,aAAa,2DAA2D,mBACzE;QACF;OACD;QACE,MAAM;QACN,MAAM;QACN,OAAO,EACL,aAAa,mBAAmB,gBAAgB,4BACjD;QACF;OACF;MACF;KACF;IACF;GACD;IACE,MAAM;IACN,MAAM;IACN,OAAO,EACL,aAAa,gDAAgD,mBAC9D;IACF;GACD;IACE,MAAM;IACN,MAAM;IACN,OAAO,EACL,aAAa,sEACd;IACF;GACD;IACE,MAAM;IACN,MAAM;IACN,OAAO,EACL,aAAa,0EACd;IACF;GACD;IACE,MAAM;IACN,MAAM;IACN,OAAO,EACL,aAAa,yCACd;IACF;GACD;IACE,MAAM;IACN,MAAM;IACN,OAAO,EACL,a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"}
package/dist/plugin.d.ts CHANGED
@@ -1,4 +1,4 @@
1
1
  import type { Config } from 'payload';
2
- import type { CouponPluginOptions } from './types';
2
+ import { CouponPluginOptions } from './types';
3
3
  export declare const payloadEcommerceCouponPlugin: (pluginOptions?: CouponPluginOptions) => (incomingConfig: Config) => Promise<Config>;
4
4
  //# sourceMappingURL=plugin.d.ts.map