@classytic/revenue 2.0.1 → 2.1.0
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/bank-feed-DJtLvz_7.mjs +133 -0
- package/dist/bank-feed.enums-BadqNJTC.d.mts +118 -0
- package/dist/bank-feed.enums-kYTLTTbe.mjs +165 -0
- package/dist/bridges/index.d.mts +1 -1
- package/dist/core/state-machines.d.mts +25 -2
- package/dist/core/state-machines.mjs +43 -3
- package/dist/{engine-types-CcjIb4Fy.d.mts → engine-types-txFXOiQS.d.mts} +451 -14
- package/dist/enums/index.d.mts +4 -3
- package/dist/enums/index.mjs +4 -3
- package/dist/{errors-DHa8JVQ-.mjs → errors-Dt46UZL_.mjs} +23 -1
- package/dist/{escrow.schema-D5X32LwX.d.mts → escrow.schema-9yh4Q-aQ.d.mts} +23 -23
- package/dist/{event-constants-CEMitnIV.mjs → event-constants-CTiDNWzc.mjs} +6 -0
- package/dist/events/index.d.mts +2 -2
- package/dist/events/index.mjs +3 -3
- package/dist/index.d.mts +21 -11
- package/dist/index.mjs +120 -19
- package/dist/providers/index.d.mts +2 -2
- package/dist/providers/index.mjs +2 -2
- package/dist/registry-h8sasoLh.d.mts +145 -0
- package/dist/repositories/create-repositories.d.mts +1 -1
- package/dist/repositories/create-repositories.mjs +1 -1
- package/dist/{revenue-bridges-sdlrR85c.d.mts → revenue-bridges-BtkWFsJu.d.mts} +107 -1
- package/dist/{revenue-event-catalog-LqxPnsU_.mjs → revenue-event-catalog-CgZ57M-f.mjs} +77 -3
- package/dist/{revenue-event-catalog-BX3g7RUi.d.mts → revenue-event-catalog-JpJcyK1E.d.mts} +198 -2
- package/dist/{settlement.repository-DHIPx5S4.mjs → settlement.repository-Ba2U17zY.mjs} +559 -17
- package/dist/shared/index.d.mts +1 -1
- package/dist/shared/index.mjs +2 -2
- package/dist/{subscription.enums-tfoAgsTv.mjs → subscription.enums-DoIr56O6.mjs} +1 -40
- package/dist/{transaction.enums-u4MshXcL.d.mts → subscription.enums-k24kLpF7.d.mts} +1 -36
- package/dist/validators/index.d.mts +158 -2
- package/dist/validators/index.mjs +95 -2
- package/package.json +7 -7
- package/dist/registry-DhFMsSn5.mjs +0 -150
- package/dist/registry-SvIGPAx_.d.mts +0 -143
- /package/dist/{audit-B39B0Sdq.mjs → audit-Ba2XB2C4.mjs} +0 -0
- /package/dist/{audit-DZ0eTr9g.d.mts → audit-DRKuLBFO.d.mts} +0 -0
- /package/dist/{context-DRqSeTPM.d.mts → context-pjP1QeE3.d.mts} +0 -0
- /package/dist/{escrow.schema-BBv9oVEW.mjs → escrow.schema-C-b41z_G.mjs} +0 -0
- /package/dist/{monetization.enums-BtiU3t8o.mjs → monetization.enums-B9HBOecd.mjs} +0 -0
- /package/dist/{monetization.enums-D2xbxXJM.d.mts → monetization.enums-DzAI4sT7.d.mts} +0 -0
- /package/dist/{splits-BAfY-a9P.mjs → splits-D8XkNWgX.mjs} +0 -0
|
@@ -1,20 +1,12 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
5
|
-
import {
|
|
1
|
+
import { _ as TRANSACTION_STATUS, a as TRANSACTION_KIND, s as initialStatusFor } from "./bank-feed.enums-kYTLTTbe.mjs";
|
|
2
|
+
import { n as createEvent, t as REVENUE_EVENTS } from "./event-constants-CTiDNWzc.mjs";
|
|
3
|
+
import { g as SETTLEMENT_STATUS, r as SUBSCRIPTION_STATUS, w as HOLD_STATUS } from "./subscription.enums-DoIr56O6.mjs";
|
|
4
|
+
import { f as SettlementNotFoundError, g as WrongTransactionKindError, h as ValidationError, m as TransactionNotFoundError, n as BankFeedImportError, p as SubscriptionNotFoundError } from "./errors-Dt46UZL_.mjs";
|
|
5
|
+
import { SETTLEMENT_STATE_MACHINE, SUBSCRIPTION_STATE_MACHINE, TRANSACTION_STATE_MACHINE, smFor } from "./core/state-machines.mjs";
|
|
6
|
+
import { a as reverseTax, c as reverseCommission, n as calculateSplits, s as calculateCommission, t as calculateOrganizationPayout } from "./splits-D8XkNWgX.mjs";
|
|
6
7
|
import { Repository, withTransaction } from "@classytic/mongokit";
|
|
7
8
|
|
|
8
9
|
//#region src/repositories/transaction.repository.ts
|
|
9
|
-
/**
|
|
10
|
-
* TransactionRepository — extends mongokit Repository.
|
|
11
|
-
*
|
|
12
|
-
* CRUD inherited: getAll, getById, getByQuery, create, update, delete, count, exists.
|
|
13
|
-
* Domain verbs: createPaymentIntent, verify, refund, handleWebhook, hold, release, split.
|
|
14
|
-
*
|
|
15
|
-
* All domain verbs return raw mongokit docs — no custom envelopes.
|
|
16
|
-
* Composite results (refund creates a new doc) are stored in metadata on the primary doc.
|
|
17
|
-
*/
|
|
18
10
|
var TransactionRepository = class extends Repository {
|
|
19
11
|
deps;
|
|
20
12
|
constructor(model, plugins = []) {
|
|
@@ -91,8 +83,10 @@ var TransactionRepository = class extends Repository {
|
|
|
91
83
|
let gatewayData = { type: params.gateway };
|
|
92
84
|
if (params.amount > 0) {
|
|
93
85
|
const intent = await provider.createIntent({
|
|
94
|
-
amount:
|
|
95
|
-
|
|
86
|
+
amount: {
|
|
87
|
+
amount: params.amount,
|
|
88
|
+
currency
|
|
89
|
+
},
|
|
96
90
|
metadata: params.metadata,
|
|
97
91
|
...params.paymentData
|
|
98
92
|
});
|
|
@@ -457,7 +451,555 @@ var TransactionRepository = class extends Repository {
|
|
|
457
451
|
for (const ev of pendingEvents) await this.publishToTransport(ev);
|
|
458
452
|
return updated;
|
|
459
453
|
}
|
|
454
|
+
/**
|
|
455
|
+
* Idempotent bulk import of bank-feed rows.
|
|
456
|
+
*
|
|
457
|
+
* Each row is upserted by `(orgId, bankAccountId, externalId)` — the
|
|
458
|
+
* partial unique index declared in `create-models.ts`. Re-running the
|
|
459
|
+
* same Plaid sync, OFX upload, or QBO CDC drain produces zero new
|
|
460
|
+
* inserts on the second call (modified counts may rise as
|
|
461
|
+
* descriptions/categories evolve upstream).
|
|
462
|
+
*
|
|
463
|
+
* Signed bank `amount` is normalized into the (`amount` >= 0, `flow`)
|
|
464
|
+
* shape revenue uses internally so downstream queries (`flow:
|
|
465
|
+
* 'inflow'`) work uniformly across kinds.
|
|
466
|
+
*
|
|
467
|
+
* Emits one `revenue:transaction.imported` event per **inserted** row
|
|
468
|
+
* (not per row in `rows` — re-imports do not re-fire). Hosts wanting
|
|
469
|
+
* batch-level signal subscribe to the per-doc events and aggregate.
|
|
470
|
+
*
|
|
471
|
+
* Per-row failures (validation, hash collisions on a non-unique
|
|
472
|
+
* `externalId`) collect into `errors[]` instead of aborting the whole
|
|
473
|
+
* batch — the typical Plaid drain pulls thousands of rows; one bad
|
|
474
|
+
* row should not block the rest.
|
|
475
|
+
*
|
|
476
|
+
* @param rows Canonical bank transactions, structurally compatible
|
|
477
|
+
* with `@classytic/fin-io` parsers' output.
|
|
478
|
+
* @param opts `bankAccountId` (required, polymorphic ID) and
|
|
479
|
+
* `source` (provenance — `'plaid'`, `'ofx'`, …).
|
|
480
|
+
*/
|
|
481
|
+
async import(rows, opts, ctx = {}) {
|
|
482
|
+
const startedAt = Date.now();
|
|
483
|
+
if (!Array.isArray(rows) || rows.length === 0) return {
|
|
484
|
+
inserted: 0,
|
|
485
|
+
updated: 0,
|
|
486
|
+
skipped: 0,
|
|
487
|
+
errors: [],
|
|
488
|
+
durationMs: 0
|
|
489
|
+
};
|
|
490
|
+
const repo = this;
|
|
491
|
+
if (!repo.bulkWrite) throw new BankFeedImportError("TransactionRepository requires `batchOperationsPlugin` for `import()`. Pass it via `createRevenue({ repositoryPlugins: { transaction: [batchOperationsPlugin()] } })` — or rely on the engine default which wires it automatically.");
|
|
492
|
+
const errors = [];
|
|
493
|
+
const tenantOption = ctx.organizationId !== void 0 ? { organizationId: ctx.organizationId } : {};
|
|
494
|
+
const ops = [];
|
|
495
|
+
for (const row of rows) {
|
|
496
|
+
if (!row.externalId || typeof row.externalId !== "string") {
|
|
497
|
+
errors.push({
|
|
498
|
+
externalId: String(row.externalId),
|
|
499
|
+
reason: "missing_external_id",
|
|
500
|
+
row
|
|
501
|
+
});
|
|
502
|
+
continue;
|
|
503
|
+
}
|
|
504
|
+
const signed = row.amount.amount;
|
|
505
|
+
if (!Number.isFinite(signed) || !Number.isInteger(signed)) {
|
|
506
|
+
errors.push({
|
|
507
|
+
externalId: row.externalId,
|
|
508
|
+
reason: "invalid_amount",
|
|
509
|
+
row
|
|
510
|
+
});
|
|
511
|
+
continue;
|
|
512
|
+
}
|
|
513
|
+
const isInflow = signed >= 0;
|
|
514
|
+
const absoluteAmount = Math.abs(signed);
|
|
515
|
+
const filter = {
|
|
516
|
+
bankAccountId: opts.bankAccountId,
|
|
517
|
+
externalId: row.externalId
|
|
518
|
+
};
|
|
519
|
+
if (ctx.organizationId !== void 0) filter.organizationId = ctx.organizationId;
|
|
520
|
+
const set = {
|
|
521
|
+
amount: absoluteAmount,
|
|
522
|
+
currency: row.amount.currency,
|
|
523
|
+
flow: isInflow ? "inflow" : "outflow",
|
|
524
|
+
postedDate: row.postedDate,
|
|
525
|
+
description: row.description,
|
|
526
|
+
method: opts.method ?? opts.source
|
|
527
|
+
};
|
|
528
|
+
if (row.valueDate !== void 0) set.valueDate = row.valueDate;
|
|
529
|
+
if (row.counterparty !== void 0) set.counterparty = row.counterparty;
|
|
530
|
+
if (row.reference !== void 0) set.reference = row.reference;
|
|
531
|
+
if (row.category !== void 0) set.vendorCategory = row.category;
|
|
532
|
+
if (row.balanceAfter !== void 0) set.balanceAfter = row.balanceAfter.amount;
|
|
533
|
+
const setOnInsert = {
|
|
534
|
+
kind: TRANSACTION_KIND.BANK_FEED,
|
|
535
|
+
status: initialStatusFor(TRANSACTION_KIND.BANK_FEED),
|
|
536
|
+
bankAccountId: opts.bankAccountId,
|
|
537
|
+
externalId: row.externalId,
|
|
538
|
+
source: opts.source,
|
|
539
|
+
type: "bank_feed",
|
|
540
|
+
tags: ["bank_feed", opts.source],
|
|
541
|
+
fee: 0,
|
|
542
|
+
tax: 0,
|
|
543
|
+
net: absoluteAmount,
|
|
544
|
+
deletedAt: null
|
|
545
|
+
};
|
|
546
|
+
if (ctx.organizationId !== void 0) setOnInsert.organizationId = ctx.organizationId;
|
|
547
|
+
ops.push({ updateOne: {
|
|
548
|
+
filter,
|
|
549
|
+
update: {
|
|
550
|
+
$set: set,
|
|
551
|
+
$setOnInsert: setOnInsert
|
|
552
|
+
},
|
|
553
|
+
upsert: true
|
|
554
|
+
} });
|
|
555
|
+
}
|
|
556
|
+
if (ops.length === 0) return {
|
|
557
|
+
inserted: 0,
|
|
558
|
+
updated: 0,
|
|
559
|
+
skipped: rows.length,
|
|
560
|
+
errors,
|
|
561
|
+
durationMs: Date.now() - startedAt
|
|
562
|
+
};
|
|
563
|
+
const sessionOption = ctx.session !== void 0 ? { session: ctx.session } : {};
|
|
564
|
+
const result = await repo.bulkWrite(ops, {
|
|
565
|
+
ordered: false,
|
|
566
|
+
...sessionOption,
|
|
567
|
+
...tenantOption
|
|
568
|
+
});
|
|
569
|
+
const inserted = (result.upsertedCount ?? 0) + (result.insertedCount ?? 0);
|
|
570
|
+
const updated = result.modifiedCount ?? 0;
|
|
571
|
+
const upsertedIds = Object.values(result.upsertedIds ?? {});
|
|
572
|
+
if (upsertedIds.length > 0) for (let i = 0; i < upsertedIds.length; i++) {
|
|
573
|
+
const id = upsertedIds[i];
|
|
574
|
+
if (id === void 0 || id === null) continue;
|
|
575
|
+
const doc = await this.getById(String(id), this.optsFromCtx(ctx, { throwOnNotFound: false }));
|
|
576
|
+
if (!doc) continue;
|
|
577
|
+
const txn = doc;
|
|
578
|
+
await this.dispatch(createEvent(REVENUE_EVENTS.TRANSACTION_IMPORTED, {
|
|
579
|
+
transaction: txn,
|
|
580
|
+
source: opts.source,
|
|
581
|
+
bankAccountId: opts.bankAccountId,
|
|
582
|
+
externalId: txn.externalId ?? ""
|
|
583
|
+
}, ctx, {
|
|
584
|
+
resource: "transaction",
|
|
585
|
+
resourceId: txn.publicId
|
|
586
|
+
}), ctx);
|
|
587
|
+
await this.deps.bridges.ledger?.onTransactionImported?.(txn, ctx);
|
|
588
|
+
}
|
|
589
|
+
return {
|
|
590
|
+
inserted,
|
|
591
|
+
updated,
|
|
592
|
+
skipped: errors.length,
|
|
593
|
+
errors,
|
|
594
|
+
durationMs: Date.now() - startedAt
|
|
595
|
+
};
|
|
596
|
+
}
|
|
597
|
+
/**
|
|
598
|
+
* Drain a bank-feed provider into the collection.
|
|
599
|
+
*
|
|
600
|
+
* Pulls pages from `provider.fetchTransactions()` (Plaid cursor, QBO
|
|
601
|
+
* CDC) and feeds each batch through `import()`. Yields the running
|
|
602
|
+
* report so a host cron can stream-progress-report to logs / metrics.
|
|
603
|
+
*
|
|
604
|
+
* Stops when the provider returns no new rows AND no removals AND no
|
|
605
|
+
* `nextCursor`. Caller is responsible for persisting the final cursor
|
|
606
|
+
* in their own checkpoint table — `result.nextCursor` is returned so
|
|
607
|
+
* the host can write it after a successful drain.
|
|
608
|
+
*
|
|
609
|
+
* Plaid `removed[]` rows (and any provider that retracts entries) are
|
|
610
|
+
* routed through `removeByFeed` so the host's LedgerBridge can void
|
|
611
|
+
* any JE that was already posted.
|
|
612
|
+
*/
|
|
613
|
+
async drainSync(providerName, params, ctx = {}) {
|
|
614
|
+
if (!this.deps.bankFeedProviders) throw new ValidationError("`bankFeedProviders` not wired on the engine. Pass `providers.bankFeed` to `createRevenue`.");
|
|
615
|
+
const provider = this.deps.bankFeedProviders.get(providerName);
|
|
616
|
+
let totalImported = 0;
|
|
617
|
+
let totalUpdated = 0;
|
|
618
|
+
let totalRemoved = 0;
|
|
619
|
+
let lastCursor;
|
|
620
|
+
const errors = [];
|
|
621
|
+
for await (const page of provider.drain(params)) {
|
|
622
|
+
if (page.transactions && page.transactions.length > 0) {
|
|
623
|
+
const report = await this.import(page.transactions, {
|
|
624
|
+
bankAccountId: params.bankAccountId,
|
|
625
|
+
source: providerName
|
|
626
|
+
}, ctx);
|
|
627
|
+
totalImported += report.inserted;
|
|
628
|
+
totalUpdated += report.updated;
|
|
629
|
+
if (report.errors.length > 0) errors.push(...report.errors);
|
|
630
|
+
}
|
|
631
|
+
if (page.removed && page.removed.length > 0) {
|
|
632
|
+
const removed = await this.removeByFeed(page.removed.map((r) => r.externalId), {
|
|
633
|
+
bankAccountId: params.bankAccountId,
|
|
634
|
+
source: providerName
|
|
635
|
+
}, ctx);
|
|
636
|
+
totalRemoved += removed.removed;
|
|
637
|
+
}
|
|
638
|
+
if (page.nextCursor) lastCursor = page.nextCursor;
|
|
639
|
+
}
|
|
640
|
+
return {
|
|
641
|
+
totalImported,
|
|
642
|
+
totalUpdated,
|
|
643
|
+
totalRemoved,
|
|
644
|
+
...lastCursor !== void 0 ? { nextCursor: lastCursor } : {},
|
|
645
|
+
errors
|
|
646
|
+
};
|
|
647
|
+
}
|
|
648
|
+
/**
|
|
649
|
+
* Parse an upload (OFX / CAMT.053 / MT940 / CSV) via a registered
|
|
650
|
+
* bank-feed provider, then `import()` the result.
|
|
651
|
+
*
|
|
652
|
+
* Convenience over manually calling `provider.parseUpload()` and
|
|
653
|
+
* threading the canonical rows into `import()` — the file-upload
|
|
654
|
+
* route handler is one line.
|
|
655
|
+
*/
|
|
656
|
+
async parseAndImport(providerName, upload, ctx = {}) {
|
|
657
|
+
if (!this.deps.bankFeedProviders) throw new ValidationError("`bankFeedProviders` not wired on the engine.");
|
|
658
|
+
const provider = this.deps.bankFeedProviders.get(providerName);
|
|
659
|
+
if (!provider.parseUpload) throw new ValidationError(`Provider '${providerName}' does not support parseUpload`);
|
|
660
|
+
const parsed = await provider.parseUpload({
|
|
661
|
+
buffer: upload.buffer,
|
|
662
|
+
...upload.format !== void 0 ? { format: upload.format } : {},
|
|
663
|
+
bankAccountId: upload.bankAccountId
|
|
664
|
+
});
|
|
665
|
+
return this.import(parsed.transactions, {
|
|
666
|
+
bankAccountId: upload.bankAccountId,
|
|
667
|
+
source: providerName
|
|
668
|
+
}, ctx);
|
|
669
|
+
}
|
|
670
|
+
/**
|
|
671
|
+
* Hand-keyed entry — treasurer logs a cash deposit, owner injects
|
|
672
|
+
* capital, refund correction. Created in `pending` (manual SM); host
|
|
673
|
+
* proceeds with `match()` → `journalize()` to post it to the ledger.
|
|
674
|
+
*
|
|
675
|
+
* `kind: 'manual'` is enforced — calls passing other kinds throw.
|
|
676
|
+
*/
|
|
677
|
+
async createManual(data, ctx = {}) {
|
|
678
|
+
return await this.create({
|
|
679
|
+
organizationId: ctx.organizationId,
|
|
680
|
+
kind: TRANSACTION_KIND.MANUAL,
|
|
681
|
+
type: data.type,
|
|
682
|
+
flow: data.flow,
|
|
683
|
+
tags: ["manual"],
|
|
684
|
+
amount: data.amount,
|
|
685
|
+
currency: data.currency,
|
|
686
|
+
fee: 0,
|
|
687
|
+
tax: 0,
|
|
688
|
+
net: data.amount,
|
|
689
|
+
method: "manual",
|
|
690
|
+
status: initialStatusFor(TRANSACTION_KIND.MANUAL),
|
|
691
|
+
source: "manual",
|
|
692
|
+
...data.description !== void 0 ? { description: data.description } : {},
|
|
693
|
+
...data.counterparty !== void 0 ? { counterparty: data.counterparty } : {},
|
|
694
|
+
...data.reference !== void 0 ? { reference: data.reference } : {},
|
|
695
|
+
...data.postedDate !== void 0 ? { postedDate: data.postedDate } : {},
|
|
696
|
+
...data.valueDate !== void 0 ? { valueDate: data.valueDate } : {},
|
|
697
|
+
...data.bankAccountId !== void 0 ? { bankAccountId: data.bankAccountId } : {},
|
|
698
|
+
...data.sourceId !== void 0 ? { sourceId: data.sourceId } : {},
|
|
699
|
+
...data.sourceModel !== void 0 ? { sourceModel: data.sourceModel } : {},
|
|
700
|
+
...data.metadata !== void 0 ? { metadata: data.metadata } : {}
|
|
701
|
+
}, this.optsFromCtx(ctx));
|
|
702
|
+
}
|
|
703
|
+
/**
|
|
704
|
+
* Match a bank-feed / manual transaction to GL accounts, optionally
|
|
705
|
+
* cross-linking to an upstream payment-flow transaction.
|
|
706
|
+
*
|
|
707
|
+
* Atomic state CAS via `claim()` — the `where: { kind: { $in: [...] } }`
|
|
708
|
+
* predicate prevents a payment-flow row from being matched through this
|
|
709
|
+
* verb. Multi-source `from` (`['imported', 'matched']`) supports
|
|
710
|
+
* re-match after `unmatch()` (`matched → imported → matched`) without
|
|
711
|
+
* losing the prior mapping if the host wants to overwrite it.
|
|
712
|
+
*
|
|
713
|
+
* After a successful claim, `LedgerBridge.onTransactionMatched` runs
|
|
714
|
+
* — the canonical implementation creates a journal entry and chains
|
|
715
|
+
* `journalize()` to record the JE ref. The bridge call is OUTSIDE the
|
|
716
|
+
* claim's CAS window because JE posting is a side effect that may
|
|
717
|
+
* take seconds (cross-process call to ledger).
|
|
718
|
+
*/
|
|
719
|
+
async match(id, data, ctx = {}) {
|
|
720
|
+
const existing = await this.getById(id, this.optsFromCtx(ctx));
|
|
721
|
+
if (!existing) throw new TransactionNotFoundError(id);
|
|
722
|
+
if (existing.kind !== TRANSACTION_KIND.BANK_FEED && existing.kind !== TRANSACTION_KIND.MANUAL) throw new WrongTransactionKindError(id, "bank_feed | manual", existing.kind);
|
|
723
|
+
smFor(existing.kind).validate(existing.status, TRANSACTION_STATUS.MATCHED, id);
|
|
724
|
+
const patch = {
|
|
725
|
+
$set: {
|
|
726
|
+
matching: {
|
|
727
|
+
...data.mapping,
|
|
728
|
+
...data.matchedBy !== void 0 ? { matchedBy: data.matchedBy } : {},
|
|
729
|
+
matchedAt: /* @__PURE__ */ new Date()
|
|
730
|
+
},
|
|
731
|
+
...data.matchedBy !== void 0 ? { verifiedBy: data.matchedBy } : {},
|
|
732
|
+
verifiedAt: /* @__PURE__ */ new Date()
|
|
733
|
+
},
|
|
734
|
+
$unset: { journalEntryRef: 1 }
|
|
735
|
+
};
|
|
736
|
+
if (data.relatedTransactionId !== void 0) patch.$set.relatedTransactionId = data.relatedTransactionId;
|
|
737
|
+
const claimed = await this.claim(existing._id, {
|
|
738
|
+
from: [
|
|
739
|
+
TRANSACTION_STATUS.IMPORTED,
|
|
740
|
+
TRANSACTION_STATUS.MATCHED,
|
|
741
|
+
TRANSACTION_STATUS.PENDING
|
|
742
|
+
],
|
|
743
|
+
to: TRANSACTION_STATUS.MATCHED,
|
|
744
|
+
where: { kind: existing.kind }
|
|
745
|
+
}, patch, this.optsFromCtx(ctx));
|
|
746
|
+
if (!claimed) throw new ValidationError(`Transaction ${id} could not be matched (race-loss or illegal state)`);
|
|
747
|
+
await this.deps.bridges.ledger?.onTransactionMatched?.(claimed, data.mapping, ctx);
|
|
748
|
+
await this.dispatch(createEvent(REVENUE_EVENTS.TRANSACTION_MATCHED, {
|
|
749
|
+
transaction: claimed,
|
|
750
|
+
mapping: data.mapping,
|
|
751
|
+
...data.relatedTransactionId !== void 0 ? { relatedTransactionId: data.relatedTransactionId } : {},
|
|
752
|
+
...data.matchedBy !== void 0 ? { matchedBy: data.matchedBy } : {}
|
|
753
|
+
}, ctx, {
|
|
754
|
+
resource: "transaction",
|
|
755
|
+
resourceId: claimed.publicId
|
|
756
|
+
}), ctx);
|
|
757
|
+
return claimed;
|
|
758
|
+
}
|
|
759
|
+
/**
|
|
760
|
+
* Revert a matched transaction back to `imported`. Clears the
|
|
761
|
+
* `matching` block and `relatedTransactionId`. Notifies the
|
|
762
|
+
* LedgerBridge (which typically voids the journal entry) AFTER the
|
|
763
|
+
* state CAS lands.
|
|
764
|
+
*
|
|
765
|
+
* Only legal for `kind: 'bank_feed'` — manual entries don't allow
|
|
766
|
+
* un-match (the manual SM has no `matched → pending` edge).
|
|
767
|
+
*/
|
|
768
|
+
async unmatch(id, options = {}, ctx = {}) {
|
|
769
|
+
const existing = await this.getById(id, this.optsFromCtx(ctx));
|
|
770
|
+
if (!existing) throw new TransactionNotFoundError(id);
|
|
771
|
+
if (existing.kind !== TRANSACTION_KIND.BANK_FEED) throw new WrongTransactionKindError(id, "bank_feed", existing.kind);
|
|
772
|
+
const priorJournalEntryRef = existing.journalEntryRef;
|
|
773
|
+
const claimed = await this.claim(existing._id, {
|
|
774
|
+
from: TRANSACTION_STATUS.MATCHED,
|
|
775
|
+
to: TRANSACTION_STATUS.IMPORTED,
|
|
776
|
+
where: { kind: TRANSACTION_KIND.BANK_FEED }
|
|
777
|
+
}, { $unset: {
|
|
778
|
+
matching: 1,
|
|
779
|
+
relatedTransactionId: 1,
|
|
780
|
+
journalEntryRef: 1,
|
|
781
|
+
verifiedBy: 1,
|
|
782
|
+
verifiedAt: 1
|
|
783
|
+
} }, this.optsFromCtx(ctx));
|
|
784
|
+
if (!claimed) throw new ValidationError(`Transaction ${id} could not be unmatched (current state is not 'matched')`);
|
|
785
|
+
await this.deps.bridges.ledger?.onTransactionUnmatched?.(claimed, priorJournalEntryRef, ctx);
|
|
786
|
+
await this.dispatch(createEvent(REVENUE_EVENTS.TRANSACTION_UNMATCHED, {
|
|
787
|
+
transaction: claimed,
|
|
788
|
+
...options.unmatchedBy !== void 0 ? { unmatchedBy: options.unmatchedBy } : {}
|
|
789
|
+
}, ctx, {
|
|
790
|
+
resource: "transaction",
|
|
791
|
+
resourceId: claimed.publicId
|
|
792
|
+
}), ctx);
|
|
793
|
+
return claimed;
|
|
794
|
+
}
|
|
795
|
+
/**
|
|
796
|
+
* Stamp the journal entry reference and transition `matched →
|
|
797
|
+
* journalized`. Typical caller is the `LedgerBridge.onTransactionMatched`
|
|
798
|
+
* implementation — after creating a JE, it calls this verb so the row
|
|
799
|
+
* carries the back-reference.
|
|
800
|
+
*/
|
|
801
|
+
async journalize(id, data, ctx = {}) {
|
|
802
|
+
const existing = await this.getById(id, this.optsFromCtx(ctx));
|
|
803
|
+
if (!existing) throw new TransactionNotFoundError(id);
|
|
804
|
+
if (existing.kind !== TRANSACTION_KIND.BANK_FEED && existing.kind !== TRANSACTION_KIND.MANUAL) throw new WrongTransactionKindError(id, "bank_feed | manual", existing.kind);
|
|
805
|
+
smFor(existing.kind).validate(existing.status, TRANSACTION_STATUS.JOURNALIZED, id);
|
|
806
|
+
const claimed = await this.claim(existing._id, {
|
|
807
|
+
from: TRANSACTION_STATUS.MATCHED,
|
|
808
|
+
to: TRANSACTION_STATUS.JOURNALIZED,
|
|
809
|
+
where: { kind: existing.kind }
|
|
810
|
+
}, { $set: { journalEntryRef: data.journalEntryRef } }, this.optsFromCtx(ctx));
|
|
811
|
+
if (!claimed) throw new ValidationError(`Transaction ${id} could not be journalized (current state is not 'matched')`);
|
|
812
|
+
await this.deps.bridges.ledger?.onTransactionJournalized?.(claimed, data.journalEntryRef, ctx);
|
|
813
|
+
await this.dispatch(createEvent(REVENUE_EVENTS.TRANSACTION_JOURNALIZED, {
|
|
814
|
+
transaction: claimed,
|
|
815
|
+
journalEntryRef: data.journalEntryRef,
|
|
816
|
+
...data.journalizedBy !== void 0 ? { journalizedBy: data.journalizedBy } : {}
|
|
817
|
+
}, ctx, {
|
|
818
|
+
resource: "transaction",
|
|
819
|
+
resourceId: claimed.publicId
|
|
820
|
+
}), ctx);
|
|
821
|
+
return claimed;
|
|
822
|
+
}
|
|
823
|
+
/**
|
|
824
|
+
* Operator skip — marks an imported / matched / pending row as
|
|
825
|
+
* rejected (terminal). Use cases: duplicate of an already-imported
|
|
826
|
+
* row, non-cash entry the host doesn't want in the ledger, manual
|
|
827
|
+
* correction overrides.
|
|
828
|
+
*
|
|
829
|
+
* `relatedTransactionId` is preserved; reversal is the host's call.
|
|
830
|
+
*/
|
|
831
|
+
async reject(id, data, ctx = {}) {
|
|
832
|
+
const existing = await this.getById(id, this.optsFromCtx(ctx));
|
|
833
|
+
if (!existing) throw new TransactionNotFoundError(id);
|
|
834
|
+
if (existing.kind !== TRANSACTION_KIND.BANK_FEED && existing.kind !== TRANSACTION_KIND.MANUAL) throw new WrongTransactionKindError(id, "bank_feed | manual", existing.kind);
|
|
835
|
+
smFor(existing.kind).validate(existing.status, TRANSACTION_STATUS.REJECTED, id);
|
|
836
|
+
const claimed = await this.claim(existing._id, {
|
|
837
|
+
from: [
|
|
838
|
+
TRANSACTION_STATUS.IMPORTED,
|
|
839
|
+
TRANSACTION_STATUS.MATCHED,
|
|
840
|
+
TRANSACTION_STATUS.PENDING
|
|
841
|
+
],
|
|
842
|
+
to: TRANSACTION_STATUS.REJECTED,
|
|
843
|
+
where: { kind: existing.kind }
|
|
844
|
+
}, { $set: {
|
|
845
|
+
failureReason: data.reason,
|
|
846
|
+
failedAt: /* @__PURE__ */ new Date(),
|
|
847
|
+
...data.rejectedBy !== void 0 ? { verifiedBy: data.rejectedBy } : {}
|
|
848
|
+
} }, this.optsFromCtx(ctx));
|
|
849
|
+
if (!claimed) throw new ValidationError(`Transaction ${id} could not be rejected (illegal current state)`);
|
|
850
|
+
await this.deps.bridges.ledger?.onTransactionRejected?.(claimed, data.reason, ctx);
|
|
851
|
+
await this.dispatch(createEvent(REVENUE_EVENTS.TRANSACTION_REJECTED, {
|
|
852
|
+
transaction: claimed,
|
|
853
|
+
reason: data.reason,
|
|
854
|
+
...data.rejectedBy !== void 0 ? { rejectedBy: data.rejectedBy } : {}
|
|
855
|
+
}, ctx, {
|
|
856
|
+
resource: "transaction",
|
|
857
|
+
resourceId: claimed.publicId
|
|
858
|
+
}), ctx);
|
|
859
|
+
return claimed;
|
|
860
|
+
}
|
|
861
|
+
/**
|
|
862
|
+
* Soft-delete bank-feed rows that the upstream feed has retracted
|
|
863
|
+
* (Plaid `removed[]`, OFX correction).
|
|
864
|
+
*
|
|
865
|
+
* Each row is matched by `(orgId, bankAccountId, externalId)`; rows
|
|
866
|
+
* already journalized are NOT silently kept — they're surfaced in
|
|
867
|
+
* `retainedJournalized` so the caller can surface them in the UI
|
|
868
|
+
* ("the feed retracted these N rows but they're posted; reverse
|
|
869
|
+
* manually"). The host's `LedgerBridge` should post a reversing JE
|
|
870
|
+
* for those before any subsequent `delete()` can succeed.
|
|
871
|
+
*
|
|
872
|
+
* @returns `removed` (count soft-deleted), `retainedJournalized`
|
|
873
|
+
* (rows kept because they're already in the GL).
|
|
874
|
+
*/
|
|
875
|
+
async removeByFeed(externalIds, opts, ctx = {}) {
|
|
876
|
+
if (externalIds.length === 0) return {
|
|
877
|
+
removed: 0,
|
|
878
|
+
retainedJournalized: []
|
|
879
|
+
};
|
|
880
|
+
const allFilter = {
|
|
881
|
+
kind: TRANSACTION_KIND.BANK_FEED,
|
|
882
|
+
bankAccountId: opts.bankAccountId,
|
|
883
|
+
externalId: { $in: externalIds },
|
|
884
|
+
deletedAt: null
|
|
885
|
+
};
|
|
886
|
+
const allDocs = await this.findAll(allFilter, this.optsFromCtx(ctx));
|
|
887
|
+
if (!Array.isArray(allDocs) || allDocs.length === 0) return {
|
|
888
|
+
removed: 0,
|
|
889
|
+
retainedJournalized: []
|
|
890
|
+
};
|
|
891
|
+
const retainedJournalized = [];
|
|
892
|
+
const removable = [];
|
|
893
|
+
for (const doc of allDocs) if (doc.status === TRANSACTION_STATUS.JOURNALIZED) retainedJournalized.push(doc);
|
|
894
|
+
else removable.push(doc);
|
|
895
|
+
let removed = 0;
|
|
896
|
+
for (const doc of removable) {
|
|
897
|
+
await this.delete(doc._id, this.optsFromCtx(ctx));
|
|
898
|
+
removed += 1;
|
|
899
|
+
await this.deps.bridges.ledger?.onTransactionRemovedByFeed?.(doc, ctx);
|
|
900
|
+
await this.dispatch(createEvent(REVENUE_EVENTS.TRANSACTION_REMOVED_BY_FEED, {
|
|
901
|
+
transaction: doc,
|
|
902
|
+
source: opts.source,
|
|
903
|
+
externalId: doc.externalId ?? ""
|
|
904
|
+
}, ctx, {
|
|
905
|
+
resource: "transaction",
|
|
906
|
+
resourceId: doc.publicId
|
|
907
|
+
}), ctx);
|
|
908
|
+
}
|
|
909
|
+
return {
|
|
910
|
+
removed,
|
|
911
|
+
retainedJournalized
|
|
912
|
+
};
|
|
913
|
+
}
|
|
914
|
+
/**
|
|
915
|
+
* Find candidate matches for cross-referencing a payment-flow row to
|
|
916
|
+
* its bank deposit (or vice-versa).
|
|
917
|
+
*
|
|
918
|
+
* Heuristic:
|
|
919
|
+
* - same currency by default; cross-currency requires `fxRate` on
|
|
920
|
+
* the candidate row (multi-currency reconciliation).
|
|
921
|
+
* - amount within `amountTolerancePct` (default 1%) — accounts for
|
|
922
|
+
* gateway fees / FX rounding.
|
|
923
|
+
* - posted/created within `toleranceDays` of the target date
|
|
924
|
+
* (default 3 days — covers ACH delays, weekend settlement).
|
|
925
|
+
* - terminal verified states only (`verified` / `completed` for
|
|
926
|
+
* payment_flow, `imported` / `matched` for bank_feed).
|
|
927
|
+
*
|
|
928
|
+
* Returned candidates are unsorted; callers rank by their own
|
|
929
|
+
* confidence model (counterparty fuzzy match, currency identity,
|
|
930
|
+
* exact-amount preference, …).
|
|
931
|
+
*/
|
|
932
|
+
async findMatchCandidates(filter, ctx = {}) {
|
|
933
|
+
const tolerance = filter.toleranceDays ?? 3;
|
|
934
|
+
const pct = filter.amountTolerancePct ?? .01;
|
|
935
|
+
const start = /* @__PURE__ */ new Date(filter.postedDate.getTime() - tolerance * 864e5);
|
|
936
|
+
const end = new Date(filter.postedDate.getTime() + tolerance * 864e5);
|
|
937
|
+
const minAmount = filter.amount * (1 - pct);
|
|
938
|
+
const maxAmount = filter.amount * (1 + pct);
|
|
939
|
+
const targetKind = filter.kind ?? TRANSACTION_KIND.PAYMENT_FLOW;
|
|
940
|
+
const query = {
|
|
941
|
+
kind: targetKind,
|
|
942
|
+
status: { $in: targetKind === TRANSACTION_KIND.PAYMENT_FLOW ? [TRANSACTION_STATUS.VERIFIED, TRANSACTION_STATUS.COMPLETED] : [TRANSACTION_STATUS.IMPORTED, TRANSACTION_STATUS.MATCHED] },
|
|
943
|
+
amount: {
|
|
944
|
+
$gte: minAmount,
|
|
945
|
+
$lte: maxAmount
|
|
946
|
+
},
|
|
947
|
+
$or: [{ postedDate: {
|
|
948
|
+
$gte: start,
|
|
949
|
+
$lte: end
|
|
950
|
+
} }, { createdAt: {
|
|
951
|
+
$gte: start,
|
|
952
|
+
$lte: end
|
|
953
|
+
} }]
|
|
954
|
+
};
|
|
955
|
+
if (filter.currency !== void 0) query.currency = filter.currency;
|
|
956
|
+
if (filter.counterpartyName !== void 0) query["counterparty.name"] = {
|
|
957
|
+
$regex: escapeRegex(filter.counterpartyName),
|
|
958
|
+
$options: "i"
|
|
959
|
+
};
|
|
960
|
+
const docs = await this.findAll(query, this.optsFromCtx(ctx, { limit: 50 }));
|
|
961
|
+
return Array.isArray(docs) ? docs : [];
|
|
962
|
+
}
|
|
963
|
+
/**
|
|
964
|
+
* Running balance for a bank account as of `asOf` (defaults to now).
|
|
965
|
+
*
|
|
966
|
+
* Uses mongokit's tenant-scoped read via `findAll` — inflows minus
|
|
967
|
+
* outflows over `kind: 'bank_feed'`, terminal states only. For audit
|
|
968
|
+
* pages where exact-to-the-cent reconciliation is required, prefer
|
|
969
|
+
* the most recent row's `balanceAfter` (banks ship that field on
|
|
970
|
+
* every entry).
|
|
971
|
+
*/
|
|
972
|
+
async getRunningBalance(bankAccountId, asOf = /* @__PURE__ */ new Date(), ctx = {}) {
|
|
973
|
+
const filter = {
|
|
974
|
+
kind: TRANSACTION_KIND.BANK_FEED,
|
|
975
|
+
bankAccountId,
|
|
976
|
+
postedDate: { $lte: asOf },
|
|
977
|
+
status: { $in: [
|
|
978
|
+
TRANSACTION_STATUS.IMPORTED,
|
|
979
|
+
TRANSACTION_STATUS.MATCHED,
|
|
980
|
+
TRANSACTION_STATUS.JOURNALIZED
|
|
981
|
+
] },
|
|
982
|
+
deletedAt: null
|
|
983
|
+
};
|
|
984
|
+
const rows = await this.findAll(filter, this.optsFromCtx(ctx));
|
|
985
|
+
let balance = 0;
|
|
986
|
+
let currency = null;
|
|
987
|
+
for (const row of rows) {
|
|
988
|
+
if (currency === null) currency = row.currency;
|
|
989
|
+
balance += row.flow === "inflow" ? row.amount : -row.amount;
|
|
990
|
+
}
|
|
991
|
+
return {
|
|
992
|
+
balance,
|
|
993
|
+
currency,
|
|
994
|
+
rowCount: rows.length,
|
|
995
|
+
asOf
|
|
996
|
+
};
|
|
997
|
+
}
|
|
460
998
|
};
|
|
999
|
+
/** Escape user-provided strings before embedding in `$regex`. */
|
|
1000
|
+
function escapeRegex(input) {
|
|
1001
|
+
return input.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
1002
|
+
}
|
|
461
1003
|
|
|
462
1004
|
//#endregion
|
|
463
1005
|
//#region src/repositories/subscription.repository.ts
|
|
@@ -656,7 +1198,7 @@ var SettlementRepository = class extends Repository {
|
|
|
656
1198
|
filters: query,
|
|
657
1199
|
limit: options.limit ?? 50,
|
|
658
1200
|
sort: { scheduledAt: 1 }
|
|
659
|
-
})).
|
|
1201
|
+
})).data ?? [];
|
|
660
1202
|
if (options.dryRun) return {
|
|
661
1203
|
processed: pending.length,
|
|
662
1204
|
succeeded: 0,
|
package/dist/shared/index.d.mts
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { A as SplitInfo, B as validateTaxCalculation, C as multiplyMoney, D as toCurrencyCode, E as sumMoney, F as TaxConfig, H as calculateCommission, I as TaxType, L as calculateTax, M as calculateOrganizationPayout, N as calculateSplits, O as toMajor, P as TaxCalculation, R as getTaxType, S as money, T as subtractMoney, U as reverseCommission, V as CommissionInfo, _ as isMoney, a as CurrencyCode, b as isZeroMoney, c as Money, d as addMoney, f as compareMoney, g as isCurrencyCode, h as fromSmallestUnit, i as CURRENCIES, j as SplitRule, k as toSmallestUnit, l as MoneyValue, m as fromMajor, n as getAuditTrail, o as CurrencyMismatchError, p as equalsMoney, r as getLastStateChange, s as MINOR_UNIT_FACTOR, t as appendAuditEvent, u as absMoney, v as isNegativeMoney, w as negateMoney, x as minorUnitFactor, y as isPositiveMoney, z as reverseTax } from "../audit-
|
|
1
|
+
import { A as SplitInfo, B as validateTaxCalculation, C as multiplyMoney, D as toCurrencyCode, E as sumMoney, F as TaxConfig, H as calculateCommission, I as TaxType, L as calculateTax, M as calculateOrganizationPayout, N as calculateSplits, O as toMajor, P as TaxCalculation, R as getTaxType, S as money, T as subtractMoney, U as reverseCommission, V as CommissionInfo, _ as isMoney, a as CurrencyCode, b as isZeroMoney, c as Money, d as addMoney, f as compareMoney, g as isCurrencyCode, h as fromSmallestUnit, i as CURRENCIES, j as SplitRule, k as toSmallestUnit, l as MoneyValue, m as fromMajor, n as getAuditTrail, o as CurrencyMismatchError, p as equalsMoney, r as getLastStateChange, s as MINOR_UNIT_FACTOR, t as appendAuditEvent, u as absMoney, v as isNegativeMoney, w as negateMoney, x as minorUnitFactor, y as isPositiveMoney, z as reverseTax } from "../audit-DRKuLBFO.mjs";
|
|
2
2
|
export { CURRENCIES, CommissionInfo, type CurrencyCode, CurrencyMismatchError, MINOR_UNIT_FACTOR, type Money, type MoneyValue, SplitInfo, SplitRule, TaxCalculation, TaxConfig, TaxType, absMoney, addMoney, appendAuditEvent, calculateCommission, calculateOrganizationPayout, calculateSplits, calculateTax, compareMoney, equalsMoney, fromMajor, fromSmallestUnit, getAuditTrail, getLastStateChange, getTaxType, isCurrencyCode, isMoney, isNegativeMoney, isPositiveMoney, isZeroMoney, minorUnitFactor, money, multiplyMoney, negateMoney, reverseCommission, reverseTax, subtractMoney, sumMoney, toCurrencyCode, toMajor, toSmallestUnit, validateTaxCalculation };
|
package/dist/shared/index.mjs
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { a as reverseTax, c as reverseCommission, i as getTaxType, n as calculateSplits, o as validateTaxCalculation, r as calculateTax, s as calculateCommission, t as calculateOrganizationPayout } from "../splits-
|
|
2
|
-
import { C as sumMoney, E as toSmallestUnit, S as subtractMoney, T as toMajor, _ as isZeroMoney, a as CurrencyMismatchError, b as multiplyMoney, c as addMoney, d as fromMajor, f as fromSmallestUnit, g as isPositiveMoney, h as isNegativeMoney, i as CURRENCIES, l as compareMoney, m as isMoney, n as getAuditTrail, o as MINOR_UNIT_FACTOR, p as isCurrencyCode, r as getLastStateChange, s as absMoney, t as appendAuditEvent, u as equalsMoney, v as minorUnitFactor, w as toCurrencyCode, x as negateMoney, y as money } from "../audit-
|
|
1
|
+
import { a as reverseTax, c as reverseCommission, i as getTaxType, n as calculateSplits, o as validateTaxCalculation, r as calculateTax, s as calculateCommission, t as calculateOrganizationPayout } from "../splits-D8XkNWgX.mjs";
|
|
2
|
+
import { C as sumMoney, E as toSmallestUnit, S as subtractMoney, T as toMajor, _ as isZeroMoney, a as CurrencyMismatchError, b as multiplyMoney, c as addMoney, d as fromMajor, f as fromSmallestUnit, g as isPositiveMoney, h as isNegativeMoney, i as CURRENCIES, l as compareMoney, m as isMoney, n as getAuditTrail, o as MINOR_UNIT_FACTOR, p as isCurrencyCode, r as getLastStateChange, s as absMoney, t as appendAuditEvent, u as equalsMoney, v as minorUnitFactor, w as toCurrencyCode, x as negateMoney, y as money } from "../audit-Ba2XB2C4.mjs";
|
|
3
3
|
|
|
4
4
|
export { CURRENCIES, CurrencyMismatchError, MINOR_UNIT_FACTOR, absMoney, addMoney, appendAuditEvent, calculateCommission, calculateOrganizationPayout, calculateSplits, calculateTax, compareMoney, equalsMoney, fromMajor, fromSmallestUnit, getAuditTrail, getLastStateChange, getTaxType, isCurrencyCode, isMoney, isNegativeMoney, isPositiveMoney, isZeroMoney, minorUnitFactor, money, multiplyMoney, negateMoney, reverseCommission, reverseTax, subtractMoney, sumMoney, toCurrencyCode, toMajor, toSmallestUnit, validateTaxCalculation };
|
|
@@ -1,42 +1,3 @@
|
|
|
1
|
-
//#region src/enums/transaction.enums.ts
|
|
2
|
-
const TRANSACTION_FLOW = {
|
|
3
|
-
INFLOW: "inflow",
|
|
4
|
-
OUTFLOW: "outflow"
|
|
5
|
-
};
|
|
6
|
-
const TRANSACTION_FLOW_VALUES = Object.values(TRANSACTION_FLOW);
|
|
7
|
-
const TRANSACTION_STATUS = {
|
|
8
|
-
PENDING: "pending",
|
|
9
|
-
PAYMENT_INITIATED: "payment_initiated",
|
|
10
|
-
PROCESSING: "processing",
|
|
11
|
-
REQUIRES_ACTION: "requires_action",
|
|
12
|
-
VERIFIED: "verified",
|
|
13
|
-
COMPLETED: "completed",
|
|
14
|
-
FAILED: "failed",
|
|
15
|
-
CANCELLED: "cancelled",
|
|
16
|
-
EXPIRED: "expired",
|
|
17
|
-
REFUNDED: "refunded",
|
|
18
|
-
PARTIALLY_REFUNDED: "partially_refunded"
|
|
19
|
-
};
|
|
20
|
-
const TRANSACTION_STATUS_VALUES = Object.values(TRANSACTION_STATUS);
|
|
21
|
-
const LIBRARY_CATEGORIES = {
|
|
22
|
-
SUBSCRIPTION: "subscription",
|
|
23
|
-
PURCHASE: "purchase"
|
|
24
|
-
};
|
|
25
|
-
const LIBRARY_CATEGORY_VALUES = Object.values(LIBRARY_CATEGORIES);
|
|
26
|
-
const transactionFlowSet = new Set(TRANSACTION_FLOW_VALUES);
|
|
27
|
-
const transactionStatusSet = new Set(TRANSACTION_STATUS_VALUES);
|
|
28
|
-
const libraryCategorySet = new Set(LIBRARY_CATEGORY_VALUES);
|
|
29
|
-
function isLibraryCategory(value) {
|
|
30
|
-
return typeof value === "string" && libraryCategorySet.has(value);
|
|
31
|
-
}
|
|
32
|
-
function isTransactionFlow(value) {
|
|
33
|
-
return typeof value === "string" && transactionFlowSet.has(value);
|
|
34
|
-
}
|
|
35
|
-
function isTransactionStatus(value) {
|
|
36
|
-
return typeof value === "string" && transactionStatusSet.has(value);
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
//#endregion
|
|
40
1
|
//#region src/enums/escrow.enums.ts
|
|
41
2
|
const HOLD_STATUS = {
|
|
42
3
|
PENDING: "pending",
|
|
@@ -169,4 +130,4 @@ function isPlanKey(value) {
|
|
|
169
130
|
}
|
|
170
131
|
|
|
171
132
|
//#endregion
|
|
172
|
-
export { isReleaseReason as A, HOLD_REASON_VALUES as C, RELEASE_REASON_VALUES as D, RELEASE_REASON as E,
|
|
133
|
+
export { isReleaseReason as A, HOLD_REASON_VALUES as C, RELEASE_REASON_VALUES as D, RELEASE_REASON as E, isHoldReason as O, HOLD_REASON as S, HOLD_STATUS_VALUES as T, SETTLEMENT_STATUS_VALUES as _, isPlanKey as a, isSettlementStatus as b, PAYOUT_METHOD_VALUES as c, SPLIT_TYPE as d, SPLIT_TYPE_VALUES as f, SETTLEMENT_STATUS as g, isSplitType as h, SUBSCRIPTION_STATUS_VALUES as i, isHoldStatus as k, SPLIT_STATUS as l, isSplitStatus as m, PLAN_KEY_VALUES as n, isSubscriptionStatus as o, isPayoutMethod as p, SUBSCRIPTION_STATUS as r, PAYOUT_METHOD as s, PLAN_KEYS as t, SPLIT_STATUS_VALUES as u, SETTLEMENT_TYPE as v, HOLD_STATUS as w, isSettlementType as x, SETTLEMENT_TYPE_VALUES as y };
|