@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
|
@@ -0,0 +1,267 @@
|
|
|
1
|
+
import { R as RevenuePlugin } from '../../plugin-Bb9HOE10.js';
|
|
2
|
+
export { d as definePlugin } from '../../plugin-Bb9HOE10.js';
|
|
3
|
+
import { T as TaxConfig } from '../../tax-CV8A0sxl.js';
|
|
4
|
+
import '../../core/events.js';
|
|
5
|
+
import '../../index-cLJBLUvx.js';
|
|
6
|
+
import 'mongoose';
|
|
7
|
+
import '@classytic/shared-types';
|
|
8
|
+
import '../../providers/index.js';
|
|
9
|
+
import '../../settlement.schema-CpamV7ZY.js';
|
|
10
|
+
import '../../split.enums-DG3TxQf9.js';
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* Logging Plugin
|
|
14
|
+
* @classytic/revenue
|
|
15
|
+
*
|
|
16
|
+
* Logs all revenue operations at specified log level
|
|
17
|
+
*/
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* Logging plugin options
|
|
21
|
+
*/
|
|
22
|
+
interface LoggingPluginOptions {
|
|
23
|
+
/** Log level: 'debug' or 'info' */
|
|
24
|
+
level?: 'debug' | 'info';
|
|
25
|
+
}
|
|
26
|
+
/**
|
|
27
|
+
* Logging plugin - logs all operations
|
|
28
|
+
*
|
|
29
|
+
* Logs payment creation, verification, and refund operations
|
|
30
|
+
*
|
|
31
|
+
* @param options - Plugin options
|
|
32
|
+
* @returns Logging plugin
|
|
33
|
+
*
|
|
34
|
+
* @example
|
|
35
|
+
* ```typescript
|
|
36
|
+
* import { Revenue } from '@classytic/revenue';
|
|
37
|
+
* import { loggingPlugin } from '@classytic/revenue/plugins';
|
|
38
|
+
*
|
|
39
|
+
* const revenue = Revenue
|
|
40
|
+
* .create()
|
|
41
|
+
* .withPlugin(loggingPlugin({ level: 'debug' }))
|
|
42
|
+
* .build();
|
|
43
|
+
* ```
|
|
44
|
+
*/
|
|
45
|
+
declare function loggingPlugin(options?: LoggingPluginOptions): RevenuePlugin;
|
|
46
|
+
|
|
47
|
+
/**
|
|
48
|
+
* Audit Plugin
|
|
49
|
+
* @classytic/revenue
|
|
50
|
+
*
|
|
51
|
+
* Records all operations for compliance and audit trails
|
|
52
|
+
*/
|
|
53
|
+
|
|
54
|
+
/**
|
|
55
|
+
* Audit entry record
|
|
56
|
+
*/
|
|
57
|
+
interface AuditEntry {
|
|
58
|
+
action: string;
|
|
59
|
+
requestId: string;
|
|
60
|
+
timestamp: Date;
|
|
61
|
+
input: Record<string, unknown>;
|
|
62
|
+
output: Record<string, unknown>;
|
|
63
|
+
idempotencyKey?: string;
|
|
64
|
+
}
|
|
65
|
+
/**
|
|
66
|
+
* Audit plugin options
|
|
67
|
+
*/
|
|
68
|
+
interface AuditPluginOptions {
|
|
69
|
+
/** Custom storage function for audit entries */
|
|
70
|
+
store?: (entry: AuditEntry) => Promise<void>;
|
|
71
|
+
}
|
|
72
|
+
/**
|
|
73
|
+
* Audit plugin - records all operations for compliance
|
|
74
|
+
*
|
|
75
|
+
* Records payment creation, refunds, and other operations with sanitized data
|
|
76
|
+
*
|
|
77
|
+
* @param options - Plugin options
|
|
78
|
+
* @returns Audit plugin
|
|
79
|
+
*
|
|
80
|
+
* @example
|
|
81
|
+
* ```typescript
|
|
82
|
+
* import { Revenue } from '@classytic/revenue';
|
|
83
|
+
* import { auditPlugin } from '@classytic/revenue/plugins';
|
|
84
|
+
*
|
|
85
|
+
* const revenue = Revenue
|
|
86
|
+
* .create()
|
|
87
|
+
* .withPlugin(auditPlugin({
|
|
88
|
+
* store: async (entry) => {
|
|
89
|
+
* await AuditLog.create(entry);
|
|
90
|
+
* }
|
|
91
|
+
* }))
|
|
92
|
+
* .build();
|
|
93
|
+
* ```
|
|
94
|
+
*/
|
|
95
|
+
declare function auditPlugin(options?: AuditPluginOptions): RevenuePlugin;
|
|
96
|
+
|
|
97
|
+
/**
|
|
98
|
+
* Metrics Plugin
|
|
99
|
+
* @classytic/revenue
|
|
100
|
+
*
|
|
101
|
+
* Collects operation metrics (duration, success/failure)
|
|
102
|
+
*/
|
|
103
|
+
|
|
104
|
+
/**
|
|
105
|
+
* Metric record
|
|
106
|
+
*/
|
|
107
|
+
interface Metric {
|
|
108
|
+
name: string;
|
|
109
|
+
duration: number;
|
|
110
|
+
success: boolean;
|
|
111
|
+
error?: string;
|
|
112
|
+
[key: string]: unknown;
|
|
113
|
+
}
|
|
114
|
+
/**
|
|
115
|
+
* Metrics plugin options
|
|
116
|
+
*/
|
|
117
|
+
interface MetricsPluginOptions {
|
|
118
|
+
/** Callback for each metric */
|
|
119
|
+
onMetric?: (metric: Metric) => void;
|
|
120
|
+
}
|
|
121
|
+
/**
|
|
122
|
+
* Metrics plugin - collects operation metrics
|
|
123
|
+
*
|
|
124
|
+
* Tracks duration and success/failure of operations
|
|
125
|
+
*
|
|
126
|
+
* @param options - Plugin options
|
|
127
|
+
* @returns Metrics plugin
|
|
128
|
+
*
|
|
129
|
+
* @example
|
|
130
|
+
* ```typescript
|
|
131
|
+
* import { Revenue } from '@classytic/revenue';
|
|
132
|
+
* import { metricsPlugin } from '@classytic/revenue/plugins';
|
|
133
|
+
*
|
|
134
|
+
* const revenue = Revenue
|
|
135
|
+
* .create()
|
|
136
|
+
* .withPlugin(metricsPlugin({
|
|
137
|
+
* onMetric: (metric) => {
|
|
138
|
+
* // Send to Datadog, Prometheus, etc.
|
|
139
|
+
* statsd.timing(metric.name, metric.duration);
|
|
140
|
+
* if (!metric.success) {
|
|
141
|
+
* statsd.increment(`${metric.name}.error`);
|
|
142
|
+
* }
|
|
143
|
+
* }
|
|
144
|
+
* }))
|
|
145
|
+
* .build();
|
|
146
|
+
* ```
|
|
147
|
+
*/
|
|
148
|
+
declare function metricsPlugin(options?: MetricsPluginOptions): RevenuePlugin;
|
|
149
|
+
|
|
150
|
+
/**
|
|
151
|
+
* Tax Plugin Options
|
|
152
|
+
*/
|
|
153
|
+
interface TaxPluginOptions {
|
|
154
|
+
/**
|
|
155
|
+
* Function to get tax configuration for an organization
|
|
156
|
+
* Apps implement this to return jurisdiction-specific config
|
|
157
|
+
*
|
|
158
|
+
* @param orgId - Organization ID
|
|
159
|
+
* @returns Tax configuration or null if not registered
|
|
160
|
+
*
|
|
161
|
+
* @example
|
|
162
|
+
* ```typescript
|
|
163
|
+
* getTaxConfig: async (orgId) => {
|
|
164
|
+
* const org = await Organization.findById(orgId);
|
|
165
|
+
* if (!org) return null;
|
|
166
|
+
*
|
|
167
|
+
* return {
|
|
168
|
+
* isRegistered: org.country === 'AU',
|
|
169
|
+
* defaultRate: org.country === 'AU' ? 0.10 : 0, // 10% GST in Australia
|
|
170
|
+
* pricesIncludeTax: org.pricesIncludeTax || false,
|
|
171
|
+
* exemptCategories: ['education', 'medical'],
|
|
172
|
+
* };
|
|
173
|
+
* }
|
|
174
|
+
* ```
|
|
175
|
+
*/
|
|
176
|
+
getTaxConfig: (orgId: string) => Promise<TaxConfig | null>;
|
|
177
|
+
/**
|
|
178
|
+
* Category mappings for resolving transaction categories
|
|
179
|
+
* Maps entity names to category strings
|
|
180
|
+
*
|
|
181
|
+
* @example
|
|
182
|
+
* ```typescript
|
|
183
|
+
* {
|
|
184
|
+
* Order: 'order_subscription',
|
|
185
|
+
* PlatformSubscription: 'platform_subscription',
|
|
186
|
+
* Membership: 'gym_membership',
|
|
187
|
+
* }
|
|
188
|
+
* ```
|
|
189
|
+
*/
|
|
190
|
+
categoryMappings?: Record<string, string>;
|
|
191
|
+
/**
|
|
192
|
+
* Categories that represent income (vs expense)
|
|
193
|
+
* Used to determine tax type: 'collected' vs 'paid'
|
|
194
|
+
*
|
|
195
|
+
* Default: ['subscription', 'purchase', 'course_enrollment']
|
|
196
|
+
*/
|
|
197
|
+
incomeCategories?: string[];
|
|
198
|
+
}
|
|
199
|
+
/**
|
|
200
|
+
* Create Tax Plugin
|
|
201
|
+
*
|
|
202
|
+
* Automatically calculates and applies tax to transactions during monetization.create()
|
|
203
|
+
*
|
|
204
|
+
* @param options - Plugin options
|
|
205
|
+
* @returns Tax plugin
|
|
206
|
+
*
|
|
207
|
+
* @example
|
|
208
|
+
* ```typescript
|
|
209
|
+
* import { Revenue } from '@classytic/revenue';
|
|
210
|
+
* import { createTaxPlugin } from '@classytic/revenue/plugins';
|
|
211
|
+
*
|
|
212
|
+
* const revenue = Revenue
|
|
213
|
+
* .create({ defaultCurrency: 'USD' })
|
|
214
|
+
* .withModels({ Transaction, Subscription })
|
|
215
|
+
* .withProvider('stripe', stripeProvider)
|
|
216
|
+
* .withPlugin(createTaxPlugin({
|
|
217
|
+
* getTaxConfig: async (orgId) => {
|
|
218
|
+
* const org = await Organization.findById(orgId);
|
|
219
|
+
* return {
|
|
220
|
+
* isRegistered: true,
|
|
221
|
+
* defaultRate: 0.15, // 15% tax
|
|
222
|
+
* pricesIncludeTax: false,
|
|
223
|
+
* exemptCategories: ['education'],
|
|
224
|
+
* };
|
|
225
|
+
* },
|
|
226
|
+
* categoryMappings: {
|
|
227
|
+
* Order: 'order_subscription',
|
|
228
|
+
* Membership: 'gym_membership',
|
|
229
|
+
* },
|
|
230
|
+
* }))
|
|
231
|
+
* .build();
|
|
232
|
+
*
|
|
233
|
+
* // Tax is now automatically calculated
|
|
234
|
+
* await revenue.monetization.create({
|
|
235
|
+
* data: { organizationId: 'org_123', customerId: 'cust_456' },
|
|
236
|
+
* planKey: 'monthly',
|
|
237
|
+
* amount: 10000, // $100
|
|
238
|
+
* entity: 'Order',
|
|
239
|
+
* monetizationType: 'subscription',
|
|
240
|
+
* });
|
|
241
|
+
* // → Creates transaction with tax: {
|
|
242
|
+
* // isApplicable: true,
|
|
243
|
+
* // rate: 0.15,
|
|
244
|
+
* // baseAmount: 10000,
|
|
245
|
+
* // taxAmount: 1500,
|
|
246
|
+
* // totalAmount: 11500,
|
|
247
|
+
* // type: 'collected'
|
|
248
|
+
* // }
|
|
249
|
+
* ```
|
|
250
|
+
*/
|
|
251
|
+
declare function createTaxPlugin(options: TaxPluginOptions): RevenuePlugin;
|
|
252
|
+
|
|
253
|
+
/**
|
|
254
|
+
* Built-in Plugins
|
|
255
|
+
* @classytic/revenue/plugins
|
|
256
|
+
*
|
|
257
|
+
* Collection of built-in plugins for common use cases
|
|
258
|
+
*/
|
|
259
|
+
|
|
260
|
+
declare const _default: {
|
|
261
|
+
loggingPlugin: typeof loggingPlugin;
|
|
262
|
+
auditPlugin: typeof auditPlugin;
|
|
263
|
+
metricsPlugin: typeof metricsPlugin;
|
|
264
|
+
createTaxPlugin: typeof createTaxPlugin;
|
|
265
|
+
};
|
|
266
|
+
|
|
267
|
+
export { type AuditEntry, type AuditPluginOptions, type LoggingPluginOptions, type Metric, type MetricsPluginOptions, type TaxPluginOptions, auditPlugin, createTaxPlugin, _default as default, loggingPlugin, metricsPlugin };
|
|
@@ -0,0 +1,292 @@
|
|
|
1
|
+
// @classytic/revenue - Enterprise Revenue Management System
|
|
2
|
+
|
|
3
|
+
// src/core/plugin.ts
|
|
4
|
+
function definePlugin(plugin) {
|
|
5
|
+
return plugin;
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
// src/infrastructure/plugins/business/logging.plugin.ts
|
|
9
|
+
function loggingPlugin(options = {}) {
|
|
10
|
+
const level = options.level ?? "info";
|
|
11
|
+
return definePlugin({
|
|
12
|
+
name: "logging",
|
|
13
|
+
version: "1.0.0",
|
|
14
|
+
description: "Logs all revenue operations",
|
|
15
|
+
hooks: {
|
|
16
|
+
"payment.create.after": async (ctx, input, next) => {
|
|
17
|
+
ctx.logger[level]("Creating payment", { amount: input.amount, currency: input.currency });
|
|
18
|
+
const result = await next();
|
|
19
|
+
ctx.logger[level]("Payment created", { paymentIntentId: result?.paymentIntentId });
|
|
20
|
+
return result;
|
|
21
|
+
},
|
|
22
|
+
"payment.verify.after": async (ctx, input, next) => {
|
|
23
|
+
ctx.logger[level]("Verifying payment", { id: input.id });
|
|
24
|
+
const result = await next();
|
|
25
|
+
ctx.logger[level]("Payment verified", { verified: result?.verified });
|
|
26
|
+
return result;
|
|
27
|
+
},
|
|
28
|
+
"payment.refund.after": async (ctx, input, next) => {
|
|
29
|
+
ctx.logger[level]("Processing refund", { transactionId: input.transactionId, amount: input.amount });
|
|
30
|
+
const result = await next();
|
|
31
|
+
ctx.logger[level]("Refund processed", { refundId: result?.refundId });
|
|
32
|
+
return result;
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
});
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
// src/infrastructure/plugins/business/audit.plugin.ts
|
|
39
|
+
function sanitizeInput(input) {
|
|
40
|
+
if (typeof input !== "object" || !input) return {};
|
|
41
|
+
const sanitized = { ...input };
|
|
42
|
+
delete sanitized.apiKey;
|
|
43
|
+
delete sanitized.secretKey;
|
|
44
|
+
delete sanitized.password;
|
|
45
|
+
return sanitized;
|
|
46
|
+
}
|
|
47
|
+
function sanitizeOutput(output) {
|
|
48
|
+
if (typeof output !== "object" || !output) return {};
|
|
49
|
+
return { ...output };
|
|
50
|
+
}
|
|
51
|
+
function auditPlugin(options = {}) {
|
|
52
|
+
const store = options.store ?? (async (entry) => {
|
|
53
|
+
});
|
|
54
|
+
return definePlugin({
|
|
55
|
+
name: "audit",
|
|
56
|
+
version: "1.0.0",
|
|
57
|
+
description: "Audit trail for all operations",
|
|
58
|
+
hooks: {
|
|
59
|
+
"payment.create.after": async (ctx, input, next) => {
|
|
60
|
+
const result = await next();
|
|
61
|
+
await store({
|
|
62
|
+
action: "payment.create",
|
|
63
|
+
requestId: ctx.meta.requestId,
|
|
64
|
+
timestamp: ctx.meta.timestamp,
|
|
65
|
+
input: sanitizeInput(input),
|
|
66
|
+
output: sanitizeOutput(result),
|
|
67
|
+
idempotencyKey: ctx.meta.idempotencyKey
|
|
68
|
+
});
|
|
69
|
+
return result;
|
|
70
|
+
},
|
|
71
|
+
"payment.refund.after": async (ctx, input, next) => {
|
|
72
|
+
const result = await next();
|
|
73
|
+
await store({
|
|
74
|
+
action: "payment.refund",
|
|
75
|
+
requestId: ctx.meta.requestId,
|
|
76
|
+
timestamp: ctx.meta.timestamp,
|
|
77
|
+
input: sanitizeInput(input),
|
|
78
|
+
output: sanitizeOutput(result),
|
|
79
|
+
idempotencyKey: ctx.meta.idempotencyKey
|
|
80
|
+
});
|
|
81
|
+
return result;
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
});
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
// src/infrastructure/plugins/business/metrics.plugin.ts
|
|
88
|
+
function metricsPlugin(options = {}) {
|
|
89
|
+
const record = options.onMetric ?? ((metric) => {
|
|
90
|
+
});
|
|
91
|
+
return definePlugin({
|
|
92
|
+
name: "metrics",
|
|
93
|
+
version: "1.0.0",
|
|
94
|
+
description: "Collects operation metrics",
|
|
95
|
+
hooks: {
|
|
96
|
+
"payment.create.before": async (_ctx, input, next) => {
|
|
97
|
+
const start = Date.now();
|
|
98
|
+
try {
|
|
99
|
+
const result = await next();
|
|
100
|
+
record({
|
|
101
|
+
name: "payment.create",
|
|
102
|
+
duration: Date.now() - start,
|
|
103
|
+
success: true,
|
|
104
|
+
amount: input.amount,
|
|
105
|
+
currency: input.currency
|
|
106
|
+
});
|
|
107
|
+
return result;
|
|
108
|
+
} catch (error) {
|
|
109
|
+
record({
|
|
110
|
+
name: "payment.create",
|
|
111
|
+
duration: Date.now() - start,
|
|
112
|
+
success: false,
|
|
113
|
+
error: error.message
|
|
114
|
+
});
|
|
115
|
+
throw error;
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
});
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
// src/shared/utils/calculators/tax.ts
|
|
123
|
+
function calculateTax(amount, category, config) {
|
|
124
|
+
if (!config?.isRegistered || config.exemptCategories?.includes(category)) {
|
|
125
|
+
return {
|
|
126
|
+
isApplicable: false,
|
|
127
|
+
rate: 0,
|
|
128
|
+
baseAmount: amount,
|
|
129
|
+
taxAmount: 0,
|
|
130
|
+
totalAmount: amount,
|
|
131
|
+
pricesIncludeTax: false
|
|
132
|
+
};
|
|
133
|
+
}
|
|
134
|
+
const rate = config.defaultRate;
|
|
135
|
+
const [baseAmount, taxAmount, totalAmount] = config.pricesIncludeTax ? [
|
|
136
|
+
// Tax-inclusive: extract tax from total
|
|
137
|
+
Math.round(amount / (1 + rate)),
|
|
138
|
+
// baseAmount
|
|
139
|
+
Math.round(amount - amount / (1 + rate)),
|
|
140
|
+
// taxAmount
|
|
141
|
+
amount
|
|
142
|
+
// totalAmount (already integer)
|
|
143
|
+
] : [
|
|
144
|
+
// Tax-exclusive: add tax to base
|
|
145
|
+
amount,
|
|
146
|
+
// baseAmount (already integer)
|
|
147
|
+
Math.round(amount * rate),
|
|
148
|
+
// taxAmount
|
|
149
|
+
Math.round(amount * (1 + rate))
|
|
150
|
+
// totalAmount
|
|
151
|
+
];
|
|
152
|
+
return {
|
|
153
|
+
isApplicable: true,
|
|
154
|
+
rate,
|
|
155
|
+
baseAmount,
|
|
156
|
+
taxAmount,
|
|
157
|
+
totalAmount,
|
|
158
|
+
pricesIncludeTax: config.pricesIncludeTax
|
|
159
|
+
};
|
|
160
|
+
}
|
|
161
|
+
function getTaxType(transactionFlow, category, exemptCategories = []) {
|
|
162
|
+
if (exemptCategories.includes(category)) {
|
|
163
|
+
return "exempt";
|
|
164
|
+
}
|
|
165
|
+
return transactionFlow === "inflow" ? "collected" : "paid";
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
// src/enums/transaction.enums.ts
|
|
169
|
+
var TRANSACTION_FLOW = {
|
|
170
|
+
INFLOW: "inflow",
|
|
171
|
+
OUTFLOW: "outflow"
|
|
172
|
+
};
|
|
173
|
+
var TRANSACTION_FLOW_VALUES = Object.values(
|
|
174
|
+
TRANSACTION_FLOW
|
|
175
|
+
);
|
|
176
|
+
var TRANSACTION_STATUS = {
|
|
177
|
+
PENDING: "pending",
|
|
178
|
+
PAYMENT_INITIATED: "payment_initiated",
|
|
179
|
+
PROCESSING: "processing",
|
|
180
|
+
REQUIRES_ACTION: "requires_action",
|
|
181
|
+
VERIFIED: "verified",
|
|
182
|
+
COMPLETED: "completed",
|
|
183
|
+
FAILED: "failed",
|
|
184
|
+
CANCELLED: "cancelled",
|
|
185
|
+
EXPIRED: "expired",
|
|
186
|
+
REFUNDED: "refunded",
|
|
187
|
+
PARTIALLY_REFUNDED: "partially_refunded"
|
|
188
|
+
};
|
|
189
|
+
var TRANSACTION_STATUS_VALUES = Object.values(
|
|
190
|
+
TRANSACTION_STATUS
|
|
191
|
+
);
|
|
192
|
+
var LIBRARY_CATEGORIES = {
|
|
193
|
+
SUBSCRIPTION: "subscription",
|
|
194
|
+
PURCHASE: "purchase"
|
|
195
|
+
};
|
|
196
|
+
var LIBRARY_CATEGORY_VALUES = Object.values(
|
|
197
|
+
LIBRARY_CATEGORIES
|
|
198
|
+
);
|
|
199
|
+
new Set(TRANSACTION_FLOW_VALUES);
|
|
200
|
+
new Set(
|
|
201
|
+
TRANSACTION_STATUS_VALUES
|
|
202
|
+
);
|
|
203
|
+
new Set(LIBRARY_CATEGORY_VALUES);
|
|
204
|
+
|
|
205
|
+
// src/shared/utils/validators/category-resolver.ts
|
|
206
|
+
function resolveCategory(entity, monetizationType, categoryMappings = {}) {
|
|
207
|
+
if (entity && categoryMappings[entity]) {
|
|
208
|
+
return categoryMappings[entity];
|
|
209
|
+
}
|
|
210
|
+
switch (monetizationType) {
|
|
211
|
+
case "subscription":
|
|
212
|
+
return LIBRARY_CATEGORIES.SUBSCRIPTION;
|
|
213
|
+
// 'subscription'
|
|
214
|
+
case "purchase":
|
|
215
|
+
return LIBRARY_CATEGORIES.PURCHASE;
|
|
216
|
+
// 'purchase'
|
|
217
|
+
default:
|
|
218
|
+
return LIBRARY_CATEGORIES.SUBSCRIPTION;
|
|
219
|
+
}
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
// src/infrastructure/plugins/business/tax.plugin.ts
|
|
223
|
+
function createTaxPlugin(options) {
|
|
224
|
+
const {
|
|
225
|
+
getTaxConfig,
|
|
226
|
+
categoryMappings = {},
|
|
227
|
+
incomeCategories = ["subscription", "purchase", "course_enrollment", "product_order"]
|
|
228
|
+
} = options;
|
|
229
|
+
return definePlugin({
|
|
230
|
+
name: "tax",
|
|
231
|
+
version: "1.0.0",
|
|
232
|
+
description: "Automatic tax calculation for transactions",
|
|
233
|
+
hooks: {
|
|
234
|
+
/**
|
|
235
|
+
* Calculate tax before monetization creation
|
|
236
|
+
* Injects tax data into the input so it's saved with the transaction
|
|
237
|
+
*/
|
|
238
|
+
"monetization.create.before": async (ctx, input, next) => {
|
|
239
|
+
const orgId = input.data.organizationId;
|
|
240
|
+
if (!orgId) {
|
|
241
|
+
ctx.logger.debug("Tax plugin: No organizationId in input.data, skipping tax calculation");
|
|
242
|
+
return next();
|
|
243
|
+
}
|
|
244
|
+
try {
|
|
245
|
+
const config = await getTaxConfig(orgId);
|
|
246
|
+
if (!config) {
|
|
247
|
+
ctx.logger.debug("Tax plugin: No tax config for org", { orgId });
|
|
248
|
+
return next();
|
|
249
|
+
}
|
|
250
|
+
const category = resolveCategory(
|
|
251
|
+
input.entity,
|
|
252
|
+
input.monetizationType || "subscription",
|
|
253
|
+
categoryMappings
|
|
254
|
+
);
|
|
255
|
+
const transactionFlow = incomeCategories.includes(category) ? "inflow" : "outflow";
|
|
256
|
+
const taxCalc = calculateTax(input.amount, category, config);
|
|
257
|
+
const taxType = getTaxType(transactionFlow, category, config.exemptCategories);
|
|
258
|
+
input.tax = {
|
|
259
|
+
...taxCalc,
|
|
260
|
+
type: taxType
|
|
261
|
+
};
|
|
262
|
+
ctx.logger.debug("Tax plugin: Tax calculated", {
|
|
263
|
+
orgId,
|
|
264
|
+
category,
|
|
265
|
+
entity: input.entity,
|
|
266
|
+
monetizationType: input.monetizationType,
|
|
267
|
+
taxAmount: taxCalc.taxAmount,
|
|
268
|
+
type: taxType
|
|
269
|
+
});
|
|
270
|
+
} catch (error) {
|
|
271
|
+
ctx.logger.error("Tax plugin: Failed to calculate tax", {
|
|
272
|
+
orgId,
|
|
273
|
+
error: error.message
|
|
274
|
+
});
|
|
275
|
+
}
|
|
276
|
+
return next();
|
|
277
|
+
}
|
|
278
|
+
}
|
|
279
|
+
});
|
|
280
|
+
}
|
|
281
|
+
|
|
282
|
+
// src/infrastructure/plugins/index.ts
|
|
283
|
+
var plugins_default = {
|
|
284
|
+
loggingPlugin,
|
|
285
|
+
auditPlugin,
|
|
286
|
+
metricsPlugin,
|
|
287
|
+
createTaxPlugin
|
|
288
|
+
};
|
|
289
|
+
|
|
290
|
+
export { auditPlugin, createTaxPlugin, plugins_default as default, definePlugin, loggingPlugin, metricsPlugin };
|
|
291
|
+
//# sourceMappingURL=index.js.map
|
|
292
|
+
//# sourceMappingURL=index.js.map
|