@happyvertical/smrt-commerce 0.51.23 → 0.51.24
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/AGENTS.md +47 -0
- package/README.md +104 -0
- package/dist/billing/credits.d.ts +33 -0
- package/dist/billing/credits.d.ts.map +1 -0
- package/dist/billing/events.d.ts +26 -0
- package/dist/billing/events.d.ts.map +1 -0
- package/dist/billing/index.d.ts +13 -0
- package/dist/billing/index.d.ts.map +1 -0
- package/dist/billing/jobs.d.ts +31 -0
- package/dist/billing/jobs.d.ts.map +1 -0
- package/dist/billing/period-close.d.ts +41 -0
- package/dist/billing/period-close.d.ts.map +1 -0
- package/dist/billing/provider.d.ts +136 -0
- package/dist/billing/provider.d.ts.map +1 -0
- package/dist/billing/runtime.d.ts +168 -0
- package/dist/billing/runtime.d.ts.map +1 -0
- package/dist/billing/stripe.d.ts +12 -0
- package/dist/billing/stripe.d.ts.map +1 -0
- package/dist/billing/units.d.ts +31 -0
- package/dist/billing/units.d.ts.map +1 -0
- package/dist/chunks/types-CRnln577.js.map +1 -1
- package/dist/chunks/units--tTn2ps8.js +52 -0
- package/dist/chunks/units--tTn2ps8.js.map +1 -0
- package/dist/collections/InvoiceLineItemCollection.d.ts +2 -1
- package/dist/collections/InvoiceLineItemCollection.d.ts.map +1 -1
- package/dist/index.d.ts +2 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +4258 -2584
- package/dist/index.js.map +1 -1
- package/dist/manifest.json +1397 -6
- package/dist/models/Invoice.d.ts +13 -2
- package/dist/models/Invoice.d.ts.map +1 -1
- package/dist/models/InvoiceLineItem.d.ts +6 -2
- package/dist/models/InvoiceLineItem.d.ts.map +1 -1
- package/dist/models/billing.d.ts +117 -0
- package/dist/models/billing.d.ts.map +1 -0
- package/dist/models/index.d.ts +1 -0
- package/dist/models/index.d.ts.map +1 -1
- package/dist/smrt-knowledge.json +529 -9
- package/dist/types/index.d.ts +3 -1
- package/dist/types/index.d.ts.map +1 -1
- package/package.json +10 -7
package/AGENTS.md
CHANGED
|
@@ -23,6 +23,52 @@ E-commerce with Contract STI hierarchy, invoice lifecycle, payment tracking, pay
|
|
|
23
23
|
|
|
24
24
|
`@happyvertical/smrt-ledgers` is a regular dependency, loaded lazily via dynamic `import()` so the coupling stays runtime-only (no hard static import; the package graph stays a DAG — see #1582). Invoice stores `arJournalId` and `revenueJournalId` as string references. `recognizeRevenue()` creates a balanced AR journal entry; `getArJournal()` returns null when no journal has been recognized yet.
|
|
25
25
|
|
|
26
|
+
## Billing-period close (#3060)
|
|
27
|
+
|
|
28
|
+
`src/billing/` closes periods from smrt-subscriptions charges; see the README
|
|
29
|
+
for usage.
|
|
30
|
+
|
|
31
|
+
- **Port, not provider.** Period close, events, and credit checkout call only
|
|
32
|
+
the `BillingProvider` port (integer minor units). `stripe.ts` adapts
|
|
33
|
+
`@happyvertical/accounting`, which takes currency *major* units; convert with
|
|
34
|
+
`units.ts` (ISO 4217 exponent) and never hand-roll a Stripe call here.
|
|
35
|
+
`sendAndReconcile` refuses a provider invoice whose subtotal or total
|
|
36
|
+
disagrees with the local invoice.
|
|
37
|
+
- **Replay safety is identity.** Close, invoice, line, payment, allocation,
|
|
38
|
+
and claim ids are `deterministicId()`s; `BillingLineSource` (conflict key
|
|
39
|
+
`source_type, source_id`) is the only double-billing guard, so never bill a
|
|
40
|
+
source without claiming it, and never widen that key. Each close step is
|
|
41
|
+
persisted before the next; `acquireCloseLease()` serializes workers. A
|
|
42
|
+
close that nets to a credit keeps its claims and ends `carried_forward`;
|
|
43
|
+
its subtotal is a `credit_carry_forward` source for the payer's next billed
|
|
44
|
+
close, which marks the carried close `completed`.
|
|
45
|
+
- **System tables.** `BillingAccount`, `BillingPeriodClose`, and
|
|
46
|
+
`BillingLineSource` are not tenant-scoped and have no generated surface.
|
|
47
|
+
Collections stay unexported; models are root exports (#3082). Invoices,
|
|
48
|
+
payments, and journals are written in the seller's tenant; payer-owned
|
|
49
|
+
subscriptions and credit grants in a system context, only after
|
|
50
|
+
verification.
|
|
51
|
+
- **Events** use smrt-jobs' delivery inbox under provider
|
|
52
|
+
`<name>-billing:<sellerTenantId>` and a provider-filtered
|
|
53
|
+
`ForgeProjectionRuntime`, so a runtime never claims another seller's
|
|
54
|
+
events; any other runtime sharing the inbox must pass `providers` too. Only
|
|
55
|
+
events this package acts on are stored: foreign checkouts are `ignored`,
|
|
56
|
+
and only `smrt_*` checkout metadata is kept; it is
|
|
57
|
+
HMAC-signed with the webhook secret at creation (empty values are omitted:
|
|
58
|
+
Stripe drops them), so another integration on the same account cannot forge
|
|
59
|
+
a credit purchase; credit is granted only when the collected total equals
|
|
60
|
+
it. Rotating the webhook secret strands in-flight checkouts (up to 24 h). `observe()` re-reads provider state, so
|
|
61
|
+
ordering never depends on delivery order. The standing hook runs inside the
|
|
62
|
+
event transaction and must be idempotent.
|
|
63
|
+
- **`Invoice.providerTaxAmount`** is added to line-item tax; it is
|
|
64
|
+
server-managed (not API-writable). `toAccountingInput()` emits major units.
|
|
65
|
+
- **Known limits** (each tracked upstream): provider customer creation is not
|
|
66
|
+
idempotent (happyvertical/sdk#1268); credit checkouts are untaxed and
|
|
67
|
+
two-decimal only (sdk#1269); `autoTopUp` cannot charge a saved card
|
|
68
|
+
(sdk#1270); Stripe line discounts and uncollectible status are worked around
|
|
69
|
+
as negative lines and event types (sdk#1271). `RetailCharge` has no
|
|
70
|
+
adjustment ledger. Flat plans are monthly, in arrears, without proration.
|
|
71
|
+
|
|
26
72
|
## Cross-Package References
|
|
27
73
|
|
|
28
74
|
- `customerId` → `@foreignKey('Customer')` (hard reference within package)
|
|
@@ -31,6 +77,7 @@ E-commerce with Contract STI hierarchy, invoice lifecycle, payment tracking, pay
|
|
|
31
77
|
- `skuId` (on `PaymentIntent`, `LicenseSale`) → plain string to smrt-products
|
|
32
78
|
- `paymentId` (on `PaymentIntent`, `Payout`, `LicenseSale`) → plain string to `Payment` (same package, but kept as plain string for cross-model consistency)
|
|
33
79
|
- `vendorId` on `Payout` → `@foreignKey(Vendor)` (hard reference within package)
|
|
80
|
+
- Billing records reference tenants with `@crossPackageRef('@happyvertical/smrt-users:Tenant')` and charges, plan periods, and adjustments by plain `sourceId`
|
|
34
81
|
|
|
35
82
|
## Gotchas
|
|
36
83
|
|
package/README.md
CHANGED
|
@@ -99,6 +99,9 @@ await payment.recordPayment({
|
|
|
99
99
|
| `PaymentAllocation` | Payment-to-invoice allocation |
|
|
100
100
|
| `Fulfillment` | Shipment/delivery tracking with carrier and address |
|
|
101
101
|
| `FulfillmentLineItem` | Individual fulfillment line item |
|
|
102
|
+
| `BillingAccount` | A payer's account with a seller: customer, provider customer, terms, standing |
|
|
103
|
+
| `BillingPeriodClose` | One payer's invoice for one period and currency; also the billing job target |
|
|
104
|
+
| `BillingLineSource` | The claim that a charge or plan period is billed on exactly one close |
|
|
102
105
|
|
|
103
106
|
### Collections
|
|
104
107
|
|
|
@@ -138,10 +141,111 @@ Invoice and Payment integrate with `@happyvertical/smrt-ledgers` via dynamic imp
|
|
|
138
141
|
|
|
139
142
|
Customer and Vendor link to `@happyvertical/smrt-profiles` via plain `profileId` string. Invoice and Payment reference `@happyvertical/smrt-ledgers` journals via plain string IDs (`arJournalId`, `revenueJournalId`, `journalId`). All models use `@TenantScoped({ mode: 'optional' })` with nullable `tenantId`.
|
|
140
143
|
|
|
144
|
+
## Billing-period close
|
|
145
|
+
|
|
146
|
+
`BillingRuntime` turns approved `@happyvertical/smrt-subscriptions` charges into
|
|
147
|
+
invoices for each billing owner, pushes them to a payment provider with
|
|
148
|
+
provider-calculated tax, posts revenue to the ledger, and applies the
|
|
149
|
+
provider's webhook events. Every provider call goes through
|
|
150
|
+
`@happyvertical/accounting`; `createStripeBillingProvider()` adapts its Stripe
|
|
151
|
+
provider to the `BillingProvider` port. Money crossing the port is integer
|
|
152
|
+
minor units.
|
|
153
|
+
|
|
154
|
+
```ts
|
|
155
|
+
import { getAccountingProvider } from '@happyvertical/accounting';
|
|
156
|
+
import {
|
|
157
|
+
BillingRuntime,
|
|
158
|
+
createStripeBillingProvider,
|
|
159
|
+
enqueueBillingPeriodClose,
|
|
160
|
+
registerBillingRuntime,
|
|
161
|
+
} from '@happyvertical/smrt-commerce';
|
|
162
|
+
|
|
163
|
+
const stripe = await getAccountingProvider({ type: 'stripe', secretKey });
|
|
164
|
+
const billing = await BillingRuntime.create({
|
|
165
|
+
db,
|
|
166
|
+
sellerTenantId: platformTenantId,
|
|
167
|
+
kind: 'provider', // or 'reseller' to bill a reseller's children
|
|
168
|
+
provider: createStripeBillingProvider({ stripe, webhookSecret }),
|
|
169
|
+
billingRelationships, // smrt-tenancy BillingRelationshipService
|
|
170
|
+
ledger: {
|
|
171
|
+
arAccountId,
|
|
172
|
+
revenueAccountId,
|
|
173
|
+
taxAccountId,
|
|
174
|
+
cashAccountId,
|
|
175
|
+
prepaidCreditAccountId,
|
|
176
|
+
},
|
|
177
|
+
onPayerStanding: async ({ payerTenantId, standing, db }) => {
|
|
178
|
+
// suspend or reinstate the payer; runs in the event transaction
|
|
179
|
+
},
|
|
180
|
+
});
|
|
181
|
+
|
|
182
|
+
// One account per payer: its customer, tax location, and terms.
|
|
183
|
+
await billing.upsertAccount({
|
|
184
|
+
payerTenantId,
|
|
185
|
+
name: 'Network Co',
|
|
186
|
+
email: 'billing@example.test',
|
|
187
|
+
billingAddress: { country: 'CA', postalCode: 'T0L 0A0' },
|
|
188
|
+
});
|
|
189
|
+
|
|
190
|
+
// Close last month (default) — safe to run on every schedule tick.
|
|
191
|
+
registerBillingRuntime('platform', billing);
|
|
192
|
+
await enqueueBillingPeriodClose({ runtime: 'platform' });
|
|
193
|
+
|
|
194
|
+
// Webhook route: verify, enqueue, respond 2xx.
|
|
195
|
+
const intake = await billing.acceptWebhook(
|
|
196
|
+
rawBody,
|
|
197
|
+
request.headers.get('stripe-signature'),
|
|
198
|
+
);
|
|
199
|
+
if (intake.type?.endsWith(':unverified_credit_purchase')) {
|
|
200
|
+
// alert: a paid checkout claimed to buy credit but failed verification
|
|
201
|
+
}
|
|
202
|
+
await billing.processEvents(); // or enqueueBillingEvents({ runtime: 'platform' })
|
|
203
|
+
|
|
204
|
+
// Prepaid credit through provider checkout.
|
|
205
|
+
const { url } = await billing.createCreditCheckout({
|
|
206
|
+
spendingPolicyId,
|
|
207
|
+
amount: 5000,
|
|
208
|
+
purchaseId: cartId,
|
|
209
|
+
successUrl,
|
|
210
|
+
cancelUrl,
|
|
211
|
+
});
|
|
212
|
+
```
|
|
213
|
+
|
|
214
|
+
- **What is billed.** A `provider` runtime bills `ClientCharge`s (and their
|
|
215
|
+
`BillingAdjustment`s) to the payer each charge names, plus monthly flat plans
|
|
216
|
+
it owns, to each subscriber's billing owner. A `reseller` runtime bills the
|
|
217
|
+
`RetailCharge`s its children owe it plus its own flat plans. Charges approved
|
|
218
|
+
before the period end are billed once, whatever period that is; flat plans
|
|
219
|
+
are billed in arrears for a closed calendar month (trials and
|
|
220
|
+
provider-managed subscriptions are skipped). One invoice per payer and
|
|
221
|
+
currency carries both kinds of lines.
|
|
222
|
+
- **Replay safety.** Close, invoice, and line ids are derived from the payer,
|
|
223
|
+
currency, and period; each charge is claimed by exactly one close; the
|
|
224
|
+
provider invoice uses the close id as its idempotency key; and every step is
|
|
225
|
+
persisted before the next, so a retry resumes where it stopped. A lease stops
|
|
226
|
+
two workers advancing the same close. A payer whose charges net to a credit
|
|
227
|
+
gets no invoice; the credit is carried to its next invoice.
|
|
228
|
+
- **Tax** comes from the provider (Stripe Tax) using the account customer's
|
|
229
|
+
`defaultBillingAddress`; the invoice records it as `providerTaxAmount`.
|
|
230
|
+
- **Events** are verified, stored in smrt-jobs' durable delivery inbox, and
|
|
231
|
+
applied against current provider state: paid invoices record a payment and
|
|
232
|
+
allocation; failures and overdue notices mark the payer `past_due` and its
|
|
233
|
+
flat-plan subscriptions `past_due`; payment reinstates them. Dunning is the
|
|
234
|
+
provider's.
|
|
235
|
+
- **Prepaid credit** purchases credit a `period: 'balance'` spending policy
|
|
236
|
+
once per checkout session, paid by the policy's tenant or, for a delegated
|
|
237
|
+
balance, the parent that set it.
|
|
238
|
+
|
|
239
|
+
See [`AGENTS.md`](./AGENTS.md#billing-period-close-3060) for invariants and
|
|
240
|
+
known limits.
|
|
241
|
+
|
|
141
242
|
## Dependencies
|
|
142
243
|
|
|
143
244
|
- `@happyvertical/smrt-core` -- ORM and code generation
|
|
144
245
|
- `@happyvertical/smrt-tenancy` -- multi-tenant scoping
|
|
246
|
+
- `@happyvertical/smrt-subscriptions` -- charges, plans, and credit balances billed by period close
|
|
247
|
+
- `@happyvertical/smrt-jobs` -- period-close jobs and the provider event inbox
|
|
248
|
+
- `@happyvertical/accounting` -- payment-provider (Stripe) calls
|
|
145
249
|
- `@happyvertical/smrt-types` -- shared type definitions
|
|
146
250
|
- Peer: `@happyvertical/smrt-ledgers`, `@happyvertical/smrt-profiles`, `@happyvertical/smrt-svelte`
|
|
147
251
|
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import { BillingProviderCheckoutSession } from './provider.js';
|
|
2
|
+
import { BillingRuntime } from './runtime.js';
|
|
3
|
+
export declare const CREDIT_PURCHASE_PURPOSE = "credit_purchase";
|
|
4
|
+
export interface CreateCreditCheckoutInput {
|
|
5
|
+
/** The `period: 'balance'` spending policy to credit. */
|
|
6
|
+
spendingPolicyId: string;
|
|
7
|
+
/** Credit to buy, in integer minor units of the policy currency. */
|
|
8
|
+
amount: number;
|
|
9
|
+
successUrl: string;
|
|
10
|
+
cancelUrl: string;
|
|
11
|
+
/**
|
|
12
|
+
* Caller-owned id for this purchase attempt (for example a cart id). A
|
|
13
|
+
* retried request with the same id returns the same checkout.
|
|
14
|
+
*/
|
|
15
|
+
purchaseId: string;
|
|
16
|
+
/** Checkout line description (default `Prepaid credit`). */
|
|
17
|
+
description?: string;
|
|
18
|
+
}
|
|
19
|
+
/** The checkout metadata a completed purchase is settled from. */
|
|
20
|
+
export interface CreditPurchaseMetadata {
|
|
21
|
+
purpose: string;
|
|
22
|
+
sellerTenantId: string;
|
|
23
|
+
payerTenantId: string;
|
|
24
|
+
billingAccountId: string;
|
|
25
|
+
spendingPolicyId: string;
|
|
26
|
+
grantedByTenantId: string;
|
|
27
|
+
amount: number;
|
|
28
|
+
currency: string;
|
|
29
|
+
}
|
|
30
|
+
/** Parse checkout metadata written by {@link createCreditCheckout}. */
|
|
31
|
+
export declare function creditMetadata(raw: Record<string, string>): CreditPurchaseMetadata | null;
|
|
32
|
+
export declare function createCreditCheckout(runtime: BillingRuntime, input: CreateCreditCheckoutInput): Promise<BillingProviderCheckoutSession>;
|
|
33
|
+
//# sourceMappingURL=credits.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"credits.d.ts","sourceRoot":"","sources":["../../src/billing/credits.ts"],"names":[],"mappings":"AAYA,OAAO,KAAK,EAAE,8BAA8B,EAAE,MAAM,eAAe,CAAC;AACpE,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,cAAc,CAAC;AAQnD,eAAO,MAAM,uBAAuB,oBAAoB,CAAC;AAEzD,MAAM,WAAW,yBAAyB;IACxC,yDAAyD;IACzD,gBAAgB,EAAE,MAAM,CAAC;IACzB,oEAAoE;IACpE,MAAM,EAAE,MAAM,CAAC;IACf,UAAU,EAAE,MAAM,CAAC;IACnB,SAAS,EAAE,MAAM,CAAC;IAClB;;;OAGG;IACH,UAAU,EAAE,MAAM,CAAC;IACnB,4DAA4D;IAC5D,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB;AAED,kEAAkE;AAClE,MAAM,WAAW,sBAAsB;IACrC,OAAO,EAAE,MAAM,CAAC;IAChB,cAAc,EAAE,MAAM,CAAC;IACvB,aAAa,EAAE,MAAM,CAAC;IACtB,gBAAgB,EAAE,MAAM,CAAC;IACzB,gBAAgB,EAAE,MAAM,CAAC;IACzB,iBAAiB,EAAE,MAAM,CAAC;IAC1B,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,EAAE,MAAM,CAAC;CAClB;AAuBD,uEAAuE;AACvE,wBAAgB,cAAc,CAC5B,GAAG,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,GAC1B,sBAAsB,GAAG,IAAI,CAwB/B;AAED,wBAAsB,oBAAoB,CACxC,OAAO,EAAE,cAAc,EACvB,KAAK,EAAE,yBAAyB,GAC/B,OAAO,CAAC,8BAA8B,CAAC,CAgEzC"}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import { ForgeProjector } from '@happyvertical/smrt-jobs';
|
|
2
|
+
import { BillingProviderEvent, BillingProviderInvoiceState, BillingProviderSubscriptionState } from './provider.js';
|
|
3
|
+
import { BillingRuntime } from './runtime.js';
|
|
4
|
+
type InvoiceEvent = Extract<BillingProviderEvent, {
|
|
5
|
+
kind: 'invoice';
|
|
6
|
+
}>;
|
|
7
|
+
type SubscriptionEvent = Extract<BillingProviderEvent, {
|
|
8
|
+
kind: 'subscription';
|
|
9
|
+
}>;
|
|
10
|
+
type CheckoutEvent = Extract<BillingProviderEvent, {
|
|
11
|
+
kind: 'checkout_completed';
|
|
12
|
+
}>;
|
|
13
|
+
type ObservedEvent = {
|
|
14
|
+
event: InvoiceEvent;
|
|
15
|
+
invoice: BillingProviderInvoiceState;
|
|
16
|
+
} | {
|
|
17
|
+
event: SubscriptionEvent;
|
|
18
|
+
subscription: BillingProviderSubscriptionState;
|
|
19
|
+
} | {
|
|
20
|
+
event: CheckoutEvent;
|
|
21
|
+
};
|
|
22
|
+
/** Apply up to `limit` queued events for a runtime; returns how many ran. */
|
|
23
|
+
export declare function processBillingEvents(runtime: BillingRuntime, limit: number): Promise<number>;
|
|
24
|
+
export declare function createBillingEventProjector(runtime: BillingRuntime): ForgeProjector<ObservedEvent>;
|
|
25
|
+
export {};
|
|
26
|
+
//# sourceMappingURL=events.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"events.d.ts","sourceRoot":"","sources":["../../src/billing/events.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAGH,OAAO,EAKL,KAAK,cAAc,EACpB,MAAM,0BAA0B,CAAC;AAoBlC,OAAO,KAAK,EACV,oBAAoB,EACpB,2BAA2B,EAC3B,gCAAgC,EACjC,MAAM,eAAe,CAAC;AACvB,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,cAAc,CAAC;AAQnD,KAAK,YAAY,GAAG,OAAO,CAAC,oBAAoB,EAAE;IAAE,IAAI,EAAE,SAAS,CAAA;CAAE,CAAC,CAAC;AACvE,KAAK,iBAAiB,GAAG,OAAO,CAC9B,oBAAoB,EACpB;IAAE,IAAI,EAAE,cAAc,CAAA;CAAE,CACzB,CAAC;AACF,KAAK,aAAa,GAAG,OAAO,CAC1B,oBAAoB,EACpB;IAAE,IAAI,EAAE,oBAAoB,CAAA;CAAE,CAC/B,CAAC;AAEF,KAAK,aAAa,GACd;IAAE,KAAK,EAAE,YAAY,CAAC;IAAC,OAAO,EAAE,2BAA2B,CAAA;CAAE,GAC7D;IACE,KAAK,EAAE,iBAAiB,CAAC;IACzB,YAAY,EAAE,gCAAgC,CAAC;CAChD,GACD;IAAE,KAAK,EAAE,aAAa,CAAA;CAAE,CAAC;AAI7B,6EAA6E;AAC7E,wBAAsB,oBAAoB,CACxC,OAAO,EAAE,cAAc,EACvB,KAAK,EAAE,MAAM,GACZ,OAAO,CAAC,MAAM,CAAC,CAkBjB;AAED,wBAAgB,2BAA2B,CACzC,OAAO,EAAE,cAAc,GACtB,cAAc,CAAC,aAAa,CAAC,CA+D/B"}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Billing-period close, provider events, and prepaid credit purchases
|
|
3
|
+
* (#3060).
|
|
4
|
+
* @packageDocumentation
|
|
5
|
+
*/
|
|
6
|
+
export type { CreateCreditCheckoutInput } from './credits.js';
|
|
7
|
+
export { type EnqueueBillingJobOptions, enqueueBillingEvents, enqueueBillingPeriodClose, getBillingRuntime, registerBillingRuntime, unregisterBillingRuntime, } from './jobs.js';
|
|
8
|
+
export { type BillingPeriod, BillingPeriodCloseError, type ClosePeriodInput, type PeriodCloseGroupResult, type PeriodCloseOutcome, type PeriodCloseResult, previousCalendarMonth, } from './period-close.js';
|
|
9
|
+
export { type BillingInvoiceEventType, type BillingProvider, type BillingProviderCheckoutInput, type BillingProviderCheckoutSession, type BillingProviderCustomerInput, type BillingProviderEvent, type BillingProviderInvoiceInput, type BillingProviderInvoiceLine, type BillingProviderInvoiceState, type BillingProviderInvoiceStatus, type BillingProviderSubscriptionState, BillingWebhookVerificationError, } from './provider.js';
|
|
10
|
+
export { type BillingLedgerAccounts, BillingRuntime, type BillingRuntimeOptions, type PayerStandingChange, type PayerStandingHook, type SyncedBillingAccount, type UpsertBillingAccountInput, } from './runtime.js';
|
|
11
|
+
export { createStripeBillingProvider, type StripeBillingProviderOptions, } from './stripe.js';
|
|
12
|
+
export { currencyMinorUnitExponent, majorToMinorUnits, minorToMajorUnits, } from './units.js';
|
|
13
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/billing/index.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AACH,YAAY,EAAE,yBAAyB,EAAE,MAAM,cAAc,CAAC;AAC9D,OAAO,EACL,KAAK,wBAAwB,EAC7B,oBAAoB,EACpB,yBAAyB,EACzB,iBAAiB,EACjB,sBAAsB,EACtB,wBAAwB,GACzB,MAAM,WAAW,CAAC;AACnB,OAAO,EACL,KAAK,aAAa,EAClB,uBAAuB,EACvB,KAAK,gBAAgB,EACrB,KAAK,sBAAsB,EAC3B,KAAK,kBAAkB,EACvB,KAAK,iBAAiB,EACtB,qBAAqB,GACtB,MAAM,mBAAmB,CAAC;AAC3B,OAAO,EACL,KAAK,uBAAuB,EAC5B,KAAK,eAAe,EACpB,KAAK,4BAA4B,EACjC,KAAK,8BAA8B,EACnC,KAAK,4BAA4B,EACjC,KAAK,oBAAoB,EACzB,KAAK,2BAA2B,EAChC,KAAK,0BAA0B,EAC/B,KAAK,2BAA2B,EAChC,KAAK,4BAA4B,EACjC,KAAK,gCAAgC,EACrC,+BAA+B,GAChC,MAAM,eAAe,CAAC;AACvB,OAAO,EACL,KAAK,qBAAqB,EAC1B,cAAc,EACd,KAAK,qBAAqB,EAC1B,KAAK,mBAAmB,EACxB,KAAK,iBAAiB,EACtB,KAAK,oBAAoB,EACzB,KAAK,yBAAyB,GAC/B,MAAM,cAAc,CAAC;AACtB,OAAO,EACL,2BAA2B,EAC3B,KAAK,4BAA4B,GAClC,MAAM,aAAa,CAAC;AACrB,OAAO,EACL,yBAAyB,EACzB,iBAAiB,EACjB,iBAAiB,GAClB,MAAM,YAAY,CAAC"}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import { SmrtJob } from '@happyvertical/smrt-jobs';
|
|
2
|
+
import { PeriodCloseResult } from './period-close.js';
|
|
3
|
+
import { BillingRuntime } from './runtime.js';
|
|
4
|
+
/** Make a runtime available to billing jobs under `name`. */
|
|
5
|
+
export declare function registerBillingRuntime(name: string, runtime: BillingRuntime): void;
|
|
6
|
+
export declare function unregisterBillingRuntime(name: string): void;
|
|
7
|
+
export declare function getBillingRuntime(name: string): BillingRuntime;
|
|
8
|
+
export declare function runBillingPeriodCloseJob(args: Record<string, unknown>): Promise<PeriodCloseResult>;
|
|
9
|
+
export declare function runBillingEventsJob(args: Record<string, unknown>): Promise<{
|
|
10
|
+
processed: number;
|
|
11
|
+
}>;
|
|
12
|
+
export interface EnqueueBillingJobOptions {
|
|
13
|
+
/** Registered runtime name. */
|
|
14
|
+
runtime: string;
|
|
15
|
+
runAt?: Date;
|
|
16
|
+
queue?: string;
|
|
17
|
+
maxAttempts?: number;
|
|
18
|
+
}
|
|
19
|
+
/**
|
|
20
|
+
* Queue a period close. Without a period the job closes the previous
|
|
21
|
+
* calendar month when it runs, so enqueueing it daily is safe.
|
|
22
|
+
*/
|
|
23
|
+
export declare function enqueueBillingPeriodClose(options: EnqueueBillingJobOptions & {
|
|
24
|
+
periodStart?: Date;
|
|
25
|
+
periodEnd?: Date;
|
|
26
|
+
}): Promise<SmrtJob>;
|
|
27
|
+
/** Queue processing of received provider events. */
|
|
28
|
+
export declare function enqueueBillingEvents(options: EnqueueBillingJobOptions & {
|
|
29
|
+
limit?: number;
|
|
30
|
+
}): Promise<SmrtJob>;
|
|
31
|
+
//# sourceMappingURL=jobs.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"jobs.d.ts","sourceRoot":"","sources":["../../src/billing/jobs.ts"],"names":[],"mappings":"AAQA,OAAO,EAAE,KAAK,OAAO,EAAqB,MAAM,0BAA0B,CAAC;AAC3E,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,mBAAmB,CAAC;AAC3D,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,cAAc,CAAC;AAmBnD,6DAA6D;AAC7D,wBAAgB,sBAAsB,CACpC,IAAI,EAAE,MAAM,EACZ,OAAO,EAAE,cAAc,GACtB,IAAI,CAGN;AAED,wBAAgB,wBAAwB,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,CAE3D;AAED,wBAAgB,iBAAiB,CAAC,IAAI,EAAE,MAAM,GAAG,cAAc,CAM9D;AAkBD,wBAAsB,wBAAwB,CAC5C,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAC5B,OAAO,CAAC,iBAAiB,CAAC,CAK5B;AAED,wBAAsB,mBAAmB,CACvC,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAC5B,OAAO,CAAC;IAAE,SAAS,EAAE,MAAM,CAAA;CAAE,CAAC,CAGhC;AAED,MAAM,WAAW,wBAAwB;IACvC,+BAA+B;IAC/B,OAAO,EAAE,MAAM,CAAC;IAChB,KAAK,CAAC,EAAE,IAAI,CAAC;IACb,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB;AA4BD;;;GAGG;AACH,wBAAgB,yBAAyB,CACvC,OAAO,EAAE,wBAAwB,GAAG;IAAE,WAAW,CAAC,EAAE,IAAI,CAAC;IAAC,SAAS,CAAC,EAAE,IAAI,CAAA;CAAE,GAC3E,OAAO,CAAC,OAAO,CAAC,CAelB;AAED,oDAAoD;AACpD,wBAAgB,oBAAoB,CAClC,OAAO,EAAE,wBAAwB,GAAG;IAAE,KAAK,CAAC,EAAE,MAAM,CAAA;CAAE,GACrD,OAAO,CAAC,OAAO,CAAC,CAclB"}
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import { BillingRuntime } from './runtime.js';
|
|
2
|
+
export interface BillingPeriod {
|
|
3
|
+
/** Inclusive start. */
|
|
4
|
+
periodStart: Date;
|
|
5
|
+
/** Exclusive end; charges approved before it are billable. */
|
|
6
|
+
periodEnd: Date;
|
|
7
|
+
}
|
|
8
|
+
export interface ClosePeriodInput {
|
|
9
|
+
periodStart?: Date;
|
|
10
|
+
periodEnd?: Date;
|
|
11
|
+
/** Clock override for tests; defaults to now. */
|
|
12
|
+
now?: Date;
|
|
13
|
+
}
|
|
14
|
+
export type PeriodCloseOutcome = 'completed' | 'empty' | 'busy' | 'carried_forward' | 'failed';
|
|
15
|
+
export interface PeriodCloseGroupResult {
|
|
16
|
+
payerTenantId: string;
|
|
17
|
+
currency: string;
|
|
18
|
+
closeId?: string;
|
|
19
|
+
invoiceId?: string;
|
|
20
|
+
providerInvoiceId?: string;
|
|
21
|
+
outcome: PeriodCloseOutcome;
|
|
22
|
+
error?: string;
|
|
23
|
+
}
|
|
24
|
+
export interface PeriodCloseResult extends BillingPeriod {
|
|
25
|
+
sellerTenantId: string;
|
|
26
|
+
groups: PeriodCloseGroupResult[];
|
|
27
|
+
}
|
|
28
|
+
/** Thrown when one or more payers could not be closed; the rest were. */
|
|
29
|
+
export declare class BillingPeriodCloseError extends Error {
|
|
30
|
+
readonly result: PeriodCloseResult;
|
|
31
|
+
constructor(result: PeriodCloseResult);
|
|
32
|
+
}
|
|
33
|
+
/** The previous calendar month in UTC relative to `now`. */
|
|
34
|
+
export declare function previousCalendarMonth(now?: Date): BillingPeriod;
|
|
35
|
+
export declare function periodCloseId(runtime: Pick<BillingRuntime, 'sellerTenantId' | 'kind'>, payerTenantId: string, currency: string, period: BillingPeriod): Promise<string>;
|
|
36
|
+
/**
|
|
37
|
+
* Close one billing period for a runtime's seller. Idempotent: re-running it
|
|
38
|
+
* for the same period resumes unfinished payers and bills nothing twice.
|
|
39
|
+
*/
|
|
40
|
+
export declare function closeBillingPeriod(runtime: BillingRuntime, input?: ClosePeriodInput): Promise<PeriodCloseResult>;
|
|
41
|
+
//# sourceMappingURL=period-close.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"period-close.d.ts","sourceRoot":"","sources":["../../src/billing/period-close.ts"],"names":[],"mappings":"AAmCA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,cAAc,CAAC;AAGnD,MAAM,WAAW,aAAa;IAC5B,uBAAuB;IACvB,WAAW,EAAE,IAAI,CAAC;IAClB,8DAA8D;IAC9D,SAAS,EAAE,IAAI,CAAC;CACjB;AAED,MAAM,WAAW,gBAAgB;IAC/B,WAAW,CAAC,EAAE,IAAI,CAAC;IACnB,SAAS,CAAC,EAAE,IAAI,CAAC;IACjB,iDAAiD;IACjD,GAAG,CAAC,EAAE,IAAI,CAAC;CACZ;AAED,MAAM,MAAM,kBAAkB,GAC1B,WAAW,GACX,OAAO,GACP,MAAM,GACN,iBAAiB,GACjB,QAAQ,CAAC;AAEb,MAAM,WAAW,sBAAsB;IACrC,aAAa,EAAE,MAAM,CAAC;IACtB,QAAQ,EAAE,MAAM,CAAC;IACjB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAC3B,OAAO,EAAE,kBAAkB,CAAC;IAC5B,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAED,MAAM,WAAW,iBAAkB,SAAQ,aAAa;IACtD,cAAc,EAAE,MAAM,CAAC;IACvB,MAAM,EAAE,sBAAsB,EAAE,CAAC;CAClC;AAED,yEAAyE;AACzE,qBAAa,uBAAwB,SAAQ,KAAK;IACpC,QAAQ,CAAC,MAAM,EAAE,iBAAiB;gBAAzB,MAAM,EAAE,iBAAiB;CAW/C;AAwBD,4DAA4D;AAC5D,wBAAgB,qBAAqB,CAAC,GAAG,OAAa,GAAG,aAAa,CAQrE;AAoCD,wBAAgB,aAAa,CAC3B,OAAO,EAAE,IAAI,CAAC,cAAc,EAAE,gBAAgB,GAAG,MAAM,CAAC,EACxD,aAAa,EAAE,MAAM,EACrB,QAAQ,EAAE,MAAM,EAChB,MAAM,EAAE,aAAa,GACpB,OAAO,CAAC,MAAM,CAAC,CAUjB;AAMD;;;GAGG;AACH,wBAAsB,kBAAkB,CACtC,OAAO,EAAE,cAAc,EACvB,KAAK,GAAE,gBAAqB,GAC3B,OAAO,CAAC,iBAAiB,CAAC,CA0D5B"}
|
|
@@ -0,0 +1,136 @@
|
|
|
1
|
+
import { SubscriptionStatus } from '@happyvertical/smrt-subscriptions';
|
|
2
|
+
import { Address } from '../types/index.js';
|
|
3
|
+
export interface BillingProviderCustomerInput {
|
|
4
|
+
/** The local billing account id, recorded on the provider customer. */
|
|
5
|
+
accountId: string;
|
|
6
|
+
/** Existing provider customer id; omitted to create one. */
|
|
7
|
+
providerCustomerId?: string;
|
|
8
|
+
name: string;
|
|
9
|
+
email?: string;
|
|
10
|
+
/** Tax location used by provider-calculated tax. */
|
|
11
|
+
billingAddress?: Address;
|
|
12
|
+
taxExempt: boolean;
|
|
13
|
+
}
|
|
14
|
+
export interface BillingProviderInvoiceLine {
|
|
15
|
+
description: string;
|
|
16
|
+
/** Signed line amount in minor units; discounts are negative lines. */
|
|
17
|
+
amount: number;
|
|
18
|
+
periodStart?: Date;
|
|
19
|
+
periodEnd?: Date;
|
|
20
|
+
}
|
|
21
|
+
export interface BillingProviderInvoiceInput {
|
|
22
|
+
/** Local invoice id; the provider tags its invoice with it. */
|
|
23
|
+
invoiceId: string;
|
|
24
|
+
invoiceNumber: string;
|
|
25
|
+
providerCustomerId: string;
|
|
26
|
+
currency: string;
|
|
27
|
+
issueDate: Date;
|
|
28
|
+
dueDate: Date;
|
|
29
|
+
lines: BillingProviderInvoiceLine[];
|
|
30
|
+
/** Sum of `lines`, in minor units. */
|
|
31
|
+
subtotal: number;
|
|
32
|
+
/** Stable key for this logical invoice; reused on every retry. */
|
|
33
|
+
idempotencyKey: string;
|
|
34
|
+
/** Ask the provider to calculate tax from the customer's tax location. */
|
|
35
|
+
automaticTax: boolean;
|
|
36
|
+
memo?: string;
|
|
37
|
+
}
|
|
38
|
+
export type BillingProviderInvoiceStatus = 'draft' | 'open' | 'paid' | 'void';
|
|
39
|
+
export interface BillingProviderInvoiceState {
|
|
40
|
+
providerInvoiceId: string;
|
|
41
|
+
status: BillingProviderInvoiceStatus;
|
|
42
|
+
currency: string;
|
|
43
|
+
/** Pre-tax subtotal, minor units. */
|
|
44
|
+
subtotal: number;
|
|
45
|
+
/** Provider-calculated tax, minor units. */
|
|
46
|
+
taxAmount: number;
|
|
47
|
+
total: number;
|
|
48
|
+
amountPaid: number;
|
|
49
|
+
amountDue: number;
|
|
50
|
+
}
|
|
51
|
+
export interface BillingProviderSubscriptionState {
|
|
52
|
+
providerSubscriptionId: string;
|
|
53
|
+
status: SubscriptionStatus;
|
|
54
|
+
currentPeriodStart?: Date;
|
|
55
|
+
currentPeriodEnd?: Date;
|
|
56
|
+
cancelAtPeriodEnd: boolean;
|
|
57
|
+
canceledAt?: Date;
|
|
58
|
+
trialEndsAt?: Date;
|
|
59
|
+
}
|
|
60
|
+
export interface BillingProviderCheckoutInput {
|
|
61
|
+
/** Stable key reused when retrying the same checkout creation. */
|
|
62
|
+
idempotencyKey: string;
|
|
63
|
+
providerCustomerId?: string;
|
|
64
|
+
customerEmail?: string;
|
|
65
|
+
currency: string;
|
|
66
|
+
/** Amount charged, minor units. */
|
|
67
|
+
amount: number;
|
|
68
|
+
description: string;
|
|
69
|
+
successUrl: string;
|
|
70
|
+
cancelUrl: string;
|
|
71
|
+
/** Opaque values returned verbatim on the completion event. */
|
|
72
|
+
metadata: Record<string, string>;
|
|
73
|
+
}
|
|
74
|
+
export interface BillingProviderCheckoutSession {
|
|
75
|
+
sessionId: string;
|
|
76
|
+
url: string | null;
|
|
77
|
+
}
|
|
78
|
+
/** Invoice lifecycle changes this package acts on. */
|
|
79
|
+
export type BillingInvoiceEventType = 'paid' | 'payment_failed' | 'overdue' | 'uncollectible' | 'voided';
|
|
80
|
+
/** A verified provider event, normalized and stripped of customer data. */
|
|
81
|
+
export type BillingProviderEvent = {
|
|
82
|
+
kind: 'invoice';
|
|
83
|
+
eventId: string;
|
|
84
|
+
type: BillingInvoiceEventType;
|
|
85
|
+
providerInvoiceId: string;
|
|
86
|
+
} | {
|
|
87
|
+
kind: 'subscription';
|
|
88
|
+
eventId: string;
|
|
89
|
+
providerSubscriptionId: string;
|
|
90
|
+
} | {
|
|
91
|
+
kind: 'checkout_completed';
|
|
92
|
+
eventId: string;
|
|
93
|
+
sessionId: string;
|
|
94
|
+
/** Only `paid` sessions settle a credit purchase. */
|
|
95
|
+
paid: boolean;
|
|
96
|
+
currency: string;
|
|
97
|
+
/** Line-item amount before discounts and tax, minor units. */
|
|
98
|
+
amountSubtotal: number;
|
|
99
|
+
/** Amount actually collected (after discounts, with tax), minor units. */
|
|
100
|
+
amountTotal: number;
|
|
101
|
+
metadata: Record<string, string>;
|
|
102
|
+
} | {
|
|
103
|
+
kind: 'ignored';
|
|
104
|
+
eventId: string;
|
|
105
|
+
type: string;
|
|
106
|
+
};
|
|
107
|
+
/**
|
|
108
|
+
* A payment provider as period close sees it. Implementations must be
|
|
109
|
+
* replay-safe: `pushInvoice` with the same `idempotencyKey` returns the same
|
|
110
|
+
* provider invoice however often it is retried.
|
|
111
|
+
*/
|
|
112
|
+
export interface BillingProvider {
|
|
113
|
+
/** Provider name recorded on local rows (`stripe`). */
|
|
114
|
+
readonly name: string;
|
|
115
|
+
syncCustomer(input: BillingProviderCustomerInput): Promise<{
|
|
116
|
+
providerCustomerId: string;
|
|
117
|
+
}>;
|
|
118
|
+
pushInvoice(input: BillingProviderInvoiceInput): Promise<{
|
|
119
|
+
providerInvoiceId: string;
|
|
120
|
+
}>;
|
|
121
|
+
/** Finalize (if still a draft) and send an invoice for payment. */
|
|
122
|
+
sendInvoice(providerInvoiceId: string): Promise<void>;
|
|
123
|
+
getInvoice(providerInvoiceId: string): Promise<BillingProviderInvoiceState>;
|
|
124
|
+
getSubscription(providerSubscriptionId: string): Promise<BillingProviderSubscriptionState>;
|
|
125
|
+
createCheckout(input: BillingProviderCheckoutInput): Promise<BillingProviderCheckoutSession>;
|
|
126
|
+
/**
|
|
127
|
+
* Verify a webhook signature and normalize the event. Rejects with
|
|
128
|
+
* {@link BillingWebhookVerificationError} when the signature is invalid;
|
|
129
|
+
* anything verified but not actionable is returned as `ignored`.
|
|
130
|
+
*/
|
|
131
|
+
verifyWebhook(payload: string, signature: string): Promise<BillingProviderEvent>;
|
|
132
|
+
}
|
|
133
|
+
export declare class BillingWebhookVerificationError extends Error {
|
|
134
|
+
constructor(message?: string);
|
|
135
|
+
}
|
|
136
|
+
//# sourceMappingURL=provider.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"provider.d.ts","sourceRoot":"","sources":["../../src/billing/provider.ts"],"names":[],"mappings":"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"}
|