@happyvertical/smrt-affiliates 0.37.1 → 0.37.3

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/dist/index.js CHANGED
@@ -1,1387 +1,1323 @@
1
- import { ObjectRegistry, crossPackageRef, foreignKey, smrt, SmrtObject, SmrtCollection } from "@happyvertical/smrt-core";
2
- ObjectRegistry.registerPackageManifest(
3
- new URL("./manifest.json", import.meta.url)
4
- );
1
+ import { ObjectRegistry, SmrtCollection, SmrtObject, crossPackageRef, foreignKey, smrt } from "@happyvertical/smrt-core";
2
+ //#region src/__smrt-register__.ts
3
+ ObjectRegistry.registerPackageManifest(new URL("./manifest.json", "" + import.meta.url));
4
+ //#endregion
5
+ //#region src/types/index.ts
5
6
  var PartnerType = /* @__PURE__ */ ((PartnerType2) => {
6
- PartnerType2["PUBLISHER"] = "publisher";
7
- PartnerType2["SALESPERSON"] = "salesperson";
8
- PartnerType2["REFERRER"] = "referrer";
9
- return PartnerType2;
7
+ PartnerType2["PUBLISHER"] = "publisher";
8
+ PartnerType2["SALESPERSON"] = "salesperson";
9
+ PartnerType2["REFERRER"] = "referrer";
10
+ return PartnerType2;
10
11
  })(PartnerType || {});
11
12
  var PartnerStatus = /* @__PURE__ */ ((PartnerStatus2) => {
12
- PartnerStatus2["PENDING"] = "pending";
13
- PartnerStatus2["ACTIVE"] = "active";
14
- PartnerStatus2["SUSPENDED"] = "suspended";
15
- return PartnerStatus2;
13
+ PartnerStatus2["PENDING"] = "pending";
14
+ PartnerStatus2["ACTIVE"] = "active";
15
+ PartnerStatus2["SUSPENDED"] = "suspended";
16
+ return PartnerStatus2;
16
17
  })(PartnerStatus || {});
17
18
  var CommissionType = /* @__PURE__ */ ((CommissionType2) => {
18
- CommissionType2["DISPLAY"] = "display";
19
- CommissionType2["REFERRAL"] = "referral";
20
- CommissionType2["SALES"] = "sales";
21
- CommissionType2["PARENT"] = "parent";
22
- CommissionType2["OVERHEAD"] = "overhead";
23
- return CommissionType2;
19
+ CommissionType2["DISPLAY"] = "display";
20
+ CommissionType2["REFERRAL"] = "referral";
21
+ CommissionType2["SALES"] = "sales";
22
+ CommissionType2["PARENT"] = "parent";
23
+ CommissionType2["OVERHEAD"] = "overhead";
24
+ return CommissionType2;
24
25
  })(CommissionType || {});
25
26
  var CommissionStatus = /* @__PURE__ */ ((CommissionStatus2) => {
26
- CommissionStatus2["PENDING"] = "pending";
27
- CommissionStatus2["INCLUDED"] = "included";
28
- CommissionStatus2["PAID"] = "paid";
29
- return CommissionStatus2;
27
+ CommissionStatus2["PENDING"] = "pending";
28
+ CommissionStatus2["INCLUDED"] = "included";
29
+ CommissionStatus2["PAID"] = "paid";
30
+ return CommissionStatus2;
30
31
  })(CommissionStatus || {});
31
32
  var PayoutStatus = /* @__PURE__ */ ((PayoutStatus2) => {
32
- PayoutStatus2["PENDING"] = "pending";
33
- PayoutStatus2["APPROVED"] = "approved";
34
- PayoutStatus2["PROCESSING"] = "processing";
35
- PayoutStatus2["COMPLETED"] = "completed";
36
- PayoutStatus2["FAILED"] = "failed";
37
- return PayoutStatus2;
33
+ PayoutStatus2["PENDING"] = "pending";
34
+ PayoutStatus2["APPROVED"] = "approved";
35
+ PayoutStatus2["PROCESSING"] = "processing";
36
+ PayoutStatus2["COMPLETED"] = "completed";
37
+ PayoutStatus2["FAILED"] = "failed";
38
+ return PayoutStatus2;
38
39
  })(PayoutStatus || {});
39
40
  var PayoutMethod = /* @__PURE__ */ ((PayoutMethod2) => {
40
- PayoutMethod2["BANK_TRANSFER"] = "bank_transfer";
41
- PayoutMethod2["CHECK"] = "check";
42
- PayoutMethod2["PAYPAL"] = "paypal";
43
- PayoutMethod2["CREDIT"] = "credit";
44
- return PayoutMethod2;
41
+ PayoutMethod2["BANK_TRANSFER"] = "bank_transfer";
42
+ PayoutMethod2["CHECK"] = "check";
43
+ PayoutMethod2["PAYPAL"] = "paypal";
44
+ PayoutMethod2["CREDIT"] = "credit";
45
+ return PayoutMethod2;
45
46
  })(PayoutMethod || {});
47
+ //#endregion
48
+ //#region src/models/Commission.ts
46
49
  var __defProp$2 = Object.defineProperty;
47
50
  var __getOwnPropDesc$2 = Object.getOwnPropertyDescriptor;
48
51
  var __decorateClass$2 = (decorators, target, key, kind) => {
49
- var result = kind > 1 ? void 0 : kind ? __getOwnPropDesc$2(target, key) : target;
50
- for (var i = decorators.length - 1, decorator; i >= 0; i--)
51
- if (decorator = decorators[i])
52
- result = (kind ? decorator(target, key, result) : decorator(result)) || result;
53
- if (kind && result) __defProp$2(target, key, result);
54
- return result;
52
+ var result = kind > 1 ? void 0 : kind ? __getOwnPropDesc$2(target, key) : target;
53
+ for (var i = decorators.length - 1, decorator; i >= 0; i--) if (decorator = decorators[i]) result = (kind ? decorator(target, key, result) : decorator(result)) || result;
54
+ if (kind && result) __defProp$2(target, key, result);
55
+ return result;
55
56
  };
