@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.
- package/README.md +603 -486
- package/dist/application/services/index.d.ts +6 -0
- package/dist/application/services/index.js +3288 -0
- package/dist/application/services/index.js.map +1 -0
- package/dist/core/events.d.ts +455 -0
- package/dist/core/events.js +122 -0
- package/dist/core/events.js.map +1 -0
- package/dist/core/index.d.ts +12 -889
- package/dist/core/index.js +2361 -705
- package/dist/core/index.js.map +1 -1
- package/dist/enums/index.d.ts +54 -25
- package/dist/enums/index.js +143 -14
- package/dist/enums/index.js.map +1 -1
- package/dist/escrow.enums-CE0VQsfe.d.ts +76 -0
- package/dist/{index-BnJWVXuw.d.ts → index-DxIK0UmZ.d.ts} +281 -26
- package/dist/index-EnfKzDbs.d.ts +806 -0
- package/dist/{index-ChVD3P9k.d.ts → index-cLJBLUvx.d.ts} +55 -81
- package/dist/index.d.ts +16 -15
- package/dist/index.js +2583 -2066
- package/dist/index.js.map +1 -1
- package/dist/infrastructure/plugins/index.d.ts +267 -0
- package/dist/infrastructure/plugins/index.js +292 -0
- package/dist/infrastructure/plugins/index.js.map +1 -0
- package/dist/money-widWVD7r.d.ts +111 -0
- package/dist/payment.enums-C1BiGlRa.d.ts +69 -0
- package/dist/plugin-Bb9HOE10.d.ts +336 -0
- package/dist/providers/index.d.ts +19 -6
- package/dist/providers/index.js +22 -3
- package/dist/providers/index.js.map +1 -1
- package/dist/reconciliation/index.d.ts +215 -0
- package/dist/reconciliation/index.js +140 -0
- package/dist/reconciliation/index.js.map +1 -0
- package/dist/{retry-80lBCmSe.d.ts → retry-D4hFUwVk.d.ts} +1 -41
- package/dist/schemas/index.d.ts +1927 -166
- package/dist/schemas/index.js +357 -40
- package/dist/schemas/index.js.map +1 -1
- package/dist/schemas/validation.d.ts +87 -12
- package/dist/schemas/validation.js +71 -17
- package/dist/schemas/validation.js.map +1 -1
- package/dist/settlement.enums-ByC1x0ye.d.ts +130 -0
- package/dist/settlement.schema-CpamV7ZY.d.ts +343 -0
- package/dist/split.enums-DG3TxQf9.d.ts +42 -0
- package/dist/tax-CV8A0sxl.d.ts +60 -0
- package/dist/utils/index.d.ts +487 -13
- package/dist/utils/index.js +370 -235
- package/dist/utils/index.js.map +1 -1
- package/package.json +27 -13
- package/dist/actions-CwG-b7fR.d.ts +0 -519
- package/dist/services/index.d.ts +0 -3
- package/dist/services/index.js +0 -1632
- package/dist/services/index.js.map +0 -1
- package/dist/split.enums-Bh24jw8p.d.ts +0 -255
- package/dist/split.schema-DYVP7Wu2.d.ts +0 -958
|
@@ -1,5 +1,6 @@
|
|
|
1
|
-
import {
|
|
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
|
|
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
|
|
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
|
|
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 };
|
package/dist/providers/index.js
CHANGED
|
@@ -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
|
|
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
|
|
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
|
|
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,
|
|
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 };
|