@wopr-network/platform-core 1.13.2 → 1.14.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/api/routes/admin-credits.d.ts +2 -2
- package/dist/api/routes/admin-credits.js +9 -4
- package/dist/api/routes/quota.d.ts +2 -2
- package/dist/api/routes/verify-email.d.ts +3 -3
- package/dist/backup/on-demand-snapshot-service.d.ts +2 -2
- package/dist/billing/payram/webhook.d.ts +3 -3
- package/dist/billing/payram/webhook.js +5 -1
- package/dist/billing/payram/webhook.test.js +5 -4
- package/dist/billing/stripe/stripe-payment-processor.d.ts +2 -2
- package/dist/billing/stripe/stripe-payment-processor.test.js +7 -0
- package/dist/billing/stripe/tenant-store.d.ts +1 -1
- package/dist/billing/stripe/tenant-store.js +1 -1
- package/dist/credits/auto-topup-charge.d.ts +2 -2
- package/dist/credits/auto-topup-charge.js +5 -1
- package/dist/credits/auto-topup-charge.test.js +5 -4
- package/dist/credits/auto-topup-usage.d.ts +2 -2
- package/dist/credits/auto-topup-usage.test.js +53 -12
- package/dist/credits/credit-expiry-cron.d.ts +2 -2
- package/dist/credits/credit-expiry-cron.js +7 -4
- package/dist/credits/credit-expiry-cron.test.js +25 -8
- package/dist/credits/credit-ledger.d.ts +2 -2
- package/dist/credits/credit-ledger.js +1 -1
- package/dist/credits/dividend-cron.d.ts +4 -6
- package/dist/credits/dividend-cron.js +10 -16
- package/dist/credits/dividend-cron.test.js +31 -44
- package/dist/credits/dividend-repository.js +19 -22
- package/dist/credits/dividend-repository.test.js +4 -3
- package/dist/credits/index.d.ts +4 -2
- package/dist/credits/index.js +2 -1
- package/dist/credits/ledger.d.ts +195 -0
- package/dist/credits/ledger.js +561 -0
- package/dist/credits/ledger.test.js +418 -0
- package/dist/credits/signup-grant.d.ts +2 -2
- package/dist/credits/signup-grant.js +4 -4
- package/dist/credits/signup-grant.test.js +5 -3
- package/dist/credits/trial-balance-cron.d.ts +19 -0
- package/dist/credits/trial-balance-cron.js +30 -0
- package/dist/credits/trial-balance-cron.test.js +55 -0
- package/dist/db/schema/gateway-service-keys.d.ts +109 -0
- package/dist/db/schema/gateway-service-keys.js +18 -0
- package/dist/db/schema/index.d.ts +2 -0
- package/dist/db/schema/index.js +2 -0
- package/dist/db/schema/ledger.d.ts +442 -0
- package/dist/db/schema/ledger.js +76 -0
- package/dist/gateway/credit-gate.d.ts +2 -2
- package/dist/gateway/credit-gate.js +5 -1
- package/dist/gateway/credit-gate.test.js +35 -33
- package/dist/gateway/gateway-routes.test.js +1 -1
- package/dist/gateway/index.d.ts +2 -0
- package/dist/gateway/index.js +1 -0
- package/dist/gateway/protocol/anthropic.js +1 -1
- package/dist/gateway/protocol/deps.d.ts +5 -5
- package/dist/gateway/protocol/openai.js +1 -1
- package/dist/gateway/proxy.d.ts +4 -4
- package/dist/gateway/route-mounting.test.js +1 -1
- package/dist/gateway/service-key-auth.d.ts +1 -1
- package/dist/gateway/service-key-auth.js +1 -1
- package/dist/gateway/service-key-repository.d.ts +27 -0
- package/dist/gateway/service-key-repository.js +64 -0
- package/dist/gateway/types.d.ts +5 -5
- package/dist/metering/reconciliation-cron.test.js +9 -8
- package/dist/metering/reconciliation-repository.js +12 -10
- package/dist/metering/reconciliation-repository.test.js +9 -8
- package/dist/monetization/affiliate/affiliate-admin-repository.js +10 -8
- package/dist/monetization/affiliate/affiliate-admin-repository.test.js +32 -13
- package/dist/monetization/affiliate/credit-match.d.ts +2 -2
- package/dist/monetization/affiliate/credit-match.js +4 -1
- package/dist/monetization/affiliate/credit-match.test.js +58 -13
- package/dist/monetization/affiliate/new-user-bonus.d.ts +2 -2
- package/dist/monetization/affiliate/new-user-bonus.js +4 -1
- package/dist/monetization/affiliate/new-user-bonus.test.js +4 -3
- package/dist/monetization/credits/auto-topup-charge.d.ts +2 -2
- package/dist/monetization/credits/auto-topup-charge.js +5 -1
- package/dist/monetization/credits/auto-topup-charge.test.js +5 -4
- package/dist/monetization/credits/auto-topup-usage.d.ts +2 -2
- package/dist/monetization/credits/auto-topup-usage.test.js +53 -12
- package/dist/monetization/credits/bot-billing.d.ts +3 -3
- package/dist/monetization/credits/bot-billing.test.js +18 -5
- package/dist/monetization/credits/credit-expiry-cron.test.js +25 -8
- package/dist/monetization/credits/dividend-cron.d.ts +2 -4
- package/dist/monetization/credits/dividend-cron.js +7 -4
- package/dist/monetization/credits/dividend-cron.test.js +26 -46
- package/dist/monetization/credits/dividend-repository.js +15 -24
- package/dist/monetization/credits/dividend-repository.test.js +4 -3
- package/dist/monetization/credits/index.d.ts +2 -2
- package/dist/monetization/credits/index.js +1 -1
- package/dist/monetization/credits/member-usage.test.js +23 -10
- package/dist/monetization/credits/phone-billing.d.ts +2 -2
- package/dist/monetization/credits/phone-billing.js +5 -1
- package/dist/monetization/credits/phone-billing.test.js +9 -12
- package/dist/monetization/credits/runtime-cron.d.ts +2 -2
- package/dist/monetization/credits/runtime-cron.js +32 -8
- package/dist/monetization/credits/runtime-cron.test.js +28 -27
- package/dist/monetization/credits/runtime-scheduler.d.ts +2 -2
- package/dist/monetization/credits/runtime-scheduler.test.js +1 -1
- package/dist/monetization/credits/signup-grant.test.js +5 -3
- package/dist/monetization/credits/storage-tier-cron.test.js +3 -2
- package/dist/monetization/credits/trial-balance-cron.test.js +42 -0
- package/dist/monetization/feature-gate.d.ts +3 -3
- package/dist/monetization/index.d.ts +3 -3
- package/dist/monetization/index.js +1 -1
- package/dist/monetization/metering/reconciliation-cron.test.js +9 -8
- package/dist/monetization/metering/reconciliation-repository.js +11 -10
- package/dist/monetization/metering/reconciliation-repository.test.js +9 -8
- package/dist/monetization/payram/webhook.d.ts +2 -2
- package/dist/monetization/payram/webhook.js +5 -1
- package/dist/monetization/payram/webhook.test.js +5 -4
- package/dist/monetization/promotions/engine.d.ts +2 -2
- package/dist/monetization/promotions/engine.js +4 -1
- package/dist/monetization/promotions/engine.test.js +3 -1
- package/dist/monetization/repository-types.d.ts +1 -1
- package/dist/monetization/socket/socket.d.ts +3 -3
- package/dist/monetization/stripe/stripe-payment-processor.d.ts +2 -2
- package/dist/monetization/stripe/stripe-payment-processor.test.js +7 -0
- package/dist/monetization/stripe/webhook.d.ts +2 -2
- package/dist/monetization/stripe/webhook.js +70 -6
- package/dist/monetization/stripe/webhook.test.js +20 -15
- package/dist/onboarding/onboarding-service.d.ts +2 -2
- package/dist/onboarding/onboarding-service.js +6 -2
- package/drizzle/migrations/0002_gateway_service_keys.sql +14 -0
- package/drizzle/migrations/0003_double_entry_ledger.sql +82 -0
- package/drizzle/migrations/meta/_journal.json +14 -0
- package/package.json +1 -1
- package/src/api/routes/admin-credits.ts +11 -14
- package/src/api/routes/quota.ts +2 -2
- package/src/api/routes/verify-email.ts +4 -4
- package/src/backup/on-demand-snapshot-service.test.ts +3 -3
- package/src/backup/on-demand-snapshot-service.ts +3 -3
- package/src/billing/payram/webhook.test.ts +7 -5
- package/src/billing/payram/webhook.ts +8 -11
- package/src/billing/stripe/stripe-payment-processor.test.ts +10 -3
- package/src/billing/stripe/stripe-payment-processor.ts +3 -3
- package/src/billing/stripe/tenant-store.ts +1 -1
- package/src/credits/auto-topup-charge.test.ts +7 -5
- package/src/credits/auto-topup-charge.ts +7 -10
- package/src/credits/auto-topup-usage.test.ts +55 -13
- package/src/credits/auto-topup-usage.ts +2 -2
- package/src/credits/credit-expiry-cron.test.ts +26 -45
- package/src/credits/credit-expiry-cron.ts +9 -12
- package/src/credits/credit-ledger.ts +3 -3
- package/src/credits/dividend-cron.test.ts +38 -45
- package/src/credits/dividend-cron.ts +12 -26
- package/src/credits/dividend-repository.test.ts +4 -3
- package/src/credits/dividend-repository.ts +21 -23
- package/src/credits/index.ts +23 -4
- package/src/credits/ledger.test.ts +514 -0
- package/src/credits/ledger.ts +851 -0
- package/src/credits/signup-grant.test.ts +7 -4
- package/src/credits/signup-grant.ts +6 -12
- package/src/credits/trial-balance-cron.test.ts +68 -0
- package/src/credits/trial-balance-cron.ts +46 -0
- package/src/db/schema/gateway-service-keys.ts +23 -0
- package/src/db/schema/index.ts +2 -0
- package/src/db/schema/ledger.ts +94 -0
- package/src/gateway/credit-gate-wiring.test.ts +3 -3
- package/src/gateway/credit-gate.test.ts +35 -33
- package/src/gateway/credit-gate.ts +6 -10
- package/src/gateway/gateway-routes.test.ts +6 -6
- package/src/gateway/index.ts +2 -0
- package/src/gateway/protocol/anthropic.ts +2 -2
- package/src/gateway/protocol/deps.ts +5 -5
- package/src/gateway/protocol/openai.ts +2 -2
- package/src/gateway/proxy.ts +4 -4
- package/src/gateway/route-mounting.test.ts +3 -3
- package/src/gateway/service-key-auth.ts +4 -2
- package/src/gateway/service-key-repository.ts +87 -0
- package/src/gateway/types.ts +5 -5
- package/src/metering/reconciliation-cron.test.ts +10 -9
- package/src/metering/reconciliation-repository.test.ts +10 -9
- package/src/metering/reconciliation-repository.ts +14 -11
- package/src/monetization/affiliate/affiliate-admin-repository.test.ts +32 -19
- package/src/monetization/affiliate/affiliate-admin-repository.ts +16 -8
- package/src/monetization/affiliate/credit-match.test.ts +60 -14
- package/src/monetization/affiliate/credit-match.ts +6 -9
- package/src/monetization/affiliate/new-user-bonus.test.ts +6 -4
- package/src/monetization/affiliate/new-user-bonus.ts +6 -9
- package/src/monetization/credits/auto-topup-charge.test.ts +7 -5
- package/src/monetization/credits/auto-topup-charge.ts +7 -10
- package/src/monetization/credits/auto-topup-usage.test.ts +55 -13
- package/src/monetization/credits/auto-topup-usage.ts +2 -2
- package/src/monetization/credits/bot-billing.test.ts +20 -6
- package/src/monetization/credits/bot-billing.ts +3 -3
- package/src/monetization/credits/credit-expiry-cron.test.ts +26 -45
- package/src/monetization/credits/dividend-cron.test.ts +34 -48
- package/src/monetization/credits/dividend-cron.ts +9 -14
- package/src/monetization/credits/dividend-repository.test.ts +4 -3
- package/src/monetization/credits/dividend-repository.ts +19 -25
- package/src/monetization/credits/index.ts +4 -4
- package/src/monetization/credits/member-usage.test.ts +25 -11
- package/src/monetization/credits/phone-billing.test.ts +18 -26
- package/src/monetization/credits/phone-billing.ts +7 -10
- package/src/monetization/credits/runtime-cron.test.ts +29 -28
- package/src/monetization/credits/runtime-cron.ts +34 -58
- package/src/monetization/credits/runtime-scheduler.test.ts +1 -1
- package/src/monetization/credits/runtime-scheduler.ts +2 -2
- package/src/monetization/credits/signup-grant.test.ts +7 -4
- package/src/monetization/credits/storage-tier-cron.test.ts +5 -3
- package/src/monetization/credits/trial-balance-cron.test.ts +52 -0
- package/src/monetization/feature-gate.ts +3 -3
- package/src/monetization/index.ts +4 -4
- package/src/monetization/metering/reconciliation-cron.test.ts +10 -9
- package/src/monetization/metering/reconciliation-repository.test.ts +11 -9
- package/src/monetization/metering/reconciliation-repository.ts +13 -11
- package/src/monetization/payram/webhook.test.ts +7 -5
- package/src/monetization/payram/webhook.ts +7 -10
- package/src/monetization/promotions/engine.test.ts +6 -5
- package/src/monetization/promotions/engine.ts +6 -3
- package/src/monetization/repository-types.ts +1 -1
- package/src/monetization/socket/socket.ts +4 -4
- package/src/monetization/stripe/stripe-payment-processor.test.ts +10 -3
- package/src/monetization/stripe/stripe-payment-processor.ts +3 -3
- package/src/monetization/stripe/webhook.test.ts +22 -16
- package/src/monetization/stripe/webhook.ts +75 -50
- package/src/onboarding/onboarding-service.ts +8 -11
- package/dist/credits/credit-ledger-extra.test.js +0 -40
- package/dist/credits/credit-ledger.bench.js +0 -33
- package/dist/credits/credit-ledger.test.d.ts +0 -4
- package/dist/credits/credit-ledger.test.js +0 -203
- package/dist/credits/credit-transaction-repository.test.js +0 -232
- package/dist/monetization/credits/credit-ledger-extra.test.d.ts +0 -1
- package/dist/monetization/credits/credit-ledger-extra.test.js +0 -39
- package/dist/monetization/credits/credit-ledger.bench.d.ts +0 -1
- package/dist/monetization/credits/credit-ledger.bench.js +0 -32
- package/dist/monetization/credits/credit-ledger.test.d.ts +0 -4
- package/dist/monetization/credits/credit-ledger.test.js +0 -202
- package/dist/monetization/credits/credit-transaction-repository.test.d.ts +0 -1
- package/dist/monetization/credits/credit-transaction-repository.test.js +0 -232
- package/src/credits/credit-ledger-extra.test.ts +0 -57
- package/src/credits/credit-ledger.bench.ts +0 -56
- package/src/credits/credit-ledger.test.ts +0 -276
- package/src/credits/credit-transaction-repository.test.ts +0 -274
- package/src/monetization/credits/credit-ledger-extra.test.ts +0 -56
- package/src/monetization/credits/credit-ledger.bench.ts +0 -55
- package/src/monetization/credits/credit-ledger.test.ts +0 -275
- package/src/monetization/credits/credit-transaction-repository.test.ts +0 -274
- /package/dist/credits/{credit-ledger-extra.test.d.ts → ledger.test.d.ts} +0 -0
- /package/dist/credits/{credit-ledger.bench.d.ts → trial-balance-cron.test.d.ts} +0 -0
- /package/dist/{credits/credit-transaction-repository.test.d.ts → monetization/credits/trial-balance-cron.test.d.ts} +0 -0
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import type { PGlite } from "@electric-sql/pglite";
|
|
2
|
+
import { Credit, DrizzleLedger, runTrialBalanceCron } from "@wopr-network/platform-core/credits";
|
|
3
|
+
import { afterAll, beforeAll, beforeEach, describe, expect, it, vi } from "vitest";
|
|
4
|
+
import { createTestDb, truncateAllTables } from "../../test/db.js";
|
|
5
|
+
|
|
6
|
+
describe("runTrialBalanceCron", () => {
|
|
7
|
+
let pool: PGlite;
|
|
8
|
+
let ledger: DrizzleLedger;
|
|
9
|
+
|
|
10
|
+
beforeAll(async () => {
|
|
11
|
+
const { db, pool: p } = await createTestDb();
|
|
12
|
+
pool = p;
|
|
13
|
+
ledger = new DrizzleLedger(db);
|
|
14
|
+
});
|
|
15
|
+
|
|
16
|
+
afterAll(async () => {
|
|
17
|
+
await pool.close();
|
|
18
|
+
});
|
|
19
|
+
|
|
20
|
+
beforeEach(async () => {
|
|
21
|
+
await truncateAllTables(pool);
|
|
22
|
+
await ledger.seedSystemAccounts();
|
|
23
|
+
});
|
|
24
|
+
|
|
25
|
+
it("returns balanced when no entries exist", async () => {
|
|
26
|
+
const result = await runTrialBalanceCron({ ledger });
|
|
27
|
+
expect(result.balanced).toBe(true);
|
|
28
|
+
expect(result.differenceRaw).toBe(0);
|
|
29
|
+
});
|
|
30
|
+
|
|
31
|
+
it("returns balanced after normal credit and debit", async () => {
|
|
32
|
+
await ledger.credit("t1", Credit.fromCents(500), "purchase");
|
|
33
|
+
await ledger.debit("t1", Credit.fromCents(200), "bot_runtime");
|
|
34
|
+
|
|
35
|
+
const result = await runTrialBalanceCron({ ledger });
|
|
36
|
+
expect(result.balanced).toBe(true);
|
|
37
|
+
expect(result.differenceRaw).toBe(0);
|
|
38
|
+
});
|
|
39
|
+
|
|
40
|
+
it("logs an error on imbalance without throwing", async () => {
|
|
41
|
+
vi.spyOn(ledger, "trialBalance").mockResolvedValueOnce({
|
|
42
|
+
totalDebits: Credit.fromCents(1000),
|
|
43
|
+
totalCredits: Credit.fromCents(900),
|
|
44
|
+
balanced: false,
|
|
45
|
+
difference: Credit.fromCents(100),
|
|
46
|
+
});
|
|
47
|
+
|
|
48
|
+
const result = await runTrialBalanceCron({ ledger });
|
|
49
|
+
expect(result.balanced).toBe(false);
|
|
50
|
+
expect(result.differenceRaw).toBe(Credit.fromCents(100).toRaw());
|
|
51
|
+
});
|
|
52
|
+
});
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type {
|
|
1
|
+
import type { ILedger } from "@wopr-network/platform-core/credits";
|
|
2
2
|
import { Credit } from "@wopr-network/platform-core/credits";
|
|
3
3
|
import type { Context, Next } from "hono";
|
|
4
4
|
import { DAILY_BOT_COST } from "./credits/runtime-cron.js";
|
|
@@ -74,7 +74,7 @@ export function createFeatureGate(cfg: FeatureGateConfig) {
|
|
|
74
74
|
/**
|
|
75
75
|
* Convenience factory that creates a requireBalance middleware from a CreditLedger instance.
|
|
76
76
|
*/
|
|
77
|
-
export function createBalanceGate(ledger:
|
|
77
|
+
export function createBalanceGate(ledger: ILedger, userKey?: string, userIdField?: string) {
|
|
78
78
|
return createFeatureGate({
|
|
79
79
|
getUserBalance: (tenantId) => ledger.balance(tenantId),
|
|
80
80
|
userKey,
|
|
@@ -94,7 +94,7 @@ export type ResolveTenantId = (c: Context) => string | undefined | Promise<strin
|
|
|
94
94
|
|
|
95
95
|
export interface CreditGateConfig {
|
|
96
96
|
/** CreditLedger instance used to check balance. */
|
|
97
|
-
ledger:
|
|
97
|
+
ledger: ILedger;
|
|
98
98
|
/** Resolve the tenant ID from the request context. */
|
|
99
99
|
resolveTenantId: ResolveTenantId;
|
|
100
100
|
}
|
|
@@ -134,11 +134,12 @@ export { BudgetChecker, DrizzleBudgetChecker } from "./budget/index.js";
|
|
|
134
134
|
// Credit ledger (WOP-384)
|
|
135
135
|
export type {
|
|
136
136
|
BillingState,
|
|
137
|
-
CreditTransaction,
|
|
138
137
|
CreditType,
|
|
139
138
|
DebitType,
|
|
140
139
|
GetActiveBotCount,
|
|
141
140
|
HistoryOptions,
|
|
141
|
+
ILedger,
|
|
142
|
+
JournalEntry,
|
|
142
143
|
OnSuspend,
|
|
143
144
|
RuntimeCronConfig,
|
|
144
145
|
RuntimeCronResult,
|
|
@@ -147,12 +148,12 @@ export type {
|
|
|
147
148
|
export {
|
|
148
149
|
BotBilling,
|
|
149
150
|
buildResourceTierCosts,
|
|
150
|
-
CreditLedger,
|
|
151
151
|
DAILY_BOT_COST,
|
|
152
152
|
DrizzleBotBilling,
|
|
153
|
-
|
|
153
|
+
DrizzleLedger,
|
|
154
154
|
grantSignupCredits,
|
|
155
155
|
InsufficientBalanceError,
|
|
156
|
+
Ledger,
|
|
156
157
|
runRuntimeDeductions,
|
|
157
158
|
SIGNUP_GRANT,
|
|
158
159
|
SUSPENSION_GRACE_DAYS,
|
|
@@ -215,7 +216,6 @@ export {
|
|
|
215
216
|
export type {
|
|
216
217
|
IBotBilling,
|
|
217
218
|
IBudgetChecker,
|
|
218
|
-
ICreditLedger,
|
|
219
219
|
IMeterAggregator,
|
|
220
220
|
IMeterEmitter,
|
|
221
221
|
IPayRamChargeRepository,
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import crypto from "node:crypto";
|
|
2
2
|
import type { PGlite } from "@electric-sql/pglite";
|
|
3
|
-
import { Credit,
|
|
3
|
+
import { Credit, DrizzleLedger } from "@wopr-network/platform-core/credits";
|
|
4
4
|
import { runReconciliation } from "@wopr-network/platform-core/metering";
|
|
5
5
|
import { afterAll, beforeAll, beforeEach, describe, expect, it, vi } from "vitest";
|
|
6
6
|
import type { DrizzleDb } from "../../db/index.js";
|
|
@@ -17,7 +17,7 @@ const DAY_END = DAY_START + 24 * 60 * 60 * 1000;
|
|
|
17
17
|
describe("runReconciliation", () => {
|
|
18
18
|
let pool: PGlite;
|
|
19
19
|
let db: DrizzleDb;
|
|
20
|
-
let ledger:
|
|
20
|
+
let ledger: DrizzleLedger;
|
|
21
21
|
let usageSummaryRepo: DrizzleUsageSummaryRepository;
|
|
22
22
|
let adapterUsageRepo: DrizzleAdapterUsageRepository;
|
|
23
23
|
|
|
@@ -25,7 +25,7 @@ describe("runReconciliation", () => {
|
|
|
25
25
|
const t = await createTestDb();
|
|
26
26
|
pool = t.pool;
|
|
27
27
|
db = t.db;
|
|
28
|
-
ledger = new
|
|
28
|
+
ledger = new DrizzleLedger(db);
|
|
29
29
|
usageSummaryRepo = new DrizzleUsageSummaryRepository(db);
|
|
30
30
|
adapterUsageRepo = new DrizzleAdapterUsageRepository(db);
|
|
31
31
|
});
|
|
@@ -36,6 +36,7 @@ describe("runReconciliation", () => {
|
|
|
36
36
|
|
|
37
37
|
beforeEach(async () => {
|
|
38
38
|
await truncateAllTables(pool);
|
|
39
|
+
await ledger.seedSystemAccounts();
|
|
39
40
|
});
|
|
40
41
|
|
|
41
42
|
/** Insert a usage_summaries row directly. */
|
|
@@ -74,7 +75,7 @@ describe("runReconciliation", () => {
|
|
|
74
75
|
await insertSummary({ tenant: "t1", totalCharge: charge.toRaw() });
|
|
75
76
|
|
|
76
77
|
await ledger.credit("t1", Credit.fromCents(500), "purchase");
|
|
77
|
-
await ledger.debit("t1", charge, "adapter_usage", "chat usage");
|
|
78
|
+
await ledger.debit("t1", charge, "adapter_usage", { description: "chat usage" });
|
|
78
79
|
|
|
79
80
|
const result = await runReconciliation({ usageSummaryRepo, adapterUsageRepo, targetDate: TODAY });
|
|
80
81
|
expect(result.tenantsChecked).toBe(1);
|
|
@@ -85,7 +86,7 @@ describe("runReconciliation", () => {
|
|
|
85
86
|
await insertSummary({ tenant: "t1", totalCharge: Credit.fromCents(100).toRaw() });
|
|
86
87
|
|
|
87
88
|
await ledger.credit("t1", Credit.fromCents(500), "purchase");
|
|
88
|
-
await ledger.debit("t1", Credit.fromCents(80), "adapter_usage", "chat usage");
|
|
89
|
+
await ledger.debit("t1", Credit.fromCents(80), "adapter_usage", { description: "chat usage" });
|
|
89
90
|
|
|
90
91
|
const result = await runReconciliation({ usageSummaryRepo, adapterUsageRepo, targetDate: TODAY });
|
|
91
92
|
expect(result.tenantsChecked).toBe(1);
|
|
@@ -117,7 +118,7 @@ describe("runReconciliation", () => {
|
|
|
117
118
|
|
|
118
119
|
await ledger.credit("t1", Credit.fromCents(500), "purchase");
|
|
119
120
|
// Debit as bot_runtime — should NOT count toward reconciliation
|
|
120
|
-
await ledger.debit("t1", Credit.fromCents(20), "bot_runtime", "daily runtime");
|
|
121
|
+
await ledger.debit("t1", Credit.fromCents(20), "bot_runtime", { description: "daily runtime" });
|
|
121
122
|
|
|
122
123
|
const result = await runReconciliation({ usageSummaryRepo, adapterUsageRepo, targetDate: TODAY });
|
|
123
124
|
// Metered 20c, ledger adapter_usage = 0 => drift = 20c
|
|
@@ -149,12 +150,12 @@ describe("runReconciliation", () => {
|
|
|
149
150
|
// t1: balanced
|
|
150
151
|
await insertSummary({ tenant: "t1", totalCharge: Credit.fromCents(50).toRaw() });
|
|
151
152
|
await ledger.credit("t1", Credit.fromCents(500), "purchase");
|
|
152
|
-
await ledger.debit("t1", Credit.fromCents(50), "adapter_usage", "chat");
|
|
153
|
+
await ledger.debit("t1", Credit.fromCents(50), "adapter_usage", { description: "chat" });
|
|
153
154
|
|
|
154
155
|
// t2: drifted
|
|
155
156
|
await insertSummary({ tenant: "t2", totalCharge: Credit.fromCents(100).toRaw() });
|
|
156
157
|
await ledger.credit("t2", Credit.fromCents(500), "purchase");
|
|
157
|
-
await ledger.debit("t2", Credit.fromCents(60), "adapter_usage", "chat");
|
|
158
|
+
await ledger.debit("t2", Credit.fromCents(60), "adapter_usage", { description: "chat" });
|
|
158
159
|
|
|
159
160
|
const result = await runReconciliation({ usageSummaryRepo, adapterUsageRepo, targetDate: TODAY });
|
|
160
161
|
expect(result.tenantsChecked).toBe(2);
|
|
@@ -192,7 +193,7 @@ describe("runReconciliation", () => {
|
|
|
192
193
|
await insertSummary({ tenant: "t1", totalCharge: Credit.fromCents(50).toRaw() });
|
|
193
194
|
|
|
194
195
|
await ledger.credit("t1", Credit.fromCents(500), "purchase");
|
|
195
|
-
await ledger.debit("t1", Credit.fromCents(80), "adapter_usage", "chat usage");
|
|
196
|
+
await ledger.debit("t1", Credit.fromCents(80), "adapter_usage", { description: "chat usage" });
|
|
196
197
|
|
|
197
198
|
const result = await runReconciliation({ usageSummaryRepo, adapterUsageRepo, targetDate: TODAY });
|
|
198
199
|
expect(result.discrepancies).toHaveLength(1);
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import crypto from "node:crypto";
|
|
2
2
|
import type { PGlite } from "@electric-sql/pglite";
|
|
3
|
-
import { Credit,
|
|
3
|
+
import { Credit, DrizzleLedger } from "@wopr-network/platform-core/credits";
|
|
4
4
|
import { afterAll, beforeAll, beforeEach, describe, expect, it } from "vitest";
|
|
5
5
|
import type { DrizzleDb } from "../../db/index.js";
|
|
6
6
|
import { createTestDb, seedUsageSummary, truncateAllTables } from "../../test/db.js";
|
|
@@ -125,12 +125,14 @@ describe("DrizzleUsageSummaryRepository", () => {
|
|
|
125
125
|
|
|
126
126
|
describe("DrizzleAdapterUsageRepository", () => {
|
|
127
127
|
let repo: DrizzleAdapterUsageRepository;
|
|
128
|
-
let ledger:
|
|
128
|
+
let ledger: DrizzleLedger;
|
|
129
129
|
|
|
130
130
|
beforeEach(async () => {
|
|
131
131
|
await truncateAllTables(pool);
|
|
132
132
|
repo = new DrizzleAdapterUsageRepository(db);
|
|
133
|
-
ledger = new
|
|
133
|
+
ledger = new DrizzleLedger(db);
|
|
134
|
+
|
|
135
|
+
await ledger.seedSystemAccounts();
|
|
134
136
|
});
|
|
135
137
|
|
|
136
138
|
it("returns empty array when no adapter_usage debits exist", async () => {
|
|
@@ -146,9 +148,9 @@ describe("DrizzleAdapterUsageRepository", () => {
|
|
|
146
148
|
await ledger.credit("t1", Credit.fromCents(1000), "purchase");
|
|
147
149
|
await ledger.credit("t2", Credit.fromCents(1000), "purchase");
|
|
148
150
|
|
|
149
|
-
await ledger.debit("t1", Credit.fromCents(30), "adapter_usage", "t1-debit-1");
|
|
150
|
-
await ledger.debit("t1", Credit.fromCents(20), "adapter_usage", "t1-debit-2");
|
|
151
|
-
await ledger.debit("t2", Credit.fromCents(50), "adapter_usage", "t2-debit-1");
|
|
151
|
+
await ledger.debit("t1", Credit.fromCents(30), "adapter_usage", { description: "t1-debit-1" });
|
|
152
|
+
await ledger.debit("t1", Credit.fromCents(20), "adapter_usage", { description: "t1-debit-2" });
|
|
153
|
+
await ledger.debit("t2", Credit.fromCents(50), "adapter_usage", { description: "t2-debit-1" });
|
|
152
154
|
|
|
153
155
|
// Query window covering today
|
|
154
156
|
const today = new Date().toISOString().slice(0, 10);
|
|
@@ -167,8 +169,8 @@ describe("DrizzleAdapterUsageRepository", () => {
|
|
|
167
169
|
|
|
168
170
|
it("excludes non-adapter_usage debit types", async () => {
|
|
169
171
|
await ledger.credit("t1", Credit.fromCents(1000), "purchase");
|
|
170
|
-
await ledger.debit("t1", Credit.fromCents(30), "adapter_usage", "adapter debit");
|
|
171
|
-
await ledger.debit("t1", Credit.fromCents(20), "bot_runtime", "runtime debit");
|
|
172
|
+
await ledger.debit("t1", Credit.fromCents(30), "adapter_usage", { description: "adapter debit" });
|
|
173
|
+
await ledger.debit("t1", Credit.fromCents(20), "bot_runtime", { description: "runtime debit" });
|
|
172
174
|
|
|
173
175
|
const today = new Date().toISOString().slice(0, 10);
|
|
174
176
|
const startIso = `${today}T00:00:00Z`;
|
|
@@ -181,7 +183,7 @@ describe("DrizzleAdapterUsageRepository", () => {
|
|
|
181
183
|
|
|
182
184
|
it("excludes credit transactions (positive amounts are not debits)", async () => {
|
|
183
185
|
await ledger.credit("t1", Credit.fromCents(1000), "purchase");
|
|
184
|
-
await ledger.debit("t1", Credit.fromCents(10), "adapter_usage", "real debit");
|
|
186
|
+
await ledger.debit("t1", Credit.fromCents(10), "adapter_usage", { description: "real debit" });
|
|
185
187
|
|
|
186
188
|
const today = new Date().toISOString().slice(0, 10);
|
|
187
189
|
const startIso = `${today}T00:00:00Z`;
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { and, eq, gte, lt, ne, sql } from "drizzle-orm";
|
|
2
2
|
import type { DrizzleDb } from "../../db/index.js";
|
|
3
|
-
import {
|
|
3
|
+
import { journalEntries, journalLines } from "../../db/schema/ledger.js";
|
|
4
4
|
import { usageSummaries } from "../../db/schema/meter-events.js";
|
|
5
5
|
|
|
6
6
|
// ---------------------------------------------------------------------------
|
|
@@ -59,24 +59,26 @@ export class DrizzleAdapterUsageRepository implements IAdapterUsageRepository {
|
|
|
59
59
|
constructor(private readonly db: DrizzleDb) {}
|
|
60
60
|
|
|
61
61
|
async getAggregatedAdapterUsageDebits(startIso: string, endIso: string): Promise<AggregatedDebit[]> {
|
|
62
|
+
// Sum the debit-side journal line amounts for adapter_usage entries.
|
|
63
|
+
// In double-entry: DR tenant liability (2000:<tenantId>), CR revenue:adapter_usage (4010).
|
|
62
64
|
const rows = await this.db
|
|
63
65
|
.select({
|
|
64
|
-
tenantId:
|
|
65
|
-
//
|
|
66
|
-
|
|
67
|
-
// raw SQL: Drizzle cannot express ABS with COALESCE and SUM
|
|
68
|
-
totalDebitRaw: sql<number>`COALESCE(SUM(ABS(amount_credits)), 0)`,
|
|
66
|
+
tenantId: journalEntries.tenantId,
|
|
67
|
+
// raw SQL: Drizzle cannot express COALESCE with SUM aggregation
|
|
68
|
+
totalDebitRaw: sql<number>`COALESCE(SUM(${journalLines.amount}), 0)`,
|
|
69
69
|
})
|
|
70
|
-
.from(
|
|
70
|
+
.from(journalLines)
|
|
71
|
+
.innerJoin(journalEntries, eq(journalEntries.id, journalLines.journalEntryId))
|
|
71
72
|
.where(
|
|
72
73
|
and(
|
|
73
|
-
eq(
|
|
74
|
+
eq(journalEntries.entryType, "adapter_usage"),
|
|
75
|
+
eq(journalLines.side, "debit"),
|
|
74
76
|
// raw SQL: Drizzle cannot express timestamptz cast for text column date comparison
|
|
75
|
-
sql`${
|
|
76
|
-
sql`${
|
|
77
|
+
sql`${journalEntries.postedAt}::timestamptz >= ${startIso}::timestamptz`,
|
|
78
|
+
sql`${journalEntries.postedAt}::timestamptz < ${endIso}::timestamptz`,
|
|
77
79
|
),
|
|
78
80
|
)
|
|
79
|
-
.groupBy(
|
|
81
|
+
.groupBy(journalEntries.tenantId);
|
|
80
82
|
|
|
81
83
|
return rows.map((r) => ({ tenantId: r.tenantId, totalDebitRaw: Number(r.totalDebitRaw) }));
|
|
82
84
|
}
|
|
@@ -12,7 +12,7 @@ import {
|
|
|
12
12
|
noOpReplayGuard,
|
|
13
13
|
PayRamChargeRepository,
|
|
14
14
|
} from "@wopr-network/platform-core/billing";
|
|
15
|
-
import {
|
|
15
|
+
import { DrizzleLedger } from "@wopr-network/platform-core/credits";
|
|
16
16
|
import { afterAll, beforeAll, beforeEach, describe, expect, it, vi } from "vitest";
|
|
17
17
|
import type { DrizzleDb } from "../../db/index.js";
|
|
18
18
|
import { createTestDb, truncateAllTables } from "../../test/db.js";
|
|
@@ -44,13 +44,15 @@ afterAll(async () => {
|
|
|
44
44
|
|
|
45
45
|
describe("handlePayRamWebhook", () => {
|
|
46
46
|
let chargeStore: PayRamChargeRepository;
|
|
47
|
-
let creditLedger:
|
|
47
|
+
let creditLedger: DrizzleLedger;
|
|
48
48
|
let deps: PayRamWebhookDeps;
|
|
49
49
|
|
|
50
50
|
beforeEach(async () => {
|
|
51
51
|
await truncateAllTables(pool);
|
|
52
52
|
chargeStore = new PayRamChargeRepository(db);
|
|
53
|
-
creditLedger = new
|
|
53
|
+
creditLedger = new DrizzleLedger(db);
|
|
54
|
+
|
|
55
|
+
await creditLedger.seedSystemAccounts();
|
|
54
56
|
deps = { chargeStore, creditLedger, replayGuard: noOpReplayGuard };
|
|
55
57
|
|
|
56
58
|
// Create a default test charge
|
|
@@ -80,14 +82,14 @@ describe("handlePayRamWebhook", () => {
|
|
|
80
82
|
const history = await creditLedger.history("tenant-a");
|
|
81
83
|
expect(history).toHaveLength(1);
|
|
82
84
|
expect(history[0].referenceId).toBe("payram:ref-test-001");
|
|
83
|
-
expect(history[0].
|
|
85
|
+
expect(history[0].entryType).toBe("purchase");
|
|
84
86
|
});
|
|
85
87
|
|
|
86
88
|
it("records fundingSource as payram", async () => {
|
|
87
89
|
await handlePayRamWebhook(deps, makePayload({ status: "FILLED" }));
|
|
88
90
|
|
|
89
91
|
const history = await creditLedger.history("tenant-a");
|
|
90
|
-
expect(history[0].fundingSource).toBe("payram");
|
|
92
|
+
expect(history[0].metadata?.fundingSource).toBe("payram");
|
|
91
93
|
});
|
|
92
94
|
|
|
93
95
|
it("marks the charge as credited after FILLED", async () => {
|
|
@@ -4,13 +4,13 @@ import type {
|
|
|
4
4
|
PayRamWebhookPayload,
|
|
5
5
|
PayRamWebhookResult,
|
|
6
6
|
} from "@wopr-network/platform-core/billing";
|
|
7
|
-
import type {
|
|
7
|
+
import type { ILedger } from "@wopr-network/platform-core/credits";
|
|
8
8
|
import { Credit } from "@wopr-network/platform-core/credits";
|
|
9
9
|
import type { BotBilling } from "../credits/bot-billing.js";
|
|
10
10
|
|
|
11
11
|
export interface PayRamWebhookDeps {
|
|
12
12
|
chargeStore: PayRamChargeRepository;
|
|
13
|
-
creditLedger:
|
|
13
|
+
creditLedger: ILedger;
|
|
14
14
|
botBilling?: BotBilling;
|
|
15
15
|
replayGuard: IWebhookSeenRepository;
|
|
16
16
|
}
|
|
@@ -60,14 +60,11 @@ export async function handlePayRamWebhook(
|
|
|
60
60
|
// overpayment stays in the PayRam wallet as a buffer.
|
|
61
61
|
const creditCents = charge.amountUsdCents;
|
|
62
62
|
|
|
63
|
-
await creditLedger.credit(
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
"
|
|
67
|
-
|
|
68
|
-
`payram:${payload.reference_id}`,
|
|
69
|
-
"payram",
|
|
70
|
-
);
|
|
63
|
+
await creditLedger.credit(charge.tenantId, Credit.fromCents(creditCents), "purchase", {
|
|
64
|
+
description: `Crypto credit purchase via PayRam (ref: ${payload.reference_id}, ${payload.currency ?? "crypto"})`,
|
|
65
|
+
referenceId: `payram:${payload.reference_id}`,
|
|
66
|
+
fundingSource: "payram",
|
|
67
|
+
});
|
|
71
68
|
|
|
72
69
|
await chargeStore.markCredited(payload.reference_id);
|
|
73
70
|
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type {
|
|
1
|
+
import type { ILedger } from "@wopr-network/platform-core/credits";
|
|
2
2
|
import { Credit } from "@wopr-network/platform-core/credits";
|
|
3
3
|
import { beforeEach, describe, expect, it, vi } from "vitest";
|
|
4
4
|
import type { ICouponRepository } from "./coupon-repository.js";
|
|
@@ -40,7 +40,7 @@ describe("PromotionEngine", () => {
|
|
|
40
40
|
let promotionRepo: IPromotionRepository;
|
|
41
41
|
let couponRepo: ICouponRepository;
|
|
42
42
|
let redemptionRepo: IRedemptionRepository;
|
|
43
|
-
let ledger:
|
|
43
|
+
let ledger: ILedger;
|
|
44
44
|
let engine: PromotionEngine;
|
|
45
45
|
|
|
46
46
|
beforeEach(() => {
|
|
@@ -95,7 +95,7 @@ describe("PromotionEngine", () => {
|
|
|
95
95
|
createdAt: new Date().toISOString(),
|
|
96
96
|
}),
|
|
97
97
|
hasReferenceId: vi.fn().mockResolvedValue(false),
|
|
98
|
-
} as unknown as
|
|
98
|
+
} as unknown as ILedger;
|
|
99
99
|
|
|
100
100
|
engine = new PromotionEngine({ promotionRepo, couponRepo, redemptionRepo, ledger });
|
|
101
101
|
});
|
|
@@ -111,8 +111,9 @@ describe("PromotionEngine", () => {
|
|
|
111
111
|
"tenant-1",
|
|
112
112
|
expect.any(Object), // Credit instance
|
|
113
113
|
"promo",
|
|
114
|
-
expect.
|
|
115
|
-
|
|
114
|
+
expect.objectContaining({
|
|
115
|
+
referenceId: "promo:promo-1:tenant-1:1",
|
|
116
|
+
}),
|
|
116
117
|
);
|
|
117
118
|
});
|
|
118
119
|
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type {
|
|
1
|
+
import type { ILedger } from "@wopr-network/platform-core/credits";
|
|
2
2
|
import { Credit } from "@wopr-network/platform-core/credits";
|
|
3
3
|
import type { ICouponRepository } from "./coupon-repository.js";
|
|
4
4
|
import type { IPromotionRepository, Promotion } from "./promotion-repository.js";
|
|
@@ -22,7 +22,7 @@ interface PromotionEngineDeps {
|
|
|
22
22
|
promotionRepo: IPromotionRepository;
|
|
23
23
|
couponRepo: ICouponRepository;
|
|
24
24
|
redemptionRepo: IRedemptionRepository;
|
|
25
|
-
ledger:
|
|
25
|
+
ledger: ILedger;
|
|
26
26
|
}
|
|
27
27
|
|
|
28
28
|
export class PromotionEngine {
|
|
@@ -113,7 +113,10 @@ export class PromotionEngine {
|
|
|
113
113
|
if (!granted) return null;
|
|
114
114
|
|
|
115
115
|
// Grant credits
|
|
116
|
-
const tx = await ledger.credit(ctx.tenantId, grantAmount, "promo",
|
|
116
|
+
const tx = await ledger.credit(ctx.tenantId, grantAmount, "promo", {
|
|
117
|
+
description: `Promotion: ${promo.name}`,
|
|
118
|
+
referenceId: refId,
|
|
119
|
+
});
|
|
117
120
|
|
|
118
121
|
// Record redemption
|
|
119
122
|
await redemptionRepo.create({
|
|
@@ -5,7 +5,7 @@ export type {
|
|
|
5
5
|
ITenantCustomerRepository,
|
|
6
6
|
PayRamChargeRecord,
|
|
7
7
|
} from "@wopr-network/platform-core/billing";
|
|
8
|
-
export type { IAutoTopupSettingsRepository,
|
|
8
|
+
export type { IAutoTopupSettingsRepository, ILedger } from "@wopr-network/platform-core/credits";
|
|
9
9
|
export type { IMeterAggregator, IMeterEmitter } from "@wopr-network/platform-core/metering";
|
|
10
10
|
export type { FraudEvent, FraudEventInput, IAffiliateFraudRepository } from "./affiliate/affiliate-fraud-repository.js";
|
|
11
11
|
export type {
|
|
@@ -15,13 +15,13 @@ import type { MeterEmitter } from "@wopr-network/platform-core/metering";
|
|
|
15
15
|
import type { AdapterCapability, AdapterResult, ProviderAdapter } from "../adapters/types.js";
|
|
16
16
|
import { withMargin } from "../adapters/types.js";
|
|
17
17
|
import type { ArbitrageRouter } from "../arbitrage/router.js";
|
|
18
|
-
import type {
|
|
18
|
+
import type { IBudgetChecker, SpendLimits } from "../budget/budget-checker.js";
|
|
19
19
|
|
|
20
20
|
export interface SocketConfig {
|
|
21
21
|
/** MeterEmitter instance for usage tracking */
|
|
22
22
|
meter: MeterEmitter;
|
|
23
|
-
/**
|
|
24
|
-
budgetChecker?:
|
|
23
|
+
/** IBudgetChecker instance for pre-call budget validation */
|
|
24
|
+
budgetChecker?: IBudgetChecker;
|
|
25
25
|
/** Default margin multiplier (default: 1.3) */
|
|
26
26
|
defaultMargin?: number;
|
|
27
27
|
/** ArbitrageRouter for cost-optimized routing (GPU-first, cheapest, 5xx failover) */
|
|
@@ -65,7 +65,7 @@ const CAPABILITY_METHOD: Record<AdapterCapability, keyof ProviderAdapter> = {
|
|
|
65
65
|
export class AdapterSocket {
|
|
66
66
|
private readonly adapters = new Map<string, ProviderAdapter>();
|
|
67
67
|
private readonly meter: MeterEmitter;
|
|
68
|
-
private readonly budgetChecker?:
|
|
68
|
+
private readonly budgetChecker?: IBudgetChecker;
|
|
69
69
|
private readonly defaultMargin: number;
|
|
70
70
|
private readonly router?: ArbitrageRouter;
|
|
71
71
|
|
|
@@ -4,7 +4,7 @@ import type {
|
|
|
4
4
|
IWebhookSeenRepository,
|
|
5
5
|
} from "@wopr-network/platform-core/billing";
|
|
6
6
|
import { PaymentMethodOwnershipError } from "@wopr-network/platform-core/billing";
|
|
7
|
-
import type {
|
|
7
|
+
import type { ILedger, JournalEntry } from "@wopr-network/platform-core/credits";
|
|
8
8
|
import { Credit } from "@wopr-network/platform-core/credits";
|
|
9
9
|
import type Stripe from "stripe";
|
|
10
10
|
import { beforeEach, describe, expect, it, vi } from "vitest";
|
|
@@ -61,7 +61,8 @@ function createMocks() {
|
|
|
61
61
|
buildCustomerIdMap: vi.fn(),
|
|
62
62
|
};
|
|
63
63
|
|
|
64
|
-
const creditLedger:
|
|
64
|
+
const creditLedger: ILedger = {
|
|
65
|
+
post: vi.fn(),
|
|
65
66
|
credit: vi.fn(),
|
|
66
67
|
debit: vi.fn(),
|
|
67
68
|
balance: vi.fn(),
|
|
@@ -72,6 +73,12 @@ function createMocks() {
|
|
|
72
73
|
expiredCredits: vi.fn(),
|
|
73
74
|
lifetimeSpend: vi.fn(),
|
|
74
75
|
lifetimeSpendBatch: vi.fn().mockResolvedValue(new Map()),
|
|
76
|
+
trialBalance: vi.fn(),
|
|
77
|
+
accountBalance: vi.fn(),
|
|
78
|
+
seedSystemAccounts: vi.fn(),
|
|
79
|
+
existsByReferenceIdLike: vi.fn(),
|
|
80
|
+
sumPurchasesForPeriod: vi.fn(),
|
|
81
|
+
getActiveTenantIdsInWindow: vi.fn(),
|
|
75
82
|
};
|
|
76
83
|
|
|
77
84
|
const replayGuard: IWebhookSeenRepository = {
|
|
@@ -340,7 +347,7 @@ describe("StripePaymentProcessor", () => {
|
|
|
340
347
|
status: "succeeded",
|
|
341
348
|
} as unknown as Stripe.Response<Stripe.PaymentIntent>);
|
|
342
349
|
vi.mocked(mocks.creditLedger.hasReferenceId).mockResolvedValue(false);
|
|
343
|
-
vi.mocked(mocks.creditLedger.credit).mockResolvedValue({} as unknown as
|
|
350
|
+
vi.mocked(mocks.creditLedger.credit).mockResolvedValue({} as unknown as JournalEntry);
|
|
344
351
|
vi.mocked(mocks.autoTopupEventLog.writeEvent).mockResolvedValue(undefined);
|
|
345
352
|
|
|
346
353
|
const result = await processor.charge({
|
|
@@ -17,7 +17,7 @@ import {
|
|
|
17
17
|
type SetupResult,
|
|
18
18
|
type WebhookResult,
|
|
19
19
|
} from "@wopr-network/platform-core/billing";
|
|
20
|
-
import type {
|
|
20
|
+
import type { ILedger } from "@wopr-network/platform-core/credits";
|
|
21
21
|
import { Credit } from "@wopr-network/platform-core/credits";
|
|
22
22
|
import type Stripe from "stripe";
|
|
23
23
|
import { chargeAutoTopup } from "../credits/auto-topup-charge.js";
|
|
@@ -30,7 +30,7 @@ export interface StripePaymentProcessorDeps {
|
|
|
30
30
|
tenantRepo: ITenantCustomerRepository;
|
|
31
31
|
webhookSecret: string;
|
|
32
32
|
priceMap?: CreditPriceMap;
|
|
33
|
-
creditLedger:
|
|
33
|
+
creditLedger: ILedger;
|
|
34
34
|
botBilling?: BotBilling;
|
|
35
35
|
replayGuard: IWebhookSeenRepository;
|
|
36
36
|
autoTopupEventLog?: IAutoTopupEventLogRepository;
|
|
@@ -43,7 +43,7 @@ export class StripePaymentProcessor implements IPaymentProcessor {
|
|
|
43
43
|
private readonly tenantRepo: ITenantCustomerRepository;
|
|
44
44
|
private readonly webhookSecret: string;
|
|
45
45
|
private readonly priceMap: CreditPriceMap;
|
|
46
|
-
private readonly creditLedger:
|
|
46
|
+
private readonly creditLedger: ILedger;
|
|
47
47
|
private readonly botBilling?: BotBilling;
|
|
48
48
|
private readonly replayGuard: IWebhookSeenRepository;
|
|
49
49
|
private readonly autoTopupEventLog?: IAutoTopupEventLogRepository;
|