56
- let Commission = class extends SmrtObject {
57
- /**
58
- * Calculate commission amount from gross revenue and rate
59
- *
60
- * @param grossRevenue - Gross revenue in cents
61
- * @param rate - Commission rate (0-1)
62
- * @returns Commission amount in cents (rounded)
63
- *
64
- * @example
65
- * ```typescript
66
- * const amount = Commission.calculateAmount(1000, 0.50); // 500 cents
67
- * ```
68
- */
69
- static calculateAmount(grossRevenue, rate) {
70
- return Math.round(grossRevenue * rate);
71
- }
72
- eventId = "";
73
- partnerId = "";
74
- /**
75
- * Commission type (display, referral, sales, parent)
76
- */
77
- commissionType = CommissionType.DISPLAY;
78
- /**
79
- * Gross revenue from the event in cents
80
- * This is the total ad revenue before commission split
81
- */
82
- grossRevenue = 0;
83
- /**
84
- * Commission rate applied (0-1)
85
- * Copied from partner at time of event for audit trail
86
- */
87
- commissionRate = 0;
88
- /**
89
- * Calculated commission amount in cents
90
- * = grossRevenue * commissionRate
91
- */
92
- commissionAmount = 0;
93
- /**
94
- * Currency code
95
- * Defaults to CAD
96
- */
97
- currency = "CAD";
98
- payoutId = "";
99
- /**
100
- * Commission status
101
- */
102
- status = CommissionStatus.PENDING;
103
- /**
104
- * Event timestamp (copied from AdEvent for reporting)
105
- */
106
- eventTimestamp = /* @__PURE__ */ new Date();
107
- /**
108
- * Network ID for aggregate queries (optional context)
109
- */
110
- networkId = "";
111
- /**
112
- * Site/Property ID for aggregate queries (optional context)
113
- */
114
- siteId = "";
115
- /**
116
- * Campaign ID for aggregate queries (optional context)
117
- */
118
- campaignId = "";
119
- /**
120
- * Additional metadata as JSON string
121
- */
122
- metadata = "";
123
- constructor(options = {}) {
124
- super(options);
125
- if (options.eventId !== void 0) this.eventId = options.eventId;
126
- if (options.partnerId !== void 0) this.partnerId = options.partnerId;
127
- if (options.commissionType !== void 0)
128
- this.commissionType = options.commissionType;
129
- if (options.grossRevenue !== void 0)
130
- this.grossRevenue = options.grossRevenue;
131
- if (options.commissionRate !== void 0)
132
- this.commissionRate = options.commissionRate;
133
- if (options.commissionAmount !== void 0)
134
- this.commissionAmount = options.commissionAmount;
135
- if (options.currency !== void 0) this.currency = options.currency;
136
- if (options.payoutId !== void 0) this.payoutId = options.payoutId;
137
- if (options.status !== void 0) this.status = options.status;
138
- if (options.eventTimestamp !== void 0)
139
- this.eventTimestamp = options.eventTimestamp;
140
- if (options.networkId !== void 0) this.networkId = options.networkId;
141
- if (options.siteId !== void 0) this.siteId = options.siteId;
142
- if (options.campaignId !== void 0) this.campaignId = options.campaignId;
143
- if (options.metadata !== void 0) this.metadata = options.metadata;
144
- }
145
- /**
146
- * Check if commission is pending (not yet in a payout)
147
- */
148
- isPending() {
149
- return this.status === CommissionStatus.PENDING;
150
- }
151
- /**
152
- * Check if commission is included in a payout
153
- */
154
- isIncluded() {
155
- return this.status === CommissionStatus.INCLUDED;
156
- }
157
- /**
158
- * Check if commission has been paid
159
- */
160
- isPaid() {
161
- return this.status === CommissionStatus.PAID;
162
- }
163
- /**
164
- * Check if this is a display commission
165
- */
166
- isDisplay() {
167
- return this.commissionType === CommissionType.DISPLAY;
168
- }
169
- /**
170
- * Check if this is a referral commission
171
- */
172
- isReferral() {
173
- return this.commissionType === CommissionType.REFERRAL;
174
- }
175
- /**
176
- * Check if this is a sales commission
177
- */
178
- isSales() {
179
- return this.commissionType === CommissionType.SALES;
180
- }
181
- /**
182
- * Check if this is a parent commission
183
- */
184
- isParent() {
185
- return this.commissionType === CommissionType.PARENT;
186
- }
187
- /**
188
- * Check if this is an overhead commission
189
- */
190
- isOverhead() {
191
- return this.commissionType === CommissionType.OVERHEAD;
192
- }
193
- /**
194
- * Get commission amount in dollars (for display)
195
- */
196
- getAmountInDollars() {
197
- return this.commissionAmount / 100;
198
- }
199
- /**
200
- * Get gross revenue in dollars (for display)
201
- */
202
- getGrossRevenueInDollars() {
203
- return this.grossRevenue / 100;
204
- }
205
- /**
206
- * Get metadata as object
207
- */
208
- getMetadata() {
209
- if (!this.metadata) return {};
210
- try {
211
- return JSON.parse(this.metadata);
212
- } catch {
213
- return {};
214
- }
215
- }
216
- /**
217
- * Set metadata from object
218
- */
219
- setMetadata(data) {
220
- this.metadata = JSON.stringify(data);
221
- }
57
+ var Commission = class extends SmrtObject {
58
+ /**
59
+ * Calculate commission amount from gross revenue and rate
60
+ *
61
+ * @param grossRevenue - Gross revenue in cents
62
+ * @param rate - Commission rate (0-1)
63
+ * @returns Commission amount in cents (rounded)
64
+ *
65
+ * @example
66
+ * ```typescript
67
+ * const amount = Commission.calculateAmount(1000, 0.50); // 500 cents
68
+ * ```
69
+ */
70
+ static calculateAmount(grossRevenue, rate) {
71
+ return Math.round(grossRevenue * rate);
72
+ }
73
+ eventId = "";
74
+ partnerId = "";
75
+ /**
76
+ * Commission type (display, referral, sales, parent)
77
+ */
78
+ commissionType = CommissionType.DISPLAY;
79
+ /**
80
+ * Gross revenue from the event in cents
81
+ * This is the total ad revenue before commission split
82
+ */
83
+ grossRevenue = 0;
84
+ /**
85
+ * Commission rate applied (0-1)
86
+ * Copied from partner at time of event for audit trail
87
+ */
88
+ commissionRate = 0;
89
+ /**
90
+ * Calculated commission amount in cents
91
+ * = grossRevenue * commissionRate
92
+ */
93
+ commissionAmount = 0;
94
+ /**
95
+ * Currency code
96
+ * Defaults to CAD
97
+ */
98
+ currency = "CAD";
99
+ payoutId = "";
100
+ /**
101
+ * Commission status
102
+ */
103
+ status = CommissionStatus.PENDING;
104
+ /**
105
+ * Event timestamp (copied from AdEvent for reporting)
106
+ */
107
+ eventTimestamp = /* @__PURE__ */ new Date();
108
+ /**
109
+ * Network ID for aggregate queries (optional context)
110
+ */
111
+ networkId = "";
112
+ /**
113
+ * Site/Property ID for aggregate queries (optional context)
114
+ */
115
+ siteId = "";
116
+ /**
117
+ * Campaign ID for aggregate queries (optional context)
118
+ */
119
+ campaignId = "";
120
+ /**
121
+ * Additional metadata as JSON string
122
+ */
123
+ metadata = "";
124
+ constructor(options = {}) {
125
+ super(options);
126
+ if (options.eventId !== void 0) this.eventId = options.eventId;
127
+ if (options.partnerId !== void 0) this.partnerId = options.partnerId;
128
+ if (options.commissionType !== void 0) this.commissionType = options.commissionType;
129
+ if (options.grossRevenue !== void 0) this.grossRevenue = options.grossRevenue;
130
+ if (options.commissionRate !== void 0) this.commissionRate = options.commissionRate;
131
+ if (options.commissionAmount !== void 0) this.commissionAmount = options.commissionAmount;
132
+ if (options.currency !== void 0) this.currency = options.currency;
133
+ if (options.payoutId !== void 0) this.payoutId = options.payoutId;
134
+ if (options.status !== void 0) this.status = options.status;
135
+ if (options.eventTimestamp !== void 0) this.eventTimestamp = options.eventTimestamp;
136
+ if (options.networkId !== void 0) this.networkId = options.networkId;
137
+ if (options.siteId !== void 0) this.siteId = options.siteId;
138
+ if (options.campaignId !== void 0) this.campaignId = options.campaignId;
139
+ if (options.metadata !== void 0) this.metadata = options.metadata;
140
+ }
141
+ /**
142
+ * Check if commission is pending (not yet in a payout)
143
+ */
144
+ isPending() {
145
+ return this.status === CommissionStatus.PENDING;
146
+ }
147
+ /**
148
+ * Check if commission is included in a payout
149
+ */
150
+ isIncluded() {
151
+ return this.status === CommissionStatus.INCLUDED;
152
+ }
153
+ /**
154
+ * Check if commission has been paid
155
+ */
156
+ isPaid() {
157
+ return this.status === CommissionStatus.PAID;
158
+ }
159
+ /**
160
+ * Check if this is a display commission
161
+ */
162
+ isDisplay() {
163
+ return this.commissionType === CommissionType.DISPLAY;
164
+ }
165
+ /**
166
+ * Check if this is a referral commission
167
+ */
168
+ isReferral() {
169
+ return this.commissionType === CommissionType.REFERRAL;
170
+ }
171
+ /**
172
+ * Check if this is a sales commission
173
+ */
174
+ isSales() {
175
+ return this.commissionType === CommissionType.SALES;
176
+ }
177
+ /**
178
+ * Check if this is a parent commission
179
+ */
180
+ isParent() {
181
+ return this.commissionType === CommissionType.PARENT;
182
+ }
183
+ /**
184
+ * Check if this is an overhead commission
185
+ */
186
+ isOverhead() {
187
+ return this.commissionType === CommissionType.OVERHEAD;
188
+ }
189
+ /**
190
+ * Get commission amount in dollars (for display)
191
+ */
192
+ getAmountInDollars() {
193
+ return this.commissionAmount / 100;
194
+ }
195
+ /**
196
+ * Get gross revenue in dollars (for display)
197
+ */
198
+ getGrossRevenueInDollars() {
199
+ return this.grossRevenue / 100;
200
+ }
201
+ /**
202
+ * Get metadata as object
203
+ */
204
+ getMetadata() {
205
+ if (!this.metadata) return {};
206
+ try {
207
+ return JSON.parse(this.metadata);
208
+ } catch {
209
+ return {};
210
+ }
211
+ }
212
+ /**
213
+ * Set metadata from object
214
+ */
215
+ setMetadata(data) {
216
+ this.metadata = JSON.stringify(data);
217
+ }
222
218
  };
223
- __decorateClass$2([
224
- crossPackageRef("@happyvertical/smrt-ads:AdEvent")
225
- ], Commission.prototype, "eventId", 2);
226
- __decorateClass$2([
227
- foreignKey("Partner")
228
- ], Commission.prototype, "partnerId", 2);
229
- __decorateClass$2([
230
- foreignKey("Payout")
231
- ], Commission.prototype, "payoutId", 2);
232
- Commission = __decorateClass$2([
233
- smrt({
234
- api: { include: ["create", "list", "get"] },
235
- // No delete (audit trail)
236
- mcp: { include: ["create", "list"] },
237
- cli: false
238
- // High volume, not useful in CLI
239
- })
240
- ], Commission);
241
- class CommissionCollection extends SmrtCollection {
242
- static _itemClass = Commission;
243
- /**
244
- * Find commissions by partner
245
- *
246
- * @param partnerId - Partner ID
247
- * @returns Array of commissions
248
- */
249
- async findByPartner(partnerId) {
250
- return await this.list({
251
- where: { partnerId },
252
- orderBy: "event_timestamp DESC"
253
- });
254
- }
255
- /**
256
- * Find commissions by ad event
257
- *
258
- * @param eventId - Ad Event ID
259
- * @returns Array of commissions
260
- */
261
- async findByEvent(eventId) {
262
- return await this.list({
263
- where: { eventId },
264
- orderBy: "created_at DESC"
265
- });
266
- }
267
- /**
268
- * Find commissions by payout
269
- *
270
- * @param payoutId - Payout ID
271
- * @returns Array of commissions
272
- */
273
- async findByPayout(payoutId) {
274
- return await this.list({
275
- where: { payoutId },
276
- orderBy: "event_timestamp DESC"
277
- });
278
- }
279
- /**
280
- * Find commissions by status
281
- *
282
- * @param status - Commission status
283
- * @returns Array of commissions
284
- */
285
- async findByStatus(status) {
286
- return await this.list({
287
- where: { status },
288
- orderBy: "event_timestamp DESC"
289
- });
290
- }
291
- /**
292
- * Find all pending commissions
293
- */
294
- async findPending() {
295
- return await this.findByStatus(CommissionStatus.PENDING);
296
- }
297
- /**
298
- * Find pending commissions for a partner
299
- *
300
- * @param partnerId - Partner ID
301
- * @returns Array of pending commissions
302
- */
303
- async findPendingByPartner(partnerId) {
304
- return await this.list({
305
- where: { partnerId, status: CommissionStatus.PENDING },
306
- orderBy: "event_timestamp DESC"
307
- });
308
- }
309
- /**
310
- * Find commissions by type
311
- *
312
- * @param commissionType - Commission type
313
- * @returns Array of commissions
314
- */
315
- async findByType(commissionType) {
316
- return await this.list({
317
- where: { commissionType },
318
- orderBy: "event_timestamp DESC"
319
- });
320
- }
321
- /**
322
- * Find commissions in date range
323
- *
324
- * @param start - Start date
325
- * @param end - End date
326
- * @returns Array of commissions
327
- */
328
- async findByDateRange(start, end) {
329
- return await this.list({
330
- where: {
331
- "event_timestamp >=": start.toISOString(),
332
- "event_timestamp <=": end.toISOString()
333
- },
334
- orderBy: "event_timestamp DESC"
335
- });
336
- }
337
- /**
338
- * Find commissions for a partner in date range
339
- *
340
- * @param partnerId - Partner ID
341
- * @param start - Start date
342
- * @param end - End date
343
- * @returns Array of commissions
344
- */
345
- async findByPartnerAndDateRange(partnerId, start, end) {
346
- return await this.list({
347
- where: {
348
- partnerId,
349
- "event_timestamp >=": start.toISOString(),
350
- "event_timestamp <=": end.toISOString()
351
- },
352
- orderBy: "event_timestamp DESC"
353
- });
354
- }
355
- // --- Network-scoped queries ---
356
- /**
357
- * Find all commissions for a network
358
- *
359
- * @param networkId - Network ID
360
- * @returns Array of commissions
361
- */
362
- async findByNetwork(networkId) {
363
- return await this.list({
364
- where: { networkId },
365
- orderBy: "event_timestamp DESC"
366
- });
367
- }
368
- /**
369
- * Find commissions for a network filtered by type
370
- *
371
- * @param networkId - Network ID
372
- * @param commissionType - Commission type
373
- * @returns Array of commissions
374
- */
375
- async findByNetworkAndType(networkId, commissionType) {
376
- return await this.list({
377
- where: { networkId, commissionType },
378
- orderBy: "event_timestamp DESC"
379
- });
380
- }
381
- /**
382
- * Find pending commissions for a network
383
- *
384
- * @param networkId - Network ID
385
- * @returns Array of pending commissions
386
- */
387
- async findPendingByNetwork(networkId) {
388
- return await this.list({
389
- where: { networkId, status: CommissionStatus.PENDING },
390
- orderBy: "event_timestamp DESC"
391
- });
392
- }
393
- /**
394
- * Get aggregate summary of commissions by type and site for a network.
395
- *
396
- * @param networkId - Network ID
397
- * @param options - Optional filters (siteId, from, to, commissionType)
398
- * @returns Summary with byType, bySite, total, and count
399
- */
400
- async getSummaryByNetwork(networkId, options = {}) {
401
- const where = { networkId };
402
- if (options.siteId) where.siteId = options.siteId;
403
- if (options.commissionType) where.commissionType = options.commissionType;
404
- if (options.from) where["event_timestamp >="] = options.from.toISOString();
405
- if (options.to) where["event_timestamp <="] = options.to.toISOString();
406
- const filtered = await this.list({ where });
407
- const byType = {
408
- overhead: 0,
409
- display: 0,
410
- referral: 0,
411
- sales: 0,
412
- parent: 0
413
- };
414
- const bySite = {};
415
- let total = 0;
416
- for (const c of filtered) {
417
- byType[c.commissionType] = (byType[c.commissionType] ?? 0) + c.commissionAmount;
418
- if (c.siteId) {
419
- bySite[c.siteId] = (bySite[c.siteId] ?? 0) + c.commissionAmount;
420
- }
421
- total += c.commissionAmount;
422
- }
423
- return { byType, bySite, total, count: filtered.length };
424
- }
425
- /**
426
- * Get pending commissions grouped by partnerId for a network.
427
- *
428
- * @param networkId - Network ID
429
- * @returns Array of payout groups (partnerId, totalPending, currency, entries)
430
- */
431
- async getPendingPayoutsByNetwork(networkId) {
432
- const pending = await this.findPendingByNetwork(networkId);
433
- const withPartner = pending.filter(
434
- (c) => c.partnerId && c.partnerId !== ""
435
- );
436
- const grouped = /* @__PURE__ */ new Map();
437
- for (const c of withPartner) {
438
- const existing = grouped.get(c.partnerId) ?? [];
439
- existing.push(c);
440
- grouped.set(c.partnerId, existing);
441
- }
442
- const payouts = [];
443
- for (const [partnerId, group] of grouped) {
444
- const totalPending = group.reduce(
445
- (sum, c) => sum + c.commissionAmount,
446
- 0
447
- );
448
- const currency = group[0]?.currency ?? "CAD";
449
- payouts.push({
450
- partnerId,
451
- totalPending,
452
- currency,
453
- entryCount: group.length,
454
- entries: group.map((c) => ({
455
- id: c.id ?? "",
456
- commissionType: c.commissionType,
457
- commissionAmount: c.commissionAmount,
458
- campaignId: c.campaignId,
459
- siteId: c.siteId
460
- }))
461
- });
462
- }
463
- payouts.sort((a, b) => b.totalPending - a.totalPending);
464
- return payouts;
465
- }
466
- // --- Aggregation queries ---
467
- /**
468
- * Sum pending commissions for a partner
469
- *
470
- * @param partnerId - Partner ID
471
- * @returns Total pending amount in cents
472
- */
473
- async sumPendingByPartner(partnerId) {
474
- const pending = await this.findPendingByPartner(partnerId);
475
- return pending.reduce((sum, c) => sum + c.commissionAmount, 0);
476
- }
477
- /**
478
- * Sum commissions by type for a partner
479
- *
480
- * @param partnerId - Partner ID
481
- * @param commissionType - Commission type
482
- * @returns Total amount in cents
483
- */
484
- async sumByPartnerAndType(partnerId, commissionType) {
485
- const commissions = await this.list({
486
- where: { partnerId, commissionType }
487
- });
488
- return commissions.reduce((sum, c) => sum + c.commissionAmount, 0);
489
- }
490
- /**
491
- * Get earnings breakdown for a partner
492
- *
493
- * @param partnerId - Partner ID
494
- * @returns Breakdown by commission type
495
- */
496
- async getEarningsBreakdown(partnerId) {
497
- const commissions = await this.findByPartner(partnerId);
498
- const breakdown = {
499
- display: 0,
500
- referral: 0,
501
- sales: 0,
502
- parent: 0,
503
- overhead: 0,
504
- total: 0
505
- };
506
- for (const c of commissions) {
507
- if (c.isPaid() || c.isIncluded()) {
508
- switch (c.commissionType) {
509
- case CommissionType.DISPLAY:
510
- breakdown.display += c.commissionAmount;
511
- break;
512
- case CommissionType.REFERRAL:
513
- breakdown.referral += c.commissionAmount;
514
- break;
515
- case CommissionType.SALES:
516
- breakdown.sales += c.commissionAmount;
517
- break;
518
- case CommissionType.PARENT:
519
- breakdown.parent += c.commissionAmount;
520
- break;
521
- case CommissionType.OVERHEAD:
522
- breakdown.overhead += c.commissionAmount;
523
- break;
524
- }
525
- }
526
- }
527
- breakdown.total = breakdown.display + breakdown.referral + breakdown.sales + breakdown.parent + breakdown.overhead;
528
- return breakdown;
529
- }
530
- /**
531
- * Get pending earnings breakdown for a partner
532
- *
533
- * @param partnerId - Partner ID
534
- * @returns Breakdown of pending commissions by type
535
- */
536
- async getPendingBreakdown(partnerId) {
537
- const pending = await this.findPendingByPartner(partnerId);
538
- const breakdown = {
539
- display: 0,
540
- referral: 0,
541
- sales: 0,
542
- parent: 0,
543
- overhead: 0,
544
- total: 0
545
- };
546
- for (const c of pending) {
547
- switch (c.commissionType) {
548
- case CommissionType.DISPLAY:
549
- breakdown.display += c.commissionAmount;
550
- break;
551
- case CommissionType.REFERRAL:
552
- breakdown.referral += c.commissionAmount;
553
- break;
554
- case CommissionType.SALES:
555
- breakdown.sales += c.commissionAmount;
556
- break;
557
- case CommissionType.PARENT:
558
- breakdown.parent += c.commissionAmount;
559
- break;
560
- case CommissionType.OVERHEAD:
561
- breakdown.overhead += c.commissionAmount;
562
- break;
563
- }
564
- }
565
- breakdown.total = breakdown.display + breakdown.referral + breakdown.sales + breakdown.parent + breakdown.overhead;
566
- return breakdown;
567
- }
568
- }
219
+ __decorateClass$2([crossPackageRef("@happyvertical/smrt-ads:AdEvent")], Commission.prototype, "eventId", 2);
220
+ __decorateClass$2([foreignKey("Partner")], Commission.prototype, "partnerId", 2);
221
+ __decorateClass$2([foreignKey("Payout")], Commission.prototype, "payoutId", 2);
222
+ Commission = __decorateClass$2([smrt({
223
+ api: { include: [
224
+ "create",
225
+ "list",
226
+ "get"
227
+ ] },
228
+ mcp: { include: ["create", "list"] },
229
+ cli: false
230
+ })], Commission);
231
+ //#endregion
232
+ //#region src/collections/CommissionCollection.ts
233
+ var CommissionCollection = class extends SmrtCollection {
234
+ static _itemClass = Commission;
235
+ /**
236
+ * Find commissions by partner
237
+ *
238
+ * @param partnerId - Partner ID
239
+ * @returns Array of commissions
240
+ */
241
+ async findByPartner(partnerId) {
242
+ return await this.list({
243
+ where: { partnerId },
244
+ orderBy: "event_timestamp DESC"
245
+ });
246
+ }
247
+ /**
248
+ * Find commissions by ad event
249
+ *
250
+ * @param eventId - Ad Event ID
251
+ * @returns Array of commissions
252
+ */
253
+ async findByEvent(eventId) {
254
+ return await this.list({
255
+ where: { eventId },
256
+ orderBy: "created_at DESC"
257
+ });
258
+ }
259
+ /**
260
+ * Find commissions by payout
261
+ *
262
+ * @param payoutId - Payout ID
263
+ * @returns Array of commissions
264
+ */
265
+ async findByPayout(payoutId) {
266
+ return await this.list({
267
+ where: { payoutId },
268
+ orderBy: "event_timestamp DESC"
269
+ });
270
+ }
271
+ /**
272
+ * Find commissions by status
273
+ *
274
+ * @param status - Commission status
275
+ * @returns Array of commissions
276
+ */
277
+ async findByStatus(status) {
278
+ return await this.list({
279
+ where: { status },
280
+ orderBy: "event_timestamp DESC"
281
+ });
282
+ }
283
+ /**
284
+ * Find all pending commissions
285
+ */
286
+ async findPending() {
287
+ return await this.findByStatus(CommissionStatus.PENDING);
288
+ }
289
+ /**
290
+ * Find pending commissions for a partner
291
+ *
292
+ * @param partnerId - Partner ID
293
+ * @returns Array of pending commissions
294
+ */
295
+ async findPendingByPartner(partnerId) {
296
+ return await this.list({
297
+ where: {
298
+ partnerId,
299
+ status: CommissionStatus.PENDING
300
+ },
301
+ orderBy: "event_timestamp DESC"
302
+ });
303
+ }
304
+ /**
305
+ * Find commissions by type
306
+ *
307
+ * @param commissionType - Commission type
308
+ * @returns Array of commissions
309
+ */
310
+ async findByType(commissionType) {
311
+ return await this.list({
312
+ where: { commissionType },
313
+ orderBy: "event_timestamp DESC"
314
+ });
315
+ }
316
+ /**
317
+ * Find commissions in date range
318
+ *
319
+ * @param start - Start date
320
+ * @param end - End date
321
+ * @returns Array of commissions
322
+ */
323
+ async findByDateRange(start, end) {
324
+ return await this.list({
325
+ where: {
326
+ "event_timestamp >=": start.toISOString(),
327
+ "event_timestamp <=": end.toISOString()
328
+ },
329
+ orderBy: "event_timestamp DESC"
330
+ });
331
+ }
332
+ /**
333
+ * Find commissions for a partner in date range
334
+ *
335
+ * @param partnerId - Partner ID
336
+ * @param start - Start date
337
+ * @param end - End date
338
+ * @returns Array of commissions
339
+ */
340
+ async findByPartnerAndDateRange(partnerId, start, end) {
341
+ return await this.list({
342
+ where: {
343
+ partnerId,
344
+ "event_timestamp >=": start.toISOString(),
345
+ "event_timestamp <=": end.toISOString()
346
+ },
347
+ orderBy: "event_timestamp DESC"
348
+ });
349
+ }
350
+ /**
351
+ * Find all commissions for a network
352
+ *
353
+ * @param networkId - Network ID
354
+ * @returns Array of commissions
355
+ */
356
+ async findByNetwork(networkId) {
357
+ return await this.list({
358
+ where: { networkId },
359
+ orderBy: "event_timestamp DESC"
360
+ });
361
+ }
362
+ /**
363
+ * Find commissions for a network filtered by type
364
+ *
365
+ * @param networkId - Network ID
366
+ * @param commissionType - Commission type
367
+ * @returns Array of commissions
368
+ */
369
+ async findByNetworkAndType(networkId, commissionType) {
370
+ return await this.list({
371
+ where: {
372
+ networkId,
373
+ commissionType
374
+ },
375
+ orderBy: "event_timestamp DESC"
376
+ });
377
+ }
378
+ /**
379
+ * Find pending commissions for a network
380
+ *
381
+ * @param networkId - Network ID
382
+ * @returns Array of pending commissions
383
+ */
384
+ async findPendingByNetwork(networkId) {
385
+ return await this.list({
386
+ where: {
387
+ networkId,
388
+ status: CommissionStatus.PENDING
389
+ },
390
+ orderBy: "event_timestamp DESC"
391
+ });
392
+ }
393
+ /**
394
+ * Get aggregate summary of commissions by type and site for a network.
395
+ *
396
+ * @param networkId - Network ID
397
+ * @param options - Optional filters (siteId, from, to, commissionType)
398
+ * @returns Summary with byType, bySite, total, and count
399
+ */
400
+ async getSummaryByNetwork(networkId, options = {}) {
401
+ const where = { networkId };
402
+ if (options.siteId) where.siteId = options.siteId;
403
+ if (options.commissionType) where.commissionType = options.commissionType;
404
+ if (options.from) where["event_timestamp >="] = options.from.toISOString();
405
+ if (options.to) where["event_timestamp <="] = options.to.toISOString();
406
+ const filtered = await this.list({ where });
407
+ const byType = {
408
+ overhead: 0,
409
+ display: 0,
410
+ referral: 0,
411
+ sales: 0,
412
+ parent: 0
413
+ };
414
+ const bySite = {};
415
+ let total = 0;
416
+ for (const c of filtered) {
417
+ byType[c.commissionType] = (byType[c.commissionType] ?? 0) + c.commissionAmount;
418
+ if (c.siteId) bySite[c.siteId] = (bySite[c.siteId] ?? 0) + c.commissionAmount;
419
+ total += c.commissionAmount;
420
+ }
421
+ return {
422
+ byType,
423
+ bySite,
424
+ total,
425
+ count: filtered.length
426
+ };
427
+ }
428
+ /**
429
+ * Get pending commissions grouped by partnerId for a network.
430
+ *
431
+ * @param networkId - Network ID
432
+ * @returns Array of payout groups (partnerId, totalPending, currency, entries)
433
+ */
434
+ async getPendingPayoutsByNetwork(networkId) {
435
+ const withPartner = (await this.findPendingByNetwork(networkId)).filter((c) => c.partnerId && c.partnerId !== "");
436
+ const grouped = /* @__PURE__ */ new Map();
437
+ for (const c of withPartner) {
438
+ const existing = grouped.get(c.partnerId) ?? [];
439
+ existing.push(c);
440
+ grouped.set(c.partnerId, existing);
441
+ }
442
+ const payouts = [];
443
+ for (const [partnerId, group] of grouped) {
444
+ const totalPending = group.reduce((sum, c) => sum + c.commissionAmount, 0);
445
+ const currency = group[0]?.currency ?? "CAD";
446
+ payouts.push({
447
+ partnerId,
448
+ totalPending,
449
+ currency,
450
+ entryCount: group.length,
451
+ entries: group.map((c) => ({
452
+ id: c.id ?? "",
453
+ commissionType: c.commissionType,
454
+ commissionAmount: c.commissionAmount,
455
+ campaignId: c.campaignId,
456
+ siteId: c.siteId
457
+ }))
458
+ });
459
+ }
460
+ payouts.sort((a, b) => b.totalPending - a.totalPending);
461
+ return payouts;
462
+ }
463
+ /**
464
+ * Sum pending commissions for a partner
465
+ *
466
+ * @param partnerId - Partner ID
467
+ * @returns Total pending amount in cents
468
+ */
469
+ async sumPendingByPartner(partnerId) {
470
+ return (await this.findPendingByPartner(partnerId)).reduce((sum, c) => sum + c.commissionAmount, 0);
471
+ }
472
+ /**
473
+ * Sum commissions by type for a partner
474
+ *
475
+ * @param partnerId - Partner ID
476
+ * @param commissionType - Commission type
477
+ * @returns Total amount in cents
478
+ */
479
+ async sumByPartnerAndType(partnerId, commissionType) {
480
+ return (await this.list({ where: {
481
+ partnerId,
482
+ commissionType
483
+ } })).reduce((sum, c) => sum + c.commissionAmount, 0);
484
+ }
485
+ /**
486
+ * Get earnings breakdown for a partner
487
+ *
488
+ * @param partnerId - Partner ID
489
+ * @returns Breakdown by commission type
490
+ */
491
+ async getEarningsBreakdown(partnerId) {
492
+ const commissions = await this.findByPartner(partnerId);
493
+ const breakdown = {
494
+ display: 0,
495
+ referral: 0,
496
+ sales: 0,
497
+ parent: 0,
498
+ overhead: 0,
499
+ total: 0
500
+ };
501
+ for (const c of commissions) if (c.isPaid() || c.isIncluded()) switch (c.commissionType) {
502
+ case CommissionType.DISPLAY:
503
+ breakdown.display += c.commissionAmount;
504
+ break;
505
+ case CommissionType.REFERRAL:
506
+ breakdown.referral += c.commissionAmount;
507
+ break;
508
+ case CommissionType.SALES:
509
+ breakdown.sales += c.commissionAmount;
510
+ break;
511
+ case CommissionType.PARENT:
512
+ breakdown.parent += c.commissionAmount;
513
+ break;
514
+ case CommissionType.OVERHEAD:
515
+ breakdown.overhead += c.commissionAmount;
516
+ break;
517
+ }
518
+ breakdown.total = breakdown.display + breakdown.referral + breakdown.sales + breakdown.parent + breakdown.overhead;
519
+ return breakdown;
520
+ }
521
+ /**
522
+ * Get pending earnings breakdown for a partner
523
+ *
524
+ * @param partnerId - Partner ID
525
+ * @returns Breakdown of pending commissions by type
526
+ */
527
+ async getPendingBreakdown(partnerId) {
528
+ const pending = await this.findPendingByPartner(partnerId);
529
+ const breakdown = {
530
+ display: 0,
531
+ referral: 0,
532
+ sales: 0,
533
+ parent: 0,
534
+ overhead: 0,
535
+ total: 0
536
+ };
537
+ for (const c of pending) switch (c.commissionType) {
538
+ case CommissionType.DISPLAY:
539
+ breakdown.display += c.commissionAmount;
540
+ break;
541
+ case CommissionType.REFERRAL:
542
+ breakdown.referral += c.commissionAmount;
543
+ break;
544
+ case CommissionType.SALES:
545
+ breakdown.sales += c.commissionAmount;
546
+ break;
547
+ case CommissionType.PARENT:
548
+ breakdown.parent += c.commissionAmount;
549
+ break;
550
+ case CommissionType.OVERHEAD:
551
+ breakdown.overhead += c.commissionAmount;
552
+ break;
553
+ }
554
+ breakdown.total = breakdown.display + breakdown.referral + breakdown.sales + breakdown.parent + breakdown.overhead;
555
+ return breakdown;
556
+ }
557
+ };
558
+ //#endregion
559
+ //#region src/models/Partner.ts
569
560
  var __defProp$1 = Object.defineProperty;
570
561
  var __getOwnPropDesc$1 = Object.getOwnPropertyDescriptor;
571
562
  var __decorateClass$1 = (decorators, target, key, kind) => {
572
- var result = kind > 1 ? void 0 : kind ? __getOwnPropDesc$1(target, key) : target;
573
- for (var i = decorators.length - 1, decorator; i >= 0; i--)
574
- if (decorator = decorators[i])
575
- result = (kind ? decorator(target, key, result) : decorator(result)) || result;
576
- if (kind && result) __defProp$1(target, key, result);
577
- return result;
563
+ var result = kind > 1 ? void 0 : kind ? __getOwnPropDesc$1(target, key) : target;
564
+ for (var i = decorators.length - 1, decorator; i >= 0; i--) if (decorator = decorators[i]) result = (kind ? decorator(target, key, result) : decorator(result)) || result;
565
+ if (kind && result) __defProp$1(target, key, result);
566
+ return result;
567
+ };
568
+ var Partner = class extends SmrtObject {
569
+ profileId = "";
570
+ propertyId = "";
571
+ /**
572
+ * Partner types as JSON array (publisher, salesperson, referrer)
573
+ * A partner can have multiple types
574
+ */
575
+ partnerTypes = "[]";
576
+ parentPartnerId = "";
577
+ referredById = "";
578
+ /**
579
+ * Share of commission that goes to parent partner (0-1)
580
+ * e.g., 0.20 means 20% of this partner's sales commission goes to parent
581
+ */
582
+ parentCommissionShare = 0;
583
+ /**
584
+ * Commission rate for display (impression) revenue (0-1)
585
+ * Default 50% - publisher earns half of ad impression revenue
586
+ */
587
+ displayCommissionRate = .5;
588
+ /**
589
+ * Commission rate for referral revenue (0-1)
590
+ * Default 5% - referrer earns 5% of referred partner's first-year revenue
591
+ */
592
+ referralCommissionRate = .05;
593
+ /**
594
+ * Commission rate for sales revenue (0-1)
595
+ * Default 10% - salesperson earns 10% of advertiser spend they brought in
596
+ */
597
+ salesCommissionRate = .1;
598
+ /**
599
+ * Minimum payout threshold in cents
600
+ * Default $50 = 5000 cents
601
+ */
602
+ payoutThreshold = 5e3;
603
+ /**
604
+ * Preferred payout method
605
+ */
606
+ payoutMethod = PayoutMethod.BANK_TRANSFER;
607
+ /**
608
+ * Currency code for all monetary values
609
+ * Defaults to CAD, allows future multi-currency support
610
+ */
611
+ currency = "CAD";
612
+ /**
613
+ * Partner status
614
+ */
615
+ status = PartnerStatus.PENDING;
616
+ /**
617
+ * Additional metadata as JSON string
618
+ * (bank details, tax info, etc.)
619
+ */
620
+ metadata = "";
621
+ constructor(options = {}) {
622
+ super(options);
623
+ if (options.profileId !== void 0) this.profileId = options.profileId;
624
+ if (options.propertyId !== void 0) this.propertyId = options.propertyId;
625
+ if (options.partnerTypes !== void 0) this.partnerTypes = options.partnerTypes;
626
+ if (options.parentPartnerId !== void 0) this.parentPartnerId = options.parentPartnerId;
627
+ if (options.referredById !== void 0) this.referredById = options.referredById;
628
+ if (options.parentCommissionShare !== void 0) this.parentCommissionShare = options.parentCommissionShare;
629
+ if (options.displayCommissionRate !== void 0) this.displayCommissionRate = options.displayCommissionRate;
630
+ if (options.referralCommissionRate !== void 0) this.referralCommissionRate = options.referralCommissionRate;
631
+ if (options.salesCommissionRate !== void 0) this.salesCommissionRate = options.salesCommissionRate;
632
+ if (options.payoutThreshold !== void 0) this.payoutThreshold = options.payoutThreshold;
633
+ if (options.payoutMethod !== void 0) this.payoutMethod = options.payoutMethod;
634
+ if (options.currency !== void 0) this.currency = options.currency;
635
+ if (options.status !== void 0) this.status = options.status;
636
+ if (options.metadata !== void 0) this.metadata = options.metadata;
637
+ }
638
+ /**
639
+ * Get partner types as array
640
+ */
641
+ getPartnerTypes() {
642
+ if (!this.partnerTypes) return [];
643
+ try {
644
+ return JSON.parse(this.partnerTypes);
645
+ } catch {
646
+ return [];
647
+ }
648
+ }
649
+ /**
650
+ * Set partner types from array
651
+ */
652
+ setPartnerTypes(types) {
653
+ this.partnerTypes = JSON.stringify(types);
654
+ }
655
+ /**
656
+ * Check if partner has a specific type
657
+ */
658
+ hasType(type) {
659
+ return this.getPartnerTypes().includes(type);
660
+ }
661
+ /**
662
+ * Check if partner is a publisher
663
+ */
664
+ isPublisher() {
665
+ return this.hasType(PartnerType.PUBLISHER);
666
+ }
667
+ /**
668
+ * Check if partner is a salesperson
669
+ */
670
+ isSalesperson() {
671
+ return this.hasType(PartnerType.SALESPERSON);
672
+ }
673
+ /**
674
+ * Check if partner is a referrer
675
+ */
676
+ isReferrer() {
677
+ return this.hasType(PartnerType.REFERRER);
678
+ }
679
+ /**
680
+ * Check if partner is active
681
+ */
682
+ isActive() {
683
+ return this.status === PartnerStatus.ACTIVE;
684
+ }
685
+ /**
686
+ * Check if partner is pending approval
687
+ */
688
+ isPending() {
689
+ return this.status === PartnerStatus.PENDING;
690
+ }
691
+ /**
692
+ * Check if partner is suspended
693
+ */
694
+ isSuspended() {
695
+ return this.status === PartnerStatus.SUSPENDED;
696
+ }
697
+ /**
698
+ * Check if partner has a parent (site-attached)
699
+ */
700
+ hasParent() {
701
+ return !!this.parentPartnerId;
702
+ }
703
+ /**
704
+ * Check if partner was referred by another partner
705
+ */
706
+ wasReferred() {
707
+ return !!this.referredById;
708
+ }
709
+ /**
710
+ * Get metadata as object
711
+ */
712
+ getMetadata() {
713
+ if (!this.metadata) return {};
714
+ try {
715
+ return JSON.parse(this.metadata);
716
+ } catch {
717
+ return {};
718
+ }
719
+ }
720
+ /**
721
+ * Set metadata from object
722
+ */
723
+ setMetadata(data) {
724
+ this.metadata = JSON.stringify(data);
725
+ }
726
+ /**
727
+ * Calculate effective sales commission rate (after parent share)
728
+ */
729
+ getEffectiveSalesRate() {
730
+ if (this.parentPartnerId && this.parentCommissionShare > 0) return this.salesCommissionRate * (1 - this.parentCommissionShare);
731
+ return this.salesCommissionRate;
732
+ }
578
733
  };
579
- let Partner = class extends SmrtObject {
580
- profileId = "";
581
- propertyId = "";
582
- /**
583
- * Partner types as JSON array (publisher, salesperson, referrer)
584
- * A partner can have multiple types
585
- */
586
- partnerTypes = "[]";
587
- parentPartnerId = "";
588
- referredById = "";
589
- /**
590
- * Share of commission that goes to parent partner (0-1)
591
- * e.g., 0.20 means 20% of this partner's sales commission goes to parent
592
- */
593
- parentCommissionShare = 0;
594
- /**
595
- * Commission rate for display (impression) revenue (0-1)
596
- * Default 50% - publisher earns half of ad impression revenue
597
- */
598
- displayCommissionRate = 0.5;
599
- /**
600
- * Commission rate for referral revenue (0-1)
601
- * Default 5% - referrer earns 5% of referred partner's first-year revenue
602
- */
603
- referralCommissionRate = 0.05;
604
- /**
605
- * Commission rate for sales revenue (0-1)
606
- * Default 10% - salesperson earns 10% of advertiser spend they brought in
607
- */
608
- salesCommissionRate = 0.1;
609
- /**
610
- * Minimum payout threshold in cents
611
- * Default $50 = 5000 cents
612
- */
613
- payoutThreshold = 5e3;
614
- /**
615
- * Preferred payout method
616
- */
617
- payoutMethod = PayoutMethod.BANK_TRANSFER;
618
- /**
619
- * Currency code for all monetary values
620
- * Defaults to CAD, allows future multi-currency support
621
- */
622
- currency = "CAD";
623
- /**
624
- * Partner status
625
- */
626
- status = PartnerStatus.PENDING;
627
- /**
628
- * Additional metadata as JSON string
629
- * (bank details, tax info, etc.)
630
- */
631
- metadata = "";
632
- constructor(options = {}) {
633
- super(options);
634
- if (options.profileId !== void 0) this.profileId = options.profileId;
635
- if (options.propertyId !== void 0) this.propertyId = options.propertyId;
636
- if (options.partnerTypes !== void 0)
637
- this.partnerTypes = options.partnerTypes;
638
- if (options.parentPartnerId !== void 0)
639
- this.parentPartnerId = options.parentPartnerId;
640
- if (options.referredById !== void 0)
641
- this.referredById = options.referredById;
642
- if (options.parentCommissionShare !== void 0)
643
- this.parentCommissionShare = options.parentCommissionShare;
644
- if (options.displayCommissionRate !== void 0)
645
- this.displayCommissionRate = options.displayCommissionRate;
646
- if (options.referralCommissionRate !== void 0)
647
- this.referralCommissionRate = options.referralCommissionRate;
648
- if (options.salesCommissionRate !== void 0)
649
- this.salesCommissionRate = options.salesCommissionRate;
650
- if (options.payoutThreshold !== void 0)
651
- this.payoutThreshold = options.payoutThreshold;
652
- if (options.payoutMethod !== void 0)
653
- this.payoutMethod = options.payoutMethod;
654
- if (options.currency !== void 0) this.currency = options.currency;
655
- if (options.status !== void 0) this.status = options.status;
656
- if (options.metadata !== void 0) this.metadata = options.metadata;
657
- }
658
- /**
659
- * Get partner types as array
660
- */
661
- getPartnerTypes() {
662
- if (!this.partnerTypes) return [];
663
- try {
664
- return JSON.parse(this.partnerTypes);
665
- } catch {
666
- return [];
667
- }
668
- }
669
- /**
670
- * Set partner types from array
671
- */
672
- setPartnerTypes(types) {
673
- this.partnerTypes = JSON.stringify(types);
674
- }
675
- /**
676
- * Check if partner has a specific type
677
- */
678
- hasType(type) {
679
- return this.getPartnerTypes().includes(type);
680
- }
681
- /**
682
- * Check if partner is a publisher
683
- */
684
- isPublisher() {
685
- return this.hasType(PartnerType.PUBLISHER);
686
- }
687
- /**
688
- * Check if partner is a salesperson
689
- */
690
- isSalesperson() {
691
- return this.hasType(PartnerType.SALESPERSON);
692
- }
693
- /**
694
- * Check if partner is a referrer
695
- */
696
- isReferrer() {
697
- return this.hasType(PartnerType.REFERRER);
698
- }
699
- /**
700
- * Check if partner is active
701
- */
702
- isActive() {
703
- return this.status === PartnerStatus.ACTIVE;
704
- }
705
- /**
706
- * Check if partner is pending approval
707
- */
708
- isPending() {
709
- return this.status === PartnerStatus.PENDING;
710
- }
711
- /**
712
- * Check if partner is suspended
713
- */
714
- isSuspended() {
715
- return this.status === PartnerStatus.SUSPENDED;
716
- }
717
- /**
718
- * Check if partner has a parent (site-attached)
719
- */
720
- hasParent() {
721
- return !!this.parentPartnerId;
722
- }
723
- /**
724
- * Check if partner was referred by another partner
725
- */
726
- wasReferred() {
727
- return !!this.referredById;
728
- }
729
- /**
730
- * Get metadata as object
731
- */
732
- getMetadata() {
733
- if (!this.metadata) return {};
734
- try {
735
- return JSON.parse(this.metadata);
736
- } catch {
737
- return {};
738
- }
739
- }
740
- /**
741
- * Set metadata from object
742
- */
743
- setMetadata(data) {
744
- this.metadata = JSON.stringify(data);
745
- }
746
- /**
747
- * Calculate effective sales commission rate (after parent share)
748
- */
749
- getEffectiveSalesRate() {
750
- if (this.parentPartnerId && this.parentCommissionShare > 0) {
751
- return this.salesCommissionRate * (1 - this.parentCommissionShare);
752
- }
753
- return this.salesCommissionRate;
754
- }
734
+ __decorateClass$1([crossPackageRef("@happyvertical/smrt-profiles:Profile")], Partner.prototype, "profileId", 2);
735
+ __decorateClass$1([crossPackageRef("@happyvertical/smrt-properties:Property")], Partner.prototype, "propertyId", 2);
736
+ __decorateClass$1([foreignKey("Partner")], Partner.prototype, "parentPartnerId", 2);
737
+ __decorateClass$1([foreignKey("Partner")], Partner.prototype, "referredById", 2);
738
+ Partner = __decorateClass$1([smrt({
739
+ api: { include: [
740
+ "list",
741
+ "get",
742
+ "create",
743
+ "update"
744
+ ] },
745
+ mcp: { include: [
746
+ "list",
747
+ "get",
748
+ "create"
749
+ ] },
750
+ cli: true
751
+ })], Partner);
752
+ //#endregion
753
+ //#region src/collections/PartnerCollection.ts
754
+ var PartnerCollection = class extends SmrtCollection {
755
+ static _itemClass = Partner;
756
+ /**
757
+ * Find partners by profile ID
758
+ *
759
+ * @param profileId - Profile ID
760
+ * @returns Array of partners
761
+ */
762
+ async findByProfile(profileId) {
763
+ return await this.list({
764
+ where: { profileId },
765
+ orderBy: "created_at DESC"
766
+ });
767
+ }
768
+ /**
769
+ * Find partner by property ID (publishers)
770
+ *
771
+ * @param propertyId - Property ID
772
+ * @returns Partner or null
773
+ */
774
+ async findByProperty(propertyId) {
775
+ return (await this.list({
776
+ where: { propertyId },
777
+ limit: 1
778
+ }))[0] || null;
779
+ }
780
+ /**
781
+ * Find partners by parent partner ID
782
+ *
783
+ * @param parentPartnerId - Parent partner ID
784
+ * @returns Array of child partners
785
+ */
786
+ async findByParent(parentPartnerId) {
787
+ return await this.list({
788
+ where: { parentPartnerId },
789
+ orderBy: "created_at DESC"
790
+ });
791
+ }
792
+ /**
793
+ * Find partners referred by a specific partner
794
+ *
795
+ * @param referredById - Referrer partner ID
796
+ * @returns Array of referred partners
797
+ */
798
+ async findByReferrer(referredById) {
799
+ return await this.list({
800
+ where: { referredById },
801
+ orderBy: "created_at DESC"
802
+ });
803
+ }
804
+ /**
805
+ * Find partners by status
806
+ *
807
+ * @param status - Partner status
808
+ * @returns Array of partners
809
+ */
810
+ async findByStatus(status) {
811
+ return await this.list({
812
+ where: { status },
813
+ orderBy: "created_at DESC"
814
+ });
815
+ }
816
+ /**
817
+ * Find all active partners
818
+ */
819
+ async findActive() {
820
+ return await this.findByStatus(PartnerStatus.ACTIVE);
821
+ }
822
+ /**
823
+ * Find all pending partners (awaiting approval)
824
+ */
825
+ async findPending() {
826
+ return await this.findByStatus(PartnerStatus.PENDING);
827
+ }
828
+ /**
829
+ * Find all suspended partners
830
+ */
831
+ async findSuspended() {
832
+ return await this.findByStatus(PartnerStatus.SUSPENDED);
833
+ }
834
+ /**
835
+ * Find partners by type (requires in-memory filtering for JSON field)
836
+ *
837
+ * @param type - Partner type to filter by
838
+ * @returns Array of partners with that type
839
+ */
840
+ async findByType(type) {
841
+ return (await this.list({})).filter((partner) => partner.hasType(type));
842
+ }
843
+ /**
844
+ * Find all publisher partners
845
+ */
846
+ async findPublishers() {
847
+ return await this.findByType(PartnerType.PUBLISHER);
848
+ }
849
+ /**
850
+ * Find all salesperson partners
851
+ */
852
+ async findSalespeople() {
853
+ return await this.findByType(PartnerType.SALESPERSON);
854
+ }
855
+ /**
856
+ * Find all referrer partners
857
+ */
858
+ async findReferrers() {
859
+ return await this.findByType(PartnerType.REFERRER);
860
+ }
861
+ /**
862
+ * Find active publishers (for ad serving)
863
+ */
864
+ async findActivePublishers() {
865
+ return (await this.findPublishers()).filter((p) => p.isActive());
866
+ }
867
+ /**
868
+ * Find partner for ad serving by property ID
869
+ * Returns active publisher partner for the property
870
+ *
871
+ * @param propertyId - Property ID
872
+ * @returns Active publisher partner or null
873
+ */
874
+ async findActiveByProperty(propertyId) {
875
+ const partner = await this.findByProperty(propertyId);
876
+ if (partner?.isActive() && partner.isPublisher()) return partner;
877
+ return null;
878
+ }
879
+ /**
880
+ * Find partners eligible for payout
881
+ * (active partners with pending commissions above threshold)
882
+ * Note: Actual threshold check requires joining with commissions
883
+ */
884
+ async findEligibleForPayout() {
885
+ return await this.findActive();
886
+ }
755
887
  };
756
- __decorateClass$1([
757
- crossPackageRef("@happyvertical/smrt-profiles:Profile")
758
- ], Partner.prototype, "profileId", 2);
759
- __decorateClass$1([
760
- crossPackageRef("@happyvertical/smrt-properties:Property")
761
- ], Partner.prototype, "propertyId", 2);
762
- __decorateClass$1([
763
- foreignKey("Partner")
764
- ], Partner.prototype, "parentPartnerId", 2);
765
- __decorateClass$1([
766
- foreignKey("Partner")
767
- ], Partner.prototype, "referredById", 2);
768
- Partner = __decorateClass$1([
769
- smrt({
770
- api: { include: ["list", "get", "create", "update"] },
771
- mcp: { include: ["list", "get", "create"] },
772
- cli: true
773
- })
774
- ], Partner);
775
- class PartnerCollection extends SmrtCollection {
776
- static _itemClass = Partner;
777
- /**
778
- * Find partners by profile ID
779
- *
780
- * @param profileId - Profile ID
781
- * @returns Array of partners
782
- */
783
- async findByProfile(profileId) {
784
- return await this.list({
785
- where: { profileId },
786
- orderBy: "created_at DESC"
787
- });
788
- }
789
- /**
790
- * Find partner by property ID (publishers)
791
- *
792
- * @param propertyId - Property ID
793
- * @returns Partner or null
794
- */
795
- async findByProperty(propertyId) {
796
- const results = await this.list({
797
- where: { propertyId },
798
- limit: 1
799
- });
800
- return results[0] || null;
801
- }
802
- /**
803
- * Find partners by parent partner ID
804
- *
805
- * @param parentPartnerId - Parent partner ID
806
- * @returns Array of child partners
807
- */
808
- async findByParent(parentPartnerId) {
809
- return await this.list({
810
- where: { parentPartnerId },
811
- orderBy: "created_at DESC"
812
- });
813
- }
814
- /**
815
- * Find partners referred by a specific partner
816
- *
817
- * @param referredById - Referrer partner ID
818
- * @returns Array of referred partners
819
- */
820
- async findByReferrer(referredById) {
821
- return await this.list({
822
- where: { referredById },
823
- orderBy: "created_at DESC"
824
- });
825
- }
826
- /**
827
- * Find partners by status
828
- *
829
- * @param status - Partner status
830
- * @returns Array of partners
831
- */
832
- async findByStatus(status) {
833
- return await this.list({
834
- where: { status },
835
- orderBy: "created_at DESC"
836
- });
837
- }
838
- /**
839
- * Find all active partners
840
- */
841
- async findActive() {
842
- return await this.findByStatus(PartnerStatus.ACTIVE);
843
- }
844
- /**
845
- * Find all pending partners (awaiting approval)
846
- */
847
- async findPending() {
848
- return await this.findByStatus(PartnerStatus.PENDING);
849
- }
850
- /**
851
- * Find all suspended partners
852
- */
853
- async findSuspended() {
854
- return await this.findByStatus(PartnerStatus.SUSPENDED);
855
- }
856
- /**
857
- * Find partners by type (requires in-memory filtering for JSON field)
858
- *
859
- * @param type - Partner type to filter by
860
- * @returns Array of partners with that type
861
- */
862
- async findByType(type) {
863
- const all = await this.list({});
864
- return all.filter((partner) => partner.hasType(type));
865
- }
866
- /**
867
- * Find all publisher partners
868
- */
869
- async findPublishers() {
870
- return await this.findByType(PartnerType.PUBLISHER);
871
- }
872
- /**
873
- * Find all salesperson partners
874
- */
875
- async findSalespeople() {
876
- return await this.findByType(PartnerType.SALESPERSON);
877
- }
878
- /**
879
- * Find all referrer partners
880
- */
881
- async findReferrers() {
882
- return await this.findByType(PartnerType.REFERRER);
883
- }
884
- /**
885
- * Find active publishers (for ad serving)
886
- */
887
- async findActivePublishers() {
888
- const publishers = await this.findPublishers();
889
- return publishers.filter((p) => p.isActive());
890
- }
891
- /**
892
- * Find partner for ad serving by property ID
893
- * Returns active publisher partner for the property
894
- *
895
- * @param propertyId - Property ID
896
- * @returns Active publisher partner or null
897
- */
898
- async findActiveByProperty(propertyId) {
899
- const partner = await this.findByProperty(propertyId);
900
- if (partner?.isActive() && partner.isPublisher()) {
901
- return partner;
902
- }
903
- return null;
904
- }
905
- /**
906
- * Find partners eligible for payout
907
- * (active partners with pending commissions above threshold)
908
- * Note: Actual threshold check requires joining with commissions
909
- */
910
- async findEligibleForPayout() {
911
- const active = await this.findActive();
912
- return active;
913
- }
914
- }
888
+ //#endregion
889
+ //#region src/models/Payout.ts
915
890
  var __defProp = Object.defineProperty;
916
891
  var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
917
892
  var __decorateClass = (decorators, target, key, kind) => {
918
- var result = kind > 1 ? void 0 : kind ? __getOwnPropDesc(target, key) : target;
919
- for (var i = decorators.length - 1, decorator; i >= 0; i--)
920
- if (decorator = decorators[i])
921
- result = (kind ? decorator(target, key, result) : decorator(result)) || result;
922
- if (kind && result) __defProp(target, key, result);
923
- return result;
893
+ var result = kind > 1 ? void 0 : kind ? __getOwnPropDesc(target, key) : target;
894
+ for (var i = decorators.length - 1, decorator; i >= 0; i--) if (decorator = decorators[i]) result = (kind ? decorator(target, key, result) : decorator(result)) || result;
895
+ if (kind && result) __defProp(target, key, result);
896
+ return result;
924
897
  };
925
- let Payout = class extends SmrtObject {
926
- partnerId = "";
927
- /**
928
- * Period start date
929
- */
930
- periodStart = /* @__PURE__ */ new Date();
931
- /**
932
- * Period end date
933
- */
934
- periodEnd = /* @__PURE__ */ new Date();
935
- /**
936
- * Total display earnings in cents
937
- */
938
- displayEarnings = 0;
939
- /**
940
- * Total referral earnings in cents
941
- */
942
- referralEarnings = 0;
943
- /**
944
- * Total sales earnings in cents
945
- */
946
- salesEarnings = 0;
947
- /**
948
- * Total parent earnings in cents (from site-attached salespeople)
949
- */
950
- parentEarnings = 0;
951
- /**
952
- * Total overhead earnings in cents (network overhead commissions)
953
- */
954
- overheadEarnings = 0;
955
- /**
956
- * Total payout amount in cents
957
- * = displayEarnings + referralEarnings + salesEarnings + parentEarnings + overheadEarnings
958
- */
959
- totalAmount = 0;
960
- /**
961
- * Currency code
962
- * Defaults to CAD
963
- */
964
- currency = "CAD";
965
- invoiceId = "";
966
- /**
967
- * Payout status
968
- */
969
- status = PayoutStatus.PENDING;
970
- /**
971
- * Payment reference (check number, transfer ID, etc.)
972
- */
973
- paymentReference = "";
974
- /**
975
- * Date payment was processed
976
- */
977
- paidAt = null;
978
- /**
979
- * Notes from admin (approval notes, issues, etc.)
980
- */
981
- notes = "";
982
- /**
983
- * Additional metadata as JSON string
984
- */
985
- metadata = "";
986
- constructor(options = {}) {
987
- super(options);
988
- if (options.partnerId !== void 0) this.partnerId = options.partnerId;
989
- if (options.periodStart !== void 0)
990
- this.periodStart = options.periodStart;
991
- if (options.periodEnd !== void 0) this.periodEnd = options.periodEnd;
992
- if (options.displayEarnings !== void 0)
993
- this.displayEarnings = options.displayEarnings;
994
- if (options.referralEarnings !== void 0)
995
- this.referralEarnings = options.referralEarnings;
996
- if (options.salesEarnings !== void 0)
997
- this.salesEarnings = options.salesEarnings;
998
- if (options.parentEarnings !== void 0)
999
- this.parentEarnings = options.parentEarnings;
1000
- if (options.overheadEarnings !== void 0)
1001
- this.overheadEarnings = options.overheadEarnings;
1002
- if (options.totalAmount !== void 0)
1003
- this.totalAmount = options.totalAmount;
1004
- if (options.currency !== void 0) this.currency = options.currency;
1005
- if (options.invoiceId !== void 0) this.invoiceId = options.invoiceId;
1006
- if (options.status !== void 0) this.status = options.status;
1007
- if (options.paymentReference !== void 0)
1008
- this.paymentReference = options.paymentReference;
1009
- if (options.paidAt !== void 0) this.paidAt = options.paidAt;
1010
- if (options.notes !== void 0) this.notes = options.notes;
1011
- if (options.metadata !== void 0) this.metadata = options.metadata;
1012
- }
1013
- /**
1014
- * Check if payout is pending approval
1015
- */
1016
- isPending() {
1017
- return this.status === PayoutStatus.PENDING;
1018
- }
1019
- /**
1020
- * Check if payout is approved (waiting for processing)
1021
- */
1022
- isApproved() {
1023
- return this.status === PayoutStatus.APPROVED;
1024
- }
1025
- /**
1026
- * Check if payout is being processed
1027
- */
1028
- isProcessing() {
1029
- return this.status === PayoutStatus.PROCESSING;
1030
- }
1031
- /**
1032
- * Check if payout is completed
1033
- */
1034
- isCompleted() {
1035
- return this.status === PayoutStatus.COMPLETED;
1036
- }
1037
- /**
1038
- * Check if payout failed
1039
- */
1040
- isFailed() {
1041
- return this.status === PayoutStatus.FAILED;
1042
- }
1043
- /**
1044
- * Get total amount in dollars (for display)
1045
- */
1046
- getTotalInDollars() {
1047
- return this.totalAmount / 100;
1048
- }
1049
- /**
1050
- * Get display earnings in dollars
1051
- */
1052
- getDisplayEarningsInDollars() {
1053
- return this.displayEarnings / 100;
1054
- }
1055
- /**
1056
- * Get referral earnings in dollars
1057
- */
1058
- getReferralEarningsInDollars() {
1059
- return this.referralEarnings / 100;
1060
- }
1061
- /**
1062
- * Get sales earnings in dollars
1063
- */
1064
- getSalesEarningsInDollars() {
1065
- return this.salesEarnings / 100;
1066
- }
1067
- /**
1068
- * Get parent earnings in dollars
1069
- */
1070
- getParentEarningsInDollars() {
1071
- return this.parentEarnings / 100;
1072
- }
1073
- /**
1074
- * Get overhead earnings in dollars
1075
- */
1076
- getOverheadEarningsInDollars() {
1077
- return this.overheadEarnings / 100;
1078
- }
1079
- /**
1080
- * Calculate total from component earnings
1081
- */
1082
- calculateTotal() {
1083
- return this.displayEarnings + this.referralEarnings + this.salesEarnings + this.parentEarnings + this.overheadEarnings;
1084
- }
1085
- /**
1086
- * Get period as human-readable string
1087
- */
1088
- getPeriodString() {
1089
- const start = this.periodStart.toISOString().split("T")[0];
1090
- const end = this.periodEnd.toISOString().split("T")[0];
1091
- return `${start} to ${end}`;
1092
- }
1093
- /**
1094
- * Get metadata as object
1095
- */
1096
- getMetadata() {
1097
- if (!this.metadata) return {};
1098
- try {
1099
- return JSON.parse(this.metadata);
1100
- } catch {
1101
- return {};
1102
- }
1103
- }
1104
- /**
1105
- * Set metadata from object
1106
- */
1107
- setMetadata(data) {
1108
- this.metadata = JSON.stringify(data);
1109
- }
1110
- // ============================================================================
1111
- // Status Transitions
1112
- // ============================================================================
1113
- /**
1114
- * Approve the payout for processing
1115
- *
1116
- * @throws Error if payout is not in pending status
1117
- */
1118
- approve() {
1119
- if (this.status !== PayoutStatus.PENDING) {
1120
- throw new Error(
1121
- `Cannot approve payout with status '${this.status}'. Only pending payouts can be approved.`
1122
- );
1123
- }
1124
- this.status = PayoutStatus.APPROVED;
1125
- }
1126
- /**
1127
- * Mark payout as processing (payment in progress)
1128
- *
1129
- * @throws Error if payout is not in approved status
1130
- */
1131
- markProcessing() {
1132
- if (this.status !== PayoutStatus.APPROVED) {
1133
- throw new Error(
1134
- `Cannot mark payout as processing with status '${this.status}'. Only approved payouts can be processed.`
1135
- );
1136
- }
1137
- this.status = PayoutStatus.PROCESSING;
1138
- }
1139
- /**
1140
- * Mark payout as completed
1141
- *
1142
- * @param paymentReference - Payment reference (check number, transfer ID, etc.)
1143
- * @throws Error if payout is not in processing status
1144
- */
1145
- complete(paymentReference) {
1146
- if (this.status !== PayoutStatus.PROCESSING) {
1147
- throw new Error(
1148
- `Cannot complete payout with status '${this.status}'. Only processing payouts can be completed.`
1149
- );
1150
- }
1151
- this.status = PayoutStatus.COMPLETED;
1152
- this.paymentReference = paymentReference;
1153
- this.paidAt = /* @__PURE__ */ new Date();
1154
- }
1155
- /**
1156
- * Mark payout as failed
1157
- *
1158
- * @param reason - Reason for failure (stored in notes)
1159
- */
1160
- fail(reason) {
1161
- if (this.status !== PayoutStatus.APPROVED && this.status !== PayoutStatus.PROCESSING) {
1162
- throw new Error(
1163
- `Cannot fail payout with status '${this.status}'. Only approved or processing payouts can fail.`
1164
- );
1165
- }
1166
- this.status = PayoutStatus.FAILED;
1167
- this.notes = reason;
1168
- }
898
+ var Payout = class extends SmrtObject {
899
+ partnerId = "";
900
+ /**
901
+ * Period start date
902
+ */
903
+ periodStart = /* @__PURE__ */ new Date();
904
+ /**
905
+ * Period end date
906
+ */
907
+ periodEnd = /* @__PURE__ */ new Date();
908
+ /**
909
+ * Total display earnings in cents
910
+ */
911
+ displayEarnings = 0;
912
+ /**
913
+ * Total referral earnings in cents
914
+ */
915
+ referralEarnings = 0;
916
+ /**
917
+ * Total sales earnings in cents
918
+ */
919
+ salesEarnings = 0;
920
+ /**
921
+ * Total parent earnings in cents (from site-attached salespeople)
922
+ */
923
+ parentEarnings = 0;
924
+ /**
925
+ * Total overhead earnings in cents (network overhead commissions)
926
+ */
927
+ overheadEarnings = 0;
928
+ /**
929
+ * Total payout amount in cents
930
+ * = displayEarnings + referralEarnings + salesEarnings + parentEarnings + overheadEarnings
931
+ */
932
+ totalAmount = 0;
933
+ /**
934
+ * Currency code
935
+ * Defaults to CAD
936
+ */
937
+ currency = "CAD";
938
+ invoiceId = "";
939
+ /**
940
+ * Payout status
941
+ */
942
+ status = PayoutStatus.PENDING;
943
+ /**
944
+ * Payment reference (check number, transfer ID, etc.)
945
+ */
946
+ paymentReference = "";
947
+ /**
948
+ * Date payment was processed
949
+ */
950
+ paidAt = null;
951
+ /**
952
+ * Notes from admin (approval notes, issues, etc.)
953
+ */
954
+ notes = "";
955
+ /**
956
+ * Additional metadata as JSON string
957
+ */
958
+ metadata = "";
959
+ constructor(options = {}) {
960
+ super(options);
961
+ if (options.partnerId !== void 0) this.partnerId = options.partnerId;
962
+ if (options.periodStart !== void 0) this.periodStart = options.periodStart;
963
+ if (options.periodEnd !== void 0) this.periodEnd = options.periodEnd;
964
+ if (options.displayEarnings !== void 0) this.displayEarnings = options.displayEarnings;
965
+ if (options.referralEarnings !== void 0) this.referralEarnings = options.referralEarnings;
966
+ if (options.salesEarnings !== void 0) this.salesEarnings = options.salesEarnings;
967
+ if (options.parentEarnings !== void 0) this.parentEarnings = options.parentEarnings;
968
+ if (options.overheadEarnings !== void 0) this.overheadEarnings = options.overheadEarnings;
969
+ if (options.totalAmount !== void 0) this.totalAmount = options.totalAmount;
970
+ if (options.currency !== void 0) this.currency = options.currency;
971
+ if (options.invoiceId !== void 0) this.invoiceId = options.invoiceId;
972
+ if (options.status !== void 0) this.status = options.status;
973
+ if (options.paymentReference !== void 0) this.paymentReference = options.paymentReference;
974
+ if (options.paidAt !== void 0) this.paidAt = options.paidAt;
975
+ if (options.notes !== void 0) this.notes = options.notes;
976
+ if (options.metadata !== void 0) this.metadata = options.metadata;
977
+ }
978
+ /**
979
+ * Check if payout is pending approval
980
+ */
981
+ isPending() {
982
+ return this.status === PayoutStatus.PENDING;
983
+ }
984
+ /**
985
+ * Check if payout is approved (waiting for processing)
986
+ */
987
+ isApproved() {
988
+ return this.status === PayoutStatus.APPROVED;
989
+ }
990
+ /**
991
+ * Check if payout is being processed
992
+ */
993
+ isProcessing() {
994
+ return this.status === PayoutStatus.PROCESSING;
995
+ }
996
+ /**
997
+ * Check if payout is completed
998
+ */
999
+ isCompleted() {
1000
+ return this.status === PayoutStatus.COMPLETED;
1001
+ }
1002
+ /**
1003
+ * Check if payout failed
1004
+ */
1005
+ isFailed() {
1006
+ return this.status === PayoutStatus.FAILED;
1007
+ }
1008
+ /**
1009
+ * Get total amount in dollars (for display)
1010
+ */
1011
+ getTotalInDollars() {
1012
+ return this.totalAmount / 100;
1013
+ }
1014
+ /**
1015
+ * Get display earnings in dollars
1016
+ */
1017
+ getDisplayEarningsInDollars() {
1018
+ return this.displayEarnings / 100;
1019
+ }
1020
+ /**
1021
+ * Get referral earnings in dollars
1022
+ */
1023
+ getReferralEarningsInDollars() {
1024
+ return this.referralEarnings / 100;
1025
+ }
1026
+ /**
1027
+ * Get sales earnings in dollars
1028
+ */
1029
+ getSalesEarningsInDollars() {
1030
+ return this.salesEarnings / 100;
1031
+ }
1032
+ /**
1033
+ * Get parent earnings in dollars
1034
+ */
1035
+ getParentEarningsInDollars() {
1036
+ return this.parentEarnings / 100;
1037
+ }
1038
+ /**
1039
+ * Get overhead earnings in dollars
1040
+ */
1041
+ getOverheadEarningsInDollars() {
1042
+ return this.overheadEarnings / 100;
1043
+ }
1044
+ /**
1045
+ * Calculate total from component earnings
1046
+ */
1047
+ calculateTotal() {
1048
+ return this.displayEarnings + this.referralEarnings + this.salesEarnings + this.parentEarnings + this.overheadEarnings;
1049
+ }
1050
+ /**
1051
+ * Get period as human-readable string
1052
+ */
1053
+ getPeriodString() {
1054
+ return `${this.periodStart.toISOString().split("T")[0]} to ${this.periodEnd.toISOString().split("T")[0]}`;
1055
+ }
1056
+ /**
1057
+ * Get metadata as object
1058
+ */
1059
+ getMetadata() {
1060
+ if (!this.metadata) return {};
1061
+ try {
1062
+ return JSON.parse(this.metadata);
1063
+ } catch {
1064
+ return {};
1065
+ }
1066
+ }
1067
+ /**
1068
+ * Set metadata from object
1069
+ */
1070
+ setMetadata(data) {
1071
+ this.metadata = JSON.stringify(data);
1072
+ }
1073
+ /**
1074
+ * Approve the payout for processing
1075
+ *
1076
+ * @throws Error if payout is not in pending status
1077
+ */
1078
+ approve() {
1079
+ if (this.status !== PayoutStatus.PENDING) throw new Error(`Cannot approve payout with status '${this.status}'. Only pending payouts can be approved.`);
1080
+ this.status = PayoutStatus.APPROVED;
1081
+ }
1082
+ /**
1083
+ * Mark payout as processing (payment in progress)
1084
+ *
1085
+ * @throws Error if payout is not in approved status
1086
+ */
1087
+ markProcessing() {
1088
+ if (this.status !== PayoutStatus.APPROVED) throw new Error(`Cannot mark payout as processing with status '${this.status}'. Only approved payouts can be processed.`);
1089
+ this.status = PayoutStatus.PROCESSING;
1090
+ }
1091
+ /**
1092
+ * Mark payout as completed
1093
+ *
1094
+ * @param paymentReference - Payment reference (check number, transfer ID, etc.)
1095
+ * @throws Error if payout is not in processing status
1096
+ */
1097
+ complete(paymentReference) {
1098
+ if (this.status !== PayoutStatus.PROCESSING) throw new Error(`Cannot complete payout with status '${this.status}'. Only processing payouts can be completed.`);
1099
+ this.status = PayoutStatus.COMPLETED;
1100
+ this.paymentReference = paymentReference;
1101
+ this.paidAt = /* @__PURE__ */ new Date();
1102
+ }
1103
+ /**
1104
+ * Mark payout as failed
1105
+ *
1106
+ * @param reason - Reason for failure (stored in notes)
1107
+ */
1108
+ fail(reason) {
1109
+ if (this.status !== PayoutStatus.APPROVED && this.status !== PayoutStatus.PROCESSING) throw new Error(`Cannot fail payout with status '${this.status}'. Only approved or processing payouts can fail.`);
1110
+ this.status = PayoutStatus.FAILED;
1111
+ this.notes = reason;
1112
+ }
1169
1113
  };
1170
- __decorateClass([
1171
- foreignKey("Partner")
1172
- ], Payout.prototype, "partnerId", 2);
1173
- __decorateClass([
1174
- crossPackageRef("@happyvertical/smrt-commerce:Invoice")
1175
- ], Payout.prototype, "invoiceId", 2);
1176
- Payout = __decorateClass([
1177
- smrt({
1178
- api: { include: ["list", "get", "create", "update"] },
1179
- mcp: { include: ["list", "get", "create"] },
1180
- cli: true
1181
- })
1182
- ], Payout);
1183
- class PayoutCollection extends SmrtCollection {
1184
- static _itemClass = Payout;
1185
- /**
1186
- * Find payouts by partner
1187
- *
1188
- * @param partnerId - Partner ID
1189
- * @returns Array of payouts
1190
- */
1191
- async findByPartner(partnerId) {
1192
- return await this.list({
1193
- where: { partnerId },
1194
- orderBy: "period_end DESC"
1195
- });
1196
- }
1197
- /**
1198
- * Find payouts by status
1199
- *
1200
- * @param status - Payout status
1201
- * @returns Array of payouts
1202
- */
1203
- async findByStatus(status) {
1204
- return await this.list({
1205
- where: { status },
1206
- orderBy: "period_end DESC"
1207
- });
1208
- }
1209
- /**
1210
- * Find all pending payouts (awaiting approval)
1211
- */
1212
- async findPending() {
1213
- return await this.findByStatus(PayoutStatus.PENDING);
1214
- }
1215
- /**
1216
- * Find all approved payouts (ready for processing)
1217
- */
1218
- async findApproved() {
1219
- return await this.findByStatus(PayoutStatus.APPROVED);
1220
- }
1221
- /**
1222
- * Find all processing payouts
1223
- */
1224
- async findProcessing() {
1225
- return await this.findByStatus(PayoutStatus.PROCESSING);
1226
- }
1227
- /**
1228
- * Find all completed payouts
1229
- */
1230
- async findCompleted() {
1231
- return await this.findByStatus(PayoutStatus.COMPLETED);
1232
- }
1233
- /**
1234
- * Find all failed payouts
1235
- */
1236
- async findFailed() {
1237
- return await this.findByStatus(PayoutStatus.FAILED);
1238
- }
1239
- /**
1240
- * Find payouts by invoice
1241
- *
1242
- * @param invoiceId - Invoice ID
1243
- * @returns Array of payouts
1244
- */
1245
- async findByInvoice(invoiceId) {
1246
- return await this.list({
1247
- where: { invoiceId },
1248
- orderBy: "period_end DESC"
1249
- });
1250
- }
1251
- /**
1252
- * Find payouts in period range
1253
- *
1254
- * @param start - Period start date
1255
- * @param end - Period end date
1256
- * @returns Array of payouts
1257
- */
1258
- async findByPeriod(start, end) {
1259
- return await this.list({
1260
- where: {
1261
- "period_start >=": start.toISOString(),
1262
- "period_end <=": end.toISOString()
1263
- },
1264
- orderBy: "period_end DESC"
1265
- });
1266
- }
1267
- /**
1268
- * Find payouts for a partner by status
1269
- *
1270
- * @param partnerId - Partner ID
1271
- * @param status - Payout status
1272
- * @returns Array of payouts
1273
- */
1274
- async findByPartnerAndStatus(partnerId, status) {
1275
- return await this.list({
1276
- where: { partnerId, status },
1277
- orderBy: "period_end DESC"
1278
- });
1279
- }
1280
- /**
1281
- * Find pending payouts for a partner
1282
- *
1283
- * @param partnerId - Partner ID
1284
- * @returns Array of pending payouts
1285
- */
1286
- async findPendingByPartner(partnerId) {
1287
- return await this.findByPartnerAndStatus(partnerId, PayoutStatus.PENDING);
1288
- }
1289
- /**
1290
- * Find completed payouts for a partner
1291
- *
1292
- * @param partnerId - Partner ID
1293
- * @returns Array of completed payouts
1294
- */
1295
- async findCompletedByPartner(partnerId) {
1296
- return await this.findByPartnerAndStatus(partnerId, PayoutStatus.COMPLETED);
1297
- }
1298
- /**
1299
- * Sum total paid to a partner
1300
- *
1301
- * @param partnerId - Partner ID
1302
- * @returns Total paid in cents
1303
- */
1304
- async sumPaidByPartner(partnerId) {
1305
- const completed = await this.findCompletedByPartner(partnerId);
1306
- return completed.reduce((sum, p) => sum + p.totalAmount, 0);
1307
- }
1308
- /**
1309
- * Sum total pending for a partner
1310
- *
1311
- * @param partnerId - Partner ID
1312
- * @returns Total pending in cents
1313
- */
1314
- async sumPendingByPartner(partnerId) {
1315
- const pending = await this.findPendingByPartner(partnerId);
1316
- return pending.reduce((sum, p) => sum + p.totalAmount, 0);
1317
- }
1318
- /**
1319
- * Get most recent payout for a partner
1320
- *
1321
- * @param partnerId - Partner ID
1322
- * @returns Most recent payout or null
1323
- */
1324
- async findLatestByPartner(partnerId) {
1325
- const results = await this.list({
1326
- where: { partnerId },
1327
- orderBy: "period_end DESC",
1328
- limit: 1
1329
- });
1330
- return results[0] || null;
1331
- }
1332
- /**
1333
- * Get payout statistics
1334
- *
1335
- * @returns Stats object
1336
- */
1337
- async getStats() {
1338
- const all = await this.list({});
1339
- const stats = {
1340
- pending: 0,
1341
- approved: 0,
1342
- processing: 0,
1343
- completed: 0,
1344
- failed: 0,
1345
- totalPaid: 0,
1346
- totalPending: 0
1347
- };
1348
- for (const p of all) {
1349
- switch (p.status) {
1350
- case PayoutStatus.PENDING:
1351
- stats.pending++;
1352
- stats.totalPending += p.totalAmount;
1353
- break;
1354
- case PayoutStatus.APPROVED:
1355
- stats.approved++;
1356
- stats.totalPending += p.totalAmount;
1357
- break;
1358
- case PayoutStatus.PROCESSING:
1359
- stats.processing++;
1360
- break;
1361
- case PayoutStatus.COMPLETED:
1362
- stats.completed++;
1363
- stats.totalPaid += p.totalAmount;
1364
- break;
1365
- case PayoutStatus.FAILED:
1366
- stats.failed++;
1367
- break;
1368
- }
1369
- }
1370
- return stats;
1371
- }
1372
- }
1373
- export {
1374
- Commission,
1375
- CommissionCollection,
1376
- CommissionStatus,
1377
- CommissionType,
1378
- Partner,
1379
- PartnerCollection,
1380
- PartnerStatus,
1381
- PartnerType,
1382
- Payout,
1383
- PayoutCollection,
1384
- PayoutMethod,
1385
- PayoutStatus
1114
+ __decorateClass([foreignKey("Partner")], Payout.prototype, "partnerId", 2);
1115
+ __decorateClass([crossPackageRef("@happyvertical/smrt-commerce:Invoice")], Payout.prototype, "invoiceId", 2);
1116
+ Payout = __decorateClass([smrt({
1117
+ api: { include: [
1118
+ "list",
1119
+ "get",
1120
+ "create",
1121
+ "update"
1122
+ ] },
1123
+ mcp: { include: [
1124
+ "list",
1125
+ "get",
1126
+ "create"
1127
+ ] },
1128
+ cli: true
1129
+ })], Payout);
1130
+ //#endregion
1131
+ //#region src/collections/PayoutCollection.ts
1132
+ var PayoutCollection = class extends SmrtCollection {
1133
+ static _itemClass = Payout;
1134
+ /**
1135
+ * Find payouts by partner
1136
+ *
1137
+ * @param partnerId - Partner ID
1138
+ * @returns Array of payouts
1139
+ */
1140
+ async findByPartner(partnerId) {
1141
+ return await this.list({
1142
+ where: { partnerId },
1143
+ orderBy: "period_end DESC"
1144
+ });
1145
+ }
1146
+ /**
1147
+ * Find payouts by status
1148
+ *
1149
+ * @param status - Payout status
1150
+ * @returns Array of payouts
1151
+ */
1152
+ async findByStatus(status) {
1153
+ return await this.list({
1154
+ where: { status },
1155
+ orderBy: "period_end DESC"
1156
+ });
1157
+ }
1158
+ /**
1159
+ * Find all pending payouts (awaiting approval)
1160
+ */
1161
+ async findPending() {
1162
+ return await this.findByStatus(PayoutStatus.PENDING);
1163
+ }
1164
+ /**
1165
+ * Find all approved payouts (ready for processing)
1166
+ */
1167
+ async findApproved() {
1168
+ return await this.findByStatus(PayoutStatus.APPROVED);
1169
+ }
1170
+ /**
1171
+ * Find all processing payouts
1172
+ */
1173
+ async findProcessing() {
1174
+ return await this.findByStatus(PayoutStatus.PROCESSING);
1175
+ }
1176
+ /**
1177
+ * Find all completed payouts
1178
+ */
1179
+ async findCompleted() {
1180
+ return await this.findByStatus(PayoutStatus.COMPLETED);
1181
+ }
1182
+ /**
1183
+ * Find all failed payouts
1184
+ */
1185
+ async findFailed() {
1186
+ return await this.findByStatus(PayoutStatus.FAILED);
1187
+ }
1188
+ /**
1189
+ * Find payouts by invoice
1190
+ *
1191
+ * @param invoiceId - Invoice ID
1192
+ * @returns Array of payouts
1193
+ */
1194
+ async findByInvoice(invoiceId) {
1195
+ return await this.list({
1196
+ where: { invoiceId },
1197
+ orderBy: "period_end DESC"
1198
+ });
1199
+ }
1200
+ /**
1201
+ * Find payouts in period range
1202
+ *
1203
+ * @param start - Period start date
1204
+ * @param end - Period end date
1205
+ * @returns Array of payouts
1206
+ */
1207
+ async findByPeriod(start, end) {
1208
+ return await this.list({
1209
+ where: {
1210
+ "period_start >=": start.toISOString(),
1211
+ "period_end <=": end.toISOString()
1212
+ },
1213
+ orderBy: "period_end DESC"
1214
+ });
1215
+ }
1216
+ /**
1217
+ * Find payouts for a partner by status
1218
+ *
1219
+ * @param partnerId - Partner ID
1220
+ * @param status - Payout status
1221
+ * @returns Array of payouts
1222
+ */
1223
+ async findByPartnerAndStatus(partnerId, status) {
1224
+ return await this.list({
1225
+ where: {
1226
+ partnerId,
1227
+ status
1228
+ },
1229
+ orderBy: "period_end DESC"
1230
+ });
1231
+ }
1232
+ /**
1233
+ * Find pending payouts for a partner
1234
+ *
1235
+ * @param partnerId - Partner ID
1236
+ * @returns Array of pending payouts
1237
+ */
1238
+ async findPendingByPartner(partnerId) {
1239
+ return await this.findByPartnerAndStatus(partnerId, PayoutStatus.PENDING);
1240
+ }
1241
+ /**
1242
+ * Find completed payouts for a partner
1243
+ *
1244
+ * @param partnerId - Partner ID
1245
+ * @returns Array of completed payouts
1246
+ */
1247
+ async findCompletedByPartner(partnerId) {
1248
+ return await this.findByPartnerAndStatus(partnerId, PayoutStatus.COMPLETED);
1249
+ }
1250
+ /**
1251
+ * Sum total paid to a partner
1252
+ *
1253
+ * @param partnerId - Partner ID
1254
+ * @returns Total paid in cents
1255
+ */
1256
+ async sumPaidByPartner(partnerId) {
1257
+ return (await this.findCompletedByPartner(partnerId)).reduce((sum, p) => sum + p.totalAmount, 0);
1258
+ }
1259
+ /**
1260
+ * Sum total pending for a partner
1261
+ *
1262
+ * @param partnerId - Partner ID
1263
+ * @returns Total pending in cents
1264
+ */
1265
+ async sumPendingByPartner(partnerId) {
1266
+ return (await this.findPendingByPartner(partnerId)).reduce((sum, p) => sum + p.totalAmount, 0);
1267
+ }
1268
+ /**
1269
+ * Get most recent payout for a partner
1270
+ *
1271
+ * @param partnerId - Partner ID
1272
+ * @returns Most recent payout or null
1273
+ */
1274
+ async findLatestByPartner(partnerId) {
1275
+ return (await this.list({
1276
+ where: { partnerId },
1277
+ orderBy: "period_end DESC",
1278
+ limit: 1
1279
+ }))[0] || null;
1280
+ }
1281
+ /**
1282
+ * Get payout statistics
1283
+ *
1284
+ * @returns Stats object
1285
+ */
1286
+ async getStats() {
1287
+ const all = await this.list({});
1288
+ const stats = {
1289
+ pending: 0,
1290
+ approved: 0,
1291
+ processing: 0,
1292
+ completed: 0,
1293
+ failed: 0,
1294
+ totalPaid: 0,
1295
+ totalPending: 0
1296
+ };
1297
+ for (const p of all) switch (p.status) {
1298
+ case PayoutStatus.PENDING:
1299
+ stats.pending++;
1300
+ stats.totalPending += p.totalAmount;
1301
+ break;
1302
+ case PayoutStatus.APPROVED:
1303
+ stats.approved++;
1304
+ stats.totalPending += p.totalAmount;
1305
+ break;
1306
+ case PayoutStatus.PROCESSING:
1307
+ stats.processing++;
1308
+ break;
1309
+ case PayoutStatus.COMPLETED:
1310
+ stats.completed++;
1311
+ stats.totalPaid += p.totalAmount;
1312
+ break;
1313
+ case PayoutStatus.FAILED:
1314
+ stats.failed++;
1315
+ break;
1316
+ }
1317
+ return stats;
1318
+ }
1386
1319
  };
1387
- //# sourceMappingURL=index.js.map
1320
+ //#endregion
1321
+ export { Commission, CommissionCollection, CommissionStatus, CommissionType, Partner, PartnerCollection, PartnerStatus, PartnerType, Payout, PayoutCollection, PayoutMethod, PayoutStatus };
1322
+
1323
+ //# sourceMappingURL=index.js.map