@classytic/revenue 2.1.3 → 2.2.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.
@@ -1,7 +1,7 @@
1
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-Dn1TKahe.mjs";
2
+ import { n as createEvent, t as REVENUE_EVENTS } from "./event-constants-DM_-A57b.mjs";
3
3
  import { g as SETTLEMENT_STATUS, r as SUBSCRIPTION_STATUS, w as HOLD_STATUS } from "./subscription.enums-95othr0i.mjs";
4
- import { f as SettlementNotFoundError, g as WrongTransactionKindError, h as ValidationError, m as TransactionNotFoundError, n as BankFeedImportError, p as SubscriptionNotFoundError } from "./errors-LYYg9wcs.mjs";
4
+ import { _ as WrongTransactionKindError, g as ValidationError, h as TransactionNotFoundError, m as SubscriptionNotFoundError, n as BankFeedImportError, o as MethodKindLockedError, p as SettlementNotFoundError } from "./errors-Bt5NRVMq.mjs";
5
5
  import { SETTLEMENT_STATE_MACHINE, SUBSCRIPTION_STATE_MACHINE, TRANSACTION_STATE_MACHINE, smFor } from "./core/state-machines.mjs";
6
6
  import { a as reverseTax, c as reverseCommission, n as calculateSplits, s as calculateCommission, t as calculateOrganizationPayout } from "./splits-CNfQj92L.mjs";
7
7
  import { Repository, repoOptionsFromCtx, withTransaction } from "@classytic/mongokit";
@@ -212,6 +212,7 @@ var TransactionRepository = class extends RevenueRepositoryBase {
212
212
  amount: params.amount,
213
213
  currency
214
214
  },
215
+ methodKind: params.methodKind,
215
216
  metadata: params.metadata,
216
217
  ...params.paymentData
217
218
  });
