@classytic/revenue 1.0.0 → 1.0.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -21
- package/README.md +1 -1
- package/dist/core/index.d.ts +10 -4
- package/dist/core/index.js +6 -12
- package/dist/core/index.js.map +1 -1
- package/dist/enums/index.d.ts +4 -4
- package/dist/enums/index.js.map +1 -1
- package/dist/index.d.ts +2 -2
- package/dist/index.js +6 -12
- package/dist/index.js.map +1 -1
- package/dist/providers/index.js.map +1 -1
- package/dist/schemas/index.d.ts +7 -7
- package/dist/schemas/index.js.map +1 -1
- package/dist/schemas/validation.d.ts +4 -4
- package/dist/schemas/validation.js.map +1 -1
- package/dist/services/index.js.map +1 -1
- package/dist/{split.enums-DHdM1YAV.d.ts → split.enums-Bh24jw8p.d.ts} +3 -3
- package/dist/{split.schema-BPdFZMbU.d.ts → split.schema-DYVP7Wu2.d.ts} +6 -6
- package/dist/utils/index.js.map +1 -1
- package/package.json +1 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/core/errors.ts","../../src/utils/hooks.ts","../../src/enums/transaction.enums.ts","../../src/utils/category-resolver.ts","../../src/utils/commission.ts","../../src/enums/monetization.enums.ts","../../src/services/monetization.service.ts","../../src/services/payment.service.ts","../../src/services/transaction.service.ts","../../src/enums/escrow.enums.ts","../../src/enums/split.enums.ts","../../src/utils/commission-split.ts","../../src/services/escrow.service.ts"],"names":[],"mappings":"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","file":"index.js","sourcesContent":["/**\r\n * Revenue Error Classes\r\n * @classytic/revenue\r\n *\r\n * Typed errors with codes for better error handling\r\n */\r\n\r\nexport interface RevenueErrorOptions {\r\n retryable?: boolean;\r\n metadata?: Record<string, unknown>;\r\n}\r\n\r\n/**\r\n * Base Revenue Error\r\n */\r\nexport class RevenueError extends Error {\r\n public readonly code: string;\r\n public readonly retryable: boolean;\r\n public readonly metadata: Record<string, unknown>;\r\n\r\n constructor(\r\n message: string,\r\n code: string,\r\n options: RevenueErrorOptions = {}\r\n ) {\r\n super(message);\r\n this.name = this.constructor.name;\r\n this.code = code;\r\n this.retryable = options.retryable ?? false;\r\n this.metadata = options.metadata ?? {};\r\n Error.captureStackTrace(this, this.constructor);\r\n }\r\n\r\n toJSON(): Record<string, unknown> {\r\n return {\r\n name: this.name,\r\n message: this.message,\r\n code: this.code,\r\n retryable: this.retryable,\r\n metadata: this.metadata,\r\n };\r\n }\r\n}\r\n\r\n/**\r\n * Configuration Errors\r\n */\r\nexport class ConfigurationError extends RevenueError {\r\n constructor(message: string, metadata: Record<string, unknown> = {}) {\r\n super(message, 'CONFIGURATION_ERROR', { retryable: false, metadata });\r\n }\r\n}\r\n\r\nexport class ModelNotRegisteredError extends ConfigurationError {\r\n constructor(modelName: string) {\r\n super(\r\n `Model \"${modelName}\" is not registered. Register it via createRevenue({ models: { ${modelName}: ... } })`,\r\n { modelName }\r\n );\r\n }\r\n}\r\n\r\n/**\r\n * Provider Errors\r\n */\r\nexport class ProviderError extends RevenueError {\r\n constructor(\r\n message: string,\r\n code: string,\r\n options: RevenueErrorOptions = {}\r\n ) {\r\n super(message, code, options);\r\n }\r\n}\r\n\r\nexport class ProviderNotFoundError extends ProviderError {\r\n constructor(providerName: string, availableProviders: string[] = []) {\r\n super(\r\n `Payment provider \"${providerName}\" not found. Available: ${availableProviders.join(', ')}`,\r\n 'PROVIDER_NOT_FOUND',\r\n { retryable: false, metadata: { providerName, availableProviders } }\r\n );\r\n }\r\n}\r\n\r\nexport class ProviderCapabilityError extends ProviderError {\r\n constructor(providerName: string, capability: string) {\r\n super(\r\n `Provider \"${providerName}\" does not support ${capability}`,\r\n 'PROVIDER_CAPABILITY_NOT_SUPPORTED',\r\n { retryable: false, metadata: { providerName, capability } }\r\n );\r\n }\r\n}\r\n\r\nexport class PaymentIntentCreationError extends ProviderError {\r\n constructor(providerName: string, originalError: Error) {\r\n super(\r\n `Failed to create payment intent with provider \"${providerName}\": ${originalError.message}`,\r\n 'PAYMENT_INTENT_CREATION_FAILED',\r\n { retryable: true, metadata: { providerName, originalError: originalError.message } }\r\n );\r\n }\r\n}\r\n\r\nexport class PaymentVerificationError extends ProviderError {\r\n constructor(paymentIntentId: string, reason: string) {\r\n super(\r\n `Payment verification failed for intent \"${paymentIntentId}\": ${reason}`,\r\n 'PAYMENT_VERIFICATION_FAILED',\r\n { retryable: true, metadata: { paymentIntentId, reason } }\r\n );\r\n }\r\n}\r\n\r\n/**\r\n * Resource Not Found Errors\r\n */\r\nexport class NotFoundError extends RevenueError {\r\n constructor(\r\n message: string,\r\n code: string,\r\n metadata: Record<string, unknown> = {}\r\n ) {\r\n super(message, code, { retryable: false, metadata });\r\n }\r\n}\r\n\r\nexport class SubscriptionNotFoundError extends NotFoundError {\r\n constructor(subscriptionId: string) {\r\n super(\r\n `Subscription not found: ${subscriptionId}`,\r\n 'SUBSCRIPTION_NOT_FOUND',\r\n { subscriptionId }\r\n );\r\n }\r\n}\r\n\r\nexport class TransactionNotFoundError extends NotFoundError {\r\n constructor(transactionId: string) {\r\n super(\r\n `Transaction not found: ${transactionId}`,\r\n 'TRANSACTION_NOT_FOUND',\r\n { transactionId }\r\n );\r\n }\r\n}\r\n\r\n/**\r\n * Validation Errors\r\n */\r\nexport class ValidationError extends RevenueError {\r\n constructor(message: string, metadata: Record<string, unknown> = {}) {\r\n super(message, 'VALIDATION_ERROR', { retryable: false, metadata });\r\n }\r\n}\r\n\r\nexport class InvalidAmountError extends ValidationError {\r\n constructor(amount: number, message?: string) {\r\n super(\r\n message ?? `Invalid amount: ${amount}. Amount must be non-negative`,\r\n { amount }\r\n );\r\n }\r\n}\r\n\r\nexport class MissingRequiredFieldError extends ValidationError {\r\n constructor(fieldName: string) {\r\n super(`Missing required field: ${fieldName}`, { fieldName });\r\n }\r\n}\r\n\r\n/**\r\n * State Errors\r\n */\r\nexport class StateError extends RevenueError {\r\n constructor(\r\n message: string,\r\n code: string,\r\n metadata: Record<string, unknown> = {}\r\n ) {\r\n super(message, code, { retryable: false, metadata });\r\n }\r\n}\r\n\r\nexport class AlreadyVerifiedError extends StateError {\r\n constructor(transactionId: string) {\r\n super(\r\n `Transaction ${transactionId} is already verified`,\r\n 'ALREADY_VERIFIED',\r\n { transactionId }\r\n );\r\n }\r\n}\r\n\r\nexport class InvalidStateTransitionError extends StateError {\r\n constructor(\r\n resourceType: string,\r\n resourceId: string,\r\n fromState: string,\r\n toState: string\r\n ) {\r\n super(\r\n `Invalid state transition for ${resourceType} ${resourceId}: ${fromState} → ${toState}`,\r\n 'INVALID_STATE_TRANSITION',\r\n { resourceType, resourceId, fromState, toState }\r\n );\r\n }\r\n}\r\n\r\nexport class SubscriptionNotActiveError extends StateError {\r\n constructor(subscriptionId: string, message?: string) {\r\n super(\r\n message ?? `Subscription ${subscriptionId} is not active`,\r\n 'SUBSCRIPTION_NOT_ACTIVE',\r\n { subscriptionId }\r\n );\r\n }\r\n}\r\n\r\n/**\r\n * Operation Errors\r\n */\r\nexport class OperationError extends RevenueError {\r\n constructor(\r\n message: string,\r\n code: string,\r\n options: RevenueErrorOptions = {}\r\n ) {\r\n super(message, code, options);\r\n }\r\n}\r\n\r\nexport class RefundNotSupportedError extends OperationError {\r\n constructor(providerName: string) {\r\n super(\r\n `Refunds are not supported by provider \"${providerName}\"`,\r\n 'REFUND_NOT_SUPPORTED',\r\n { retryable: false, metadata: { providerName } }\r\n );\r\n }\r\n}\r\n\r\nexport class RefundError extends OperationError {\r\n constructor(transactionId: string, reason: string) {\r\n super(\r\n `Refund failed for transaction ${transactionId}: ${reason}`,\r\n 'REFUND_FAILED',\r\n { retryable: true, metadata: { transactionId, reason } }\r\n );\r\n }\r\n}\r\n\r\n/**\r\n * Error Code Constants\r\n */\r\nexport const ERROR_CODES = {\r\n // Configuration\r\n CONFIGURATION_ERROR: 'CONFIGURATION_ERROR',\r\n MODEL_NOT_REGISTERED: 'MODEL_NOT_REGISTERED',\r\n\r\n // Provider\r\n PROVIDER_NOT_FOUND: 'PROVIDER_NOT_FOUND',\r\n PROVIDER_CAPABILITY_NOT_SUPPORTED: 'PROVIDER_CAPABILITY_NOT_SUPPORTED',\r\n PAYMENT_INTENT_CREATION_FAILED: 'PAYMENT_INTENT_CREATION_FAILED',\r\n PAYMENT_VERIFICATION_FAILED: 'PAYMENT_VERIFICATION_FAILED',\r\n\r\n // Not Found\r\n SUBSCRIPTION_NOT_FOUND: 'SUBSCRIPTION_NOT_FOUND',\r\n TRANSACTION_NOT_FOUND: 'TRANSACTION_NOT_FOUND',\r\n\r\n // Validation\r\n VALIDATION_ERROR: 'VALIDATION_ERROR',\r\n INVALID_AMOUNT: 'INVALID_AMOUNT',\r\n MISSING_REQUIRED_FIELD: 'MISSING_REQUIRED_FIELD',\r\n\r\n // State\r\n ALREADY_VERIFIED: 'ALREADY_VERIFIED',\r\n INVALID_STATE_TRANSITION: 'INVALID_STATE_TRANSITION',\r\n SUBSCRIPTION_NOT_ACTIVE: 'SUBSCRIPTION_NOT_ACTIVE',\r\n\r\n // Operations\r\n REFUND_NOT_SUPPORTED: 'REFUND_NOT_SUPPORTED',\r\n REFUND_FAILED: 'REFUND_FAILED',\r\n} as const;\r\n\r\nexport type ErrorCode = typeof ERROR_CODES[keyof typeof ERROR_CODES];\r\n\r\n/**\r\n * Check if error is retryable\r\n */\r\nexport function isRetryable(error: unknown): boolean {\r\n return error instanceof RevenueError && error.retryable;\r\n}\r\n\r\n/**\r\n * Check if error is from revenue package\r\n */\r\nexport function isRevenueError(error: unknown): error is RevenueError {\r\n return error instanceof RevenueError;\r\n}\r\n\r\n","/**\r\n * Hook Utilities\r\n * @classytic/revenue\r\n *\r\n * Fire-and-forget hook execution - never blocks main flow\r\n */\r\n\r\nimport type { Logger, HooksRegistry } from '../types/index.js';\r\n\r\n/**\r\n * Trigger hooks asynchronously without waiting\r\n * Errors are logged but never thrown\r\n *\r\n * @param hooks - Hooks object\r\n * @param event - Event name\r\n * @param data - Event data\r\n * @param logger - Logger instance\r\n */\r\nexport function triggerHook(\r\n hooks: HooksRegistry,\r\n event: string,\r\n data: unknown,\r\n logger: Logger\r\n): void {\r\n const handlers = hooks[event] ?? [];\r\n\r\n if (handlers.length === 0) {\r\n return; // No handlers, return immediately\r\n }\r\n\r\n // Fire-and-forget: Don't await, don't block\r\n Promise.all(\r\n handlers.map((handler) =>\r\n Promise.resolve(handler(data)).catch((error: Error) => {\r\n logger.error(`Hook \"${event}\" failed:`, {\r\n error: error.message,\r\n stack: error.stack,\r\n event,\r\n // Don't log full data (could be huge)\r\n dataKeys: Object.keys(data as object),\r\n });\r\n })\r\n )\r\n ).catch(() => {\r\n // Swallow any Promise.all errors (already logged individually)\r\n });\r\n\r\n // Return immediately - hooks run in background\r\n}\r\n\r\nexport default triggerHook;\r\n\r\n","/**\r\n * Transaction Enums\r\n * @classytic/revenue\r\n *\r\n * Library-managed transaction enums only.\r\n * Users should define their own categories and merge with these.\r\n */\r\n\r\n// ============ TRANSACTION TYPE ============\r\n/**\r\n * Transaction Type - Income vs Expense\r\n *\r\n * INCOME: Money coming in (payments, subscriptions, purchases)\r\n * EXPENSE: Money going out (refunds, payouts)\r\n *\r\n * Users can map these in their config via transactionTypeMapping\r\n */\r\nexport const TRANSACTION_TYPE = {\r\n INCOME: 'income',\r\n EXPENSE: 'expense',\r\n} as const;\r\n\r\nexport type TransactionType = typeof TRANSACTION_TYPE;\r\nexport type TransactionTypeValue = TransactionType[keyof TransactionType];\r\nexport const TRANSACTION_TYPE_VALUES = Object.values(TRANSACTION_TYPE);\r\n\r\n// ============ TRANSACTION STATUS ============\r\n/**\r\n * Transaction Status - Library-managed states\r\n */\r\nexport const TRANSACTION_STATUS = {\r\n PENDING: 'pending',\r\n PAYMENT_INITIATED: 'payment_initiated',\r\n PROCESSING: 'processing',\r\n REQUIRES_ACTION: 'requires_action',\r\n VERIFIED: 'verified',\r\n COMPLETED: 'completed',\r\n FAILED: 'failed',\r\n CANCELLED: 'cancelled',\r\n EXPIRED: 'expired',\r\n REFUNDED: 'refunded',\r\n PARTIALLY_REFUNDED: 'partially_refunded',\r\n} as const;\r\n\r\nexport type TransactionStatus = typeof TRANSACTION_STATUS;\r\nexport type TransactionStatusValue = TransactionStatus[keyof TransactionStatus];\r\nexport const TRANSACTION_STATUS_VALUES = Object.values(TRANSACTION_STATUS);\r\n\r\n// ============ LIBRARY CATEGORIES ============\r\n/**\r\n * Categories managed by this library\r\n *\r\n * SUBSCRIPTION: Recurring subscription payments\r\n * PURCHASE: One-time purchases\r\n *\r\n * Users should spread these into their own category enums:\r\n *\r\n * @example\r\n * import { LIBRARY_CATEGORIES } from '@classytic/revenue';\r\n *\r\n * export const MY_CATEGORIES = {\r\n * ...LIBRARY_CATEGORIES,\r\n * SALARY: 'salary',\r\n * RENT: 'rent',\r\n * EQUIPMENT: 'equipment',\r\n * } as const;\r\n */\r\nexport const LIBRARY_CATEGORIES = {\r\n SUBSCRIPTION: 'subscription',\r\n PURCHASE: 'purchase',\r\n} as const;\r\n\r\nexport type LibraryCategories = typeof LIBRARY_CATEGORIES;\r\nexport type LibraryCategoryValue = LibraryCategories[keyof LibraryCategories];\r\nexport const LIBRARY_CATEGORY_VALUES = Object.values(LIBRARY_CATEGORIES);\r\n\r\n","/**\r\n * Category Resolver Utility\r\n * @classytic/revenue\r\n *\r\n * Resolves transaction category based on referenceModel and categoryMappings\r\n */\r\n\r\nimport { LIBRARY_CATEGORIES } from '../enums/transaction.enums.js';\r\nimport type { MonetizationTypeValue } from '../types/index.js';\r\n\r\n/**\r\n * Resolve category for a transaction based on entity and monetizationType\r\n *\r\n * Resolution Logic:\r\n * 1. If categoryMappings[entity] exists → use it\r\n * 2. Otherwise → fall back to default library category\r\n *\r\n * @param entity - The logical entity/identifier (e.g., 'Order', 'PlatformSubscription', 'Membership')\r\n * NOTE: This is NOT a database model name - it's just a logical identifier\r\n * @param monetizationType - The monetization type ('subscription', 'purchase', 'free')\r\n * @param categoryMappings - User-defined category mappings from config\r\n * @returns Category name for the transaction\r\n *\r\n * @example\r\n * // With mapping defined\r\n * resolveCategory('Order', 'subscription', { Order: 'order_subscription' })\r\n * // Returns: 'order_subscription'\r\n *\r\n * @example\r\n * // Without mapping, falls back to library default\r\n * resolveCategory('Order', 'subscription', {})\r\n * // Returns: 'subscription'\r\n *\r\n * @example\r\n * // Different entities with different mappings\r\n * const mappings = {\r\n * Order: 'order_subscription',\r\n * PlatformSubscription: 'platform_subscription',\r\n * TenantUpgrade: 'tenant_upgrade',\r\n * Membership: 'gym_membership',\r\n * Enrollment: 'course_enrollment',\r\n * };\r\n * resolveCategory('PlatformSubscription', 'subscription', mappings)\r\n * // Returns: 'platform_subscription'\r\n */\r\nexport function resolveCategory(\r\n entity: string | null | undefined,\r\n monetizationType: MonetizationTypeValue,\r\n categoryMappings: Record<string, string> = {}\r\n): string {\r\n // If user has defined a custom mapping for this entity, use it\r\n if (entity && categoryMappings[entity]) {\r\n return categoryMappings[entity];\r\n }\r\n\r\n // Otherwise, fall back to library default based on monetization type\r\n switch (monetizationType) {\r\n case 'subscription':\r\n return LIBRARY_CATEGORIES.SUBSCRIPTION; // 'subscription'\r\n case 'purchase':\r\n return LIBRARY_CATEGORIES.PURCHASE; // 'purchase'\r\n default:\r\n return LIBRARY_CATEGORIES.SUBSCRIPTION; // Default to subscription\r\n }\r\n}\r\n\r\n/**\r\n * Validate that a category is defined in user's Transaction model enum\r\n * This is informational - actual validation happens at Mongoose schema level\r\n *\r\n * @param category - Category to validate\r\n * @param allowedCategories - List of allowed categories\r\n * @returns Whether category is valid\r\n */\r\nexport function isCategoryValid(\r\n category: string,\r\n allowedCategories: string[] = []\r\n): boolean {\r\n return allowedCategories.includes(category);\r\n}\r\n\r\nexport default resolveCategory;\r\n\r\n","/**\r\n * Commission Calculation Utility\r\n * @classytic/revenue\r\n *\r\n * Handles platform commission calculation with gateway fee deduction\r\n */\r\n\r\nimport type { CommissionInfo } from '../types/index.js';\r\n\r\n/**\r\n * Build commission object for transaction\r\n *\r\n * @param amount - Transaction amount\r\n * @param commissionRate - Commission rate (0 to 1, e.g., 0.10 for 10%)\r\n * @param gatewayFeeRate - Gateway fee rate (0 to 1, e.g., 0.018 for 1.8%)\r\n * @returns Commission object or null\r\n */\r\nexport function calculateCommission(\r\n amount: number,\r\n commissionRate: number,\r\n gatewayFeeRate: number = 0\r\n): CommissionInfo | null {\r\n // No commission if rate is 0 or negative\r\n if (!commissionRate || commissionRate <= 0) {\r\n return null;\r\n }\r\n\r\n // Validate inputs\r\n if (amount < 0) {\r\n throw new Error('Transaction amount cannot be negative');\r\n }\r\n\r\n if (commissionRate < 0 || commissionRate > 1) {\r\n throw new Error('Commission rate must be between 0 and 1');\r\n }\r\n\r\n if (gatewayFeeRate < 0 || gatewayFeeRate > 1) {\r\n throw new Error('Gateway fee rate must be between 0 and 1');\r\n }\r\n\r\n // Calculate commission\r\n const grossAmount = Math.round(amount * commissionRate * 100) / 100; // Round to 2 decimals\r\n const gatewayFeeAmount = Math.round(amount * gatewayFeeRate * 100) / 100;\r\n const netAmount = Math.max(0, Math.round((grossAmount - gatewayFeeAmount) * 100) / 100);\r\n\r\n return {\r\n rate: commissionRate,\r\n grossAmount,\r\n gatewayFeeRate,\r\n gatewayFeeAmount,\r\n netAmount,\r\n status: 'pending',\r\n };\r\n}\r\n\r\n/**\r\n * Reverse commission on refund (proportional)\r\n *\r\n * @param originalCommission - Original commission object\r\n * @param originalAmount - Original transaction amount\r\n * @param refundAmount - Amount being refunded\r\n * @returns Reversed commission or null\r\n */\r\nexport function reverseCommission(\r\n originalCommission: CommissionInfo | null | undefined,\r\n originalAmount: number,\r\n refundAmount: number\r\n): CommissionInfo | null {\r\n if (!originalCommission?.netAmount) {\r\n return null;\r\n }\r\n\r\n // Calculate proportional refund\r\n const refundRatio = refundAmount / originalAmount;\r\n const reversedNetAmount = Math.round(originalCommission.netAmount * refundRatio * 100) / 100;\r\n const reversedGrossAmount = Math.round(originalCommission.grossAmount * refundRatio * 100) / 100;\r\n const reversedGatewayFee = Math.round(originalCommission.gatewayFeeAmount * refundRatio * 100) / 100;\r\n\r\n return {\r\n rate: originalCommission.rate,\r\n grossAmount: reversedGrossAmount,\r\n gatewayFeeRate: originalCommission.gatewayFeeRate,\r\n gatewayFeeAmount: reversedGatewayFee,\r\n netAmount: reversedNetAmount,\r\n status: 'waived', // Commission waived due to refund\r\n };\r\n}\r\n\r\nexport default {\r\n calculateCommission,\r\n reverseCommission,\r\n};\r\n\r\n","/**\r\n * Monetization Enums\r\n * @classytic/revenue\r\n *\r\n * General monetization enums and constants\r\n */\r\n\r\n// ============ MONETIZATION TYPES ============\r\nexport const MONETIZATION_TYPES = {\r\n FREE: 'free',\r\n PURCHASE: 'purchase',\r\n SUBSCRIPTION: 'subscription',\r\n} as const;\r\n\r\nexport type MonetizationTypes = typeof MONETIZATION_TYPES;\r\nexport type MonetizationTypeValue = MonetizationTypes[keyof MonetizationTypes];\r\nexport const MONETIZATION_TYPE_VALUES = Object.values(MONETIZATION_TYPES);\r\n\r\n","/**\r\n * Monetization Service\r\n * @classytic/revenue\r\n *\r\n * Framework-agnostic monetization management service with DI\r\n * Handles purchases, subscriptions, and free items using provider system\r\n */\r\n\r\nimport { nanoid } from 'nanoid';\r\nimport {\r\n MissingRequiredFieldError,\r\n InvalidAmountError,\r\n ProviderNotFoundError,\r\n SubscriptionNotFoundError,\r\n ModelNotRegisteredError,\r\n SubscriptionNotActiveError,\r\n PaymentIntentCreationError,\r\n InvalidStateTransitionError,\r\n} from '../core/errors.js';\r\nimport { triggerHook } from '../utils/hooks.js';\r\nimport { resolveCategory } from '../utils/category-resolver.js';\r\nimport { calculateCommission } from '../utils/commission.js';\r\nimport { MONETIZATION_TYPES } from '../enums/monetization.enums.js';\r\nimport { TRANSACTION_TYPE } from '../enums/transaction.enums.js';\r\nimport type { Container } from '../core/container.js';\r\nimport type {\r\n ModelsRegistry,\r\n ProvidersRegistry,\r\n HooksRegistry,\r\n RevenueConfig,\r\n Logger,\r\n MonetizationCreateParams,\r\n MonetizationCreateResult,\r\n ActivateOptions,\r\n RenewalParams,\r\n CancelOptions,\r\n PauseOptions,\r\n ResumeOptions,\r\n ListOptions,\r\n SubscriptionDocument,\r\n TransactionDocument,\r\n PaymentIntentData,\r\n TransactionTypeValue,\r\n} from '../types/index.js';\r\n\r\n/**\r\n * Monetization Service\r\n * Uses DI container for all dependencies\r\n */\r\nexport class MonetizationService {\r\n private readonly models: ModelsRegistry;\r\n private readonly providers: ProvidersRegistry;\r\n private readonly config: RevenueConfig;\r\n private readonly hooks: HooksRegistry;\r\n private readonly logger: Logger;\r\n\r\n constructor(container: Container) {\r\n this.models = container.get<ModelsRegistry>('models');\r\n this.providers = container.get<ProvidersRegistry>('providers');\r\n this.config = container.get<RevenueConfig>('config');\r\n this.hooks = container.get<HooksRegistry>('hooks');\r\n this.logger = container.get<Logger>('logger');\r\n }\r\n\r\n /**\r\n * Create a new monetization (purchase, subscription, or free item)\r\n *\r\n * @param params - Monetization parameters\r\n *\r\n * @example\r\n * // One-time purchase\r\n * await revenue.monetization.create({\r\n * data: {\r\n * organizationId: '...',\r\n * customerId: '...',\r\n * referenceId: order._id,\r\n * referenceModel: 'Order',\r\n * },\r\n * planKey: 'one_time',\r\n * monetizationType: 'purchase',\r\n * gateway: 'bkash',\r\n * amount: 1500,\r\n * });\r\n *\r\n * // Recurring subscription\r\n * await revenue.monetization.create({\r\n * data: {\r\n * organizationId: '...',\r\n * customerId: '...',\r\n * referenceId: subscription._id,\r\n * referenceModel: 'Subscription',\r\n * },\r\n * planKey: 'monthly',\r\n * monetizationType: 'subscription',\r\n * gateway: 'stripe',\r\n * amount: 2000,\r\n * });\r\n *\r\n * @returns Result with subscription, transaction, and paymentIntent\r\n */\r\n async create(params: MonetizationCreateParams): Promise<MonetizationCreateResult> {\r\n const {\r\n data,\r\n planKey,\r\n amount,\r\n currency = 'BDT',\r\n gateway = 'manual',\r\n entity = null,\r\n monetizationType = MONETIZATION_TYPES.SUBSCRIPTION,\r\n paymentData,\r\n metadata = {},\r\n idempotencyKey = null,\r\n } = params;\r\n\r\n // Validate required fields\r\n // Note: organizationId is OPTIONAL (only needed for multi-tenant)\r\n\r\n if (!planKey) {\r\n throw new MissingRequiredFieldError('planKey');\r\n }\r\n\r\n if (amount < 0) {\r\n throw new InvalidAmountError(amount);\r\n }\r\n\r\n const isFree = amount === 0;\r\n\r\n // Get provider\r\n const provider = this.providers[gateway];\r\n if (!provider) {\r\n throw new ProviderNotFoundError(gateway, Object.keys(this.providers));\r\n }\r\n\r\n // Create payment intent if not free\r\n let paymentIntent: PaymentIntentData | null = null;\r\n let transaction: TransactionDocument | null = null;\r\n\r\n if (!isFree) {\r\n // Create payment intent via provider\r\n try {\r\n paymentIntent = await provider.createIntent({\r\n amount,\r\n currency,\r\n metadata: {\r\n ...metadata,\r\n type: 'subscription',\r\n planKey,\r\n },\r\n });\r\n } catch (error) {\r\n throw new PaymentIntentCreationError(gateway, error as Error);\r\n }\r\n\r\n // Resolve category based on entity and monetizationType\r\n const category = resolveCategory(entity, monetizationType, this.config.categoryMappings);\r\n\r\n // Resolve transaction type using config mapping or default to 'income'\r\n const transactionType: TransactionTypeValue = \r\n this.config.transactionTypeMapping?.subscription ??\r\n this.config.transactionTypeMapping?.[monetizationType] ??\r\n TRANSACTION_TYPE.INCOME;\r\n\r\n // Calculate commission if configured\r\n const commissionRate = this.config.commissionRates?.[category] ?? 0;\r\n const gatewayFeeRate = this.config.gatewayFeeRates?.[gateway] ?? 0;\r\n const commission = calculateCommission(amount, commissionRate, gatewayFeeRate);\r\n\r\n // Create transaction record\r\n const TransactionModel = this.models.Transaction;\r\n transaction = await TransactionModel.create({\r\n organizationId: data.organizationId,\r\n customerId: data.customerId ?? null,\r\n amount,\r\n currency,\r\n category,\r\n type: transactionType,\r\n method: ((paymentData as Record<string, unknown>)?.method as string) ?? 'manual',\r\n status: paymentIntent.status === 'succeeded' ? 'verified' : 'pending',\r\n gateway: {\r\n type: gateway,\r\n sessionId: paymentIntent.sessionId,\r\n paymentIntentId: paymentIntent.paymentIntentId,\r\n provider: paymentIntent.provider,\r\n metadata: paymentIntent.metadata,\r\n },\r\n paymentDetails: {\r\n provider: gateway,\r\n ...paymentData,\r\n },\r\n ...(commission && { commission }), // Only include if commission exists\r\n // Polymorphic reference (top-level, not metadata)\r\n ...(data.referenceId && { referenceId: data.referenceId }),\r\n ...(data.referenceModel && { referenceModel: data.referenceModel }),\r\n metadata: {\r\n ...metadata,\r\n planKey,\r\n entity,\r\n monetizationType,\r\n paymentIntentId: paymentIntent.id,\r\n },\r\n idempotencyKey: idempotencyKey ?? `sub_${nanoid(16)}`,\r\n }) as TransactionDocument;\r\n }\r\n\r\n // Create subscription record (if Subscription model exists)\r\n let subscription: SubscriptionDocument | null = null;\r\n if (this.models.Subscription) {\r\n const SubscriptionModel = this.models.Subscription;\r\n\r\n // Create subscription with proper reference tracking\r\n const subscriptionData = {\r\n organizationId: data.organizationId,\r\n customerId: data.customerId ?? null,\r\n planKey,\r\n amount,\r\n currency,\r\n status: isFree ? 'active' : 'pending',\r\n isActive: isFree,\r\n gateway,\r\n transactionId: transaction?._id ?? null,\r\n paymentIntentId: paymentIntent?.id ?? null,\r\n metadata: {\r\n ...metadata,\r\n isFree,\r\n entity,\r\n monetizationType,\r\n },\r\n ...data,\r\n } as Record<string, unknown>;\r\n\r\n // Remove referenceId/referenceModel from subscription (they're for transactions)\r\n delete subscriptionData.referenceId;\r\n delete subscriptionData.referenceModel;\r\n\r\n subscription = await SubscriptionModel.create(subscriptionData) as SubscriptionDocument;\r\n }\r\n\r\n // Trigger hooks - emit specific event based on monetization type\r\n const eventData = {\r\n subscription,\r\n transaction,\r\n paymentIntent,\r\n isFree,\r\n monetizationType,\r\n };\r\n\r\n // Emit specific monetization event\r\n if (monetizationType === MONETIZATION_TYPES.PURCHASE) {\r\n this._triggerHook('purchase.created', eventData);\r\n } else if (monetizationType === MONETIZATION_TYPES.SUBSCRIPTION) {\r\n this._triggerHook('subscription.created', eventData);\r\n } else if (monetizationType === MONETIZATION_TYPES.FREE) {\r\n this._triggerHook('free.created', eventData);\r\n }\r\n\r\n // Also emit generic event for backward compatibility\r\n this._triggerHook('monetization.created', eventData);\r\n\r\n return {\r\n subscription,\r\n transaction,\r\n paymentIntent,\r\n };\r\n }\r\n\r\n /**\r\n * Activate subscription after payment verification\r\n *\r\n * @param subscriptionId - Subscription ID or transaction ID\r\n * @param options - Activation options\r\n * @returns Updated subscription\r\n */\r\n async activate(\r\n subscriptionId: string,\r\n options: ActivateOptions = {}\r\n ): Promise<SubscriptionDocument> {\r\n const { timestamp = new Date() } = options;\r\n\r\n if (!this.models.Subscription) {\r\n throw new ModelNotRegisteredError('Subscription');\r\n }\r\n\r\n const SubscriptionModel = this.models.Subscription;\r\n const subscription = await SubscriptionModel.findById(subscriptionId) as SubscriptionDocument | null;\r\n\r\n if (!subscription) {\r\n throw new SubscriptionNotFoundError(subscriptionId);\r\n }\r\n\r\n if (subscription.isActive) {\r\n this.logger.warn('Subscription already active', { subscriptionId });\r\n return subscription;\r\n }\r\n\r\n // Calculate period dates based on plan\r\n const periodEnd = this._calculatePeriodEnd(subscription.planKey, timestamp);\r\n\r\n // Update subscription\r\n subscription.isActive = true;\r\n subscription.status = 'active';\r\n subscription.startDate = timestamp;\r\n subscription.endDate = periodEnd;\r\n subscription.activatedAt = timestamp;\r\n\r\n await subscription.save();\r\n\r\n // Trigger hook\r\n this._triggerHook('subscription.activated', {\r\n subscription,\r\n activatedAt: timestamp,\r\n });\r\n\r\n return subscription;\r\n }\r\n\r\n /**\r\n * Renew subscription\r\n *\r\n * @param subscriptionId - Subscription ID\r\n * @param params - Renewal parameters\r\n * @returns { subscription, transaction, paymentIntent }\r\n */\r\n async renew(\r\n subscriptionId: string,\r\n params: RenewalParams = {}\r\n ): Promise<MonetizationCreateResult> {\r\n const {\r\n gateway = 'manual',\r\n entity = null,\r\n paymentData,\r\n metadata = {},\r\n idempotencyKey = null,\r\n } = params;\r\n\r\n if (!this.models.Subscription) {\r\n throw new ModelNotRegisteredError('Subscription');\r\n }\r\n\r\n const SubscriptionModel = this.models.Subscription;\r\n const subscription = await SubscriptionModel.findById(subscriptionId) as SubscriptionDocument | null;\r\n\r\n if (!subscription) {\r\n throw new SubscriptionNotFoundError(subscriptionId);\r\n }\r\n\r\n if (subscription.amount === 0) {\r\n throw new InvalidAmountError(0, 'Free subscriptions do not require renewal');\r\n }\r\n\r\n // Get provider\r\n const provider = this.providers[gateway];\r\n if (!provider) {\r\n throw new ProviderNotFoundError(gateway, Object.keys(this.providers));\r\n }\r\n\r\n // Create payment intent\r\n let paymentIntent: PaymentIntentData | null = null;\r\n try {\r\n paymentIntent = await provider.createIntent({\r\n amount: subscription.amount,\r\n currency: subscription.currency ?? 'BDT',\r\n metadata: {\r\n ...metadata,\r\n type: 'subscription_renewal',\r\n subscriptionId: subscription._id.toString(),\r\n },\r\n });\r\n } catch (error) {\r\n this.logger.error('Failed to create payment intent for renewal:', error);\r\n throw new PaymentIntentCreationError(gateway, error as Error);\r\n }\r\n\r\n // Resolve category - use provided entity or inherit from subscription metadata\r\n const effectiveEntity = entity ?? (subscription.metadata as Record<string, unknown>)?.entity as string | null;\r\n const effectiveMonetizationType = \r\n ((subscription.metadata as Record<string, unknown>)?.monetizationType as string) ?? MONETIZATION_TYPES.SUBSCRIPTION;\r\n const category = resolveCategory(effectiveEntity, effectiveMonetizationType as 'subscription' | 'purchase' | 'free', this.config.categoryMappings);\r\n\r\n // Resolve transaction type using config mapping or default to 'income'\r\n const transactionType: TransactionTypeValue = \r\n this.config.transactionTypeMapping?.subscription_renewal ??\r\n this.config.transactionTypeMapping?.subscription ??\r\n this.config.transactionTypeMapping?.[effectiveMonetizationType] ??\r\n TRANSACTION_TYPE.INCOME;\r\n\r\n // Calculate commission if configured\r\n const commissionRate = this.config.commissionRates?.[category] ?? 0;\r\n const gatewayFeeRate = this.config.gatewayFeeRates?.[gateway] ?? 0;\r\n const commission = calculateCommission(subscription.amount, commissionRate, gatewayFeeRate);\r\n\r\n // Create transaction\r\n const TransactionModel = this.models.Transaction;\r\n const transaction = await TransactionModel.create({\r\n organizationId: subscription.organizationId,\r\n customerId: subscription.customerId,\r\n amount: subscription.amount,\r\n currency: subscription.currency ?? 'BDT',\r\n category,\r\n type: transactionType,\r\n method: ((paymentData as Record<string, unknown>)?.method as string) ?? 'manual',\r\n status: paymentIntent.status === 'succeeded' ? 'verified' : 'pending',\r\n gateway: {\r\n type: gateway,\r\n sessionId: paymentIntent.sessionId,\r\n paymentIntentId: paymentIntent.paymentIntentId,\r\n provider: paymentIntent.provider,\r\n metadata: paymentIntent.metadata,\r\n },\r\n paymentDetails: {\r\n provider: gateway,\r\n ...paymentData,\r\n },\r\n ...(commission && { commission }), // Only include if commission exists\r\n // Polymorphic reference to subscription\r\n referenceId: subscription._id,\r\n referenceModel: 'Subscription',\r\n metadata: {\r\n ...metadata,\r\n subscriptionId: subscription._id.toString(), // Keep for backward compat\r\n entity: effectiveEntity,\r\n monetizationType: effectiveMonetizationType,\r\n isRenewal: true,\r\n paymentIntentId: paymentIntent.id,\r\n },\r\n idempotencyKey: idempotencyKey ?? `renewal_${nanoid(16)}`,\r\n }) as TransactionDocument;\r\n\r\n // Update subscription\r\n subscription.status = 'pending_renewal' as SubscriptionDocument['status'];\r\n subscription.renewalTransactionId = transaction._id;\r\n subscription.renewalCount = (subscription.renewalCount ?? 0) + 1;\r\n await subscription.save();\r\n\r\n // Trigger hook\r\n this._triggerHook('subscription.renewed', {\r\n subscription,\r\n transaction,\r\n paymentIntent,\r\n renewalCount: subscription.renewalCount,\r\n });\r\n\r\n return {\r\n subscription,\r\n transaction,\r\n paymentIntent,\r\n };\r\n }\r\n\r\n /**\r\n * Cancel subscription\r\n *\r\n * @param subscriptionId - Subscription ID\r\n * @param options - Cancellation options\r\n * @returns Updated subscription\r\n */\r\n async cancel(\r\n subscriptionId: string,\r\n options: CancelOptions = {}\r\n ): Promise<SubscriptionDocument> {\r\n const { immediate = false, reason = null } = options;\r\n\r\n if (!this.models.Subscription) {\r\n throw new ModelNotRegisteredError('Subscription');\r\n }\r\n\r\n const SubscriptionModel = this.models.Subscription;\r\n const subscription = await SubscriptionModel.findById(subscriptionId) as SubscriptionDocument | null;\r\n\r\n if (!subscription) {\r\n throw new SubscriptionNotFoundError(subscriptionId);\r\n }\r\n\r\n const now = new Date();\r\n\r\n if (immediate) {\r\n subscription.isActive = false;\r\n subscription.status = 'cancelled';\r\n subscription.canceledAt = now;\r\n subscription.cancellationReason = reason;\r\n } else {\r\n // Schedule cancellation at period end\r\n subscription.cancelAt = subscription.endDate ?? now;\r\n subscription.cancellationReason = reason;\r\n }\r\n\r\n await subscription.save();\r\n\r\n // Trigger hook\r\n this._triggerHook('subscription.cancelled', {\r\n subscription,\r\n immediate,\r\n reason,\r\n canceledAt: immediate ? now : subscription.cancelAt,\r\n });\r\n\r\n return subscription;\r\n }\r\n\r\n /**\r\n * Pause subscription\r\n *\r\n * @param subscriptionId - Subscription ID\r\n * @param options - Pause options\r\n * @returns Updated subscription\r\n */\r\n async pause(\r\n subscriptionId: string,\r\n options: PauseOptions = {}\r\n ): Promise<SubscriptionDocument> {\r\n const { reason = null } = options;\r\n\r\n if (!this.models.Subscription) {\r\n throw new ModelNotRegisteredError('Subscription');\r\n }\r\n\r\n const SubscriptionModel = this.models.Subscription;\r\n const subscription = await SubscriptionModel.findById(subscriptionId) as SubscriptionDocument | null;\r\n\r\n if (!subscription) {\r\n throw new SubscriptionNotFoundError(subscriptionId);\r\n }\r\n\r\n if (!subscription.isActive) {\r\n throw new SubscriptionNotActiveError(subscriptionId, 'Only active subscriptions can be paused');\r\n }\r\n\r\n const pausedAt = new Date();\r\n subscription.isActive = false;\r\n subscription.status = 'paused';\r\n subscription.pausedAt = pausedAt;\r\n subscription.pauseReason = reason;\r\n\r\n await subscription.save();\r\n\r\n // Trigger hook\r\n this._triggerHook('subscription.paused', {\r\n subscription,\r\n reason,\r\n pausedAt,\r\n });\r\n\r\n return subscription;\r\n }\r\n\r\n /**\r\n * Resume subscription\r\n *\r\n * @param subscriptionId - Subscription ID\r\n * @param options - Resume options\r\n * @returns Updated subscription\r\n */\r\n async resume(\r\n subscriptionId: string,\r\n options: ResumeOptions = {}\r\n ): Promise<SubscriptionDocument> {\r\n const { extendPeriod = false } = options;\r\n\r\n if (!this.models.Subscription) {\r\n throw new ModelNotRegisteredError('Subscription');\r\n }\r\n\r\n const SubscriptionModel = this.models.Subscription;\r\n const subscription = await SubscriptionModel.findById(subscriptionId) as SubscriptionDocument | null;\r\n\r\n if (!subscription) {\r\n throw new SubscriptionNotFoundError(subscriptionId);\r\n }\r\n\r\n if (!subscription.pausedAt) {\r\n throw new InvalidStateTransitionError(\r\n 'resume',\r\n 'paused',\r\n subscription.status,\r\n 'Only paused subscriptions can be resumed'\r\n );\r\n }\r\n\r\n const now = new Date();\r\n const pausedAt = new Date(subscription.pausedAt);\r\n const pauseDuration = now.getTime() - pausedAt.getTime();\r\n\r\n subscription.isActive = true;\r\n subscription.status = 'active';\r\n subscription.pausedAt = null;\r\n subscription.pauseReason = null;\r\n\r\n // Optionally extend period by pause duration\r\n if (extendPeriod && subscription.endDate) {\r\n const currentEnd = new Date(subscription.endDate);\r\n subscription.endDate = new Date(currentEnd.getTime() + pauseDuration);\r\n }\r\n\r\n await subscription.save();\r\n\r\n // Trigger hook\r\n this._triggerHook('subscription.resumed', {\r\n subscription,\r\n extendPeriod,\r\n pauseDuration,\r\n resumedAt: now,\r\n });\r\n\r\n return subscription;\r\n }\r\n\r\n /**\r\n * List subscriptions with filters\r\n *\r\n * @param filters - Query filters\r\n * @param options - Query options (limit, skip, sort)\r\n * @returns Subscriptions\r\n */\r\n async list(\r\n filters: Record<string, unknown> = {},\r\n options: ListOptions = {}\r\n ): Promise<SubscriptionDocument[]> {\r\n if (!this.models.Subscription) {\r\n throw new ModelNotRegisteredError('Subscription');\r\n }\r\n\r\n const SubscriptionModel = this.models.Subscription;\r\n const { limit = 50, skip = 0, sort = { createdAt: -1 } } = options;\r\n\r\n const subscriptions = await (SubscriptionModel as unknown as {\r\n find(filter: object): { limit(n: number): { skip(n: number): { sort(s: object): Promise<SubscriptionDocument[]> } } };\r\n })\r\n .find(filters)\r\n .limit(limit)\r\n .skip(skip)\r\n .sort(sort);\r\n\r\n return subscriptions;\r\n }\r\n\r\n /**\r\n * Get subscription by ID\r\n *\r\n * @param subscriptionId - Subscription ID\r\n * @returns Subscription\r\n */\r\n async get(subscriptionId: string): Promise<SubscriptionDocument> {\r\n if (!this.models.Subscription) {\r\n throw new ModelNotRegisteredError('Subscription');\r\n }\r\n\r\n const SubscriptionModel = this.models.Subscription;\r\n const subscription = await SubscriptionModel.findById(subscriptionId) as SubscriptionDocument | null;\r\n\r\n if (!subscription) {\r\n throw new SubscriptionNotFoundError(subscriptionId);\r\n }\r\n\r\n return subscription;\r\n }\r\n\r\n /**\r\n * Calculate period end date based on plan key\r\n * @private\r\n */\r\n private _calculatePeriodEnd(planKey: string, startDate: Date = new Date()): Date {\r\n const start = new Date(startDate);\r\n const end = new Date(start);\r\n\r\n switch (planKey) {\r\n case 'monthly':\r\n end.setMonth(end.getMonth() + 1);\r\n break;\r\n case 'quarterly':\r\n end.setMonth(end.getMonth() + 3);\r\n break;\r\n case 'yearly':\r\n end.setFullYear(end.getFullYear() + 1);\r\n break;\r\n default:\r\n // Default to 30 days\r\n end.setDate(end.getDate() + 30);\r\n }\r\n\r\n return end;\r\n }\r\n\r\n /**\r\n * Trigger event hook (fire-and-forget, non-blocking)\r\n * @private\r\n */\r\n private _triggerHook(event: string, data: unknown): void {\r\n triggerHook(this.hooks, event, data, this.logger);\r\n }\r\n}\r\n\r\nexport default MonetizationService;\r\n\r\n","/**\r\n * Payment Service\r\n * @classytic/revenue\r\n *\r\n * Framework-agnostic payment verification and management service with DI\r\n * Handles payment verification, refunds, and status updates\r\n */\r\n\r\nimport {\r\n TransactionNotFoundError,\r\n ProviderNotFoundError,\r\n ProviderError,\r\n AlreadyVerifiedError,\r\n PaymentVerificationError,\r\n RefundNotSupportedError,\r\n RefundError,\r\n ProviderCapabilityError,\r\n ValidationError,\r\n} from '../core/errors.js';\r\nimport { triggerHook } from '../utils/hooks.js';\r\nimport { reverseCommission } from '../utils/commission.js';\r\nimport { TRANSACTION_TYPE } from '../enums/transaction.enums.js';\r\nimport type { Container } from '../core/container.js';\r\nimport type {\r\n ModelsRegistry,\r\n ProvidersRegistry,\r\n HooksRegistry,\r\n RevenueConfig,\r\n Logger,\r\n TransactionDocument,\r\n PaymentVerifyOptions,\r\n PaymentVerifyResult,\r\n PaymentStatusResult,\r\n RefundOptions,\r\n PaymentRefundResult,\r\n WebhookResult,\r\n ListOptions,\r\n PaymentResultData,\r\n PaymentProviderInterface,\r\n TransactionTypeValue,\r\n MongooseModel,\r\n} from '../types/index.js';\r\n\r\n/**\r\n * Payment Service\r\n * Uses DI container for all dependencies\r\n */\r\nexport class PaymentService {\r\n private readonly models: ModelsRegistry;\r\n private readonly providers: ProvidersRegistry;\r\n private readonly config: RevenueConfig;\r\n private readonly hooks: HooksRegistry;\r\n private readonly logger: Logger;\r\n\r\n constructor(container: Container) {\r\n this.models = container.get<ModelsRegistry>('models');\r\n this.providers = container.get<ProvidersRegistry>('providers');\r\n this.config = container.get<RevenueConfig>('config');\r\n this.hooks = container.get<HooksRegistry>('hooks');\r\n this.logger = container.get<Logger>('logger');\r\n }\r\n\r\n /**\r\n * Verify a payment\r\n *\r\n * @param paymentIntentId - Payment intent ID, session ID, or transaction ID\r\n * @param options - Verification options\r\n * @returns { transaction, status }\r\n */\r\n async verify(\r\n paymentIntentId: string,\r\n options: PaymentVerifyOptions = {}\r\n ): Promise<PaymentVerifyResult> {\r\n const { verifiedBy = null } = options;\r\n\r\n const TransactionModel = this.models.Transaction;\r\n const transaction = await this._findTransaction(TransactionModel, paymentIntentId);\r\n\r\n if (!transaction) {\r\n throw new TransactionNotFoundError(paymentIntentId);\r\n }\r\n\r\n if (transaction.status === 'verified' || transaction.status === 'completed') {\r\n throw new AlreadyVerifiedError(transaction._id.toString());\r\n }\r\n\r\n // Get provider for verification\r\n const gatewayType = transaction.gateway?.type ?? 'manual';\r\n const provider = this.providers[gatewayType];\r\n\r\n if (!provider) {\r\n throw new ProviderNotFoundError(gatewayType, Object.keys(this.providers));\r\n }\r\n\r\n // Verify payment with provider\r\n let paymentResult: PaymentResultData | null = null;\r\n try {\r\n paymentResult = await provider.verifyPayment(paymentIntentId);\r\n } catch (error) {\r\n this.logger.error('Payment verification failed:', error);\r\n\r\n // Update transaction as failed\r\n transaction.status = 'failed';\r\n transaction.failureReason = (error as Error).message;\r\n transaction.metadata = {\r\n ...transaction.metadata,\r\n verificationError: (error as Error).message,\r\n failedAt: new Date().toISOString(),\r\n };\r\n await transaction.save();\r\n\r\n // Trigger payment.failed hook\r\n this._triggerHook('payment.failed', {\r\n transaction,\r\n error: (error as Error).message,\r\n provider: gatewayType,\r\n paymentIntentId,\r\n });\r\n\r\n throw new PaymentVerificationError(paymentIntentId, (error as Error).message);\r\n }\r\n\r\n // Validate amount and currency match\r\n if (paymentResult.amount && paymentResult.amount !== transaction.amount) {\r\n throw new ValidationError(\r\n `Amount mismatch: expected ${transaction.amount}, got ${paymentResult.amount}`,\r\n { expected: transaction.amount, actual: paymentResult.amount }\r\n );\r\n }\r\n\r\n if (paymentResult.currency && paymentResult.currency.toUpperCase() !== transaction.currency.toUpperCase()) {\r\n throw new ValidationError(\r\n `Currency mismatch: expected ${transaction.currency}, got ${paymentResult.currency}`,\r\n { expected: transaction.currency, actual: paymentResult.currency }\r\n );\r\n }\r\n\r\n // Update transaction based on verification result\r\n transaction.status = paymentResult.status === 'succeeded' ? 'verified' : paymentResult.status;\r\n transaction.verifiedAt = paymentResult.paidAt ?? new Date();\r\n transaction.verifiedBy = verifiedBy;\r\n transaction.gateway = {\r\n ...transaction.gateway,\r\n type: transaction.gateway?.type ?? 'manual',\r\n verificationData: paymentResult.metadata,\r\n };\r\n\r\n await transaction.save();\r\n\r\n // Trigger hook\r\n this._triggerHook('payment.verified', {\r\n transaction,\r\n paymentResult,\r\n verifiedBy,\r\n });\r\n\r\n return {\r\n transaction,\r\n paymentResult,\r\n status: transaction.status,\r\n };\r\n }\r\n\r\n /**\r\n * Get payment status\r\n *\r\n * @param paymentIntentId - Payment intent ID, session ID, or transaction ID\r\n * @returns { transaction, status }\r\n */\r\n async getStatus(paymentIntentId: string): Promise<PaymentStatusResult> {\r\n const TransactionModel = this.models.Transaction;\r\n const transaction = await this._findTransaction(TransactionModel, paymentIntentId);\r\n\r\n if (!transaction) {\r\n throw new TransactionNotFoundError(paymentIntentId);\r\n }\r\n\r\n // Get provider\r\n const gatewayType = transaction.gateway?.type ?? 'manual';\r\n const provider = this.providers[gatewayType];\r\n\r\n if (!provider) {\r\n throw new ProviderNotFoundError(gatewayType, Object.keys(this.providers));\r\n }\r\n\r\n // Get status from provider\r\n let paymentResult: PaymentResultData | null = null;\r\n try {\r\n paymentResult = await provider.getStatus(paymentIntentId);\r\n } catch (error) {\r\n this.logger.warn('Failed to get payment status from provider:', error);\r\n // Return transaction status as fallback\r\n return {\r\n transaction,\r\n status: transaction.status,\r\n provider: gatewayType,\r\n };\r\n }\r\n\r\n return {\r\n transaction,\r\n paymentResult,\r\n status: paymentResult.status,\r\n provider: gatewayType,\r\n };\r\n }\r\n\r\n /**\r\n * Refund a payment\r\n *\r\n * @param paymentId - Payment intent ID, session ID, or transaction ID\r\n * @param amount - Amount to refund (optional, full refund if not provided)\r\n * @param options - Refund options\r\n * @returns { transaction, refundResult }\r\n */\r\n async refund(\r\n paymentId: string,\r\n amount: number | null = null,\r\n options: RefundOptions = {}\r\n ): Promise<PaymentRefundResult> {\r\n const { reason = null } = options;\r\n\r\n const TransactionModel = this.models.Transaction;\r\n const transaction = await this._findTransaction(TransactionModel, paymentId);\r\n\r\n if (!transaction) {\r\n throw new TransactionNotFoundError(paymentId);\r\n }\r\n\r\n if (transaction.status !== 'verified' && transaction.status !== 'completed') {\r\n throw new RefundError(transaction._id.toString(), 'Only verified/completed transactions can be refunded');\r\n }\r\n\r\n // Get provider\r\n const gatewayType = transaction.gateway?.type ?? 'manual';\r\n const provider = this.providers[gatewayType];\r\n\r\n if (!provider) {\r\n throw new ProviderNotFoundError(gatewayType, Object.keys(this.providers));\r\n }\r\n\r\n // Check if provider supports refunds\r\n const capabilities = provider.getCapabilities();\r\n if (!capabilities.supportsRefunds) {\r\n throw new RefundNotSupportedError(gatewayType);\r\n }\r\n\r\n // Calculate refundable amount\r\n const refundedSoFar = transaction.refundedAmount ?? 0;\r\n const refundableAmount = transaction.amount - refundedSoFar;\r\n const refundAmount = amount ?? refundableAmount;\r\n\r\n // Validate refund amount\r\n if (refundAmount <= 0) {\r\n throw new ValidationError(`Refund amount must be positive, got ${refundAmount}`);\r\n }\r\n\r\n if (refundAmount > refundableAmount) {\r\n throw new ValidationError(\r\n `Refund amount (${refundAmount}) exceeds refundable balance (${refundableAmount})`,\r\n { refundAmount, refundableAmount, alreadyRefunded: refundedSoFar }\r\n );\r\n }\r\n\r\n // Refund via provider\r\n let refundResult;\r\n\r\n try {\r\n refundResult = await provider.refund(paymentId, refundAmount, { reason: reason ?? undefined });\r\n } catch (error) {\r\n this.logger.error('Refund failed:', error);\r\n throw new RefundError(paymentId, (error as Error).message);\r\n }\r\n\r\n // Create separate refund transaction (EXPENSE) for proper accounting\r\n const refundTransactionType: TransactionTypeValue = \r\n this.config.transactionTypeMapping?.refund ?? TRANSACTION_TYPE.EXPENSE;\r\n\r\n // Reverse commission proportionally for refund\r\n const refundCommission = transaction.commission\r\n ? reverseCommission(transaction.commission, transaction.amount, refundAmount)\r\n : null;\r\n\r\n const refundTransaction = await TransactionModel.create({\r\n organizationId: transaction.organizationId,\r\n customerId: transaction.customerId,\r\n amount: refundAmount,\r\n currency: transaction.currency,\r\n category: transaction.category,\r\n type: refundTransactionType, // EXPENSE - money going out\r\n method: transaction.method ?? 'manual',\r\n status: 'completed',\r\n gateway: {\r\n type: transaction.gateway?.type ?? 'manual',\r\n paymentIntentId: refundResult.id,\r\n provider: refundResult.provider,\r\n },\r\n paymentDetails: transaction.paymentDetails,\r\n ...(refundCommission && { commission: refundCommission }), // Reversed commission\r\n // Polymorphic reference (copy from original transaction)\r\n ...(transaction.referenceId && { referenceId: transaction.referenceId }),\r\n ...(transaction.referenceModel && { referenceModel: transaction.referenceModel }),\r\n metadata: {\r\n ...transaction.metadata,\r\n isRefund: true,\r\n originalTransactionId: transaction._id.toString(),\r\n refundReason: reason,\r\n refundResult: refundResult.metadata,\r\n },\r\n idempotencyKey: `refund_${transaction._id}_${Date.now()}`,\r\n }) as TransactionDocument;\r\n\r\n // Update original transaction status\r\n const isPartialRefund = refundAmount < transaction.amount;\r\n transaction.status = isPartialRefund ? 'partially_refunded' : 'refunded';\r\n transaction.refundedAmount = (transaction.refundedAmount ?? 0) + refundAmount;\r\n transaction.refundedAt = refundResult.refundedAt ?? new Date();\r\n transaction.metadata = {\r\n ...transaction.metadata,\r\n refundTransactionId: refundTransaction._id.toString(),\r\n refundReason: reason,\r\n };\r\n\r\n await transaction.save();\r\n\r\n // Trigger hook\r\n this._triggerHook('payment.refunded', {\r\n transaction,\r\n refundTransaction,\r\n refundResult,\r\n refundAmount,\r\n reason,\r\n isPartialRefund,\r\n });\r\n\r\n return {\r\n transaction,\r\n refundTransaction,\r\n refundResult,\r\n status: transaction.status,\r\n };\r\n }\r\n\r\n /**\r\n * Handle webhook from payment provider\r\n *\r\n * @param provider - Provider name\r\n * @param payload - Webhook payload\r\n * @param headers - Request headers\r\n * @returns { event, transaction }\r\n */\r\n async handleWebhook(\r\n providerName: string,\r\n payload: unknown,\r\n headers: Record<string, string> = {}\r\n ): Promise<WebhookResult> {\r\n const provider = this.providers[providerName];\r\n\r\n if (!provider) {\r\n throw new ProviderNotFoundError(providerName, Object.keys(this.providers));\r\n }\r\n\r\n // Check if provider supports webhooks\r\n const capabilities = provider.getCapabilities();\r\n if (!capabilities.supportsWebhooks) {\r\n throw new ProviderCapabilityError(providerName, 'webhooks');\r\n }\r\n\r\n // Process webhook via provider\r\n let webhookEvent;\r\n try {\r\n webhookEvent = await provider.handleWebhook(payload, headers);\r\n } catch (error) {\r\n this.logger.error('Webhook processing failed:', error);\r\n throw new ProviderError(\r\n `Webhook processing failed for ${providerName}: ${(error as Error).message}`,\r\n 'WEBHOOK_PROCESSING_FAILED',\r\n { retryable: false }\r\n );\r\n }\r\n\r\n // Validate webhook event structure\r\n if (!webhookEvent?.data?.sessionId && !webhookEvent?.data?.paymentIntentId) {\r\n throw new ValidationError(\r\n `Invalid webhook event structure from ${providerName}: missing sessionId or paymentIntentId`,\r\n { provider: providerName, eventType: webhookEvent?.type }\r\n );\r\n }\r\n\r\n // Find transaction by sessionId first (for checkout flows), then paymentIntentId\r\n const TransactionModel = this.models.Transaction;\r\n let transaction: TransactionDocument | null = null;\r\n\r\n if (webhookEvent.data.sessionId) {\r\n transaction = await (TransactionModel as unknown as {\r\n findOne(filter: object): Promise<TransactionDocument | null>;\r\n }).findOne({\r\n 'gateway.sessionId': webhookEvent.data.sessionId,\r\n });\r\n }\r\n\r\n if (!transaction && webhookEvent.data.paymentIntentId) {\r\n transaction = await (TransactionModel as unknown as {\r\n findOne(filter: object): Promise<TransactionDocument | null>;\r\n }).findOne({\r\n 'gateway.paymentIntentId': webhookEvent.data.paymentIntentId,\r\n });\r\n }\r\n\r\n if (!transaction) {\r\n this.logger.warn('Transaction not found for webhook event', {\r\n provider: providerName,\r\n eventId: webhookEvent.id,\r\n sessionId: webhookEvent.data.sessionId,\r\n paymentIntentId: webhookEvent.data.paymentIntentId,\r\n });\r\n throw new TransactionNotFoundError(\r\n webhookEvent.data.sessionId ?? webhookEvent.data.paymentIntentId ?? 'unknown'\r\n );\r\n }\r\n\r\n // Update gateway with complete information from webhook\r\n if (webhookEvent.data.sessionId && !transaction.gateway?.sessionId) {\r\n transaction.gateway = {\r\n ...transaction.gateway,\r\n type: transaction.gateway?.type ?? 'manual',\r\n sessionId: webhookEvent.data.sessionId,\r\n };\r\n }\r\n if (webhookEvent.data.paymentIntentId && !transaction.gateway?.paymentIntentId) {\r\n transaction.gateway = {\r\n ...transaction.gateway,\r\n type: transaction.gateway?.type ?? 'manual',\r\n paymentIntentId: webhookEvent.data.paymentIntentId,\r\n };\r\n }\r\n\r\n // Check for duplicate webhook processing (idempotency)\r\n if (transaction.webhook?.eventId === webhookEvent.id && transaction.webhook?.processedAt) {\r\n this.logger.warn('Webhook already processed', {\r\n transactionId: transaction._id,\r\n eventId: webhookEvent.id,\r\n });\r\n return {\r\n event: webhookEvent,\r\n transaction,\r\n status: 'already_processed',\r\n };\r\n }\r\n\r\n // Update transaction based on webhook event\r\n transaction.webhook = {\r\n eventId: webhookEvent.id,\r\n eventType: webhookEvent.type,\r\n receivedAt: new Date(),\r\n processedAt: new Date(),\r\n data: webhookEvent.data,\r\n };\r\n\r\n // Update status based on webhook type\r\n if (webhookEvent.type === 'payment.succeeded') {\r\n transaction.status = 'verified';\r\n transaction.verifiedAt = webhookEvent.createdAt;\r\n } else if (webhookEvent.type === 'payment.failed') {\r\n transaction.status = 'failed';\r\n } else if (webhookEvent.type === 'refund.succeeded') {\r\n transaction.status = 'refunded';\r\n transaction.refundedAt = webhookEvent.createdAt;\r\n }\r\n\r\n await transaction.save();\r\n\r\n // Trigger hook\r\n this._triggerHook(`payment.webhook.${webhookEvent.type}`, {\r\n event: webhookEvent,\r\n transaction,\r\n });\r\n\r\n return {\r\n event: webhookEvent,\r\n transaction,\r\n status: 'processed',\r\n };\r\n }\r\n\r\n /**\r\n * List payments/transactions with filters\r\n *\r\n * @param filters - Query filters\r\n * @param options - Query options (limit, skip, sort)\r\n * @returns Transactions\r\n */\r\n async list(\r\n filters: Record<string, unknown> = {},\r\n options: ListOptions = {}\r\n ): Promise<TransactionDocument[]> {\r\n const TransactionModel = this.models.Transaction;\r\n const { limit = 50, skip = 0, sort = { createdAt: -1 } } = options;\r\n\r\n const transactions = await (TransactionModel as unknown as {\r\n find(filter: object): { limit(n: number): { skip(n: number): { sort(s: object): Promise<TransactionDocument[]> } } };\r\n })\r\n .find(filters)\r\n .limit(limit)\r\n .skip(skip)\r\n .sort(sort);\r\n\r\n return transactions;\r\n }\r\n\r\n /**\r\n * Get payment/transaction by ID\r\n *\r\n * @param transactionId - Transaction ID\r\n * @returns Transaction\r\n */\r\n async get(transactionId: string): Promise<TransactionDocument> {\r\n const TransactionModel = this.models.Transaction;\r\n const transaction = await TransactionModel.findById(transactionId) as TransactionDocument | null;\r\n\r\n if (!transaction) {\r\n throw new TransactionNotFoundError(transactionId);\r\n }\r\n\r\n return transaction;\r\n }\r\n\r\n /**\r\n * Get provider instance\r\n *\r\n * @param providerName - Provider name\r\n * @returns Provider instance\r\n */\r\n getProvider(providerName: string): PaymentProviderInterface {\r\n const provider = this.providers[providerName];\r\n if (!provider) {\r\n throw new ProviderNotFoundError(providerName, Object.keys(this.providers));\r\n }\r\n return provider;\r\n }\r\n\r\n /**\r\n * Trigger event hook (fire-and-forget, non-blocking)\r\n * @private\r\n */\r\n private _triggerHook(event: string, data: unknown): void {\r\n triggerHook(this.hooks, event, data, this.logger);\r\n }\r\n\r\n /**\r\n * Find transaction by sessionId, paymentIntentId, or transaction ID\r\n * @private\r\n */\r\n private async _findTransaction(\r\n TransactionModel: MongooseModel<TransactionDocument>,\r\n identifier: string\r\n ): Promise<TransactionDocument | null> {\r\n let transaction = await (TransactionModel as unknown as {\r\n findOne(filter: object): Promise<TransactionDocument | null>;\r\n }).findOne({\r\n 'gateway.sessionId': identifier,\r\n });\r\n\r\n if (!transaction) {\r\n transaction = await (TransactionModel as unknown as {\r\n findOne(filter: object): Promise<TransactionDocument | null>;\r\n }).findOne({\r\n 'gateway.paymentIntentId': identifier,\r\n });\r\n }\r\n\r\n if (!transaction) {\r\n transaction = await TransactionModel.findById(identifier) as TransactionDocument | null;\r\n }\r\n\r\n return transaction;\r\n }\r\n}\r\n\r\nexport default PaymentService;\r\n\r\n","/**\r\n * Transaction Service\r\n * @classytic/revenue\r\n *\r\n * Thin, focused transaction service for core operations\r\n * Users handle their own analytics, exports, and complex queries\r\n *\r\n * Works with ANY model implementation:\r\n * - Plain Mongoose models\r\n * - @classytic/mongokit Repository instances\r\n * - Any other abstraction with compatible interface\r\n */\r\n\r\nimport { TransactionNotFoundError } from '../core/errors.js';\r\nimport { triggerHook } from '../utils/hooks.js';\r\nimport type { Container } from '../core/container.js';\r\nimport type {\r\n ModelsRegistry,\r\n HooksRegistry,\r\n Logger,\r\n TransactionDocument,\r\n TransactionListResult,\r\n ListOptions,\r\n} from '../types/index.js';\r\n\r\n/**\r\n * Transaction Service\r\n * Focused on core transaction lifecycle operations\r\n */\r\nexport class TransactionService {\r\n private readonly models: ModelsRegistry;\r\n private readonly hooks: HooksRegistry;\r\n private readonly logger: Logger;\r\n\r\n constructor(container: Container) {\r\n this.models = container.get<ModelsRegistry>('models');\r\n this.hooks = container.get<HooksRegistry>('hooks');\r\n this.logger = container.get<Logger>('logger');\r\n }\r\n\r\n /**\r\n * Get transaction by ID\r\n *\r\n * @param transactionId - Transaction ID\r\n * @returns Transaction\r\n */\r\n async get(transactionId: string): Promise<TransactionDocument> {\r\n const TransactionModel = this.models.Transaction;\r\n const transaction = await TransactionModel.findById(transactionId) as TransactionDocument | null;\r\n\r\n if (!transaction) {\r\n throw new TransactionNotFoundError(transactionId);\r\n }\r\n\r\n return transaction;\r\n }\r\n\r\n /**\r\n * List transactions with filters\r\n *\r\n * @param filters - Query filters\r\n * @param options - Query options (limit, skip, sort, populate)\r\n * @returns { transactions, total, page, limit }\r\n */\r\n async list(\r\n filters: Record<string, unknown> = {},\r\n options: ListOptions = {}\r\n ): Promise<TransactionListResult> {\r\n const TransactionModel = this.models.Transaction;\r\n const {\r\n limit = 50,\r\n skip = 0,\r\n page = null,\r\n sort = { createdAt: -1 },\r\n populate = [],\r\n } = options;\r\n\r\n // Calculate pagination\r\n const actualSkip = page ? (page - 1) * limit : skip;\r\n\r\n // Build query\r\n type QueryBuilder = {\r\n find(filter: object): QueryBuilder;\r\n limit(n: number): QueryBuilder;\r\n skip(n: number): QueryBuilder;\r\n sort(s: object): QueryBuilder;\r\n populate(field: string): QueryBuilder;\r\n then<T>(resolve: (value: TransactionDocument[]) => T): Promise<T>;\r\n };\r\n\r\n let query = (TransactionModel as unknown as {\r\n find(filter: object): QueryBuilder;\r\n }).find(filters)\r\n .limit(limit)\r\n .skip(actualSkip)\r\n .sort(sort);\r\n\r\n // Apply population if supported\r\n if (populate.length > 0 && typeof query.populate === 'function') {\r\n populate.forEach((field) => {\r\n query = query.populate(field);\r\n });\r\n }\r\n\r\n const transactions = await query as unknown as TransactionDocument[];\r\n\r\n // Count documents (works with both Mongoose and Repository)\r\n type ModelWithCount = {\r\n countDocuments?(filter: object): Promise<number>;\r\n count?(filter: object): Promise<number>;\r\n };\r\n\r\n const model = TransactionModel as unknown as ModelWithCount;\r\n const total = await (model.countDocuments\r\n ? model.countDocuments(filters)\r\n : model.count?.(filters)) ?? 0;\r\n\r\n return {\r\n transactions,\r\n total,\r\n page: page ?? Math.floor(actualSkip / limit) + 1,\r\n limit,\r\n pages: Math.ceil(total / limit),\r\n };\r\n }\r\n\r\n /**\r\n * Update transaction\r\n *\r\n * @param transactionId - Transaction ID\r\n * @param updates - Fields to update\r\n * @returns Updated transaction\r\n */\r\n async update(\r\n transactionId: string,\r\n updates: Partial<TransactionDocument>\r\n ): Promise<TransactionDocument> {\r\n const TransactionModel = this.models.Transaction;\r\n\r\n // Support both Repository pattern and Mongoose\r\n type ModelWithUpdate = {\r\n update?(id: string, data: object): Promise<TransactionDocument | null>;\r\n findByIdAndUpdate?(id: string, data: object, options?: object): Promise<TransactionDocument | null>;\r\n };\r\n\r\n const model = TransactionModel as unknown as ModelWithUpdate;\r\n let transaction: TransactionDocument | null;\r\n\r\n if (typeof model.update === 'function') {\r\n // Repository pattern\r\n transaction = await model.update(transactionId, updates);\r\n } else if (typeof model.findByIdAndUpdate === 'function') {\r\n // Plain Mongoose\r\n transaction = await model.findByIdAndUpdate(\r\n transactionId,\r\n { $set: updates },\r\n { new: true }\r\n );\r\n } else {\r\n throw new Error('Transaction model does not support update operations');\r\n }\r\n\r\n if (!transaction) {\r\n throw new TransactionNotFoundError(transactionId);\r\n }\r\n\r\n // Trigger hook (fire-and-forget, non-blocking)\r\n this._triggerHook('transaction.updated', {\r\n transaction,\r\n updates,\r\n });\r\n\r\n return transaction;\r\n }\r\n\r\n /**\r\n * Trigger event hook (fire-and-forget, non-blocking)\r\n * @private\r\n */\r\n private _triggerHook(event: string, data: unknown): void {\r\n triggerHook(this.hooks, event, data, this.logger);\r\n }\r\n}\r\n\r\nexport default TransactionService;\r\n\r\n","/**\r\n * Escrow/Hold Enums\r\n * @classytic/revenue\r\n *\r\n * Enums for platform-as-intermediary payment flow\r\n */\r\n\r\nexport const HOLD_STATUS = {\r\n PENDING: 'pending',\r\n HELD: 'held',\r\n RELEASED: 'released',\r\n CANCELLED: 'cancelled',\r\n EXPIRED: 'expired',\r\n PARTIALLY_RELEASED: 'partially_released',\r\n} as const;\r\n\r\nexport type HoldStatus = typeof HOLD_STATUS;\r\nexport type HoldStatusValue = HoldStatus[keyof HoldStatus];\r\nexport const HOLD_STATUS_VALUES = Object.values(HOLD_STATUS);\r\n\r\nexport const RELEASE_REASON = {\r\n PAYMENT_VERIFIED: 'payment_verified',\r\n MANUAL_RELEASE: 'manual_release',\r\n AUTO_RELEASE: 'auto_release',\r\n DISPUTE_RESOLVED: 'dispute_resolved',\r\n} as const;\r\n\r\nexport type ReleaseReason = typeof RELEASE_REASON;\r\nexport type ReleaseReasonValue = ReleaseReason[keyof ReleaseReason];\r\nexport const RELEASE_REASON_VALUES = Object.values(RELEASE_REASON);\r\n\r\nexport const HOLD_REASON = {\r\n PAYMENT_VERIFICATION: 'payment_verification',\r\n FRAUD_CHECK: 'fraud_check',\r\n MANUAL_REVIEW: 'manual_review',\r\n DISPUTE: 'dispute',\r\n COMPLIANCE: 'compliance',\r\n} as const;\r\n\r\nexport type HoldReason = typeof HOLD_REASON;\r\nexport type HoldReasonValue = HoldReason[keyof HoldReason];\r\nexport const HOLD_REASON_VALUES = Object.values(HOLD_REASON);\r\n\r\n","/**\r\n * Split Payment Enums\r\n * @classytic/revenue\r\n *\r\n * Enums for multi-party commission splits\r\n */\r\n\r\nexport const SPLIT_TYPE = {\r\n PLATFORM_COMMISSION: 'platform_commission',\r\n AFFILIATE_COMMISSION: 'affiliate_commission',\r\n REFERRAL_COMMISSION: 'referral_commission',\r\n PARTNER_COMMISSION: 'partner_commission',\r\n CUSTOM: 'custom',\r\n} as const;\r\n\r\nexport type SplitType = typeof SPLIT_TYPE;\r\nexport type SplitTypeValue = SplitType[keyof SplitType];\r\nexport const SPLIT_TYPE_VALUES = Object.values(SPLIT_TYPE);\r\n\r\nexport const SPLIT_STATUS = {\r\n PENDING: 'pending',\r\n DUE: 'due',\r\n PAID: 'paid',\r\n WAIVED: 'waived',\r\n CANCELLED: 'cancelled',\r\n} as const;\r\n\r\nexport type SplitStatus = typeof SPLIT_STATUS;\r\nexport type SplitStatusValue = SplitStatus[keyof SplitStatus];\r\nexport const SPLIT_STATUS_VALUES = Object.values(SPLIT_STATUS);\r\n\r\nexport const PAYOUT_METHOD = {\r\n BANK_TRANSFER: 'bank_transfer',\r\n MOBILE_WALLET: 'mobile_wallet',\r\n PLATFORM_BALANCE: 'platform_balance',\r\n CRYPTO: 'crypto',\r\n CHECK: 'check',\r\n MANUAL: 'manual',\r\n} as const;\r\n\r\nexport type PayoutMethod = typeof PAYOUT_METHOD;\r\nexport type PayoutMethodValue = PayoutMethod[keyof PayoutMethod];\r\nexport const PAYOUT_METHOD_VALUES = Object.values(PAYOUT_METHOD);\r\n\r\n","/**\r\n * Commission Split Utilities\r\n * @classytic/revenue\r\n *\r\n * Multi-party commission split calculation for affiliate/referral systems\r\n */\r\n\r\nimport { SPLIT_TYPE, SPLIT_STATUS } from '../enums/split.enums.js';\r\nimport type {\r\n SplitRule,\r\n SplitInfo,\r\n CommissionInfo,\r\n CommissionWithSplitsOptions,\r\n} from '../types/index.js';\r\n\r\n/**\r\n * Calculate multi-party commission splits\r\n *\r\n * @param amount - Transaction amount\r\n * @param splitRules - Split configuration\r\n * @param gatewayFeeRate - Gateway fee rate (optional)\r\n * @returns Split objects\r\n *\r\n * @example\r\n * calculateSplits(1000, [\r\n * { type: 'platform_commission', recipientId: 'platform', recipientType: 'platform', rate: 0.10 },\r\n * { type: 'affiliate_commission', recipientId: 'affiliate-123', recipientType: 'user', rate: 0.02 },\r\n * ], 0.018);\r\n *\r\n * Returns:\r\n * [\r\n * { type: 'platform_commission', recipientId: 'platform', grossAmount: 100, gatewayFeeAmount: 18, netAmount: 82, ... },\r\n * { type: 'affiliate_commission', recipientId: 'affiliate-123', grossAmount: 20, gatewayFeeAmount: 0, netAmount: 20, ... },\r\n * ]\r\n */\r\nexport function calculateSplits(\r\n amount: number,\r\n splitRules: SplitRule[] = [],\r\n gatewayFeeRate: number = 0\r\n): SplitInfo[] {\r\n if (!splitRules || splitRules.length === 0) {\r\n return [];\r\n }\r\n\r\n if (amount < 0) {\r\n throw new Error('Transaction amount cannot be negative');\r\n }\r\n\r\n if (gatewayFeeRate < 0 || gatewayFeeRate > 1) {\r\n throw new Error('Gateway fee rate must be between 0 and 1');\r\n }\r\n\r\n const totalRate = splitRules.reduce((sum, rule) => sum + rule.rate, 0);\r\n if (totalRate > 1) {\r\n throw new Error(`Total split rate (${totalRate}) cannot exceed 1.0`);\r\n }\r\n\r\n return splitRules.map((rule, index) => {\r\n if (rule.rate < 0 || rule.rate > 1) {\r\n throw new Error(`Split rate must be between 0 and 1 for split ${index}`);\r\n }\r\n\r\n const grossAmount = Math.round(amount * rule.rate * 100) / 100;\r\n\r\n const gatewayFeeAmount = index === 0 && gatewayFeeRate > 0\r\n ? Math.round(amount * gatewayFeeRate * 100) / 100\r\n : 0;\r\n\r\n const netAmount = Math.max(0, Math.round((grossAmount - gatewayFeeAmount) * 100) / 100);\r\n\r\n return {\r\n type: rule.type ?? SPLIT_TYPE.CUSTOM,\r\n recipientId: rule.recipientId,\r\n recipientType: rule.recipientType,\r\n rate: rule.rate,\r\n grossAmount,\r\n gatewayFeeRate: gatewayFeeAmount > 0 ? gatewayFeeRate : 0,\r\n gatewayFeeAmount,\r\n netAmount,\r\n status: SPLIT_STATUS.PENDING,\r\n dueDate: rule.dueDate ?? null,\r\n metadata: rule.metadata ?? {},\r\n };\r\n });\r\n}\r\n\r\n/**\r\n * Calculate organization payout after splits\r\n *\r\n * @param amount - Total transaction amount\r\n * @param splits - Calculated splits\r\n * @returns Amount organization receives\r\n */\r\nexport function calculateOrganizationPayout(\r\n amount: number,\r\n splits: SplitInfo[] = []\r\n): number {\r\n const totalSplitAmount = splits.reduce((sum, split) => sum + split.grossAmount, 0);\r\n return Math.max(0, Math.round((amount - totalSplitAmount) * 100) / 100);\r\n}\r\n\r\n/**\r\n * Reverse splits proportionally on refund\r\n *\r\n * @param originalSplits - Original split objects\r\n * @param originalAmount - Original transaction amount\r\n * @param refundAmount - Amount being refunded\r\n * @returns Reversed splits\r\n */\r\nexport function reverseSplits(\r\n originalSplits: SplitInfo[] | undefined | null,\r\n originalAmount: number,\r\n refundAmount: number\r\n): SplitInfo[] {\r\n if (!originalSplits || originalSplits.length === 0) {\r\n return [];\r\n }\r\n\r\n const refundRatio = refundAmount / originalAmount;\r\n\r\n return originalSplits.map((split) => ({\r\n ...split,\r\n grossAmount: Math.round(split.grossAmount * refundRatio * 100) / 100,\r\n gatewayFeeAmount: Math.round(split.gatewayFeeAmount * refundRatio * 100) / 100,\r\n netAmount: Math.round(split.netAmount * refundRatio * 100) / 100,\r\n status: SPLIT_STATUS.WAIVED,\r\n }));\r\n}\r\n\r\n/**\r\n * Build commission object with splits support\r\n * Backward compatible with existing calculateCommission\r\n *\r\n * @param amount - Transaction amount\r\n * @param commissionRate - Platform commission rate\r\n * @param gatewayFeeRate - Gateway fee rate\r\n * @param options - Additional options\r\n * @returns Commission with optional splits\r\n */\r\nexport function calculateCommissionWithSplits(\r\n amount: number,\r\n commissionRate: number,\r\n gatewayFeeRate: number = 0,\r\n options: CommissionWithSplitsOptions = {}\r\n): CommissionInfo | null {\r\n const { affiliateRate = 0, affiliateId = null, affiliateType = 'user' } = options;\r\n\r\n if (commissionRate <= 0 && affiliateRate <= 0) {\r\n return null;\r\n }\r\n\r\n const splitRules: SplitRule[] = [];\r\n\r\n if (commissionRate > 0) {\r\n splitRules.push({\r\n type: SPLIT_TYPE.PLATFORM_COMMISSION,\r\n recipientId: 'platform',\r\n recipientType: 'platform',\r\n rate: commissionRate,\r\n });\r\n }\r\n\r\n if (affiliateRate > 0 && affiliateId) {\r\n splitRules.push({\r\n type: SPLIT_TYPE.AFFILIATE_COMMISSION,\r\n recipientId: affiliateId,\r\n recipientType: affiliateType,\r\n rate: affiliateRate,\r\n });\r\n }\r\n\r\n const splits = calculateSplits(amount, splitRules, gatewayFeeRate);\r\n\r\n const platformSplit = splits.find((s) => s.type === SPLIT_TYPE.PLATFORM_COMMISSION);\r\n const affiliateSplit = splits.find((s) => s.type === SPLIT_TYPE.AFFILIATE_COMMISSION);\r\n\r\n return {\r\n rate: commissionRate,\r\n grossAmount: platformSplit?.grossAmount ?? 0,\r\n gatewayFeeRate: platformSplit?.gatewayFeeRate ?? 0,\r\n gatewayFeeAmount: platformSplit?.gatewayFeeAmount ?? 0,\r\n netAmount: platformSplit?.netAmount ?? 0,\r\n status: 'pending',\r\n ...(splits.length > 0 && { splits }),\r\n ...(affiliateSplit && {\r\n affiliate: {\r\n recipientId: affiliateSplit.recipientId,\r\n recipientType: affiliateSplit.recipientType,\r\n rate: affiliateSplit.rate,\r\n grossAmount: affiliateSplit.grossAmount,\r\n netAmount: affiliateSplit.netAmount,\r\n },\r\n }),\r\n };\r\n}\r\n\r\nexport default {\r\n calculateSplits,\r\n calculateOrganizationPayout,\r\n reverseSplits,\r\n calculateCommissionWithSplits,\r\n};\r\n\r\n","/**\r\n * Escrow Service\r\n * @classytic/revenue\r\n *\r\n * Platform-as-intermediary payment flow\r\n * Hold funds → Verify → Split/Deduct → Release to organization\r\n */\r\n\r\nimport { TransactionNotFoundError } from '../core/errors.js';\r\nimport { HOLD_STATUS, RELEASE_REASON, HOLD_REASON } from '../enums/escrow.enums.js';\r\nimport { TRANSACTION_TYPE, TRANSACTION_STATUS } from '../enums/transaction.enums.js';\r\nimport { SPLIT_STATUS } from '../enums/split.enums.js';\r\nimport { triggerHook } from '../utils/hooks.js';\r\nimport { calculateSplits, calculateOrganizationPayout } from '../utils/commission-split.js';\r\nimport type { Container } from '../core/container.js';\r\nimport type {\r\n ModelsRegistry,\r\n HooksRegistry,\r\n Logger,\r\n TransactionDocument,\r\n HoldOptions,\r\n ReleaseOptions,\r\n ReleaseResult,\r\n CancelHoldOptions,\r\n SplitResult,\r\n EscrowStatusResult,\r\n SplitRule,\r\n SplitInfo,\r\n} from '../types/index.js';\r\n\r\nexport class EscrowService {\r\n private readonly models: ModelsRegistry;\r\n private readonly hooks: HooksRegistry;\r\n private readonly logger: Logger;\r\n\r\n constructor(container: Container) {\r\n this.models = container.get<ModelsRegistry>('models');\r\n this.hooks = container.get<HooksRegistry>('hooks');\r\n this.logger = container.get<Logger>('logger');\r\n }\r\n\r\n /**\r\n * Hold funds in escrow\r\n *\r\n * @param transactionId - Transaction to hold\r\n * @param options - Hold options\r\n * @returns Updated transaction\r\n */\r\n async hold(\r\n transactionId: string,\r\n options: HoldOptions = {}\r\n ): Promise<TransactionDocument> {\r\n const {\r\n reason = HOLD_REASON.PAYMENT_VERIFICATION,\r\n holdUntil = null,\r\n metadata = {},\r\n } = options;\r\n\r\n const TransactionModel = this.models.Transaction;\r\n const transaction = await TransactionModel.findById(transactionId) as TransactionDocument | null;\r\n\r\n if (!transaction) {\r\n throw new TransactionNotFoundError(transactionId);\r\n }\r\n\r\n if (transaction.status !== TRANSACTION_STATUS.VERIFIED) {\r\n throw new Error(`Cannot hold transaction with status: ${transaction.status}. Must be verified.`);\r\n }\r\n\r\n transaction.hold = {\r\n status: HOLD_STATUS.HELD,\r\n heldAmount: transaction.amount,\r\n releasedAmount: 0,\r\n reason,\r\n heldAt: new Date(),\r\n ...(holdUntil && { holdUntil }),\r\n releases: [],\r\n metadata,\r\n };\r\n\r\n await transaction.save();\r\n\r\n this._triggerHook('escrow.held', {\r\n transaction,\r\n heldAmount: transaction.amount,\r\n reason,\r\n });\r\n\r\n return transaction;\r\n }\r\n\r\n /**\r\n * Release funds from escrow to recipient\r\n *\r\n * @param transactionId - Transaction to release\r\n * @param options - Release options\r\n * @returns { transaction, releaseTransaction }\r\n */\r\n async release(\r\n transactionId: string,\r\n options: ReleaseOptions\r\n ): Promise<ReleaseResult> {\r\n const {\r\n amount = null,\r\n recipientId,\r\n recipientType = 'organization',\r\n reason = RELEASE_REASON.PAYMENT_VERIFIED,\r\n releasedBy = null,\r\n createTransaction = true,\r\n metadata = {},\r\n } = options;\r\n\r\n const TransactionModel = this.models.Transaction;\r\n const transaction = await TransactionModel.findById(transactionId) as TransactionDocument | null;\r\n\r\n if (!transaction) {\r\n throw new TransactionNotFoundError(transactionId);\r\n }\r\n\r\n if (!transaction.hold || transaction.hold.status !== HOLD_STATUS.HELD) {\r\n throw new Error(`Transaction is not in held status. Current: ${transaction.hold?.status ?? 'none'}`);\r\n }\r\n\r\n if (!recipientId) {\r\n throw new Error('recipientId is required for release');\r\n }\r\n\r\n const releaseAmount = amount ?? (transaction.hold.heldAmount - transaction.hold.releasedAmount);\r\n const availableAmount = transaction.hold.heldAmount - transaction.hold.releasedAmount;\r\n\r\n if (releaseAmount > availableAmount) {\r\n throw new Error(`Release amount (${releaseAmount}) exceeds available held amount (${availableAmount})`);\r\n }\r\n\r\n const releaseRecord = {\r\n amount: releaseAmount,\r\n recipientId,\r\n recipientType,\r\n releasedAt: new Date(),\r\n releasedBy,\r\n reason,\r\n metadata,\r\n };\r\n\r\n transaction.hold.releases.push(releaseRecord);\r\n transaction.hold.releasedAmount += releaseAmount;\r\n\r\n const isFullRelease = transaction.hold.releasedAmount >= transaction.hold.heldAmount;\r\n const isPartialRelease = transaction.hold.releasedAmount > 0 && transaction.hold.releasedAmount < transaction.hold.heldAmount;\r\n\r\n if (isFullRelease) {\r\n transaction.hold.status = HOLD_STATUS.RELEASED;\r\n transaction.hold.releasedAt = new Date();\r\n transaction.status = TRANSACTION_STATUS.COMPLETED;\r\n } else if (isPartialRelease) {\r\n transaction.hold.status = HOLD_STATUS.PARTIALLY_RELEASED;\r\n }\r\n\r\n await transaction.save();\r\n\r\n let releaseTransaction: TransactionDocument | null = null;\r\n if (createTransaction) {\r\n releaseTransaction = await TransactionModel.create({\r\n organizationId: transaction.organizationId,\r\n customerId: recipientId,\r\n amount: releaseAmount,\r\n currency: transaction.currency,\r\n category: transaction.category,\r\n type: TRANSACTION_TYPE.INCOME,\r\n method: transaction.method,\r\n status: TRANSACTION_STATUS.COMPLETED,\r\n gateway: transaction.gateway,\r\n referenceId: transaction.referenceId,\r\n referenceModel: transaction.referenceModel,\r\n metadata: {\r\n ...metadata,\r\n isRelease: true,\r\n heldTransactionId: transaction._id.toString(),\r\n releaseReason: reason,\r\n recipientType,\r\n },\r\n idempotencyKey: `release_${transaction._id}_${Date.now()}`,\r\n }) as TransactionDocument;\r\n }\r\n\r\n this._triggerHook('escrow.released', {\r\n transaction,\r\n releaseTransaction,\r\n releaseAmount,\r\n recipientId,\r\n recipientType,\r\n reason,\r\n isFullRelease,\r\n isPartialRelease,\r\n });\r\n\r\n return {\r\n transaction,\r\n releaseTransaction,\r\n releaseAmount,\r\n isFullRelease,\r\n isPartialRelease,\r\n };\r\n }\r\n\r\n /**\r\n * Cancel hold and release back to customer\r\n *\r\n * @param transactionId - Transaction to cancel hold\r\n * @param options - Cancel options\r\n * @returns Updated transaction\r\n */\r\n async cancel(\r\n transactionId: string,\r\n options: CancelHoldOptions = {}\r\n ): Promise<TransactionDocument> {\r\n const { reason = 'Hold cancelled', metadata = {} } = options;\r\n\r\n const TransactionModel = this.models.Transaction;\r\n const transaction = await TransactionModel.findById(transactionId) as TransactionDocument | null;\r\n\r\n if (!transaction) {\r\n throw new TransactionNotFoundError(transactionId);\r\n }\r\n\r\n if (!transaction.hold || transaction.hold.status !== HOLD_STATUS.HELD) {\r\n throw new Error(`Transaction is not in held status. Current: ${transaction.hold?.status ?? 'none'}`);\r\n }\r\n\r\n transaction.hold.status = HOLD_STATUS.CANCELLED;\r\n transaction.hold.cancelledAt = new Date();\r\n transaction.hold.metadata = {\r\n ...transaction.hold.metadata,\r\n ...metadata,\r\n cancelReason: reason,\r\n };\r\n\r\n transaction.status = TRANSACTION_STATUS.CANCELLED;\r\n\r\n await transaction.save();\r\n\r\n this._triggerHook('escrow.cancelled', {\r\n transaction,\r\n reason,\r\n });\r\n\r\n return transaction;\r\n }\r\n\r\n /**\r\n * Split payment to multiple recipients\r\n * Deducts splits from held amount and releases remainder to organization\r\n *\r\n * @param transactionId - Transaction to split\r\n * @param splitRules - Split configuration\r\n * @returns { transaction, splitTransactions, organizationTransaction }\r\n */\r\n async split(\r\n transactionId: string,\r\n splitRules: SplitRule[] = []\r\n ): Promise<SplitResult> {\r\n const TransactionModel = this.models.Transaction;\r\n const transaction = await TransactionModel.findById(transactionId) as TransactionDocument | null;\r\n\r\n if (!transaction) {\r\n throw new TransactionNotFoundError(transactionId);\r\n }\r\n\r\n if (!transaction.hold || transaction.hold.status !== HOLD_STATUS.HELD) {\r\n throw new Error(`Transaction must be held before splitting. Current: ${transaction.hold?.status ?? 'none'}`);\r\n }\r\n\r\n if (!splitRules || splitRules.length === 0) {\r\n throw new Error('splitRules cannot be empty');\r\n }\r\n\r\n const splits = calculateSplits(\r\n transaction.amount,\r\n splitRules,\r\n transaction.commission?.gatewayFeeRate ?? 0\r\n );\r\n\r\n transaction.splits = splits;\r\n await transaction.save();\r\n\r\n const splitTransactions: TransactionDocument[] = [];\r\n\r\n for (const split of splits) {\r\n const splitTransaction = await TransactionModel.create({\r\n organizationId: transaction.organizationId,\r\n customerId: split.recipientId,\r\n amount: split.netAmount,\r\n currency: transaction.currency,\r\n category: split.type,\r\n type: TRANSACTION_TYPE.EXPENSE,\r\n method: transaction.method,\r\n status: TRANSACTION_STATUS.COMPLETED,\r\n gateway: transaction.gateway,\r\n referenceId: transaction.referenceId,\r\n referenceModel: transaction.referenceModel,\r\n metadata: {\r\n isSplit: true,\r\n splitType: split.type,\r\n recipientType: split.recipientType,\r\n originalTransactionId: transaction._id.toString(),\r\n grossAmount: split.grossAmount,\r\n gatewayFeeAmount: split.gatewayFeeAmount,\r\n },\r\n idempotencyKey: `split_${transaction._id}_${split.recipientId}_${Date.now()}`,\r\n }) as TransactionDocument;\r\n\r\n (split as SplitInfo & { payoutTransactionId?: string }).payoutTransactionId = splitTransaction._id.toString();\r\n split.status = SPLIT_STATUS.PAID;\r\n (split as SplitInfo & { paidDate?: Date }).paidDate = new Date();\r\n\r\n splitTransactions.push(splitTransaction);\r\n }\r\n\r\n await transaction.save();\r\n\r\n const organizationPayout = calculateOrganizationPayout(transaction.amount, splits);\r\n\r\n const organizationTransaction = await this.release(transactionId, {\r\n amount: organizationPayout,\r\n recipientId: transaction.organizationId?.toString() ?? '',\r\n recipientType: 'organization',\r\n reason: RELEASE_REASON.PAYMENT_VERIFIED,\r\n createTransaction: true,\r\n metadata: {\r\n afterSplits: true,\r\n totalSplits: splits.length,\r\n totalSplitAmount: transaction.amount - organizationPayout,\r\n },\r\n });\r\n\r\n this._triggerHook('escrow.split', {\r\n transaction,\r\n splits,\r\n splitTransactions,\r\n organizationTransaction: organizationTransaction.releaseTransaction,\r\n organizationPayout,\r\n });\r\n\r\n return {\r\n transaction,\r\n splits,\r\n splitTransactions,\r\n organizationTransaction: organizationTransaction.releaseTransaction,\r\n organizationPayout,\r\n };\r\n }\r\n\r\n /**\r\n * Get escrow status\r\n *\r\n * @param transactionId - Transaction ID\r\n * @returns Escrow status\r\n */\r\n async getStatus(transactionId: string): Promise<EscrowStatusResult> {\r\n const TransactionModel = this.models.Transaction;\r\n const transaction = await TransactionModel.findById(transactionId) as TransactionDocument | null;\r\n\r\n if (!transaction) {\r\n throw new TransactionNotFoundError(transactionId);\r\n }\r\n\r\n return {\r\n transaction,\r\n hold: transaction.hold ?? null,\r\n splits: transaction.splits ?? [],\r\n hasHold: !!transaction.hold,\r\n hasSplits: transaction.splits ? transaction.splits.length > 0 : false,\r\n };\r\n }\r\n\r\n private _triggerHook(event: string, data: unknown): void {\r\n triggerHook(this.hooks, event, data, this.logger);\r\n }\r\n}\r\n\r\nexport default EscrowService;\r\n\r\n"]}
|
|
1
|
+
{"version":3,"sources":["../../src/core/errors.ts","../../src/utils/hooks.ts","../../src/enums/transaction.enums.ts","../../src/utils/category-resolver.ts","../../src/utils/commission.ts","../../src/enums/monetization.enums.ts","../../src/services/monetization.service.ts","../../src/services/payment.service.ts","../../src/services/transaction.service.ts","../../src/enums/escrow.enums.ts","../../src/enums/split.enums.ts","../../src/utils/commission-split.ts","../../src/services/escrow.service.ts"],"names":[],"mappings":"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","file":"index.js","sourcesContent":["/**\n * Revenue Error Classes\n * @classytic/revenue\n *\n * Typed errors with codes for better error handling\n */\n\nexport interface RevenueErrorOptions {\n retryable?: boolean;\n metadata?: Record<string, unknown>;\n}\n\n/**\n * Base Revenue Error\n */\nexport class RevenueError extends Error {\n public readonly code: string;\n public readonly retryable: boolean;\n public readonly metadata: Record<string, unknown>;\n\n constructor(\n message: string,\n code: string,\n options: RevenueErrorOptions = {}\n ) {\n super(message);\n this.name = this.constructor.name;\n this.code = code;\n this.retryable = options.retryable ?? false;\n this.metadata = options.metadata ?? {};\n Error.captureStackTrace(this, this.constructor);\n }\n\n toJSON(): Record<string, unknown> {\n return {\n name: this.name,\n message: this.message,\n code: this.code,\n retryable: this.retryable,\n metadata: this.metadata,\n };\n }\n}\n\n/**\n * Configuration Errors\n */\nexport class ConfigurationError extends RevenueError {\n constructor(message: string, metadata: Record<string, unknown> = {}) {\n super(message, 'CONFIGURATION_ERROR', { retryable: false, metadata });\n }\n}\n\nexport class ModelNotRegisteredError extends ConfigurationError {\n constructor(modelName: string) {\n super(\n `Model \"${modelName}\" is not registered. Register it via createRevenue({ models: { ${modelName}: ... } })`,\n { modelName }\n );\n }\n}\n\n/**\n * Provider Errors\n */\nexport class ProviderError extends RevenueError {\n constructor(\n message: string,\n code: string,\n options: RevenueErrorOptions = {}\n ) {\n super(message, code, options);\n }\n}\n\nexport class ProviderNotFoundError extends ProviderError {\n constructor(providerName: string, availableProviders: string[] = []) {\n super(\n `Payment provider \"${providerName}\" not found. Available: ${availableProviders.join(', ')}`,\n 'PROVIDER_NOT_FOUND',\n { retryable: false, metadata: { providerName, availableProviders } }\n );\n }\n}\n\nexport class ProviderCapabilityError extends ProviderError {\n constructor(providerName: string, capability: string) {\n super(\n `Provider \"${providerName}\" does not support ${capability}`,\n 'PROVIDER_CAPABILITY_NOT_SUPPORTED',\n { retryable: false, metadata: { providerName, capability } }\n );\n }\n}\n\nexport class PaymentIntentCreationError extends ProviderError {\n constructor(providerName: string, originalError: Error) {\n super(\n `Failed to create payment intent with provider \"${providerName}\": ${originalError.message}`,\n 'PAYMENT_INTENT_CREATION_FAILED',\n { retryable: true, metadata: { providerName, originalError: originalError.message } }\n );\n }\n}\n\nexport class PaymentVerificationError extends ProviderError {\n constructor(paymentIntentId: string, reason: string) {\n super(\n `Payment verification failed for intent \"${paymentIntentId}\": ${reason}`,\n 'PAYMENT_VERIFICATION_FAILED',\n { retryable: true, metadata: { paymentIntentId, reason } }\n );\n }\n}\n\n/**\n * Resource Not Found Errors\n */\nexport class NotFoundError extends RevenueError {\n constructor(\n message: string,\n code: string,\n metadata: Record<string, unknown> = {}\n ) {\n super(message, code, { retryable: false, metadata });\n }\n}\n\nexport class SubscriptionNotFoundError extends NotFoundError {\n constructor(subscriptionId: string) {\n super(\n `Subscription not found: ${subscriptionId}`,\n 'SUBSCRIPTION_NOT_FOUND',\n { subscriptionId }\n );\n }\n}\n\nexport class TransactionNotFoundError extends NotFoundError {\n constructor(transactionId: string) {\n super(\n `Transaction not found: ${transactionId}`,\n 'TRANSACTION_NOT_FOUND',\n { transactionId }\n );\n }\n}\n\n/**\n * Validation Errors\n */\nexport class ValidationError extends RevenueError {\n constructor(message: string, metadata: Record<string, unknown> = {}) {\n super(message, 'VALIDATION_ERROR', { retryable: false, metadata });\n }\n}\n\nexport class InvalidAmountError extends ValidationError {\n constructor(amount: number, message?: string) {\n super(\n message ?? `Invalid amount: ${amount}. Amount must be non-negative`,\n { amount }\n );\n }\n}\n\nexport class MissingRequiredFieldError extends ValidationError {\n constructor(fieldName: string) {\n super(`Missing required field: ${fieldName}`, { fieldName });\n }\n}\n\n/**\n * State Errors\n */\nexport class StateError extends RevenueError {\n constructor(\n message: string,\n code: string,\n metadata: Record<string, unknown> = {}\n ) {\n super(message, code, { retryable: false, metadata });\n }\n}\n\nexport class AlreadyVerifiedError extends StateError {\n constructor(transactionId: string) {\n super(\n `Transaction ${transactionId} is already verified`,\n 'ALREADY_VERIFIED',\n { transactionId }\n );\n }\n}\n\nexport class InvalidStateTransitionError extends StateError {\n constructor(\n resourceType: string,\n resourceId: string,\n fromState: string,\n toState: string\n ) {\n super(\n `Invalid state transition for ${resourceType} ${resourceId}: ${fromState} → ${toState}`,\n 'INVALID_STATE_TRANSITION',\n { resourceType, resourceId, fromState, toState }\n );\n }\n}\n\nexport class SubscriptionNotActiveError extends StateError {\n constructor(subscriptionId: string, message?: string) {\n super(\n message ?? `Subscription ${subscriptionId} is not active`,\n 'SUBSCRIPTION_NOT_ACTIVE',\n { subscriptionId }\n );\n }\n}\n\n/**\n * Operation Errors\n */\nexport class OperationError extends RevenueError {\n constructor(\n message: string,\n code: string,\n options: RevenueErrorOptions = {}\n ) {\n super(message, code, options);\n }\n}\n\nexport class RefundNotSupportedError extends OperationError {\n constructor(providerName: string) {\n super(\n `Refunds are not supported by provider \"${providerName}\"`,\n 'REFUND_NOT_SUPPORTED',\n { retryable: false, metadata: { providerName } }\n );\n }\n}\n\nexport class RefundError extends OperationError {\n constructor(transactionId: string, reason: string) {\n super(\n `Refund failed for transaction ${transactionId}: ${reason}`,\n 'REFUND_FAILED',\n { retryable: true, metadata: { transactionId, reason } }\n );\n }\n}\n\n/**\n * Error Code Constants\n */\nexport const ERROR_CODES = {\n // Configuration\n CONFIGURATION_ERROR: 'CONFIGURATION_ERROR',\n MODEL_NOT_REGISTERED: 'MODEL_NOT_REGISTERED',\n\n // Provider\n PROVIDER_NOT_FOUND: 'PROVIDER_NOT_FOUND',\n PROVIDER_CAPABILITY_NOT_SUPPORTED: 'PROVIDER_CAPABILITY_NOT_SUPPORTED',\n PAYMENT_INTENT_CREATION_FAILED: 'PAYMENT_INTENT_CREATION_FAILED',\n PAYMENT_VERIFICATION_FAILED: 'PAYMENT_VERIFICATION_FAILED',\n\n // Not Found\n SUBSCRIPTION_NOT_FOUND: 'SUBSCRIPTION_NOT_FOUND',\n TRANSACTION_NOT_FOUND: 'TRANSACTION_NOT_FOUND',\n\n // Validation\n VALIDATION_ERROR: 'VALIDATION_ERROR',\n INVALID_AMOUNT: 'INVALID_AMOUNT',\n MISSING_REQUIRED_FIELD: 'MISSING_REQUIRED_FIELD',\n\n // State\n ALREADY_VERIFIED: 'ALREADY_VERIFIED',\n INVALID_STATE_TRANSITION: 'INVALID_STATE_TRANSITION',\n SUBSCRIPTION_NOT_ACTIVE: 'SUBSCRIPTION_NOT_ACTIVE',\n\n // Operations\n REFUND_NOT_SUPPORTED: 'REFUND_NOT_SUPPORTED',\n REFUND_FAILED: 'REFUND_FAILED',\n} as const;\n\nexport type ErrorCode = typeof ERROR_CODES[keyof typeof ERROR_CODES];\n\n/**\n * Check if error is retryable\n */\nexport function isRetryable(error: unknown): boolean {\n return error instanceof RevenueError && error.retryable;\n}\n\n/**\n * Check if error is from revenue package\n */\nexport function isRevenueError(error: unknown): error is RevenueError {\n return error instanceof RevenueError;\n}\n\n","/**\n * Hook Utilities\n * @classytic/revenue\n *\n * Fire-and-forget hook execution - never blocks main flow\n */\n\nimport type { Logger, HooksRegistry } from '../types/index.js';\n\n/**\n * Trigger hooks asynchronously without waiting\n * Errors are logged but never thrown\n *\n * @param hooks - Hooks object\n * @param event - Event name\n * @param data - Event data\n * @param logger - Logger instance\n */\nexport function triggerHook(\n hooks: HooksRegistry,\n event: string,\n data: unknown,\n logger: Logger\n): void {\n const handlers = hooks[event] ?? [];\n\n if (handlers.length === 0) {\n return; // No handlers, return immediately\n }\n\n // Fire-and-forget: Don't await, don't block\n Promise.all(\n handlers.map((handler) =>\n Promise.resolve(handler(data)).catch((error: Error) => {\n logger.error(`Hook \"${event}\" failed:`, {\n error: error.message,\n stack: error.stack,\n event,\n // Don't log full data (could be huge)\n dataKeys: Object.keys(data as object),\n });\n })\n )\n ).catch(() => {\n // Swallow any Promise.all errors (already logged individually)\n });\n\n // Return immediately - hooks run in background\n}\n\nexport default triggerHook;\n\n","/**\n * Transaction Enums\n * @classytic/revenue\n *\n * Library-managed transaction enums only.\n * Users should define their own categories and merge with these.\n */\n\n// ============ TRANSACTION TYPE ============\n/**\n * Transaction Type - Income vs Expense\n *\n * INCOME: Money coming in (payments, subscriptions, purchases)\n * EXPENSE: Money going out (refunds, payouts)\n *\n * Users can map these in their config via transactionTypeMapping\n */\nexport const TRANSACTION_TYPE = {\n INCOME: 'income',\n EXPENSE: 'expense',\n} as const;\n\nexport type TransactionType = typeof TRANSACTION_TYPE;\nexport type TransactionTypeValue = TransactionType[keyof TransactionType];\nexport const TRANSACTION_TYPE_VALUES = Object.values(TRANSACTION_TYPE);\n\n// ============ TRANSACTION STATUS ============\n/**\n * Transaction Status - Library-managed states\n */\nexport const TRANSACTION_STATUS = {\n PENDING: 'pending',\n PAYMENT_INITIATED: 'payment_initiated',\n PROCESSING: 'processing',\n REQUIRES_ACTION: 'requires_action',\n VERIFIED: 'verified',\n COMPLETED: 'completed',\n FAILED: 'failed',\n CANCELLED: 'cancelled',\n EXPIRED: 'expired',\n REFUNDED: 'refunded',\n PARTIALLY_REFUNDED: 'partially_refunded',\n} as const;\n\nexport type TransactionStatus = typeof TRANSACTION_STATUS;\nexport type TransactionStatusValue = TransactionStatus[keyof TransactionStatus];\nexport const TRANSACTION_STATUS_VALUES = Object.values(TRANSACTION_STATUS);\n\n// ============ LIBRARY CATEGORIES ============\n/**\n * Categories managed by this library\n *\n * SUBSCRIPTION: Recurring subscription payments\n * PURCHASE: One-time purchases\n *\n * Users should spread these into their own category enums:\n *\n * @example\n * import { LIBRARY_CATEGORIES } from '@classytic/revenue';\n *\n * export const MY_CATEGORIES = {\n * ...LIBRARY_CATEGORIES,\n * SALARY: 'salary',\n * RENT: 'rent',\n * EQUIPMENT: 'equipment',\n * } as const;\n */\nexport const LIBRARY_CATEGORIES = {\n SUBSCRIPTION: 'subscription',\n PURCHASE: 'purchase',\n} as const;\n\nexport type LibraryCategories = typeof LIBRARY_CATEGORIES;\nexport type LibraryCategoryValue = LibraryCategories[keyof LibraryCategories];\nexport const LIBRARY_CATEGORY_VALUES = Object.values(LIBRARY_CATEGORIES);\n\n","/**\n * Category Resolver Utility\n * @classytic/revenue\n *\n * Resolves transaction category based on referenceModel and categoryMappings\n */\n\nimport { LIBRARY_CATEGORIES } from '../enums/transaction.enums.js';\nimport type { MonetizationTypeValue } from '../types/index.js';\n\n/**\n * Resolve category for a transaction based on entity and monetizationType\n *\n * Resolution Logic:\n * 1. If categoryMappings[entity] exists → use it\n * 2. Otherwise → fall back to default library category\n *\n * @param entity - The logical entity/identifier (e.g., 'Order', 'PlatformSubscription', 'Membership')\n * NOTE: This is NOT a database model name - it's just a logical identifier\n * @param monetizationType - The monetization type ('subscription', 'purchase', 'free')\n * @param categoryMappings - User-defined category mappings from config\n * @returns Category name for the transaction\n *\n * @example\n * // With mapping defined\n * resolveCategory('Order', 'subscription', { Order: 'order_subscription' })\n * // Returns: 'order_subscription'\n *\n * @example\n * // Without mapping, falls back to library default\n * resolveCategory('Order', 'subscription', {})\n * // Returns: 'subscription'\n *\n * @example\n * // Different entities with different mappings\n * const mappings = {\n * Order: 'order_subscription',\n * PlatformSubscription: 'platform_subscription',\n * TenantUpgrade: 'tenant_upgrade',\n * Membership: 'gym_membership',\n * Enrollment: 'course_enrollment',\n * };\n * resolveCategory('PlatformSubscription', 'subscription', mappings)\n * // Returns: 'platform_subscription'\n */\nexport function resolveCategory(\n entity: string | null | undefined,\n monetizationType: MonetizationTypeValue,\n categoryMappings: Record<string, string> = {}\n): string {\n // If user has defined a custom mapping for this entity, use it\n if (entity && categoryMappings[entity]) {\n return categoryMappings[entity];\n }\n\n // Otherwise, fall back to library default based on monetization type\n switch (monetizationType) {\n case 'subscription':\n return LIBRARY_CATEGORIES.SUBSCRIPTION; // 'subscription'\n case 'purchase':\n return LIBRARY_CATEGORIES.PURCHASE; // 'purchase'\n default:\n return LIBRARY_CATEGORIES.SUBSCRIPTION; // Default to subscription\n }\n}\n\n/**\n * Validate that a category is defined in user's Transaction model enum\n * This is informational - actual validation happens at Mongoose schema level\n *\n * @param category - Category to validate\n * @param allowedCategories - List of allowed categories\n * @returns Whether category is valid\n */\nexport function isCategoryValid(\n category: string,\n allowedCategories: string[] = []\n): boolean {\n return allowedCategories.includes(category);\n}\n\nexport default resolveCategory;\n\n","/**\n * Commission Calculation Utility\n * @classytic/revenue\n *\n * Handles platform commission calculation with gateway fee deduction\n */\n\nimport type { CommissionInfo } from '../types/index.js';\n\n/**\n * Build commission object for transaction\n *\n * @param amount - Transaction amount\n * @param commissionRate - Commission rate (0 to 1, e.g., 0.10 for 10%)\n * @param gatewayFeeRate - Gateway fee rate (0 to 1, e.g., 0.018 for 1.8%)\n * @returns Commission object or null\n */\nexport function calculateCommission(\n amount: number,\n commissionRate: number,\n gatewayFeeRate: number = 0\n): CommissionInfo | null {\n // No commission if rate is 0 or negative\n if (!commissionRate || commissionRate <= 0) {\n return null;\n }\n\n // Validate inputs\n if (amount < 0) {\n throw new Error('Transaction amount cannot be negative');\n }\n\n if (commissionRate < 0 || commissionRate > 1) {\n throw new Error('Commission rate must be between 0 and 1');\n }\n\n if (gatewayFeeRate < 0 || gatewayFeeRate > 1) {\n throw new Error('Gateway fee rate must be between 0 and 1');\n }\n\n // Calculate commission\n const grossAmount = Math.round(amount * commissionRate * 100) / 100; // Round to 2 decimals\n const gatewayFeeAmount = Math.round(amount * gatewayFeeRate * 100) / 100;\n const netAmount = Math.max(0, Math.round((grossAmount - gatewayFeeAmount) * 100) / 100);\n\n return {\n rate: commissionRate,\n grossAmount,\n gatewayFeeRate,\n gatewayFeeAmount,\n netAmount,\n status: 'pending',\n };\n}\n\n/**\n * Reverse commission on refund (proportional)\n *\n * @param originalCommission - Original commission object\n * @param originalAmount - Original transaction amount\n * @param refundAmount - Amount being refunded\n * @returns Reversed commission or null\n */\nexport function reverseCommission(\n originalCommission: CommissionInfo | null | undefined,\n originalAmount: number,\n refundAmount: number\n): CommissionInfo | null {\n if (!originalCommission?.netAmount) {\n return null;\n }\n\n // Calculate proportional refund\n const refundRatio = refundAmount / originalAmount;\n const reversedNetAmount = Math.round(originalCommission.netAmount * refundRatio * 100) / 100;\n const reversedGrossAmount = Math.round(originalCommission.grossAmount * refundRatio * 100) / 100;\n const reversedGatewayFee = Math.round(originalCommission.gatewayFeeAmount * refundRatio * 100) / 100;\n\n return {\n rate: originalCommission.rate,\n grossAmount: reversedGrossAmount,\n gatewayFeeRate: originalCommission.gatewayFeeRate,\n gatewayFeeAmount: reversedGatewayFee,\n netAmount: reversedNetAmount,\n status: 'waived', // Commission waived due to refund\n };\n}\n\nexport default {\n calculateCommission,\n reverseCommission,\n};\n\n","/**\n * Monetization Enums\n * @classytic/revenue\n *\n * General monetization enums and constants\n */\n\n// ============ MONETIZATION TYPES ============\nexport const MONETIZATION_TYPES = {\n FREE: 'free',\n PURCHASE: 'purchase',\n SUBSCRIPTION: 'subscription',\n} as const;\n\nexport type MonetizationTypes = typeof MONETIZATION_TYPES;\nexport type MonetizationTypeValue = MonetizationTypes[keyof MonetizationTypes];\nexport const MONETIZATION_TYPE_VALUES = Object.values(MONETIZATION_TYPES);\n\n","/**\n * Monetization Service\n * @classytic/revenue\n *\n * Framework-agnostic monetization management service with DI\n * Handles purchases, subscriptions, and free items using provider system\n */\n\nimport { nanoid } from 'nanoid';\nimport {\n MissingRequiredFieldError,\n InvalidAmountError,\n ProviderNotFoundError,\n SubscriptionNotFoundError,\n ModelNotRegisteredError,\n SubscriptionNotActiveError,\n PaymentIntentCreationError,\n InvalidStateTransitionError,\n} from '../core/errors.js';\nimport { triggerHook } from '../utils/hooks.js';\nimport { resolveCategory } from '../utils/category-resolver.js';\nimport { calculateCommission } from '../utils/commission.js';\nimport { MONETIZATION_TYPES } from '../enums/monetization.enums.js';\nimport { TRANSACTION_TYPE } from '../enums/transaction.enums.js';\nimport type { Container } from '../core/container.js';\nimport type {\n ModelsRegistry,\n ProvidersRegistry,\n HooksRegistry,\n RevenueConfig,\n Logger,\n MonetizationCreateParams,\n MonetizationCreateResult,\n ActivateOptions,\n RenewalParams,\n CancelOptions,\n PauseOptions,\n ResumeOptions,\n ListOptions,\n SubscriptionDocument,\n TransactionDocument,\n PaymentIntentData,\n TransactionTypeValue,\n} from '../types/index.js';\n\n/**\n * Monetization Service\n * Uses DI container for all dependencies\n */\nexport class MonetizationService {\n private readonly models: ModelsRegistry;\n private readonly providers: ProvidersRegistry;\n private readonly config: RevenueConfig;\n private readonly hooks: HooksRegistry;\n private readonly logger: Logger;\n\n constructor(container: Container) {\n this.models = container.get<ModelsRegistry>('models');\n this.providers = container.get<ProvidersRegistry>('providers');\n this.config = container.get<RevenueConfig>('config');\n this.hooks = container.get<HooksRegistry>('hooks');\n this.logger = container.get<Logger>('logger');\n }\n\n /**\n * Create a new monetization (purchase, subscription, or free item)\n *\n * @param params - Monetization parameters\n *\n * @example\n * // One-time purchase\n * await revenue.monetization.create({\n * data: {\n * organizationId: '...',\n * customerId: '...',\n * referenceId: order._id,\n * referenceModel: 'Order',\n * },\n * planKey: 'one_time',\n * monetizationType: 'purchase',\n * gateway: 'bkash',\n * amount: 1500,\n * });\n *\n * // Recurring subscription\n * await revenue.monetization.create({\n * data: {\n * organizationId: '...',\n * customerId: '...',\n * referenceId: subscription._id,\n * referenceModel: 'Subscription',\n * },\n * planKey: 'monthly',\n * monetizationType: 'subscription',\n * gateway: 'stripe',\n * amount: 2000,\n * });\n *\n * @returns Result with subscription, transaction, and paymentIntent\n */\n async create(params: MonetizationCreateParams): Promise<MonetizationCreateResult> {\n const {\n data,\n planKey,\n amount,\n currency = 'BDT',\n gateway = 'manual',\n entity = null,\n monetizationType = MONETIZATION_TYPES.SUBSCRIPTION,\n paymentData,\n metadata = {},\n idempotencyKey = null,\n } = params;\n\n // Validate required fields\n // Note: organizationId is OPTIONAL (only needed for multi-tenant)\n\n if (!planKey) {\n throw new MissingRequiredFieldError('planKey');\n }\n\n if (amount < 0) {\n throw new InvalidAmountError(amount);\n }\n\n const isFree = amount === 0;\n\n // Get provider\n const provider = this.providers[gateway];\n if (!provider) {\n throw new ProviderNotFoundError(gateway, Object.keys(this.providers));\n }\n\n // Create payment intent if not free\n let paymentIntent: PaymentIntentData | null = null;\n let transaction: TransactionDocument | null = null;\n\n if (!isFree) {\n // Create payment intent via provider\n try {\n paymentIntent = await provider.createIntent({\n amount,\n currency,\n metadata: {\n ...metadata,\n type: 'subscription',\n planKey,\n },\n });\n } catch (error) {\n throw new PaymentIntentCreationError(gateway, error as Error);\n }\n\n // Resolve category based on entity and monetizationType\n const category = resolveCategory(entity, monetizationType, this.config.categoryMappings);\n\n // Resolve transaction type using config mapping or default to 'income'\n const transactionType: TransactionTypeValue = \n this.config.transactionTypeMapping?.subscription ??\n this.config.transactionTypeMapping?.[monetizationType] ??\n TRANSACTION_TYPE.INCOME;\n\n // Calculate commission if configured\n const commissionRate = this.config.commissionRates?.[category] ?? 0;\n const gatewayFeeRate = this.config.gatewayFeeRates?.[gateway] ?? 0;\n const commission = calculateCommission(amount, commissionRate, gatewayFeeRate);\n\n // Create transaction record\n const TransactionModel = this.models.Transaction;\n transaction = await TransactionModel.create({\n organizationId: data.organizationId,\n customerId: data.customerId ?? null,\n amount,\n currency,\n category,\n type: transactionType,\n method: ((paymentData as Record<string, unknown>)?.method as string) ?? 'manual',\n status: paymentIntent.status === 'succeeded' ? 'verified' : 'pending',\n gateway: {\n type: gateway,\n sessionId: paymentIntent.sessionId,\n paymentIntentId: paymentIntent.paymentIntentId,\n provider: paymentIntent.provider,\n metadata: paymentIntent.metadata,\n },\n paymentDetails: {\n provider: gateway,\n ...paymentData,\n },\n ...(commission && { commission }), // Only include if commission exists\n // Polymorphic reference (top-level, not metadata)\n ...(data.referenceId && { referenceId: data.referenceId }),\n ...(data.referenceModel && { referenceModel: data.referenceModel }),\n metadata: {\n ...metadata,\n planKey,\n entity,\n monetizationType,\n paymentIntentId: paymentIntent.id,\n },\n idempotencyKey: idempotencyKey ?? `sub_${nanoid(16)}`,\n }) as TransactionDocument;\n }\n\n // Create subscription record (if Subscription model exists)\n let subscription: SubscriptionDocument | null = null;\n if (this.models.Subscription) {\n const SubscriptionModel = this.models.Subscription;\n\n // Create subscription with proper reference tracking\n const subscriptionData = {\n organizationId: data.organizationId,\n customerId: data.customerId ?? null,\n planKey,\n amount,\n currency,\n status: isFree ? 'active' : 'pending',\n isActive: isFree,\n gateway,\n transactionId: transaction?._id ?? null,\n paymentIntentId: paymentIntent?.id ?? null,\n metadata: {\n ...metadata,\n isFree,\n entity,\n monetizationType,\n },\n ...data,\n } as Record<string, unknown>;\n\n // Remove referenceId/referenceModel from subscription (they're for transactions)\n delete subscriptionData.referenceId;\n delete subscriptionData.referenceModel;\n\n subscription = await SubscriptionModel.create(subscriptionData) as SubscriptionDocument;\n }\n\n // Trigger hooks - emit specific event based on monetization type\n const eventData = {\n subscription,\n transaction,\n paymentIntent,\n isFree,\n monetizationType,\n };\n\n // Emit specific monetization event\n if (monetizationType === MONETIZATION_TYPES.PURCHASE) {\n this._triggerHook('purchase.created', eventData);\n } else if (monetizationType === MONETIZATION_TYPES.SUBSCRIPTION) {\n this._triggerHook('subscription.created', eventData);\n } else if (monetizationType === MONETIZATION_TYPES.FREE) {\n this._triggerHook('free.created', eventData);\n }\n\n // Also emit generic event for backward compatibility\n this._triggerHook('monetization.created', eventData);\n\n return {\n subscription,\n transaction,\n paymentIntent,\n };\n }\n\n /**\n * Activate subscription after payment verification\n *\n * @param subscriptionId - Subscription ID or transaction ID\n * @param options - Activation options\n * @returns Updated subscription\n */\n async activate(\n subscriptionId: string,\n options: ActivateOptions = {}\n ): Promise<SubscriptionDocument> {\n const { timestamp = new Date() } = options;\n\n if (!this.models.Subscription) {\n throw new ModelNotRegisteredError('Subscription');\n }\n\n const SubscriptionModel = this.models.Subscription;\n const subscription = await SubscriptionModel.findById(subscriptionId) as SubscriptionDocument | null;\n\n if (!subscription) {\n throw new SubscriptionNotFoundError(subscriptionId);\n }\n\n if (subscription.isActive) {\n this.logger.warn('Subscription already active', { subscriptionId });\n return subscription;\n }\n\n // Calculate period dates based on plan\n const periodEnd = this._calculatePeriodEnd(subscription.planKey, timestamp);\n\n // Update subscription\n subscription.isActive = true;\n subscription.status = 'active';\n subscription.startDate = timestamp;\n subscription.endDate = periodEnd;\n subscription.activatedAt = timestamp;\n\n await subscription.save();\n\n // Trigger hook\n this._triggerHook('subscription.activated', {\n subscription,\n activatedAt: timestamp,\n });\n\n return subscription;\n }\n\n /**\n * Renew subscription\n *\n * @param subscriptionId - Subscription ID\n * @param params - Renewal parameters\n * @returns { subscription, transaction, paymentIntent }\n */\n async renew(\n subscriptionId: string,\n params: RenewalParams = {}\n ): Promise<MonetizationCreateResult> {\n const {\n gateway = 'manual',\n entity = null,\n paymentData,\n metadata = {},\n idempotencyKey = null,\n } = params;\n\n if (!this.models.Subscription) {\n throw new ModelNotRegisteredError('Subscription');\n }\n\n const SubscriptionModel = this.models.Subscription;\n const subscription = await SubscriptionModel.findById(subscriptionId) as SubscriptionDocument | null;\n\n if (!subscription) {\n throw new SubscriptionNotFoundError(subscriptionId);\n }\n\n if (subscription.amount === 0) {\n throw new InvalidAmountError(0, 'Free subscriptions do not require renewal');\n }\n\n // Get provider\n const provider = this.providers[gateway];\n if (!provider) {\n throw new ProviderNotFoundError(gateway, Object.keys(this.providers));\n }\n\n // Create payment intent\n let paymentIntent: PaymentIntentData | null = null;\n try {\n paymentIntent = await provider.createIntent({\n amount: subscription.amount,\n currency: subscription.currency ?? 'BDT',\n metadata: {\n ...metadata,\n type: 'subscription_renewal',\n subscriptionId: subscription._id.toString(),\n },\n });\n } catch (error) {\n this.logger.error('Failed to create payment intent for renewal:', error);\n throw new PaymentIntentCreationError(gateway, error as Error);\n }\n\n // Resolve category - use provided entity or inherit from subscription metadata\n const effectiveEntity = entity ?? (subscription.metadata as Record<string, unknown>)?.entity as string | null;\n const effectiveMonetizationType = \n ((subscription.metadata as Record<string, unknown>)?.monetizationType as string) ?? MONETIZATION_TYPES.SUBSCRIPTION;\n const category = resolveCategory(effectiveEntity, effectiveMonetizationType as 'subscription' | 'purchase' | 'free', this.config.categoryMappings);\n\n // Resolve transaction type using config mapping or default to 'income'\n const transactionType: TransactionTypeValue = \n this.config.transactionTypeMapping?.subscription_renewal ??\n this.config.transactionTypeMapping?.subscription ??\n this.config.transactionTypeMapping?.[effectiveMonetizationType] ??\n TRANSACTION_TYPE.INCOME;\n\n // Calculate commission if configured\n const commissionRate = this.config.commissionRates?.[category] ?? 0;\n const gatewayFeeRate = this.config.gatewayFeeRates?.[gateway] ?? 0;\n const commission = calculateCommission(subscription.amount, commissionRate, gatewayFeeRate);\n\n // Create transaction\n const TransactionModel = this.models.Transaction;\n const transaction = await TransactionModel.create({\n organizationId: subscription.organizationId,\n customerId: subscription.customerId,\n amount: subscription.amount,\n currency: subscription.currency ?? 'BDT',\n category,\n type: transactionType,\n method: ((paymentData as Record<string, unknown>)?.method as string) ?? 'manual',\n status: paymentIntent.status === 'succeeded' ? 'verified' : 'pending',\n gateway: {\n type: gateway,\n sessionId: paymentIntent.sessionId,\n paymentIntentId: paymentIntent.paymentIntentId,\n provider: paymentIntent.provider,\n metadata: paymentIntent.metadata,\n },\n paymentDetails: {\n provider: gateway,\n ...paymentData,\n },\n ...(commission && { commission }), // Only include if commission exists\n // Polymorphic reference to subscription\n referenceId: subscription._id,\n referenceModel: 'Subscription',\n metadata: {\n ...metadata,\n subscriptionId: subscription._id.toString(), // Keep for backward compat\n entity: effectiveEntity,\n monetizationType: effectiveMonetizationType,\n isRenewal: true,\n paymentIntentId: paymentIntent.id,\n },\n idempotencyKey: idempotencyKey ?? `renewal_${nanoid(16)}`,\n }) as TransactionDocument;\n\n // Update subscription\n subscription.status = 'pending_renewal' as SubscriptionDocument['status'];\n subscription.renewalTransactionId = transaction._id;\n subscription.renewalCount = (subscription.renewalCount ?? 0) + 1;\n await subscription.save();\n\n // Trigger hook\n this._triggerHook('subscription.renewed', {\n subscription,\n transaction,\n paymentIntent,\n renewalCount: subscription.renewalCount,\n });\n\n return {\n subscription,\n transaction,\n paymentIntent,\n };\n }\n\n /**\n * Cancel subscription\n *\n * @param subscriptionId - Subscription ID\n * @param options - Cancellation options\n * @returns Updated subscription\n */\n async cancel(\n subscriptionId: string,\n options: CancelOptions = {}\n ): Promise<SubscriptionDocument> {\n const { immediate = false, reason = null } = options;\n\n if (!this.models.Subscription) {\n throw new ModelNotRegisteredError('Subscription');\n }\n\n const SubscriptionModel = this.models.Subscription;\n const subscription = await SubscriptionModel.findById(subscriptionId) as SubscriptionDocument | null;\n\n if (!subscription) {\n throw new SubscriptionNotFoundError(subscriptionId);\n }\n\n const now = new Date();\n\n if (immediate) {\n subscription.isActive = false;\n subscription.status = 'cancelled';\n subscription.canceledAt = now;\n subscription.cancellationReason = reason;\n } else {\n // Schedule cancellation at period end\n subscription.cancelAt = subscription.endDate ?? now;\n subscription.cancellationReason = reason;\n }\n\n await subscription.save();\n\n // Trigger hook\n this._triggerHook('subscription.cancelled', {\n subscription,\n immediate,\n reason,\n canceledAt: immediate ? now : subscription.cancelAt,\n });\n\n return subscription;\n }\n\n /**\n * Pause subscription\n *\n * @param subscriptionId - Subscription ID\n * @param options - Pause options\n * @returns Updated subscription\n */\n async pause(\n subscriptionId: string,\n options: PauseOptions = {}\n ): Promise<SubscriptionDocument> {\n const { reason = null } = options;\n\n if (!this.models.Subscription) {\n throw new ModelNotRegisteredError('Subscription');\n }\n\n const SubscriptionModel = this.models.Subscription;\n const subscription = await SubscriptionModel.findById(subscriptionId) as SubscriptionDocument | null;\n\n if (!subscription) {\n throw new SubscriptionNotFoundError(subscriptionId);\n }\n\n if (!subscription.isActive) {\n throw new SubscriptionNotActiveError(subscriptionId, 'Only active subscriptions can be paused');\n }\n\n const pausedAt = new Date();\n subscription.isActive = false;\n subscription.status = 'paused';\n subscription.pausedAt = pausedAt;\n subscription.pauseReason = reason;\n\n await subscription.save();\n\n // Trigger hook\n this._triggerHook('subscription.paused', {\n subscription,\n reason,\n pausedAt,\n });\n\n return subscription;\n }\n\n /**\n * Resume subscription\n *\n * @param subscriptionId - Subscription ID\n * @param options - Resume options\n * @returns Updated subscription\n */\n async resume(\n subscriptionId: string,\n options: ResumeOptions = {}\n ): Promise<SubscriptionDocument> {\n const { extendPeriod = false } = options;\n\n if (!this.models.Subscription) {\n throw new ModelNotRegisteredError('Subscription');\n }\n\n const SubscriptionModel = this.models.Subscription;\n const subscription = await SubscriptionModel.findById(subscriptionId) as SubscriptionDocument | null;\n\n if (!subscription) {\n throw new SubscriptionNotFoundError(subscriptionId);\n }\n\n if (!subscription.pausedAt) {\n throw new InvalidStateTransitionError(\n 'resume',\n 'paused',\n subscription.status,\n 'Only paused subscriptions can be resumed'\n );\n }\n\n const now = new Date();\n const pausedAt = new Date(subscription.pausedAt);\n const pauseDuration = now.getTime() - pausedAt.getTime();\n\n subscription.isActive = true;\n subscription.status = 'active';\n subscription.pausedAt = null;\n subscription.pauseReason = null;\n\n // Optionally extend period by pause duration\n if (extendPeriod && subscription.endDate) {\n const currentEnd = new Date(subscription.endDate);\n subscription.endDate = new Date(currentEnd.getTime() + pauseDuration);\n }\n\n await subscription.save();\n\n // Trigger hook\n this._triggerHook('subscription.resumed', {\n subscription,\n extendPeriod,\n pauseDuration,\n resumedAt: now,\n });\n\n return subscription;\n }\n\n /**\n * List subscriptions with filters\n *\n * @param filters - Query filters\n * @param options - Query options (limit, skip, sort)\n * @returns Subscriptions\n */\n async list(\n filters: Record<string, unknown> = {},\n options: ListOptions = {}\n ): Promise<SubscriptionDocument[]> {\n if (!this.models.Subscription) {\n throw new ModelNotRegisteredError('Subscription');\n }\n\n const SubscriptionModel = this.models.Subscription;\n const { limit = 50, skip = 0, sort = { createdAt: -1 } } = options;\n\n const subscriptions = await (SubscriptionModel as unknown as {\n find(filter: object): { limit(n: number): { skip(n: number): { sort(s: object): Promise<SubscriptionDocument[]> } } };\n })\n .find(filters)\n .limit(limit)\n .skip(skip)\n .sort(sort);\n\n return subscriptions;\n }\n\n /**\n * Get subscription by ID\n *\n * @param subscriptionId - Subscription ID\n * @returns Subscription\n */\n async get(subscriptionId: string): Promise<SubscriptionDocument> {\n if (!this.models.Subscription) {\n throw new ModelNotRegisteredError('Subscription');\n }\n\n const SubscriptionModel = this.models.Subscription;\n const subscription = await SubscriptionModel.findById(subscriptionId) as SubscriptionDocument | null;\n\n if (!subscription) {\n throw new SubscriptionNotFoundError(subscriptionId);\n }\n\n return subscription;\n }\n\n /**\n * Calculate period end date based on plan key\n * @private\n */\n private _calculatePeriodEnd(planKey: string, startDate: Date = new Date()): Date {\n const start = new Date(startDate);\n const end = new Date(start);\n\n switch (planKey) {\n case 'monthly':\n end.setMonth(end.getMonth() + 1);\n break;\n case 'quarterly':\n end.setMonth(end.getMonth() + 3);\n break;\n case 'yearly':\n end.setFullYear(end.getFullYear() + 1);\n break;\n default:\n // Default to 30 days\n end.setDate(end.getDate() + 30);\n }\n\n return end;\n }\n\n /**\n * Trigger event hook (fire-and-forget, non-blocking)\n * @private\n */\n private _triggerHook(event: string, data: unknown): void {\n triggerHook(this.hooks, event, data, this.logger);\n }\n}\n\nexport default MonetizationService;\n\n","/**\n * Payment Service\n * @classytic/revenue\n *\n * Framework-agnostic payment verification and management service with DI\n * Handles payment verification, refunds, and status updates\n */\n\nimport {\n TransactionNotFoundError,\n ProviderNotFoundError,\n ProviderError,\n AlreadyVerifiedError,\n PaymentVerificationError,\n RefundNotSupportedError,\n RefundError,\n ProviderCapabilityError,\n ValidationError,\n} from '../core/errors.js';\nimport { triggerHook } from '../utils/hooks.js';\nimport { reverseCommission } from '../utils/commission.js';\nimport { TRANSACTION_TYPE } from '../enums/transaction.enums.js';\nimport type { Container } from '../core/container.js';\nimport type {\n ModelsRegistry,\n ProvidersRegistry,\n HooksRegistry,\n RevenueConfig,\n Logger,\n TransactionDocument,\n PaymentVerifyOptions,\n PaymentVerifyResult,\n PaymentStatusResult,\n RefundOptions,\n PaymentRefundResult,\n WebhookResult,\n ListOptions,\n PaymentResultData,\n PaymentProviderInterface,\n TransactionTypeValue,\n MongooseModel,\n} from '../types/index.js';\n\n/**\n * Payment Service\n * Uses DI container for all dependencies\n */\nexport class PaymentService {\n private readonly models: ModelsRegistry;\n private readonly providers: ProvidersRegistry;\n private readonly config: RevenueConfig;\n private readonly hooks: HooksRegistry;\n private readonly logger: Logger;\n\n constructor(container: Container) {\n this.models = container.get<ModelsRegistry>('models');\n this.providers = container.get<ProvidersRegistry>('providers');\n this.config = container.get<RevenueConfig>('config');\n this.hooks = container.get<HooksRegistry>('hooks');\n this.logger = container.get<Logger>('logger');\n }\n\n /**\n * Verify a payment\n *\n * @param paymentIntentId - Payment intent ID, session ID, or transaction ID\n * @param options - Verification options\n * @returns { transaction, status }\n */\n async verify(\n paymentIntentId: string,\n options: PaymentVerifyOptions = {}\n ): Promise<PaymentVerifyResult> {\n const { verifiedBy = null } = options;\n\n const TransactionModel = this.models.Transaction;\n const transaction = await this._findTransaction(TransactionModel, paymentIntentId);\n\n if (!transaction) {\n throw new TransactionNotFoundError(paymentIntentId);\n }\n\n if (transaction.status === 'verified' || transaction.status === 'completed') {\n throw new AlreadyVerifiedError(transaction._id.toString());\n }\n\n // Get provider for verification\n const gatewayType = transaction.gateway?.type ?? 'manual';\n const provider = this.providers[gatewayType];\n\n if (!provider) {\n throw new ProviderNotFoundError(gatewayType, Object.keys(this.providers));\n }\n\n // Verify payment with provider\n let paymentResult: PaymentResultData | null = null;\n try {\n paymentResult = await provider.verifyPayment(paymentIntentId);\n } catch (error) {\n this.logger.error('Payment verification failed:', error);\n\n // Update transaction as failed\n transaction.status = 'failed';\n transaction.failureReason = (error as Error).message;\n transaction.metadata = {\n ...transaction.metadata,\n verificationError: (error as Error).message,\n failedAt: new Date().toISOString(),\n };\n await transaction.save();\n\n // Trigger payment.failed hook\n this._triggerHook('payment.failed', {\n transaction,\n error: (error as Error).message,\n provider: gatewayType,\n paymentIntentId,\n });\n\n throw new PaymentVerificationError(paymentIntentId, (error as Error).message);\n }\n\n // Validate amount and currency match\n if (paymentResult.amount && paymentResult.amount !== transaction.amount) {\n throw new ValidationError(\n `Amount mismatch: expected ${transaction.amount}, got ${paymentResult.amount}`,\n { expected: transaction.amount, actual: paymentResult.amount }\n );\n }\n\n if (paymentResult.currency && paymentResult.currency.toUpperCase() !== transaction.currency.toUpperCase()) {\n throw new ValidationError(\n `Currency mismatch: expected ${transaction.currency}, got ${paymentResult.currency}`,\n { expected: transaction.currency, actual: paymentResult.currency }\n );\n }\n\n // Update transaction based on verification result\n transaction.status = paymentResult.status === 'succeeded' ? 'verified' : paymentResult.status;\n transaction.verifiedAt = paymentResult.paidAt ?? new Date();\n transaction.verifiedBy = verifiedBy;\n transaction.gateway = {\n ...transaction.gateway,\n type: transaction.gateway?.type ?? 'manual',\n verificationData: paymentResult.metadata,\n };\n\n await transaction.save();\n\n // Trigger hook\n this._triggerHook('payment.verified', {\n transaction,\n paymentResult,\n verifiedBy,\n });\n\n return {\n transaction,\n paymentResult,\n status: transaction.status,\n };\n }\n\n /**\n * Get payment status\n *\n * @param paymentIntentId - Payment intent ID, session ID, or transaction ID\n * @returns { transaction, status }\n */\n async getStatus(paymentIntentId: string): Promise<PaymentStatusResult> {\n const TransactionModel = this.models.Transaction;\n const transaction = await this._findTransaction(TransactionModel, paymentIntentId);\n\n if (!transaction) {\n throw new TransactionNotFoundError(paymentIntentId);\n }\n\n // Get provider\n const gatewayType = transaction.gateway?.type ?? 'manual';\n const provider = this.providers[gatewayType];\n\n if (!provider) {\n throw new ProviderNotFoundError(gatewayType, Object.keys(this.providers));\n }\n\n // Get status from provider\n let paymentResult: PaymentResultData | null = null;\n try {\n paymentResult = await provider.getStatus(paymentIntentId);\n } catch (error) {\n this.logger.warn('Failed to get payment status from provider:', error);\n // Return transaction status as fallback\n return {\n transaction,\n status: transaction.status,\n provider: gatewayType,\n };\n }\n\n return {\n transaction,\n paymentResult,\n status: paymentResult.status,\n provider: gatewayType,\n };\n }\n\n /**\n * Refund a payment\n *\n * @param paymentId - Payment intent ID, session ID, or transaction ID\n * @param amount - Amount to refund (optional, full refund if not provided)\n * @param options - Refund options\n * @returns { transaction, refundResult }\n */\n async refund(\n paymentId: string,\n amount: number | null = null,\n options: RefundOptions = {}\n ): Promise<PaymentRefundResult> {\n const { reason = null } = options;\n\n const TransactionModel = this.models.Transaction;\n const transaction = await this._findTransaction(TransactionModel, paymentId);\n\n if (!transaction) {\n throw new TransactionNotFoundError(paymentId);\n }\n\n if (transaction.status !== 'verified' && transaction.status !== 'completed') {\n throw new RefundError(transaction._id.toString(), 'Only verified/completed transactions can be refunded');\n }\n\n // Get provider\n const gatewayType = transaction.gateway?.type ?? 'manual';\n const provider = this.providers[gatewayType];\n\n if (!provider) {\n throw new ProviderNotFoundError(gatewayType, Object.keys(this.providers));\n }\n\n // Check if provider supports refunds\n const capabilities = provider.getCapabilities();\n if (!capabilities.supportsRefunds) {\n throw new RefundNotSupportedError(gatewayType);\n }\n\n // Calculate refundable amount\n const refundedSoFar = transaction.refundedAmount ?? 0;\n const refundableAmount = transaction.amount - refundedSoFar;\n const refundAmount = amount ?? refundableAmount;\n\n // Validate refund amount\n if (refundAmount <= 0) {\n throw new ValidationError(`Refund amount must be positive, got ${refundAmount}`);\n }\n\n if (refundAmount > refundableAmount) {\n throw new ValidationError(\n `Refund amount (${refundAmount}) exceeds refundable balance (${refundableAmount})`,\n { refundAmount, refundableAmount, alreadyRefunded: refundedSoFar }\n );\n }\n\n // Refund via provider\n let refundResult;\n\n try {\n refundResult = await provider.refund(paymentId, refundAmount, { reason: reason ?? undefined });\n } catch (error) {\n this.logger.error('Refund failed:', error);\n throw new RefundError(paymentId, (error as Error).message);\n }\n\n // Create separate refund transaction (EXPENSE) for proper accounting\n const refundTransactionType: TransactionTypeValue = \n this.config.transactionTypeMapping?.refund ?? TRANSACTION_TYPE.EXPENSE;\n\n // Reverse commission proportionally for refund\n const refundCommission = transaction.commission\n ? reverseCommission(transaction.commission, transaction.amount, refundAmount)\n : null;\n\n const refundTransaction = await TransactionModel.create({\n organizationId: transaction.organizationId,\n customerId: transaction.customerId,\n amount: refundAmount,\n currency: transaction.currency,\n category: transaction.category,\n type: refundTransactionType, // EXPENSE - money going out\n method: transaction.method ?? 'manual',\n status: 'completed',\n gateway: {\n type: transaction.gateway?.type ?? 'manual',\n paymentIntentId: refundResult.id,\n provider: refundResult.provider,\n },\n paymentDetails: transaction.paymentDetails,\n ...(refundCommission && { commission: refundCommission }), // Reversed commission\n // Polymorphic reference (copy from original transaction)\n ...(transaction.referenceId && { referenceId: transaction.referenceId }),\n ...(transaction.referenceModel && { referenceModel: transaction.referenceModel }),\n metadata: {\n ...transaction.metadata,\n isRefund: true,\n originalTransactionId: transaction._id.toString(),\n refundReason: reason,\n refundResult: refundResult.metadata,\n },\n idempotencyKey: `refund_${transaction._id}_${Date.now()}`,\n }) as TransactionDocument;\n\n // Update original transaction status\n const isPartialRefund = refundAmount < transaction.amount;\n transaction.status = isPartialRefund ? 'partially_refunded' : 'refunded';\n transaction.refundedAmount = (transaction.refundedAmount ?? 0) + refundAmount;\n transaction.refundedAt = refundResult.refundedAt ?? new Date();\n transaction.metadata = {\n ...transaction.metadata,\n refundTransactionId: refundTransaction._id.toString(),\n refundReason: reason,\n };\n\n await transaction.save();\n\n // Trigger hook\n this._triggerHook('payment.refunded', {\n transaction,\n refundTransaction,\n refundResult,\n refundAmount,\n reason,\n isPartialRefund,\n });\n\n return {\n transaction,\n refundTransaction,\n refundResult,\n status: transaction.status,\n };\n }\n\n /**\n * Handle webhook from payment provider\n *\n * @param provider - Provider name\n * @param payload - Webhook payload\n * @param headers - Request headers\n * @returns { event, transaction }\n */\n async handleWebhook(\n providerName: string,\n payload: unknown,\n headers: Record<string, string> = {}\n ): Promise<WebhookResult> {\n const provider = this.providers[providerName];\n\n if (!provider) {\n throw new ProviderNotFoundError(providerName, Object.keys(this.providers));\n }\n\n // Check if provider supports webhooks\n const capabilities = provider.getCapabilities();\n if (!capabilities.supportsWebhooks) {\n throw new ProviderCapabilityError(providerName, 'webhooks');\n }\n\n // Process webhook via provider\n let webhookEvent;\n try {\n webhookEvent = await provider.handleWebhook(payload, headers);\n } catch (error) {\n this.logger.error('Webhook processing failed:', error);\n throw new ProviderError(\n `Webhook processing failed for ${providerName}: ${(error as Error).message}`,\n 'WEBHOOK_PROCESSING_FAILED',\n { retryable: false }\n );\n }\n\n // Validate webhook event structure\n if (!webhookEvent?.data?.sessionId && !webhookEvent?.data?.paymentIntentId) {\n throw new ValidationError(\n `Invalid webhook event structure from ${providerName}: missing sessionId or paymentIntentId`,\n { provider: providerName, eventType: webhookEvent?.type }\n );\n }\n\n // Find transaction by sessionId first (for checkout flows), then paymentIntentId\n const TransactionModel = this.models.Transaction;\n let transaction: TransactionDocument | null = null;\n\n if (webhookEvent.data.sessionId) {\n transaction = await (TransactionModel as unknown as {\n findOne(filter: object): Promise<TransactionDocument | null>;\n }).findOne({\n 'gateway.sessionId': webhookEvent.data.sessionId,\n });\n }\n\n if (!transaction && webhookEvent.data.paymentIntentId) {\n transaction = await (TransactionModel as unknown as {\n findOne(filter: object): Promise<TransactionDocument | null>;\n }).findOne({\n 'gateway.paymentIntentId': webhookEvent.data.paymentIntentId,\n });\n }\n\n if (!transaction) {\n this.logger.warn('Transaction not found for webhook event', {\n provider: providerName,\n eventId: webhookEvent.id,\n sessionId: webhookEvent.data.sessionId,\n paymentIntentId: webhookEvent.data.paymentIntentId,\n });\n throw new TransactionNotFoundError(\n webhookEvent.data.sessionId ?? webhookEvent.data.paymentIntentId ?? 'unknown'\n );\n }\n\n // Update gateway with complete information from webhook\n if (webhookEvent.data.sessionId && !transaction.gateway?.sessionId) {\n transaction.gateway = {\n ...transaction.gateway,\n type: transaction.gateway?.type ?? 'manual',\n sessionId: webhookEvent.data.sessionId,\n };\n }\n if (webhookEvent.data.paymentIntentId && !transaction.gateway?.paymentIntentId) {\n transaction.gateway = {\n ...transaction.gateway,\n type: transaction.gateway?.type ?? 'manual',\n paymentIntentId: webhookEvent.data.paymentIntentId,\n };\n }\n\n // Check for duplicate webhook processing (idempotency)\n if (transaction.webhook?.eventId === webhookEvent.id && transaction.webhook?.processedAt) {\n this.logger.warn('Webhook already processed', {\n transactionId: transaction._id,\n eventId: webhookEvent.id,\n });\n return {\n event: webhookEvent,\n transaction,\n status: 'already_processed',\n };\n }\n\n // Update transaction based on webhook event\n transaction.webhook = {\n eventId: webhookEvent.id,\n eventType: webhookEvent.type,\n receivedAt: new Date(),\n processedAt: new Date(),\n data: webhookEvent.data,\n };\n\n // Update status based on webhook type\n if (webhookEvent.type === 'payment.succeeded') {\n transaction.status = 'verified';\n transaction.verifiedAt = webhookEvent.createdAt;\n } else if (webhookEvent.type === 'payment.failed') {\n transaction.status = 'failed';\n } else if (webhookEvent.type === 'refund.succeeded') {\n transaction.status = 'refunded';\n transaction.refundedAt = webhookEvent.createdAt;\n }\n\n await transaction.save();\n\n // Trigger hook\n this._triggerHook(`payment.webhook.${webhookEvent.type}`, {\n event: webhookEvent,\n transaction,\n });\n\n return {\n event: webhookEvent,\n transaction,\n status: 'processed',\n };\n }\n\n /**\n * List payments/transactions with filters\n *\n * @param filters - Query filters\n * @param options - Query options (limit, skip, sort)\n * @returns Transactions\n */\n async list(\n filters: Record<string, unknown> = {},\n options: ListOptions = {}\n ): Promise<TransactionDocument[]> {\n const TransactionModel = this.models.Transaction;\n const { limit = 50, skip = 0, sort = { createdAt: -1 } } = options;\n\n const transactions = await (TransactionModel as unknown as {\n find(filter: object): { limit(n: number): { skip(n: number): { sort(s: object): Promise<TransactionDocument[]> } } };\n })\n .find(filters)\n .limit(limit)\n .skip(skip)\n .sort(sort);\n\n return transactions;\n }\n\n /**\n * Get payment/transaction by ID\n *\n * @param transactionId - Transaction ID\n * @returns Transaction\n */\n async get(transactionId: string): Promise<TransactionDocument> {\n const TransactionModel = this.models.Transaction;\n const transaction = await TransactionModel.findById(transactionId) as TransactionDocument | null;\n\n if (!transaction) {\n throw new TransactionNotFoundError(transactionId);\n }\n\n return transaction;\n }\n\n /**\n * Get provider instance\n *\n * @param providerName - Provider name\n * @returns Provider instance\n */\n getProvider(providerName: string): PaymentProviderInterface {\n const provider = this.providers[providerName];\n if (!provider) {\n throw new ProviderNotFoundError(providerName, Object.keys(this.providers));\n }\n return provider;\n }\n\n /**\n * Trigger event hook (fire-and-forget, non-blocking)\n * @private\n */\n private _triggerHook(event: string, data: unknown): void {\n triggerHook(this.hooks, event, data, this.logger);\n }\n\n /**\n * Find transaction by sessionId, paymentIntentId, or transaction ID\n * @private\n */\n private async _findTransaction(\n TransactionModel: MongooseModel<TransactionDocument>,\n identifier: string\n ): Promise<TransactionDocument | null> {\n let transaction = await (TransactionModel as unknown as {\n findOne(filter: object): Promise<TransactionDocument | null>;\n }).findOne({\n 'gateway.sessionId': identifier,\n });\n\n if (!transaction) {\n transaction = await (TransactionModel as unknown as {\n findOne(filter: object): Promise<TransactionDocument | null>;\n }).findOne({\n 'gateway.paymentIntentId': identifier,\n });\n }\n\n if (!transaction) {\n transaction = await TransactionModel.findById(identifier) as TransactionDocument | null;\n }\n\n return transaction;\n }\n}\n\nexport default PaymentService;\n\n","/**\n * Transaction Service\n * @classytic/revenue\n *\n * Thin, focused transaction service for core operations\n * Users handle their own analytics, exports, and complex queries\n *\n * Works with ANY model implementation:\n * - Plain Mongoose models\n * - @classytic/mongokit Repository instances\n * - Any other abstraction with compatible interface\n */\n\nimport { TransactionNotFoundError } from '../core/errors.js';\nimport { triggerHook } from '../utils/hooks.js';\nimport type { Container } from '../core/container.js';\nimport type {\n ModelsRegistry,\n HooksRegistry,\n Logger,\n TransactionDocument,\n TransactionListResult,\n ListOptions,\n} from '../types/index.js';\n\n/**\n * Transaction Service\n * Focused on core transaction lifecycle operations\n */\nexport class TransactionService {\n private readonly models: ModelsRegistry;\n private readonly hooks: HooksRegistry;\n private readonly logger: Logger;\n\n constructor(container: Container) {\n this.models = container.get<ModelsRegistry>('models');\n this.hooks = container.get<HooksRegistry>('hooks');\n this.logger = container.get<Logger>('logger');\n }\n\n /**\n * Get transaction by ID\n *\n * @param transactionId - Transaction ID\n * @returns Transaction\n */\n async get(transactionId: string): Promise<TransactionDocument> {\n const TransactionModel = this.models.Transaction;\n const transaction = await TransactionModel.findById(transactionId) as TransactionDocument | null;\n\n if (!transaction) {\n throw new TransactionNotFoundError(transactionId);\n }\n\n return transaction;\n }\n\n /**\n * List transactions with filters\n *\n * @param filters - Query filters\n * @param options - Query options (limit, skip, sort, populate)\n * @returns { transactions, total, page, limit }\n */\n async list(\n filters: Record<string, unknown> = {},\n options: ListOptions = {}\n ): Promise<TransactionListResult> {\n const TransactionModel = this.models.Transaction;\n const {\n limit = 50,\n skip = 0,\n page = null,\n sort = { createdAt: -1 },\n populate = [],\n } = options;\n\n // Calculate pagination\n const actualSkip = page ? (page - 1) * limit : skip;\n\n // Build query\n type QueryBuilder = {\n find(filter: object): QueryBuilder;\n limit(n: number): QueryBuilder;\n skip(n: number): QueryBuilder;\n sort(s: object): QueryBuilder;\n populate(field: string): QueryBuilder;\n then<T>(resolve: (value: TransactionDocument[]) => T): Promise<T>;\n };\n\n let query = (TransactionModel as unknown as {\n find(filter: object): QueryBuilder;\n }).find(filters)\n .limit(limit)\n .skip(actualSkip)\n .sort(sort);\n\n // Apply population if supported\n if (populate.length > 0 && typeof query.populate === 'function') {\n populate.forEach((field) => {\n query = query.populate(field);\n });\n }\n\n const transactions = await query as unknown as TransactionDocument[];\n\n // Count documents (works with both Mongoose and Repository)\n type ModelWithCount = {\n countDocuments?(filter: object): Promise<number>;\n count?(filter: object): Promise<number>;\n };\n\n const model = TransactionModel as unknown as ModelWithCount;\n const total = await (model.countDocuments\n ? model.countDocuments(filters)\n : model.count?.(filters)) ?? 0;\n\n return {\n transactions,\n total,\n page: page ?? Math.floor(actualSkip / limit) + 1,\n limit,\n pages: Math.ceil(total / limit),\n };\n }\n\n /**\n * Update transaction\n *\n * @param transactionId - Transaction ID\n * @param updates - Fields to update\n * @returns Updated transaction\n */\n async update(\n transactionId: string,\n updates: Partial<TransactionDocument>\n ): Promise<TransactionDocument> {\n const TransactionModel = this.models.Transaction;\n\n // Support both Repository pattern and Mongoose\n type ModelWithUpdate = {\n update?(id: string, data: object): Promise<TransactionDocument | null>;\n findByIdAndUpdate?(id: string, data: object, options?: object): Promise<TransactionDocument | null>;\n };\n\n const model = TransactionModel as unknown as ModelWithUpdate;\n let transaction: TransactionDocument | null;\n\n if (typeof model.update === 'function') {\n // Repository pattern\n transaction = await model.update(transactionId, updates);\n } else if (typeof model.findByIdAndUpdate === 'function') {\n // Plain Mongoose\n transaction = await model.findByIdAndUpdate(\n transactionId,\n { $set: updates },\n { new: true }\n );\n } else {\n throw new Error('Transaction model does not support update operations');\n }\n\n if (!transaction) {\n throw new TransactionNotFoundError(transactionId);\n }\n\n // Trigger hook (fire-and-forget, non-blocking)\n this._triggerHook('transaction.updated', {\n transaction,\n updates,\n });\n\n return transaction;\n }\n\n /**\n * Trigger event hook (fire-and-forget, non-blocking)\n * @private\n */\n private _triggerHook(event: string, data: unknown): void {\n triggerHook(this.hooks, event, data, this.logger);\n }\n}\n\nexport default TransactionService;\n\n","/**\n * Escrow/Hold Enums\n * @classytic/revenue\n *\n * Enums for platform-as-intermediary payment flow\n */\n\nexport const HOLD_STATUS = {\n PENDING: 'pending',\n HELD: 'held',\n RELEASED: 'released',\n CANCELLED: 'cancelled',\n EXPIRED: 'expired',\n PARTIALLY_RELEASED: 'partially_released',\n} as const;\n\nexport type HoldStatus = typeof HOLD_STATUS;\nexport type HoldStatusValue = HoldStatus[keyof HoldStatus];\nexport const HOLD_STATUS_VALUES = Object.values(HOLD_STATUS);\n\nexport const RELEASE_REASON = {\n PAYMENT_VERIFIED: 'payment_verified',\n MANUAL_RELEASE: 'manual_release',\n AUTO_RELEASE: 'auto_release',\n DISPUTE_RESOLVED: 'dispute_resolved',\n} as const;\n\nexport type ReleaseReason = typeof RELEASE_REASON;\nexport type ReleaseReasonValue = ReleaseReason[keyof ReleaseReason];\nexport const RELEASE_REASON_VALUES = Object.values(RELEASE_REASON);\n\nexport const HOLD_REASON = {\n PAYMENT_VERIFICATION: 'payment_verification',\n FRAUD_CHECK: 'fraud_check',\n MANUAL_REVIEW: 'manual_review',\n DISPUTE: 'dispute',\n COMPLIANCE: 'compliance',\n} as const;\n\nexport type HoldReason = typeof HOLD_REASON;\nexport type HoldReasonValue = HoldReason[keyof HoldReason];\nexport const HOLD_REASON_VALUES = Object.values(HOLD_REASON);\n\n","/**\n * Split Payment Enums\n * @classytic/revenue\n *\n * Enums for multi-party commission splits\n */\n\nexport const SPLIT_TYPE = {\n PLATFORM_COMMISSION: 'platform_commission',\n AFFILIATE_COMMISSION: 'affiliate_commission',\n REFERRAL_COMMISSION: 'referral_commission',\n PARTNER_COMMISSION: 'partner_commission',\n CUSTOM: 'custom',\n} as const;\n\nexport type SplitType = typeof SPLIT_TYPE;\nexport type SplitTypeValue = SplitType[keyof SplitType];\nexport const SPLIT_TYPE_VALUES = Object.values(SPLIT_TYPE);\n\nexport const SPLIT_STATUS = {\n PENDING: 'pending',\n DUE: 'due',\n PAID: 'paid',\n WAIVED: 'waived',\n CANCELLED: 'cancelled',\n} as const;\n\nexport type SplitStatus = typeof SPLIT_STATUS;\nexport type SplitStatusValue = SplitStatus[keyof SplitStatus];\nexport const SPLIT_STATUS_VALUES = Object.values(SPLIT_STATUS);\n\nexport const PAYOUT_METHOD = {\n BANK_TRANSFER: 'bank_transfer',\n MOBILE_WALLET: 'mobile_wallet',\n PLATFORM_BALANCE: 'platform_balance',\n CRYPTO: 'crypto',\n CHECK: 'check',\n MANUAL: 'manual',\n} as const;\n\nexport type PayoutMethod = typeof PAYOUT_METHOD;\nexport type PayoutMethodValue = PayoutMethod[keyof PayoutMethod];\nexport const PAYOUT_METHOD_VALUES = Object.values(PAYOUT_METHOD);\n\n","/**\n * Commission Split Utilities\n * @classytic/revenue\n *\n * Multi-party commission split calculation for affiliate/referral systems\n */\n\nimport { SPLIT_TYPE, SPLIT_STATUS } from '../enums/split.enums.js';\nimport type {\n SplitRule,\n SplitInfo,\n CommissionInfo,\n CommissionWithSplitsOptions,\n} from '../types/index.js';\n\n/**\n * Calculate multi-party commission splits\n *\n * @param amount - Transaction amount\n * @param splitRules - Split configuration\n * @param gatewayFeeRate - Gateway fee rate (optional)\n * @returns Split objects\n *\n * @example\n * calculateSplits(1000, [\n * { type: 'platform_commission', recipientId: 'platform', recipientType: 'platform', rate: 0.10 },\n * { type: 'affiliate_commission', recipientId: 'affiliate-123', recipientType: 'user', rate: 0.02 },\n * ], 0.018);\n *\n * Returns:\n * [\n * { type: 'platform_commission', recipientId: 'platform', grossAmount: 100, gatewayFeeAmount: 18, netAmount: 82, ... },\n * { type: 'affiliate_commission', recipientId: 'affiliate-123', grossAmount: 20, gatewayFeeAmount: 0, netAmount: 20, ... },\n * ]\n */\nexport function calculateSplits(\n amount: number,\n splitRules: SplitRule[] = [],\n gatewayFeeRate: number = 0\n): SplitInfo[] {\n if (!splitRules || splitRules.length === 0) {\n return [];\n }\n\n if (amount < 0) {\n throw new Error('Transaction amount cannot be negative');\n }\n\n if (gatewayFeeRate < 0 || gatewayFeeRate > 1) {\n throw new Error('Gateway fee rate must be between 0 and 1');\n }\n\n const totalRate = splitRules.reduce((sum, rule) => sum + rule.rate, 0);\n if (totalRate > 1) {\n throw new Error(`Total split rate (${totalRate}) cannot exceed 1.0`);\n }\n\n return splitRules.map((rule, index) => {\n if (rule.rate < 0 || rule.rate > 1) {\n throw new Error(`Split rate must be between 0 and 1 for split ${index}`);\n }\n\n const grossAmount = Math.round(amount * rule.rate * 100) / 100;\n\n const gatewayFeeAmount = index === 0 && gatewayFeeRate > 0\n ? Math.round(amount * gatewayFeeRate * 100) / 100\n : 0;\n\n const netAmount = Math.max(0, Math.round((grossAmount - gatewayFeeAmount) * 100) / 100);\n\n return {\n type: rule.type ?? SPLIT_TYPE.CUSTOM,\n recipientId: rule.recipientId,\n recipientType: rule.recipientType,\n rate: rule.rate,\n grossAmount,\n gatewayFeeRate: gatewayFeeAmount > 0 ? gatewayFeeRate : 0,\n gatewayFeeAmount,\n netAmount,\n status: SPLIT_STATUS.PENDING,\n dueDate: rule.dueDate ?? null,\n metadata: rule.metadata ?? {},\n };\n });\n}\n\n/**\n * Calculate organization payout after splits\n *\n * @param amount - Total transaction amount\n * @param splits - Calculated splits\n * @returns Amount organization receives\n */\nexport function calculateOrganizationPayout(\n amount: number,\n splits: SplitInfo[] = []\n): number {\n const totalSplitAmount = splits.reduce((sum, split) => sum + split.grossAmount, 0);\n return Math.max(0, Math.round((amount - totalSplitAmount) * 100) / 100);\n}\n\n/**\n * Reverse splits proportionally on refund\n *\n * @param originalSplits - Original split objects\n * @param originalAmount - Original transaction amount\n * @param refundAmount - Amount being refunded\n * @returns Reversed splits\n */\nexport function reverseSplits(\n originalSplits: SplitInfo[] | undefined | null,\n originalAmount: number,\n refundAmount: number\n): SplitInfo[] {\n if (!originalSplits || originalSplits.length === 0) {\n return [];\n }\n\n const refundRatio = refundAmount / originalAmount;\n\n return originalSplits.map((split) => ({\n ...split,\n grossAmount: Math.round(split.grossAmount * refundRatio * 100) / 100,\n gatewayFeeAmount: Math.round(split.gatewayFeeAmount * refundRatio * 100) / 100,\n netAmount: Math.round(split.netAmount * refundRatio * 100) / 100,\n status: SPLIT_STATUS.WAIVED,\n }));\n}\n\n/**\n * Build commission object with splits support\n * Backward compatible with existing calculateCommission\n *\n * @param amount - Transaction amount\n * @param commissionRate - Platform commission rate\n * @param gatewayFeeRate - Gateway fee rate\n * @param options - Additional options\n * @returns Commission with optional splits\n */\nexport function calculateCommissionWithSplits(\n amount: number,\n commissionRate: number,\n gatewayFeeRate: number = 0,\n options: CommissionWithSplitsOptions = {}\n): CommissionInfo | null {\n const { affiliateRate = 0, affiliateId = null, affiliateType = 'user' } = options;\n\n if (commissionRate <= 0 && affiliateRate <= 0) {\n return null;\n }\n\n const splitRules: SplitRule[] = [];\n\n if (commissionRate > 0) {\n splitRules.push({\n type: SPLIT_TYPE.PLATFORM_COMMISSION,\n recipientId: 'platform',\n recipientType: 'platform',\n rate: commissionRate,\n });\n }\n\n if (affiliateRate > 0 && affiliateId) {\n splitRules.push({\n type: SPLIT_TYPE.AFFILIATE_COMMISSION,\n recipientId: affiliateId,\n recipientType: affiliateType,\n rate: affiliateRate,\n });\n }\n\n const splits = calculateSplits(amount, splitRules, gatewayFeeRate);\n\n const platformSplit = splits.find((s) => s.type === SPLIT_TYPE.PLATFORM_COMMISSION);\n const affiliateSplit = splits.find((s) => s.type === SPLIT_TYPE.AFFILIATE_COMMISSION);\n\n return {\n rate: commissionRate,\n grossAmount: platformSplit?.grossAmount ?? 0,\n gatewayFeeRate: platformSplit?.gatewayFeeRate ?? 0,\n gatewayFeeAmount: platformSplit?.gatewayFeeAmount ?? 0,\n netAmount: platformSplit?.netAmount ?? 0,\n status: 'pending',\n ...(splits.length > 0 && { splits }),\n ...(affiliateSplit && {\n affiliate: {\n recipientId: affiliateSplit.recipientId,\n recipientType: affiliateSplit.recipientType,\n rate: affiliateSplit.rate,\n grossAmount: affiliateSplit.grossAmount,\n netAmount: affiliateSplit.netAmount,\n },\n }),\n };\n}\n\nexport default {\n calculateSplits,\n calculateOrganizationPayout,\n reverseSplits,\n calculateCommissionWithSplits,\n};\n\n","/**\n * Escrow Service\n * @classytic/revenue\n *\n * Platform-as-intermediary payment flow\n * Hold funds → Verify → Split/Deduct → Release to organization\n */\n\nimport { TransactionNotFoundError } from '../core/errors.js';\nimport { HOLD_STATUS, RELEASE_REASON, HOLD_REASON } from '../enums/escrow.enums.js';\nimport { TRANSACTION_TYPE, TRANSACTION_STATUS } from '../enums/transaction.enums.js';\nimport { SPLIT_STATUS } from '../enums/split.enums.js';\nimport { triggerHook } from '../utils/hooks.js';\nimport { calculateSplits, calculateOrganizationPayout } from '../utils/commission-split.js';\nimport type { Container } from '../core/container.js';\nimport type {\n ModelsRegistry,\n HooksRegistry,\n Logger,\n TransactionDocument,\n HoldOptions,\n ReleaseOptions,\n ReleaseResult,\n CancelHoldOptions,\n SplitResult,\n EscrowStatusResult,\n SplitRule,\n SplitInfo,\n} from '../types/index.js';\n\nexport class EscrowService {\n private readonly models: ModelsRegistry;\n private readonly hooks: HooksRegistry;\n private readonly logger: Logger;\n\n constructor(container: Container) {\n this.models = container.get<ModelsRegistry>('models');\n this.hooks = container.get<HooksRegistry>('hooks');\n this.logger = container.get<Logger>('logger');\n }\n\n /**\n * Hold funds in escrow\n *\n * @param transactionId - Transaction to hold\n * @param options - Hold options\n * @returns Updated transaction\n */\n async hold(\n transactionId: string,\n options: HoldOptions = {}\n ): Promise<TransactionDocument> {\n const {\n reason = HOLD_REASON.PAYMENT_VERIFICATION,\n holdUntil = null,\n metadata = {},\n } = options;\n\n const TransactionModel = this.models.Transaction;\n const transaction = await TransactionModel.findById(transactionId) as TransactionDocument | null;\n\n if (!transaction) {\n throw new TransactionNotFoundError(transactionId);\n }\n\n if (transaction.status !== TRANSACTION_STATUS.VERIFIED) {\n throw new Error(`Cannot hold transaction with status: ${transaction.status}. Must be verified.`);\n }\n\n transaction.hold = {\n status: HOLD_STATUS.HELD,\n heldAmount: transaction.amount,\n releasedAmount: 0,\n reason,\n heldAt: new Date(),\n ...(holdUntil && { holdUntil }),\n releases: [],\n metadata,\n };\n\n await transaction.save();\n\n this._triggerHook('escrow.held', {\n transaction,\n heldAmount: transaction.amount,\n reason,\n });\n\n return transaction;\n }\n\n /**\n * Release funds from escrow to recipient\n *\n * @param transactionId - Transaction to release\n * @param options - Release options\n * @returns { transaction, releaseTransaction }\n */\n async release(\n transactionId: string,\n options: ReleaseOptions\n ): Promise<ReleaseResult> {\n const {\n amount = null,\n recipientId,\n recipientType = 'organization',\n reason = RELEASE_REASON.PAYMENT_VERIFIED,\n releasedBy = null,\n createTransaction = true,\n metadata = {},\n } = options;\n\n const TransactionModel = this.models.Transaction;\n const transaction = await TransactionModel.findById(transactionId) as TransactionDocument | null;\n\n if (!transaction) {\n throw new TransactionNotFoundError(transactionId);\n }\n\n if (!transaction.hold || transaction.hold.status !== HOLD_STATUS.HELD) {\n throw new Error(`Transaction is not in held status. Current: ${transaction.hold?.status ?? 'none'}`);\n }\n\n if (!recipientId) {\n throw new Error('recipientId is required for release');\n }\n\n const releaseAmount = amount ?? (transaction.hold.heldAmount - transaction.hold.releasedAmount);\n const availableAmount = transaction.hold.heldAmount - transaction.hold.releasedAmount;\n\n if (releaseAmount > availableAmount) {\n throw new Error(`Release amount (${releaseAmount}) exceeds available held amount (${availableAmount})`);\n }\n\n const releaseRecord = {\n amount: releaseAmount,\n recipientId,\n recipientType,\n releasedAt: new Date(),\n releasedBy,\n reason,\n metadata,\n };\n\n transaction.hold.releases.push(releaseRecord);\n transaction.hold.releasedAmount += releaseAmount;\n\n const isFullRelease = transaction.hold.releasedAmount >= transaction.hold.heldAmount;\n const isPartialRelease = transaction.hold.releasedAmount > 0 && transaction.hold.releasedAmount < transaction.hold.heldAmount;\n\n if (isFullRelease) {\n transaction.hold.status = HOLD_STATUS.RELEASED;\n transaction.hold.releasedAt = new Date();\n transaction.status = TRANSACTION_STATUS.COMPLETED;\n } else if (isPartialRelease) {\n transaction.hold.status = HOLD_STATUS.PARTIALLY_RELEASED;\n }\n\n await transaction.save();\n\n let releaseTransaction: TransactionDocument | null = null;\n if (createTransaction) {\n releaseTransaction = await TransactionModel.create({\n organizationId: transaction.organizationId,\n customerId: recipientId,\n amount: releaseAmount,\n currency: transaction.currency,\n category: transaction.category,\n type: TRANSACTION_TYPE.INCOME,\n method: transaction.method,\n status: TRANSACTION_STATUS.COMPLETED,\n gateway: transaction.gateway,\n referenceId: transaction.referenceId,\n referenceModel: transaction.referenceModel,\n metadata: {\n ...metadata,\n isRelease: true,\n heldTransactionId: transaction._id.toString(),\n releaseReason: reason,\n recipientType,\n },\n idempotencyKey: `release_${transaction._id}_${Date.now()}`,\n }) as TransactionDocument;\n }\n\n this._triggerHook('escrow.released', {\n transaction,\n releaseTransaction,\n releaseAmount,\n recipientId,\n recipientType,\n reason,\n isFullRelease,\n isPartialRelease,\n });\n\n return {\n transaction,\n releaseTransaction,\n releaseAmount,\n isFullRelease,\n isPartialRelease,\n };\n }\n\n /**\n * Cancel hold and release back to customer\n *\n * @param transactionId - Transaction to cancel hold\n * @param options - Cancel options\n * @returns Updated transaction\n */\n async cancel(\n transactionId: string,\n options: CancelHoldOptions = {}\n ): Promise<TransactionDocument> {\n const { reason = 'Hold cancelled', metadata = {} } = options;\n\n const TransactionModel = this.models.Transaction;\n const transaction = await TransactionModel.findById(transactionId) as TransactionDocument | null;\n\n if (!transaction) {\n throw new TransactionNotFoundError(transactionId);\n }\n\n if (!transaction.hold || transaction.hold.status !== HOLD_STATUS.HELD) {\n throw new Error(`Transaction is not in held status. Current: ${transaction.hold?.status ?? 'none'}`);\n }\n\n transaction.hold.status = HOLD_STATUS.CANCELLED;\n transaction.hold.cancelledAt = new Date();\n transaction.hold.metadata = {\n ...transaction.hold.metadata,\n ...metadata,\n cancelReason: reason,\n };\n\n transaction.status = TRANSACTION_STATUS.CANCELLED;\n\n await transaction.save();\n\n this._triggerHook('escrow.cancelled', {\n transaction,\n reason,\n });\n\n return transaction;\n }\n\n /**\n * Split payment to multiple recipients\n * Deducts splits from held amount and releases remainder to organization\n *\n * @param transactionId - Transaction to split\n * @param splitRules - Split configuration\n * @returns { transaction, splitTransactions, organizationTransaction }\n */\n async split(\n transactionId: string,\n splitRules: SplitRule[] = []\n ): Promise<SplitResult> {\n const TransactionModel = this.models.Transaction;\n const transaction = await TransactionModel.findById(transactionId) as TransactionDocument | null;\n\n if (!transaction) {\n throw new TransactionNotFoundError(transactionId);\n }\n\n if (!transaction.hold || transaction.hold.status !== HOLD_STATUS.HELD) {\n throw new Error(`Transaction must be held before splitting. Current: ${transaction.hold?.status ?? 'none'}`);\n }\n\n if (!splitRules || splitRules.length === 0) {\n throw new Error('splitRules cannot be empty');\n }\n\n const splits = calculateSplits(\n transaction.amount,\n splitRules,\n transaction.commission?.gatewayFeeRate ?? 0\n );\n\n transaction.splits = splits;\n await transaction.save();\n\n const splitTransactions: TransactionDocument[] = [];\n\n for (const split of splits) {\n const splitTransaction = await TransactionModel.create({\n organizationId: transaction.organizationId,\n customerId: split.recipientId,\n amount: split.netAmount,\n currency: transaction.currency,\n category: split.type,\n type: TRANSACTION_TYPE.EXPENSE,\n method: transaction.method,\n status: TRANSACTION_STATUS.COMPLETED,\n gateway: transaction.gateway,\n referenceId: transaction.referenceId,\n referenceModel: transaction.referenceModel,\n metadata: {\n isSplit: true,\n splitType: split.type,\n recipientType: split.recipientType,\n originalTransactionId: transaction._id.toString(),\n grossAmount: split.grossAmount,\n gatewayFeeAmount: split.gatewayFeeAmount,\n },\n idempotencyKey: `split_${transaction._id}_${split.recipientId}_${Date.now()}`,\n }) as TransactionDocument;\n\n (split as SplitInfo & { payoutTransactionId?: string }).payoutTransactionId = splitTransaction._id.toString();\n split.status = SPLIT_STATUS.PAID;\n (split as SplitInfo & { paidDate?: Date }).paidDate = new Date();\n\n splitTransactions.push(splitTransaction);\n }\n\n await transaction.save();\n\n const organizationPayout = calculateOrganizationPayout(transaction.amount, splits);\n\n const organizationTransaction = await this.release(transactionId, {\n amount: organizationPayout,\n recipientId: transaction.organizationId?.toString() ?? '',\n recipientType: 'organization',\n reason: RELEASE_REASON.PAYMENT_VERIFIED,\n createTransaction: true,\n metadata: {\n afterSplits: true,\n totalSplits: splits.length,\n totalSplitAmount: transaction.amount - organizationPayout,\n },\n });\n\n this._triggerHook('escrow.split', {\n transaction,\n splits,\n splitTransactions,\n organizationTransaction: organizationTransaction.releaseTransaction,\n organizationPayout,\n });\n\n return {\n transaction,\n splits,\n splitTransactions,\n organizationTransaction: organizationTransaction.releaseTransaction,\n organizationPayout,\n };\n }\n\n /**\n * Get escrow status\n *\n * @param transactionId - Transaction ID\n * @returns Escrow status\n */\n async getStatus(transactionId: string): Promise<EscrowStatusResult> {\n const TransactionModel = this.models.Transaction;\n const transaction = await TransactionModel.findById(transactionId) as TransactionDocument | null;\n\n if (!transaction) {\n throw new TransactionNotFoundError(transactionId);\n }\n\n return {\n transaction,\n hold: transaction.hold ?? null,\n splits: transaction.splits ?? [],\n hasHold: !!transaction.hold,\n hasSplits: transaction.splits ? transaction.splits.length > 0 : false,\n };\n }\n\n private _triggerHook(event: string, data: unknown): void {\n triggerHook(this.hooks, event, data, this.logger);\n }\n}\n\nexport default EscrowService;\n\n"]}
|