@classytic/revenue 1.0.2 → 1.1.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.
Files changed (53) hide show
  1. package/README.md +603 -486
  2. package/dist/application/services/index.d.ts +6 -0
  3. package/dist/application/services/index.js +3288 -0
  4. package/dist/application/services/index.js.map +1 -0
  5. package/dist/core/events.d.ts +455 -0
  6. package/dist/core/events.js +122 -0
  7. package/dist/core/events.js.map +1 -0
  8. package/dist/core/index.d.ts +12 -889
  9. package/dist/core/index.js +2361 -705
  10. package/dist/core/index.js.map +1 -1
  11. package/dist/enums/index.d.ts +54 -25
  12. package/dist/enums/index.js +143 -14
  13. package/dist/enums/index.js.map +1 -1
  14. package/dist/escrow.enums-CE0VQsfe.d.ts +76 -0
  15. package/dist/{index-BnJWVXuw.d.ts → index-DxIK0UmZ.d.ts} +281 -26
  16. package/dist/index-EnfKzDbs.d.ts +806 -0
  17. package/dist/{index-ChVD3P9k.d.ts → index-cLJBLUvx.d.ts} +55 -81
  18. package/dist/index.d.ts +16 -15
  19. package/dist/index.js +2583 -2066
  20. package/dist/index.js.map +1 -1
  21. package/dist/infrastructure/plugins/index.d.ts +267 -0
  22. package/dist/infrastructure/plugins/index.js +292 -0
  23. package/dist/infrastructure/plugins/index.js.map +1 -0
  24. package/dist/money-widWVD7r.d.ts +111 -0
  25. package/dist/payment.enums-C1BiGlRa.d.ts +69 -0
  26. package/dist/plugin-Bb9HOE10.d.ts +336 -0
  27. package/dist/providers/index.d.ts +19 -6
  28. package/dist/providers/index.js +22 -3
  29. package/dist/providers/index.js.map +1 -1
  30. package/dist/reconciliation/index.d.ts +215 -0
  31. package/dist/reconciliation/index.js +140 -0
  32. package/dist/reconciliation/index.js.map +1 -0
  33. package/dist/{retry-80lBCmSe.d.ts → retry-D4hFUwVk.d.ts} +1 -41
  34. package/dist/schemas/index.d.ts +1927 -166
  35. package/dist/schemas/index.js +357 -40
  36. package/dist/schemas/index.js.map +1 -1
  37. package/dist/schemas/validation.d.ts +87 -12
  38. package/dist/schemas/validation.js +71 -17
  39. package/dist/schemas/validation.js.map +1 -1
  40. package/dist/settlement.enums-ByC1x0ye.d.ts +130 -0
  41. package/dist/settlement.schema-CpamV7ZY.d.ts +343 -0
  42. package/dist/split.enums-DG3TxQf9.d.ts +42 -0
  43. package/dist/tax-CV8A0sxl.d.ts +60 -0
  44. package/dist/utils/index.d.ts +487 -13
  45. package/dist/utils/index.js +370 -235
  46. package/dist/utils/index.js.map +1 -1
  47. package/package.json +27 -13
  48. package/dist/actions-CwG-b7fR.d.ts +0 -519
  49. package/dist/services/index.d.ts +0 -3
  50. package/dist/services/index.js +0 -1632
  51. package/dist/services/index.js.map +0 -1
  52. package/dist/split.enums-Bh24jw8p.d.ts +0 -255
  53. package/dist/split.schema-DYVP7Wu2.d.ts +0 -958
@@ -1,5 +1,6 @@
1
- import { q as CreateIntentParams, r as PaymentIntentData, s as PaymentResultData, t as RefundResultData, u as WebhookEventData, v as ProviderCapabilities } from '../index-ChVD3P9k.js';
1
+ import { l as CreateIntentParams, P as PaymentIntentData, b as PaymentResultData, m as RefundResultData, W as WebhookEventData, n as ProviderCapabilities } from '../index-cLJBLUvx.js';
2
2
  import 'mongoose';
3
+ import '@classytic/shared-types';
3
4
 
4
5
  /**
5
6
  * Payment Provider Base Class
@@ -19,7 +20,7 @@ declare class PaymentIntent implements PaymentIntentData {
19
20
  readonly provider: string;
20
21
  readonly status: string;
21
22
  readonly amount: number;
22
- readonly currency: string;
23
+ readonly currency?: string;
23
24
  readonly metadata: Record<string, unknown>;
24
25
  readonly clientSecret?: string;
25
26
  readonly paymentUrl?: string;
@@ -33,9 +34,9 @@ declare class PaymentIntent implements PaymentIntentData {
33
34
  declare class PaymentResult implements PaymentResultData {
34
35
  readonly id: string;
35
36
  readonly provider: string;
36
- readonly status: 'succeeded' | 'failed' | 'processing';
37
+ readonly status: 'succeeded' | 'failed' | 'processing' | 'requires_action';
37
38
  readonly amount?: number;
38
- readonly currency: string;
39
+ readonly currency?: string;
39
40
  readonly paidAt?: Date;
40
41
  readonly metadata: Record<string, unknown>;
41
42
  readonly raw?: unknown;
@@ -49,7 +50,7 @@ declare class RefundResult implements RefundResultData {
49
50
  readonly provider: string;
50
51
  readonly status: 'succeeded' | 'failed' | 'processing';
51
52
  readonly amount?: number;
52
- readonly currency: string;
53
+ readonly currency?: string;
53
54
  readonly refundedAt?: Date;
54
55
  readonly reason?: string;
55
56
  readonly metadata: Record<string, unknown>;
@@ -79,7 +80,19 @@ declare class WebhookEvent implements WebhookEventData {
79
80
  declare abstract class PaymentProvider {
80
81
  readonly config: Record<string, unknown>;
81
82
  readonly name: string;
83
+ /** Default currency - injected by Revenue when provider is registered */
84
+ private _defaultCurrency;
82
85
  constructor(config?: Record<string, unknown>);