@@ -238,6 +239,7 @@ var TransactionRepository = class extends RevenueRepositoryBase {
238
239
  tax: 0,
239
240
  net: params.amount - (commission?.gatewayFeeAmount ?? 0),
240
241
  method: params.gateway,
242
+ methodKind: params.methodKind,
241
243
  status: params.amount === 0 ? TRANSACTION_STATUS.VERIFIED : TRANSACTION_STATUS.PENDING,
242
244
  gateway: gatewayData,
243
245
  commission: commission ?? void 0,
@@ -342,6 +344,7 @@ var TransactionRepository = class extends RevenueRepositoryBase {
342
344
  tax: reversedTax?.taxAmount ?? 0,
343
345
  net: refundAmount - (reversedCommission?.gatewayFeeAmount ?? 0) - (reversedTax?.taxAmount ?? 0),
344
346
  method: transaction.method,
347
+ methodKind: transaction.methodKind,
345
348
  status: TRANSACTION_STATUS.VERIFIED,
346
349
  gateway: transaction.gateway,
347
350
  commission: reversedCommission ?? void 0,
@@ -479,6 +482,7 @@ var TransactionRepository = class extends RevenueRepositoryBase {
479
482
  tax: 0,
480
483
  net: releaseAmount,
481
484
  method: transaction.method,
485
+ methodKind: transaction.methodKind,
482
486
  status: TRANSACTION_STATUS.VERIFIED,
483
487
  relatedTransactionId: transaction._id,
484
488
  sourceId: transaction.sourceId,
@@ -533,6 +537,7 @@ var TransactionRepository = class extends RevenueRepositoryBase {
533
537
  tax: 0,
534
538
  net: s.netAmount,
535
539
  method: transaction.method,
540
+ methodKind: transaction.methodKind,
536
541
  status: TRANSACTION_STATUS.VERIFIED,
537
542
  relatedTransactionId: transaction._id,
538
543
  sourceId: transaction.sourceId,
@@ -557,6 +562,7 @@ var TransactionRepository = class extends RevenueRepositoryBase {
557
562
  tax: 0,
558
563
  net: orgPayout,
559
564
  method: transaction.method,
565
+ methodKind: transaction.methodKind,
560
566
  status: TRANSACTION_STATUS.VERIFIED,
561
567
  relatedTransactionId: transaction._id,
562
568
  verifiedAt: /* @__PURE__ */ new Date()
@@ -604,6 +610,7 @@ var TransactionRepository = class extends RevenueRepositoryBase {
604
610
  * `source` (provenance — `'plaid'`, `'ofx'`, …).
605
611
  */
606
612
  async import(rows, opts, ctx = {}) {
613
+ if (!opts.methodKind) throw new BankFeedImportError("`opts.methodKind` is required on TransactionRepository.import() — pick the canonical PaymentMethodKind for the source (e.g. `'bank_transfer'` for Plaid/OFX, `'card'` for a Stripe balance, `'wallet'` for PayPal, `'cryptocurrency'` for an exchange).");
607
614
  const startedAt = Date.now();
608
615
  if (!Array.isArray(rows) || rows.length === 0) return {
609
616
  inserted: 0,
@@ -663,6 +670,7 @@ var TransactionRepository = class extends RevenueRepositoryBase {
663
670
  source: opts.source,
664
671
  type: "bank_feed",
665
672
  tags: ["bank_feed", opts.source],
673
+ methodKind: opts.methodKind,
666
674
  fee: 0,
667
675
  tax: 0,
668
676
  net: absoluteAmount,
@@ -747,7 +755,8 @@ var TransactionRepository = class extends RevenueRepositoryBase {
747
755
  if (page.transactions && page.transactions.length > 0) {
748
756
  const report = await this.import(page.transactions, {
749
757
  bankAccountId: params.bankAccountId,
750
- source: providerName
758
+ source: providerName,
759
+ methodKind: params.methodKind
751
760
  }, ctx);
752
761
  totalImported += report.inserted;
753
762
  totalUpdated += report.updated;
@@ -789,7 +798,8 @@ var TransactionRepository = class extends RevenueRepositoryBase {
789
798
  });
790
799
  return this.import(parsed.transactions, {
791
800
  bankAccountId: upload.bankAccountId,
792
- source: providerName
801
+ source: providerName,
802
+ methodKind: upload.methodKind
793
803
  }, ctx);
794
804
  }
795
805
  /**
@@ -812,6 +822,7 @@ var TransactionRepository = class extends RevenueRepositoryBase {
812
822
  tax: 0,
813
823
  net: data.amount,
814
824
  method: "manual",
825
+ methodKind: data.methodKind,
815
826
  status: initialStatusFor(TRANSACTION_KIND.MANUAL),
816
827
  source: "manual",
817
828
  ...data.description !== void 0 ? { description: data.description } : {},
@@ -826,6 +837,56 @@ var TransactionRepository = class extends RevenueRepositoryBase {
826
837
  }, this.optsFromCtx(ctx));
827
838
  }
828
839
  /**
840
+ * Backfill the `methodKind` on a Transaction created with kind
841
+ * unknown — the canonical use case is hosted-checkout (Stripe
842
+ * Checkout, PayPal redirect, Razorpay Checkout) where the customer
843
+ * picks their payment method on the gateway's UI, AFTER the host has
844
+ * already created the PaymentIntent + Transaction with
845
+ * `methodKind: 'other'`.
846
+ *
847
+ * Call this from your verification / webhook handler once you know
848
+ * the customer's actual choice — e.g. inside
849
+ * `payment_intent.succeeded`:
850
+ *
851
+ * ```ts
852
+ * await transactionRepository.backfillMethodKind(
853
+ * tx._id,
854
+ * stripePaymentIntentToKind(event.data.object),
855
+ * ctx,
856
+ * );
857
+ * ```
858
+ *
859
+ * **Guard rule.** Atomic CAS — succeeds only when the doc has
860
+ * `methodKind === 'other'` AND `status === 'pending'`. Any other
861
+ * combination throws `MethodKindLockedError` (HTTP 409): once a
862
+ * transaction has a specific kind (or has settled past pending),
863
+ * silently overwriting it would corrupt downstream analytics and
864
+ * accounting reports.
865
+ *
866
+ * Emits `revenue:transaction.updated` with `changedFields:
867
+ * ['methodKind']` so subscribers can re-bucket the row.
868
+ */
869
+ async backfillMethodKind(transactionId, methodKind, ctx = {}) {
870
+ const updated = await this.findOneAndUpdate({
871
+ _id: transactionId,
872
+ methodKind: "other",
873
+ status: TRANSACTION_STATUS.PENDING
874
+ }, { $set: { methodKind } }, { returnDocument: "after" });
875
+ if (!updated) {
876
+ const existing = await this.getById(transactionId, this.optsFromCtx(ctx, { throwOnNotFound: false }));
877
+ if (!existing) throw new TransactionNotFoundError(transactionId);
878
+ throw new MethodKindLockedError(transactionId, existing.methodKind ?? "unknown", existing.status ?? "unknown");
879
+ }
880
+ await this.dispatch(createEvent(REVENUE_EVENTS.TRANSACTION_UPDATED, {
881
+ transaction: updated,
882
+ changedFields: ["methodKind"]
883
+ }, ctx, {
884
+ resource: "transaction",
885
+ resourceId: updated.publicId
886
+ }), ctx);
887
+ return updated;
888
+ }
889
+ /**
829
890
  * Match a bank-feed / manual transaction to GL accounts, optionally
830
891
  * cross-linking to an upstream payment-flow transaction.
831
892
  *
@@ -1,4 +1,4 @@
1
- import { A as transactionBaseSchema, C as subscriptionBaseSchema, D as TransactionCreateInput, E as subscriptionUpdateSchema, M as transactionListFilterSchema, N as transactionUpdateSchema, O as TransactionListFilter, S as SubscriptionUpdateInput, T as subscriptionListFilterSchema, _ as settlementCreateSchema, a as escrowReleaseSchema, b as SubscriptionCreateInput, c as PaymentVerifyInput, d as paymentVerifySchema, f as refundSchema, g as settlementBaseSchema, h as SettlementUpdateInput, i as escrowHoldSchema, j as transactionCreateSchema, k as TransactionUpdateInput, l as RefundInput, m as SettlementListFilter, n as EscrowReleaseInput, o as splitRuleSchema, p as SettlementCreateInput, r as SplitRuleInput, s as PaymentIntentInput, t as EscrowHoldInput, u as paymentIntentSchema, v as settlementListFilterSchema, w as subscriptionCreateSchema, x as SubscriptionListFilter, y as settlementUpdateSchema } from "../escrow.schema-YuBgjL-I.mjs";
1
+ import { A as transactionBaseSchema, C as subscriptionBaseSchema, D as TransactionCreateInput, E as subscriptionUpdateSchema, M as transactionListFilterSchema, N as transactionUpdateSchema, O as TransactionListFilter, S as SubscriptionUpdateInput, T as subscriptionListFilterSchema, _ as settlementCreateSchema, a as escrowReleaseSchema, b as SubscriptionCreateInput, c as PaymentVerifyInput, d as paymentVerifySchema, f as refundSchema, g as settlementBaseSchema, h as SettlementUpdateInput, i as escrowHoldSchema, j as transactionCreateSchema, k as TransactionUpdateInput, l as RefundInput, m as SettlementListFilter, n as EscrowReleaseInput, o as splitRuleSchema, p as SettlementCreateInput, r as SplitRuleInput, s as PaymentIntentInput, t as EscrowHoldInput, u as paymentIntentSchema, v as settlementListFilterSchema, w as subscriptionCreateSchema, x as SubscriptionListFilter, y as settlementUpdateSchema } from "../escrow.schema-BdDHuQ8C.mjs";
2
2
  import { z } from "zod";
3
3
 
4
4
  //#region src/validators/bank-feed.schema.d.ts
@@ -1,5 +1,5 @@
1
1
  import { n as BANK_FEED_SOURCE_VALUES, o as TRANSACTION_KIND_VALUES } from "../bank-feed.enums-kYTLTTbe.mjs";
2
- import { _ as transactionListFilterSchema, a as paymentVerifySchema, c as settlementCreateSchema, d as subscriptionBaseSchema, f as subscriptionCreateSchema, g as transactionCreateSchema, h as transactionBaseSchema, i as paymentIntentSchema, l as settlementListFilterSchema, m as subscriptionUpdateSchema, n as escrowReleaseSchema, o as refundSchema, p as subscriptionListFilterSchema, r as splitRuleSchema, s as settlementBaseSchema, t as escrowHoldSchema, u as settlementUpdateSchema, v as transactionUpdateSchema } from "../escrow.schema-C-b41z_G.mjs";
2
+ import { _ as transactionListFilterSchema, a as paymentVerifySchema, c as settlementCreateSchema, d as subscriptionBaseSchema, f as subscriptionCreateSchema, g as transactionCreateSchema, h as transactionBaseSchema, i as paymentIntentSchema, l as settlementListFilterSchema, m as subscriptionUpdateSchema, n as escrowReleaseSchema, o as refundSchema, p as subscriptionListFilterSchema, r as splitRuleSchema, s as settlementBaseSchema, t as escrowHoldSchema, u as settlementUpdateSchema, v as transactionUpdateSchema } from "../escrow.schema-BcKdzrJ7.mjs";
3
3
  import { z } from "zod";
4
4
 
5
5
  //#region src/validators/bank-feed.schema.ts
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@classytic/revenue",
3
- "version": "2.1.3",
3
+ "version": "2.2.0",
4
4
  "description": "Payment lifecycle engine — transactions, subscriptions, escrow, settlements, commissions. MongoKit-powered, Arc-compatible, framework-agnostic.",
5
5
  "type": "module",
6
6
  "sideEffects": false,
@@ -101,7 +101,7 @@
101
101
  ],
102
102
  "peerDependencies": {
103
103
  "@classytic/mongokit": ">=3.13.3",
104
- "@classytic/primitives": ">=0.5.0",
104
+ "@classytic/primitives": ">=0.7.1",
105
105
  "@classytic/repo-core": ">=0.4.2",
106
106
  "mongoose": ">=9.4.1",
107
107
  "zod": ">=4.0.0"
@@ -111,7 +111,7 @@
111
111
  },
112
112
  "devDependencies": {
113
113
  "@classytic/mongokit": "^3.13.3",
114
- "@classytic/primitives": ">=0.5.0",
114
+ "@classytic/primitives": "^0.7.1",
115
115
  "@classytic/repo-core": "^0.4.2",
116
116
  "@types/node": "^22.8.7",
117
117
  "mongoose": "^9.4.1",