86
+ /**
87
+ * Get the default currency for this provider
88
+ * Used when creating PaymentIntent, PaymentResult, RefundResult without explicit currency
89
+ */
90
+ get defaultCurrency(): string;
91
+ /**
92
+ * Set the default currency (called by Revenue when registering provider)
93
+ * @internal
94
+ */
95
+ setDefaultCurrency(currency: string): void;
83
96
  /**
84
97
  * Create a payment intent
85
98
  * @param params - Payment parameters
@@ -129,4 +142,4 @@ declare abstract class PaymentProvider {
129
142
  getCapabilities(): ProviderCapabilities;
130
143
  }
131
144
 
132
- export { PaymentIntent, PaymentProvider, PaymentProvider as PaymentProviderDefault, PaymentResult, RefundResult, WebhookEvent };
145
+ export { CreateIntentParams, PaymentIntent, PaymentIntentData, PaymentProvider, PaymentProvider as PaymentProviderDefault, PaymentResult, PaymentResultData, ProviderCapabilities, RefundResult, RefundResultData, WebhookEvent, WebhookEventData };
@@ -21,7 +21,7 @@ var PaymentIntent = class {
21
21
  this.provider = data.provider;
22
22
  this.status = data.status;
23
23
  this.amount = data.amount;
24
- this.currency = data.currency ?? "BDT";
24
+ this.currency = data.currency;
25
25
  this.metadata = data.metadata ?? {};
26
26
  this.clientSecret = data.clientSecret;
27
27
  this.paymentUrl = data.paymentUrl;
@@ -43,7 +43,7 @@ var PaymentResult = class {
43
43
  this.provider = data.provider;
44
44
  this.status = data.status;
45
45
  this.amount = data.amount;
46
- this.currency = data.currency ?? "BDT";
46
+ this.currency = data.currency;
47
47
  this.paidAt = data.paidAt;
48
48
  this.metadata = data.metadata ?? {};
49
49
  this.raw = data.raw;
@@ -64,7 +64,7 @@ var RefundResult = class {
64
64
  this.provider = data.provider;
65
65
  this.status = data.status;
66
66
  this.amount = data.amount;
67
- this.currency = data.currency ?? "BDT";
67
+ this.currency = data.currency;
68
68
  this.refundedAt = data.refundedAt;
69
69
  this.reason = data.reason;
70
70
  this.metadata = data.metadata ?? {};
@@ -90,9 +90,28 @@ var WebhookEvent = class {
90
90
  var PaymentProvider = class {
91
91
  config;
92
92
  name;
93
+ /** Default currency - injected by Revenue when provider is registered */
94
+ _defaultCurrency = "USD";
93
95
  constructor(config = {}) {
94
96
  this.config = config;
95
97
  this.name = "base";
98
+ if (config.defaultCurrency && typeof config.defaultCurrency === "string") {
99
+ this._defaultCurrency = config.defaultCurrency;
100
+ }
101
+ }
102
+ /**
103
+ * Get the default currency for this provider
104
+ * Used when creating PaymentIntent, PaymentResult, RefundResult without explicit currency
105
+ */
106
+ get defaultCurrency() {
107
+ return this._defaultCurrency;
108
+ }
109
+ /**
110
+ * Set the default currency (called by Revenue when registering provider)
111
+ * @internal
112
+ */
113
+ setDefaultCurrency(currency) {
114
+ this._defaultCurrency = currency;
96
115
  }
97
116
  /**
98
117
  * Verify webhook signature (optional)
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/providers/base.ts"],"names":[],"mappings":"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","file":"index.js","sourcesContent":["/**\n * Payment Provider Base Class\n * @classytic/revenue\n *\n * Abstract base class for all payment providers\n * Inspired by: Vercel AI SDK, Stripe SDK\n */\n\nimport type {\n CreateIntentParams,\n PaymentIntentData,\n PaymentResultData,\n RefundResultData,\n WebhookEventData,\n ProviderCapabilities,\n} from '../types/index.js';\n\n/**\n * Payment Intent - standardized response from createIntent\n */\nexport class PaymentIntent implements PaymentIntentData {\n public readonly id: string;\n public readonly sessionId: string | null;\n public readonly paymentIntentId: string | null;\n public readonly provider: string;\n public readonly status: string;\n public readonly amount: number;\n public readonly currency: string;\n public readonly metadata: Record<string, unknown>;\n public readonly clientSecret?: string;\n public readonly paymentUrl?: string;\n public readonly instructions?: string;\n public readonly raw?: unknown;\n\n constructor(data: PaymentIntentData) {\n this.id = data.id;\n this.sessionId = data.sessionId ?? null;\n this.paymentIntentId = data.paymentIntentId ?? null;\n this.provider = data.provider;\n this.status = data.status;\n this.amount = data.amount;\n this.currency = data.currency ?? 'BDT';\n this.metadata = data.metadata ?? {};\n this.clientSecret = data.clientSecret;\n this.paymentUrl = data.paymentUrl;\n this.instructions = data.instructions;\n this.raw = data.raw;\n }\n}\n\n/**\n * Payment Result - standardized response from verifyPayment\n */\nexport class PaymentResult implements PaymentResultData {\n public readonly id: string;\n public readonly provider: string;\n public readonly status: 'succeeded' | 'failed' | 'processing';\n public readonly amount?: number;\n public readonly currency: string;\n public readonly paidAt?: Date;\n public readonly metadata: Record<string, unknown>;\n public readonly raw?: unknown;\n\n constructor(data: PaymentResultData) {\n this.id = data.id;\n this.provider = data.provider;\n this.status = data.status;\n this.amount = data.amount;\n this.currency = data.currency ?? 'BDT';\n this.paidAt = data.paidAt;\n this.metadata = data.metadata ?? {};\n this.raw = data.raw;\n }\n}\n\n/**\n * Refund Result - standardized response from refund\n */\nexport class RefundResult implements RefundResultData {\n public readonly id: string;\n public readonly provider: string;\n public readonly status: 'succeeded' | 'failed' | 'processing';\n public readonly amount?: number;\n public readonly currency: string;\n public readonly refundedAt?: Date;\n public readonly reason?: string;\n public readonly metadata: Record<string, unknown>;\n public readonly raw?: unknown;\n\n constructor(data: RefundResultData) {\n this.id = data.id;\n this.provider = data.provider;\n this.status = data.status;\n this.amount = data.amount;\n this.currency = data.currency ?? 'BDT';\n this.refundedAt = data.refundedAt;\n this.reason = data.reason;\n this.metadata = data.metadata ?? {};\n this.raw = data.raw;\n }\n}\n\n/**\n * Webhook Event - standardized webhook event\n */\nexport class WebhookEvent implements WebhookEventData {\n public readonly id: string;\n public readonly provider: string;\n public readonly type: string;\n public readonly data: { sessionId?: string; paymentIntentId?: string; [key: string]: unknown };\n public readonly createdAt?: Date;\n public readonly raw?: unknown;\n\n constructor(data: WebhookEventData) {\n this.id = data.id;\n this.provider = data.provider;\n this.type = data.type;\n this.data = data.data;\n this.createdAt = data.createdAt;\n this.raw = data.raw;\n }\n}\n\n/**\n * Base Payment Provider\n * All payment providers must extend this class\n */\nexport abstract class PaymentProvider {\n public readonly config: Record<string, unknown>;\n public readonly name: string;\n\n constructor(config: Record<string, unknown> = {}) {\n this.config = config;\n this.name = 'base'; // Override in subclass\n }\n\n /**\n * Create a payment intent\n * @param params - Payment parameters\n * @returns Promise<PaymentIntent>\n */\n abstract createIntent(params: CreateIntentParams): Promise<PaymentIntent>;\n\n /**\n * Verify a payment\n * @param intentId - Payment intent ID\n * @returns Promise<PaymentResult>\n */\n abstract verifyPayment(intentId: string): Promise<PaymentResult>;\n\n /**\n * Get payment status\n * @param intentId - Payment intent ID\n * @returns Promise<PaymentResult>\n */\n abstract getStatus(intentId: string): Promise<PaymentResult>;\n\n /**\n * Refund a payment\n * @param paymentId - Payment ID\n * @param amount - Amount to refund (optional, full refund if not provided)\n * @param options - Refund options\n * @returns Promise<RefundResult>\n */\n abstract refund(\n paymentId: string,\n amount?: number | null,\n options?: { reason?: string }\n ): Promise<RefundResult>;\n\n /**\n * Handle webhook from provider\n * @param payload - Webhook payload\n * @param headers - Request headers (for signature verification)\n * @returns Promise<WebhookEvent>\n */\n abstract handleWebhook(\n payload: unknown,\n headers?: Record<string, string>\n ): Promise<WebhookEvent>;\n\n /**\n * Verify webhook signature (optional)\n * @param payload - Webhook payload\n * @param signature - Webhook signature\n * @returns boolean\n */\n verifyWebhookSignature(_payload: unknown, _signature: string): boolean {\n // Override in subclass if provider supports webhook signatures\n return true;\n }\n\n /**\n * Get provider capabilities\n * @returns ProviderCapabilities\n */\n getCapabilities(): ProviderCapabilities {\n return {\n supportsWebhooks: false,\n supportsRefunds: false,\n supportsPartialRefunds: false,\n requiresManualVerification: true,\n };\n }\n}\n\nexport default PaymentProvider;\n\n"]}
1
+ {"version":3,"sources":["../../src/providers/base.ts"],"names":[],"mappings":"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","file":"index.js","sourcesContent":["/**\n * Payment Provider Base Class\n * @classytic/revenue\n *\n * Abstract base class for all payment providers\n * Inspired by: Vercel AI SDK, Stripe SDK\n */\n\nimport type {\n CreateIntentParams,\n PaymentIntentData,\n PaymentResultData,\n RefundResultData,\n WebhookEventData,\n ProviderCapabilities,\n} from '../shared/types/index.js';\n\n/**\n * Payment Intent - standardized response from createIntent\n */\nexport class PaymentIntent implements PaymentIntentData {\n public readonly id: string;\n public readonly sessionId: string | null;\n public readonly paymentIntentId: string | null;\n public readonly provider: string;\n public readonly status: string;\n public readonly amount: number;\n public readonly currency?: string;\n public readonly metadata: Record<string, unknown>;\n public readonly clientSecret?: string;\n public readonly paymentUrl?: string;\n public readonly instructions?: string;\n public readonly raw?: unknown;\n\n constructor(data: PaymentIntentData) {\n this.id = data.id;\n this.sessionId = data.sessionId ?? null;\n this.paymentIntentId = data.paymentIntentId ?? null;\n this.provider = data.provider;\n this.status = data.status;\n this.amount = data.amount;\n this.currency = data.currency; // Don't default - use app's defaultCurrency config\n this.metadata = data.metadata ?? {};\n this.clientSecret = data.clientSecret;\n this.paymentUrl = data.paymentUrl;\n this.instructions = data.instructions;\n this.raw = data.raw;\n }\n}\n\n/**\n * Payment Result - standardized response from verifyPayment\n */\nexport class PaymentResult implements PaymentResultData {\n public readonly id: string;\n public readonly provider: string;\n public readonly status: 'succeeded' | 'failed' | 'processing' | 'requires_action';\n public readonly amount?: number;\n public readonly currency?: string;\n public readonly paidAt?: Date;\n public readonly metadata: Record<string, unknown>;\n public readonly raw?: unknown;\n\n constructor(data: PaymentResultData) {\n this.id = data.id;\n this.provider = data.provider;\n this.status = data.status;\n this.amount = data.amount;\n this.currency = data.currency; // Don't default - let transaction's currency be used\n this.paidAt = data.paidAt;\n this.metadata = data.metadata ?? {};\n this.raw = data.raw;\n }\n}\n\n/**\n * Refund Result - standardized response from refund\n */\nexport class RefundResult implements RefundResultData {\n public readonly id: string;\n public readonly provider: string;\n public readonly status: 'succeeded' | 'failed' | 'processing';\n public readonly amount?: number;\n public readonly currency?: string;\n public readonly refundedAt?: Date;\n public readonly reason?: string;\n public readonly metadata: Record<string, unknown>;\n public readonly raw?: unknown;\n\n constructor(data: RefundResultData) {\n this.id = data.id;\n this.provider = data.provider;\n this.status = data.status;\n this.amount = data.amount;\n this.currency = data.currency; // Don't default - let transaction's currency be used\n this.refundedAt = data.refundedAt;\n this.reason = data.reason;\n this.metadata = data.metadata ?? {};\n this.raw = data.raw;\n }\n}\n\n/**\n * Webhook Event - standardized webhook event\n */\nexport class WebhookEvent implements WebhookEventData {\n public readonly id: string;\n public readonly provider: string;\n public readonly type: string;\n public readonly data: { sessionId?: string; paymentIntentId?: string; [key: string]: unknown };\n public readonly createdAt?: Date;\n public readonly raw?: unknown;\n\n constructor(data: WebhookEventData) {\n this.id = data.id;\n this.provider = data.provider;\n this.type = data.type;\n this.data = data.data;\n this.createdAt = data.createdAt;\n this.raw = data.raw;\n }\n}\n\n/**\n * Base Payment Provider\n * All payment providers must extend this class\n */\nexport abstract class PaymentProvider {\n public readonly config: Record<string, unknown>;\n public readonly name: string;\n\n /** Default currency - injected by Revenue when provider is registered */\n private _defaultCurrency: string = 'USD';\n\n constructor(config: Record<string, unknown> = {}) {\n this.config = config;\n this.name = 'base'; // Override in subclass\n\n // Allow defaultCurrency to be passed via config\n if (config.defaultCurrency && typeof config.defaultCurrency === 'string') {\n this._defaultCurrency = config.defaultCurrency;\n }\n }\n\n /**\n * Get the default currency for this provider\n * Used when creating PaymentIntent, PaymentResult, RefundResult without explicit currency\n */\n get defaultCurrency(): string {\n return this._defaultCurrency;\n }\n\n /**\n * Set the default currency (called by Revenue when registering provider)\n * @internal\n */\n setDefaultCurrency(currency: string): void {\n this._defaultCurrency = currency;\n }\n\n /**\n * Create a payment intent\n * @param params - Payment parameters\n * @returns Promise<PaymentIntent>\n */\n abstract createIntent(params: CreateIntentParams): Promise<PaymentIntent>;\n\n /**\n * Verify a payment\n * @param intentId - Payment intent ID\n * @returns Promise<PaymentResult>\n */\n abstract verifyPayment(intentId: string): Promise<PaymentResult>;\n\n /**\n * Get payment status\n * @param intentId - Payment intent ID\n * @returns Promise<PaymentResult>\n */\n abstract getStatus(intentId: string): Promise<PaymentResult>;\n\n /**\n * Refund a payment\n * @param paymentId - Payment ID\n * @param amount - Amount to refund (optional, full refund if not provided)\n * @param options - Refund options\n * @returns Promise<RefundResult>\n */\n abstract refund(\n paymentId: string,\n amount?: number | null,\n options?: { reason?: string }\n ): Promise<RefundResult>;\n\n /**\n * Handle webhook from provider\n * @param payload - Webhook payload\n * @param headers - Request headers (for signature verification)\n * @returns Promise<WebhookEvent>\n */\n abstract handleWebhook(\n payload: unknown,\n headers?: Record<string, string>\n ): Promise<WebhookEvent>;\n\n /**\n * Verify webhook signature (optional)\n * @param payload - Webhook payload\n * @param signature - Webhook signature\n * @returns boolean\n */\n verifyWebhookSignature(_payload: unknown, _signature: string): boolean {\n // Override in subclass if provider supports webhook signatures\n return true;\n }\n\n /**\n * Get provider capabilities\n * @returns ProviderCapabilities\n */\n getCapabilities(): ProviderCapabilities {\n return {\n supportsWebhooks: false,\n supportsRefunds: false,\n supportsPartialRefunds: false,\n requiresManualVerification: true,\n };\n }\n}\n\nexport default PaymentProvider;\n\n"]}
@@ -0,0 +1,215 @@
1
+ import { T as TransactionDocument, M as MongooseModel } from '../index-cLJBLUvx.js';
2
+ import 'mongoose';
3
+ import '@classytic/shared-types';
4
+
5
+ /**
6
+ * Reconciliation Types
7
+ * @classytic/revenue
8
+ *
9
+ * Types for comparing gateway reports with database records
10
+ */
11
+
12
+ /**
13
+ * Gateway Settlement Record
14
+ * Data from payment gateway's settlement report (Stripe, PayPal, etc.)
15
+ */
16
+ interface GatewaySettlement {
17
+ /** Settlement ID from gateway */
18
+ settlementId: string;
19
+ /** Transaction/payment ID from gateway */
20
+ transactionId: string;
21
+ /** Amount settled */
22
+ amount: number;
23
+ /** Currency */
24
+ currency: string;
25
+ /** When funds were settled */
26
+ settledAt: Date;
27
+ /** Gateway fee deducted */
28
+ gatewayFee?: number;
29
+ /** Net amount received (amount - gatewayFee) */
30
+ netAmount?: number;
31
+ /** Payment status in gateway */
32
+ status?: string;
33
+ /** Additional gateway metadata */
34
+ metadata?: Record<string, unknown>;
35
+ }
36
+ /**
37
+ * Reconciliation Options
38
+ * Configuration for reconciliation process
39
+ */
40
+ interface ReconciliationOptions {
41
+ /** Filter by organization */
42
+ organizationId?: string;
43
+ /** Filter by payment gateway */
44
+ gateway?: string;
45
+ /** Start date for reconciliation period */
46
+ startDate?: Date;
47
+ /** End date for reconciliation period */
48
+ endDate?: Date;
49
+ /** Automatically match by transactionId */
50
+ autoMatch?: boolean;
51
+ /** Tolerance for amount mismatches (in cents) */
52
+ amountTolerance?: number;
53
+ }
54
+ /**
55
+ * Reconciliation Report
56
+ * Result of reconciling gateway settlements with database transactions
57
+ */
58
+ interface ReconciliationReport {
59
+ /** Summary statistics */
60
+ summary: {
61
+ /** Total transactions in gateway report */
62
+ totalGatewayTransactions: number;
63
+ /** Total transactions in database */
64
+ totalDbTransactions: number;
65
+ /** Number of matched transactions */
66
+ matched: number;
67
+ /** Number missing in database */
68
+ missing: number;
69
+ /** Number extra in database (not in gateway) */
70
+ extra: number;
71
+ /** Number with amount mismatches */
72
+ amountMismatches: number;
73
+ /** Total amount difference across all mismatches */
74
+ totalAmountDiff: number;
75
+ };
76
+ /** Transactions in gateway but not in database */
77
+ missingInDb: GatewaySettlement[];
78
+ /** Transactions in database but not in gateway */
79
+ missingInGateway: TransactionDocument[];
80
+ /** Transactions with amount mismatches */
81
+ amountMismatches: Array<{
82
+ transactionId: string;
83
+ gatewayAmount: number;
84
+ dbAmount: number;
85
+ diff: number;
86
+ transaction?: TransactionDocument;
87
+ gatewayRecord?: GatewaySettlement;
88
+ }>;
89
+ /** Successfully matched transactions */
90
+ matched: Array<{
91
+ transactionId: string;
92
+ amount: number;
93
+ transaction: TransactionDocument;
94
+ gatewayRecord: GatewaySettlement;
95
+ }>;
96
+ /** Reconciliation metadata */
97
+ metadata: {
98
+ reconciledAt: Date;
99
+ period: {
100
+ start?: Date;
101
+ end?: Date;
102
+ };
103
+ gateway?: string;
104
+ organizationId?: string;
105
+ };
106
+ }
107
+ /**
108
+ * Discrepancy Type
109
+ */
110
+ type DiscrepancyType = 'missing_in_db' | 'missing_in_gateway' | 'amount_mismatch' | 'status_mismatch';
111
+ /**
112
+ * Discrepancy Record
113
+ * Individual reconciliation discrepancy
114
+ */
115
+ interface Discrepancy {
116
+ type: DiscrepancyType;
117
+ transactionId: string;
118
+ severity: 'low' | 'medium' | 'high';
119
+ description: string;
120
+ gatewayData?: GatewaySettlement;
121
+ dbData?: TransactionDocument;
122
+ diff?: number;
123
+ }
124
+
125
+ /**
126
+ * Reconciliation Utilities
127
+ * @classytic/revenue
128
+ *
129
+ * Compare gateway settlement reports with database transactions
130
+ * Find missing transactions, amount mismatches, and discrepancies
131
+ */
132
+
133
+ /**
134
+ * Reconcile gateway settlements with database transactions
135
+ *
136
+ * Compares payment gateway's settlement report with your database to identify:
137
+ * - Transactions in gateway but missing in DB
138
+ * - Transactions in DB but missing in gateway
139
+ * - Amount mismatches between gateway and DB
140
+ *
141
+ * @param gatewaySettlements - Settlement data from payment gateway
142
+ * @param TransactionModel - Mongoose Transaction model
143
+ * @param options - Reconciliation options
144
+ * @returns Reconciliation report with findings
145
+ *
146
+ * @example
147
+ * ```typescript
148
+ * import { reconcileSettlement } from '@classytic/revenue/reconciliation';
149
+ *
150
+ * // Get Stripe settlements for January
151
+ * const stripeSettlements = await stripe.balanceTransactions.list({
152
+ * created: { gte: jan1, lte: jan31 },
153
+ * });
154
+ *
155
+ * // Reconcile with database
156
+ * const report = await reconcileSettlement(
157
+ * stripeSettlements.data.map(s => ({
158
+ * settlementId: s.id,
159
+ * transactionId: s.source,
160
+ * amount: s.amount,
161
+ * currency: s.currency,
162
+ * settledAt: new Date(s.created * 1000),
163
+ * gatewayFee: s.fee,
164
+ * netAmount: s.net,
165
+ * })),
166
+ * TransactionModel,
167
+ * { gateway: 'stripe', startDate: jan1, endDate: jan31 }
168
+ * );
169
+ *
170
+ * console.log(report.summary);
171
+ * // { matched: 1245, missing: 2, extra: 1, amountMismatches: 3 }
172
+ * ```
173
+ */
174
+ declare function reconcileSettlement(gatewaySettlements: GatewaySettlement[], TransactionModel: MongooseModel<TransactionDocument>, options?: ReconciliationOptions): Promise<ReconciliationReport>;
175
+ /**
176
+ * Find transactions missing in database
177
+ *
178
+ * @param organizationId - Organization to check
179
+ * @param dateRange - Date range to search
180
+ * @param gateway - Payment gateway
181
+ * @param TransactionModel - Mongoose Transaction model
182
+ * @returns Missing transaction IDs
183
+ */
184
+ declare function findMissingTransactions(_organizationId: string, _dateRange: {
185
+ start: Date;
186
+ end: Date;
187
+ }, _gateway: string, _TransactionModel: MongooseModel<TransactionDocument>): Promise<{
188
+ inGateway: string[];
189
+ inDb: string[];
190
+ }>;
191
+ /**
192
+ * Find amount mismatches between gateway and database
193
+ *
194
+ * @param organizationId - Organization to check
195
+ * @param dateRange - Date range to search
196
+ * @param threshold - Amount difference threshold (cents)
197
+ * @param TransactionModel - Mongoose Transaction model
198
+ * @returns Array of mismatches
199
+ */
200
+ declare function findAmountMismatches(_organizationId: string, _dateRange: {
201
+ start: Date;
202
+ end: Date;
203
+ }, _threshold: number | undefined, _TransactionModel: MongooseModel<TransactionDocument>): Promise<Array<{
204
+ transactionId: string;
205
+ diff: number;
206
+ }>>;
207
+ /**
208
+ * Generate reconciliation discrepancies
209
+ *
210
+ * @param report - Reconciliation report
211
+ * @returns Array of discrepancies sorted by severity
212
+ */
213
+ declare function generateDiscrepancies(report: ReconciliationReport): Discrepancy[];
214
+
215
+ export { type Discrepancy, type DiscrepancyType, type GatewaySettlement, type ReconciliationOptions, type ReconciliationReport, findAmountMismatches, findMissingTransactions, generateDiscrepancies, reconcileSettlement };
@@ -0,0 +1,140 @@
1
+ // @classytic/revenue - Enterprise Revenue Management System
2
+
3
+ // src/reconciliation/reconciler.ts
4
+ async function reconcileSettlement(gatewaySettlements, TransactionModel, options = {}) {
5
+ const {
6
+ organizationId,
7
+ gateway,
8
+ startDate,
9
+ endDate,
10
+ autoMatch: _autoMatch = true,
11
+ amountTolerance = 1
12
+ // 1 cent tolerance
13
+ } = options;
14
+ const query = {};
15
+ if (organizationId) query.organizationId = organizationId;
16
+ if (gateway) query["gateway.type"] = gateway;
17
+ if (startDate || endDate) {
18
+ query.createdAt = {};
19
+ if (startDate) query.createdAt.$gte = startDate;
20
+ if (endDate) query.createdAt.$lte = endDate;
21
+ }
22
+ const dbTransactions = await TransactionModel.find(query);
23
+ const gatewayMap = /* @__PURE__ */ new Map();
24
+ const dbMap = /* @__PURE__ */ new Map();
25
+ for (const settlement of gatewaySettlements) {
26
+ gatewayMap.set(settlement.transactionId, settlement);
27
+ }
28
+ for (const transaction of dbTransactions) {
29
+ const key = transaction.gateway?.paymentIntentId || transaction._id.toString();
30
+ dbMap.set(key, transaction);
31
+ }
32
+ const report = {
33
+ summary: {
34
+ totalGatewayTransactions: gatewaySettlements.length,
35
+ totalDbTransactions: dbTransactions.length,
36
+ matched: 0,
37
+ missing: 0,
38
+ extra: 0,
39
+ amountMismatches: 0,
40
+ totalAmountDiff: 0
41
+ },
42
+ missingInDb: [],
43
+ missingInGateway: [],
44
+ amountMismatches: [],
45
+ matched: [],
46
+ metadata: {
47
+ reconciledAt: /* @__PURE__ */ new Date(),
48
+ period: { start: startDate, end: endDate },
49
+ gateway,
50
+ organizationId
51
+ }
52
+ };
53
+ for (const [gatewayTxId, gatewaySettlement] of gatewayMap.entries()) {
54
+ const dbTransaction = dbMap.get(gatewayTxId);
55
+ if (!dbTransaction) {
56
+ report.missingInDb.push(gatewaySettlement);
57
+ report.summary.missing++;
58
+ } else {
59
+ const amountDiff = Math.abs(dbTransaction.amount - gatewaySettlement.amount);
60
+ if (amountDiff > amountTolerance) {
61
+ report.amountMismatches.push({
62
+ transactionId: gatewayTxId,
63
+ gatewayAmount: gatewaySettlement.amount,
64
+ dbAmount: dbTransaction.amount,
65
+ diff: dbTransaction.amount - gatewaySettlement.amount,
66
+ transaction: dbTransaction,
67
+ gatewayRecord: gatewaySettlement
68
+ });
69
+ report.summary.amountMismatches++;
70
+ report.summary.totalAmountDiff += amountDiff;
71
+ } else {
72
+ report.matched.push({
73
+ transactionId: gatewayTxId,
74
+ amount: dbTransaction.amount,
75
+ transaction: dbTransaction,
76
+ gatewayRecord: gatewaySettlement
77
+ });
78
+ report.summary.matched++;
79
+ }
80
+ dbMap.delete(gatewayTxId);
81
+ }
82
+ }
83
+ for (const [_, transaction] of dbMap.entries()) {
84
+ report.missingInGateway.push(transaction);
85
+ report.summary.extra++;
86
+ }
87
+ return report;
88
+ }
89
+ async function findMissingTransactions(_organizationId, _dateRange, _gateway, _TransactionModel) {
90
+ return {
91
+ inGateway: [],
92
+ // Transactions in gateway but not in DB
93
+ inDb: []
94
+ // Transactions in DB but not confirmed by gateway
95
+ };
96
+ }
97
+ async function findAmountMismatches(_organizationId, _dateRange, _threshold = 1, _TransactionModel) {
98
+ const mismatches = [];
99
+ return mismatches;
100
+ }
101
+ function generateDiscrepancies(report) {
102
+ const discrepancies = [];
103
+ for (const gateway of report.missingInDb) {
104
+ discrepancies.push({
105
+ type: "missing_in_db",
106
+ transactionId: gateway.transactionId,
107
+ severity: "high",
108
+ description: `Transaction ${gateway.transactionId} found in gateway (${gateway.amount} ${gateway.currency}) but missing in database`,
109
+ gatewayData: gateway
110
+ });
111
+ }
112
+ for (const transaction of report.missingInGateway) {
113
+ discrepancies.push({
114
+ type: "missing_in_gateway",
115
+ transactionId: transaction._id.toString(),
116
+ severity: "medium",
117
+ description: `Transaction ${transaction._id} found in database but not in gateway report`,
118
+ dbData: transaction
119
+ });
120
+ }
121
+ for (const mismatch of report.amountMismatches) {
122
+ const severity = Math.abs(mismatch.diff) > 1e3 ? "high" : Math.abs(mismatch.diff) > 100 ? "medium" : "low";
123
+ discrepancies.push({
124
+ type: "amount_mismatch",
125
+ transactionId: mismatch.transactionId,
126
+ severity,
127
+ description: `Amount mismatch: Gateway shows ${mismatch.gatewayAmount}, DB shows ${mismatch.dbAmount} (diff: ${mismatch.diff})`,
128
+ gatewayData: mismatch.gatewayRecord,
129
+ dbData: mismatch.transaction,
130
+ diff: mismatch.diff
131
+ });
132
+ }
133
+ const severityOrder = { high: 0, medium: 1, low: 2 };
134
+ discrepancies.sort((a, b) => severityOrder[a.severity] - severityOrder[b.severity]);
135
+ return discrepancies;
136
+ }
137
+
138
+ export { findAmountMismatches, findMissingTransactions, generateDiscrepancies, reconcileSettlement };
139
+ //# sourceMappingURL=index.js.map
140
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/reconciliation/reconciler.ts"],"names":[],"mappings":"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","file":"index.js","sourcesContent":["/**\n * Reconciliation Utilities\n * @classytic/revenue\n *\n * Compare gateway settlement reports with database transactions\n * Find missing transactions, amount mismatches, and discrepancies\n */\n\nimport type {\n GatewaySettlement,\n ReconciliationOptions,\n ReconciliationReport,\n Discrepancy,\n} from '../shared/types/reconciliation.js';\nimport type { TransactionDocument, MongooseModel } from '../shared/types/index.js';\n\n/**\n * Reconcile gateway settlements with database transactions\n *\n * Compares payment gateway's settlement report with your database to identify:\n * - Transactions in gateway but missing in DB\n * - Transactions in DB but missing in gateway\n * - Amount mismatches between gateway and DB\n *\n * @param gatewaySettlements - Settlement data from payment gateway\n * @param TransactionModel - Mongoose Transaction model\n * @param options - Reconciliation options\n * @returns Reconciliation report with findings\n *\n * @example\n * ```typescript\n * import { reconcileSettlement } from '@classytic/revenue/reconciliation';\n *\n * // Get Stripe settlements for January\n * const stripeSettlements = await stripe.balanceTransactions.list({\n * created: { gte: jan1, lte: jan31 },\n * });\n *\n * // Reconcile with database\n * const report = await reconcileSettlement(\n * stripeSettlements.data.map(s => ({\n * settlementId: s.id,\n * transactionId: s.source,\n * amount: s.amount,\n * currency: s.currency,\n * settledAt: new Date(s.created * 1000),\n * gatewayFee: s.fee,\n * netAmount: s.net,\n * })),\n * TransactionModel,\n * { gateway: 'stripe', startDate: jan1, endDate: jan31 }\n * );\n *\n * console.log(report.summary);\n * // { matched: 1245, missing: 2, extra: 1, amountMismatches: 3 }\n * ```\n */\nexport async function reconcileSettlement(\n gatewaySettlements: GatewaySettlement[],\n TransactionModel: MongooseModel<TransactionDocument>,\n options: ReconciliationOptions = {}\n): Promise<ReconciliationReport> {\n const {\n organizationId,\n gateway,\n startDate,\n endDate,\n autoMatch: _autoMatch = true,\n amountTolerance = 1, // 1 cent tolerance\n } = options;\n\n // Build query for DB transactions\n const query: Record<string, unknown> = {};\n if (organizationId) query.organizationId = organizationId;\n if (gateway) query['gateway.type'] = gateway;\n\n if (startDate || endDate) {\n query.createdAt = {};\n if (startDate) (query.createdAt as Record<string, unknown>).$gte = startDate;\n if (endDate) (query.createdAt as Record<string, unknown>).$lte = endDate;\n }\n\n // Get database transactions\n const dbTransactions = await (TransactionModel as unknown as {\n find(filter: object): Promise<TransactionDocument[]>;\n }).find(query);\n\n // Create lookup maps\n const gatewayMap = new Map<string, GatewaySettlement>();\n const dbMap = new Map<string, TransactionDocument>();\n\n for (const settlement of gatewaySettlements) {\n gatewayMap.set(settlement.transactionId, settlement);\n }\n\n for (const transaction of dbTransactions) {\n // Use gateway.paymentIntentId as the key for matching\n const key = (transaction.gateway?.paymentIntentId || transaction._id.toString());\n dbMap.set(key, transaction);\n }\n\n // Initialize report\n const report: ReconciliationReport = {\n summary: {\n totalGatewayTransactions: gatewaySettlements.length,\n totalDbTransactions: dbTransactions.length,\n matched: 0,\n missing: 0,\n extra: 0,\n amountMismatches: 0,\n totalAmountDiff: 0,\n },\n missingInDb: [],\n missingInGateway: [],\n amountMismatches: [],\n matched: [],\n metadata: {\n reconciledAt: new Date(),\n period: { start: startDate, end: endDate },\n gateway,\n organizationId,\n },\n };\n\n // Find matches and mismatches\n for (const [gatewayTxId, gatewaySettlement] of gatewayMap.entries()) {\n const dbTransaction = dbMap.get(gatewayTxId);\n\n if (!dbTransaction) {\n // Missing in DB\n report.missingInDb.push(gatewaySettlement);\n report.summary.missing++;\n } else {\n // Found - check amount\n const amountDiff = Math.abs(dbTransaction.amount - gatewaySettlement.amount);\n\n if (amountDiff > amountTolerance) {\n // Amount mismatch\n report.amountMismatches.push({\n transactionId: gatewayTxId,\n gatewayAmount: gatewaySettlement.amount,\n dbAmount: dbTransaction.amount,\n diff: dbTransaction.amount - gatewaySettlement.amount,\n transaction: dbTransaction,\n gatewayRecord: gatewaySettlement,\n });\n report.summary.amountMismatches++;\n report.summary.totalAmountDiff += amountDiff;\n } else {\n // Matched!\n report.matched.push({\n transactionId: gatewayTxId,\n amount: dbTransaction.amount,\n transaction: dbTransaction,\n gatewayRecord: gatewaySettlement,\n });\n report.summary.matched++;\n }\n\n // Mark as processed\n dbMap.delete(gatewayTxId);\n }\n }\n\n // Remaining DB transactions = extra (not in gateway)\n for (const [_, transaction] of dbMap.entries()) {\n report.missingInGateway.push(transaction);\n report.summary.extra++;\n }\n\n return report;\n}\n\n/**\n * Find transactions missing in database\n *\n * @param organizationId - Organization to check\n * @param dateRange - Date range to search\n * @param gateway - Payment gateway\n * @param TransactionModel - Mongoose Transaction model\n * @returns Missing transaction IDs\n */\nexport async function findMissingTransactions(\n _organizationId: string,\n _dateRange: { start: Date; end: Date },\n _gateway: string,\n _TransactionModel: MongooseModel<TransactionDocument>\n): Promise<{ inGateway: string[]; inDb: string[] }> {\n // This is a simplified version - in production, you'd fetch from gateway API\n // For now, return structure for apps to implement\n return {\n inGateway: [], // Transactions in gateway but not in DB\n inDb: [], // Transactions in DB but not confirmed by gateway\n };\n}\n\n/**\n * Find amount mismatches between gateway and database\n *\n * @param organizationId - Organization to check\n * @param dateRange - Date range to search\n * @param threshold - Amount difference threshold (cents)\n * @param TransactionModel - Mongoose Transaction model\n * @returns Array of mismatches\n */\nexport async function findAmountMismatches(\n _organizationId: string,\n _dateRange: { start: Date; end: Date },\n _threshold: number = 1,\n _TransactionModel: MongooseModel<TransactionDocument>\n): Promise<Array<{ transactionId: string; diff: number }>> {\n // This is a stub function for apps to implement\n // In production, query transactions and compare with gateway data\n\n const mismatches: Array<{ transactionId: string; diff: number }> = [];\n\n return mismatches;\n}\n\n/**\n * Generate reconciliation discrepancies\n *\n * @param report - Reconciliation report\n * @returns Array of discrepancies sorted by severity\n */\nexport function generateDiscrepancies(report: ReconciliationReport): Discrepancy[] {\n const discrepancies: Discrepancy[] = [];\n\n // Missing in DB (HIGH severity)\n for (const gateway of report.missingInDb) {\n discrepancies.push({\n type: 'missing_in_db',\n transactionId: gateway.transactionId,\n severity: 'high',\n description: `Transaction ${gateway.transactionId} found in gateway (${gateway.amount} ${gateway.currency}) but missing in database`,\n gatewayData: gateway,\n });\n }\n\n // Missing in gateway (MEDIUM severity)\n for (const transaction of report.missingInGateway) {\n discrepancies.push({\n type: 'missing_in_gateway',\n transactionId: transaction._id.toString(),\n severity: 'medium',\n description: `Transaction ${transaction._id} found in database but not in gateway report`,\n dbData: transaction,\n });\n }\n\n // Amount mismatches (severity based on amount)\n for (const mismatch of report.amountMismatches) {\n const severity: 'low' | 'medium' | 'high' = Math.abs(mismatch.diff) > 1000 ? 'high' : Math.abs(mismatch.diff) > 100 ? 'medium' : 'low';\n\n discrepancies.push({\n type: 'amount_mismatch',\n transactionId: mismatch.transactionId,\n severity,\n description: `Amount mismatch: Gateway shows ${mismatch.gatewayAmount}, DB shows ${mismatch.dbAmount} (diff: ${mismatch.diff})`,\n gatewayData: mismatch.gatewayRecord,\n dbData: mismatch.transaction,\n diff: mismatch.diff,\n });\n }\n\n // Sort by severity\n const severityOrder = { high: 0, medium: 1, low: 2 };\n discrepancies.sort((a, b) => severityOrder[a.severity] - severityOrder[b.severity]);\n\n return discrepancies;\n}\n"]}
@@ -123,43 +123,10 @@ interface RetryConfig {
123
123
  /** Callback on each retry */
124
124
  onRetry?: (error: unknown, attempt: number, delay: number) => void;
125
125
  }
126
- interface RetryState {
127
- attempt: number;
128
- totalDelay: number;
129
- errors: Error[];
130
- }
131
- /**
132
- * Calculate delay with exponential backoff and jitter
133
- */
134
- declare function calculateDelay(attempt: number, config: RetryConfig): number;
135
- /**
136
- * Check if error is retryable by default
137
- */
138
- declare function isRetryableError(error: unknown): boolean;
139
126
  /**
140
127
  * Execute operation with retry logic
141
128
  */
142
129
  declare function retry<T>(operation: () => Promise<T>, config?: Partial<RetryConfig>): Promise<T>;
143
- /**
144
- * Execute operation with retry, returning Result instead of throwing
145
- */
146
- declare function retryWithResult<T>(operation: () => Promise<T>, config?: Partial<RetryConfig>): Promise<Result<T, RetryExhaustedError>>;
147
- /**
148
- * Error thrown when all retries are exhausted
149
- */
150
- declare class RetryExhaustedError extends Error {
151
- readonly attempts: number;
152
- readonly errors: Error[];
153
- constructor(message: string, errors: Error[]);
154
- /**
155
- * Get the last error
156
- */
157
- get lastError(): Error | undefined;
158
- /**
159
- * Get the first error
160
- */
161
- get firstError(): Error | undefined;
162
- }
163
130
  type CircuitState = 'closed' | 'open' | 'half-open';
164
131
  interface CircuitBreakerConfig {
165
132
  /** Number of failures before opening circuit */
@@ -223,12 +190,5 @@ declare class CircuitOpenError extends Error {
223
190
  * Create a circuit breaker
224
191
  */
225
192
  declare function createCircuitBreaker(config?: Partial<CircuitBreakerConfig>): CircuitBreaker;
226
- /**
227
- * Execute with both retry and circuit breaker
228
- */
229
- declare function resilientExecute<T>(operation: () => Promise<T>, options?: {
230
- retry?: Partial<RetryConfig>;
231
- circuitBreaker?: CircuitBreaker;
232
- }): Promise<T>;
233
193
 
234
- export { CircuitBreaker as C, type Err as E, type Ok as O, Result as R, isErr as a, unwrapOr as b, mapErr as c, tryCatchSync as d, err as e, flatMap as f, all as g, match as h, isOk as i, retryWithResult as j, calculateDelay as k, isRetryableError as l, map as m, RetryExhaustedError as n, ok as o, createCircuitBreaker as p, CircuitOpenError as q, retry as r, resilientExecute as s, tryCatch as t, unwrap as u, type CircuitState as v, type CircuitBreakerConfig as w, type RetryConfig as x, type RetryState as y };
194
+ export { CircuitBreaker as C, type Err as E, type Ok as O, Result as R, isErr as a, unwrapOr as b, mapErr as c, tryCatchSync as d, err as e, flatMap as f, all as g, match as h, isOk as i, createCircuitBreaker as j, type RetryConfig as k, type CircuitBreakerConfig as l, map as m, type CircuitState as n, ok as o, retry as r, tryCatch as t, unwrap as u };