@happyvertical/smrt-commerce 0.51.26 → 0.51.28

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 CHANGED
@@ -42,6 +42,20 @@ for usage.
42
42
  close that nets to a credit keeps its claims and ends `carried_forward`;
43
43
  its subtotal is a `credit_carry_forward` source for the payer's next billed
44
44
  close, which marks the carried close `completed`.
45
+ - **Cycles and flat-plan coverage (#3116).** `cycles.ts` is the schedule
46
+ (pure; `BillingAccount.billingAnchorAt`, null = calendar months). A close
47
+ with no period closes each payer's `lastEndedBillingPeriod()`. Flat-plan
48
+ claims are the exception to "id from the source": their `sourceId` is
49
+ `<subscriptionId>:seq:<chainSequence>` and their `periodStart/End` is the
50
+ exact time they bill. `claimFlatWindow()` reads the last number, then the
51
+ coverage (claims ending after the window start), claims one gap as number
52
+ n + 1, and retries on conflict; reading in that order is what makes it
53
+ safe. That numbering, not the period, stops overlaps when schedules or
54
+ payers change — never claim a flat plan outside it, and keep both reads
55
+ bounded (no whole-history scans). Each numbered claim is its own invoice
56
+ line keyed `lineKey|periodStart` (a function of the claim alone, so a
57
+ resumed close rebuilds the same line ids). Proration is
58
+ `prorateMinorUnits()` (half up, BigInt) against the period's full cycle.
45
59
  - **System tables.** `BillingAccount`, `BillingPeriodClose`, and
46
60
  `BillingLineSource` are not tenant-scoped and have no generated surface.
47
61
  Collections stay unexported; models are root exports (#3082). Invoices,
@@ -67,7 +81,9 @@ for usage.
67
81
  two-decimal only (sdk#1269); `autoTopUp` cannot charge a saved card
68
82
  (sdk#1270); Stripe line discounts and uncollectible status are worked around
69
83
  as negative lines and event types (sdk#1271). `RetailCharge` has no
70
- adjustment ledger. Flat plans are monthly, in arrears, without proration.
84
+ adjustment ledger. Flat plans are monthly, in arrears; plan changes are not
85
+ prorated (#3119). The Stripe adapter passes line service periods but
86
+ the accounting SDK does not send them to Stripe yet (happyvertical/sdk#1274).
71
87
 
72
88
  ## Cross-Package References
73
89
 
package/README.md CHANGED
@@ -187,7 +187,16 @@ await billing.upsertAccount({
187
187
  billingAddress: { country: 'CA', postalCode: 'T0L 0A0' },
188
188
  });
189
189
 
190
- // Close last month (default) — safe to run on every schedule tick.
190
+ // Optional: bill this payer from its activation date instead of calendar
191
+ // months, prorating flat plans added mid-period (see "Billing cycles").
192
+ await billing.upsertAccount({
193
+ payerTenantId,
194
+ name: 'Network Co',
195
+ billingAnchorAt: activatedAt,
196
+ prorateFlatPlans: true,
197
+ });
198
+
199
+ // Close each payer's last ended period — safe to run on every schedule tick.
191
200
  registerBillingRuntime('platform', billing);
192
201
  await enqueueBillingPeriodClose({ runtime: 'platform' });
193
202
 
@@ -216,15 +225,75 @@ const { url } = await billing.createCreditCheckout({
216
225
  it owns, to each subscriber's billing owner. A `reseller` runtime bills the
217
226
  `RetailCharge`s its children owe it plus its own flat plans. Charges approved
218
227
  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
228
+ are billed in arrears for the payer's closed period (trials and
220
229
  provider-managed subscriptions are skipped). One invoice per payer and
221
230
  currency carries both kinds of lines.
222
231
  - **Replay safety.** Close, invoice, and line ids are derived from the payer,
223
232
  currency, and period; each charge is claimed by exactly one close; the
224
233
  provider invoice uses the close id as its idempotency key; and every step is
225
234
  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
235
+ two workers advancing the same close. A close without a period also resumes
236
+ every unfinished close whose period has ended, even one the payer's current
237
+ schedule no longer produces (#3116). A payer whose charges net to a credit
227
238
  gets no invoice; the credit is carried to its next invoice.
239
+ - **Billing cycles (#3116).** A payer's periods follow its account's
240
+ `billingAnchorAt`. Unset (the default) they are UTC calendar months. Set,
241
+ they run monthly from the anchor at its UTC time of day; a day the month
242
+ lacks is clamped to its last day, always from the anchor itself (an anchor
243
+ on Jan 31 bills Jan 31 → Feb 28 → Mar 31). Before the anchor the schedule is
244
+ calendar months, and the anchor's own month ends at the anchor (a *stub*).
245
+ `closePeriod()` / `enqueueBillingPeriodClose()` with no period close each
246
+ payer's **last ended period on its own schedule**, so payers on different
247
+ anchors are closed by the same daily tick. An explicit
248
+ `{ periodStart, periodEnd }` closes that period for calendar payers (flat
249
+ plans only when it is a calendar month, as before) and for anchored payers
250
+ whose schedule has exactly that period. `billingPeriodFor(payer, at)` returns
251
+ a payer's current period; `billingPeriodContaining()`,
252
+ `lastEndedBillingPeriod()`, and `prorateMinorUnits()` are exported.
253
+ - **Proration.** A flat plan is priced `price × billed time / cycle length`,
254
+ in integer minor units rounded half up (exact integer arithmetic; the
255
+ cycle is the period's own month, so February prorates over 28 or 29 days).
256
+ With `prorateFlatPlans` off (default) the billed time is the whole period
257
+ whenever the subscription was active in it and out of trial at its start —
258
+ the pre-#3116 behavior. With it on, the billed time is exactly the time the
259
+ subscription was active and out of trial: a subscription starting, leaving
260
+ trial, or canceled mid-period is billed pro rata. Proration happens before
261
+ the account's flat discount. Split into parts, prorated amounts can differ
262
+ from the full price by a minor unit.
263
+ - **First period.** *Anchor at signup* (set `billingAnchorAt` to the
264
+ signup/activation instant): the first period is a full period from signup;
265
+ nothing before it is billed. *Bill from signup to the next anchor* (keep a
266
+ fixed anchor, or calendar months, and set `prorateFlatPlans`): the first
267
+ period is billed pro rata from signup. Items added later are prorated to the
268
+ payer's anchor when `prorateFlatPlans` is on and billed a full period
269
+ otherwise.
270
+ - **Mid-period changes.** Billing is in arrears, so a cancellation needs no
271
+ credit: with proration the canceled period is billed up to `canceledAt`,
272
+ without it in full. A plan change is billed at the plan in effect at close
273
+ for the whole window (no plan-change proration yet, #3119), and a cancellation
274
+ back-dated into an already billed period is not credited — issue an
275
+ adjustment.
276
+ - **No double billing across schedule changes.** Every flat-plan claim records
277
+ the exact time it bills, and a subscription's claims are numbered, so only
278
+ one worker can write the next claim and two can never claim the same time.
279
+ Moving an account from calendar months to an anchor, moving an anchor, or
280
+ moving a subscription to a payer on another schedule bills only time not yet
281
+ billed, prorated. For example, calendar months through February and then an
282
+ anchor on Mar 20 bills the Mar 1 → Mar 20 stub pro rata, then Mar 20 → Apr
283
+ 20. Time around an already billed window is billed as separate lines, each
284
+ with its own service period. Stop workers running a pre-#3116 version
285
+ before relying on this: they claim flat plans outside the numbering.
286
+ - **Service periods.** Each flat-plan invoice line carries its billed window
287
+ as `periodStart`/`periodEnd`, down to the provider port. The Stripe adapter
288
+ passes them on; `@happyvertical/accounting` does not send them to Stripe yet
289
+ (happyvertical/sdk#1274).
290
+ - **Upgrading to #3116.** Additive schema only: `_smrt_billing_accounts` gains
291
+ `billing_anchor_at` (nullable) and `prorate_flat_plans` (default false), and
292
+ `_smrt_billing_line_sources` gains `chain_sequence` (default 0) and an index
293
+ on `(line_key, chain_sequence)`; run `smrt db:migrate`.
294
+ Existing accounts stay on calendar months, and claims written before the
295
+ upgrade (`<subscriptionId>:<periodStart>`, number 0) count as billed
296
+ coverage, so nothing is billed again after it.
228
297
  - **Tax** comes from the provider (Stripe Tax) using the account customer's
229
298
  `defaultBillingAddress`; the invoice records it as `providerTaxAmount`.
230
299
  - **Events** are verified, stored in smrt-jobs' durable delivery inbox, and
@@ -0,0 +1,31 @@
1
+ import { BillingPeriod } from './period-close.js';
2
+ /** A period of a payer's schedule and the full cycle it prorates against. */
3
+ export interface ScheduledBillingPeriod extends BillingPeriod {
4
+ /** Start of the full monthly cycle (equals `periodStart` except for a stub). */
5
+ cycleStart: Date;
6
+ /** End of the full monthly cycle (equals `periodEnd` except for a stub). */
7
+ cycleEnd: Date;
8
+ }
9
+ /**
10
+ * `anchor` plus `months` calendar months at the anchor's UTC time of day,
11
+ * with the day clamped to the target month's last day.
12
+ */
13
+ export declare function addBillingMonths(anchor: Date, months: number): Date;
14
+ /**
15
+ * The period of a schedule (calendar months when `anchor` is null) that
16
+ * contains `at`.
17
+ */
18
+ export declare function billingPeriodContaining(anchor: Date | null | undefined, at: Date): ScheduledBillingPeriod;
19
+ /**
20
+ * The most recent period of a schedule that has ended by `now` — what a
21
+ * period close with no explicit period bills. With no anchor this is the
22
+ * previous calendar month.
23
+ */
24
+ export declare function lastEndedBillingPeriod(anchor: Date | null | undefined, now?: Date): ScheduledBillingPeriod;
25
+ /**
26
+ * `amount × coveredMs / cycleMs` in integer minor units, rounded half up
27
+ * (exact integer arithmetic, no floating point). Coverage of the whole cycle
28
+ * or more returns `amount` unchanged; no coverage returns 0.
29
+ */
30
+ export declare function prorateMinorUnits(amount: number, coveredMs: number, cycleMs: number): number;
31
+ //# sourceMappingURL=cycles.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cycles.d.ts","sourceRoot":"","sources":["../../src/billing/cycles.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;GAmBG;AACH,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,mBAAmB,CAAC;AAEvD,6EAA6E;AAC7E,MAAM,WAAW,sBAAuB,SAAQ,aAAa;IAC3D,gFAAgF;IAChF,UAAU,EAAE,IAAI,CAAC;IACjB,4EAA4E;IAC5E,QAAQ,EAAE,IAAI,CAAC;CAChB;AAMD;;;GAGG;AACH,wBAAgB,gBAAgB,CAAC,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,MAAM,GAAG,IAAI,CAgBnE;AAyBD;;;GAGG;AACH,wBAAgB,uBAAuB,CACrC,MAAM,EAAE,IAAI,GAAG,IAAI,GAAG,SAAS,EAC/B,EAAE,EAAE,IAAI,GACP,sBAAsB,CAgCxB;AAED;;;;GAIG;AACH,wBAAgB,sBAAsB,CACpC,MAAM,EAAE,IAAI,GAAG,IAAI,GAAG,SAAS,EAC/B,GAAG,GAAE,IAAiB,GACrB,sBAAsB,CAMxB;AAED;;;;GAIG;AACH,wBAAgB,iBAAiB,CAC/B,MAAM,EAAE,MAAM,EACd,SAAS,EAAE,MAAM,EACjB,OAAO,EAAE,MAAM,GACd,MAAM,CAWR"}
@@ -4,6 +4,7 @@
4
4
  * @packageDocumentation
5
5
  */
6
6
  export type { CreateCreditCheckoutInput } from './credits.js';
7
+ export { addBillingMonths, billingPeriodContaining, lastEndedBillingPeriod, prorateMinorUnits, type ScheduledBillingPeriod, } from './cycles.js';
7
8
  export { type EnqueueBillingJobOptions, enqueueBillingEvents, enqueueBillingPeriodClose, getBillingRuntime, registerBillingRuntime, unregisterBillingRuntime, } from './jobs.js';
8
9
  export { type BillingPeriod, BillingPeriodCloseError, type ClosePeriodInput, type PeriodCloseGroupResult, type PeriodCloseOutcome, type PeriodCloseResult, previousCalendarMonth, } from './period-close.js';
9
10
  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';
@@ -1 +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"}
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,gBAAgB,EAChB,uBAAuB,EACvB,sBAAsB,EACtB,iBAAiB,EACjB,KAAK,sBAAsB,GAC5B,MAAM,aAAa,CAAC;AACrB,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"}
@@ -17,8 +17,10 @@ export interface EnqueueBillingJobOptions {
17
17
  maxAttempts?: number;
18
18
  }
19
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.
20
+ * Queue a period close. Without a period the job closes each payer's last
21
+ * ended period on its own schedule when it runs (the previous calendar month,
22
+ * or the last anchor-to-anchor period for an anchored account, #3116), so
23
+ * enqueueing it daily is safe.
22
24
  */
23
25
  export declare function enqueueBillingPeriodClose(options: EnqueueBillingJobOptions & {
24
26
  periodStart?: Date;
@@ -1 +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"}
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;;;;;GAKG;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"}
@@ -5,6 +5,14 @@ export interface BillingPeriod {
5
5
  /** Exclusive end; charges approved before it are billable. */
6
6
  periodEnd: Date;
7
7
  }
8
+ /**
9
+ * Without a period, each payer's most recent ended period on its own schedule
10
+ * is closed (#3116): the previous calendar month for a payer without a
11
+ * billing anchor, the last anchor-to-anchor period for one with. With a
12
+ * period, that exact period is closed for every calendar-schedule payer (flat
13
+ * plans only when it is a calendar month) and for each anchored payer whose
14
+ * schedule contains exactly that period.
15
+ */
8
16
  export interface ClosePeriodInput {
9
17
  periodStart?: Date;
10
18
  periodEnd?: Date;
@@ -15,12 +23,19 @@ export type PeriodCloseOutcome = 'completed' | 'empty' | 'busy' | 'carried_forwa
15
23
  export interface PeriodCloseGroupResult {
16
24
  payerTenantId: string;
17
25
  currency: string;
26
+ /** The payer's period this group closed (#3116). */
27
+ periodStart: Date;
28
+ periodEnd: Date;
18
29
  closeId?: string;
19
30
  invoiceId?: string;
20
31
  providerInvoiceId?: string;
21
32
  outcome: PeriodCloseOutcome;
22
33
  error?: string;
23
34
  }
35
+ /**
36
+ * `periodStart`/`periodEnd` are the explicit period, or the previous calendar
37
+ * month for a close without one; each group carries the payer's own period.
38
+ */
24
39
  export interface PeriodCloseResult extends BillingPeriod {
25
40
  sellerTenantId: string;
26
41
  groups: PeriodCloseGroupResult[];
@@ -34,8 +49,9 @@ export declare class BillingPeriodCloseError extends Error {
34
49
  export declare function previousCalendarMonth(now?: Date): BillingPeriod;
35
50
  export declare function periodCloseId(runtime: Pick<BillingRuntime, 'sellerTenantId' | 'kind'>, payerTenantId: string, currency: string, period: BillingPeriod): Promise<string>;
36
51
  /**
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.
52
+ * Close billing periods for a runtime's seller: each payer's last ended
53
+ * period, or one explicit period (see {@link ClosePeriodInput}). Idempotent:
54
+ * re-running it resumes unfinished payers and bills nothing twice.
39
55
  */
40
56
  export declare function closeBillingPeriod(runtime: BillingRuntime, input?: ClosePeriodInput): Promise<PeriodCloseResult>;
41
57
  //# sourceMappingURL=period-close.d.ts.map
@@ -1 +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"}
1
+ {"version":3,"file":"period-close.d.ts","sourceRoot":"","sources":["../../src/billing/period-close.ts"],"names":[],"mappings":"AA4CA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,cAAc,CAAC;AAQnD,MAAM,WAAW,aAAa;IAC5B,uBAAuB;IACvB,WAAW,EAAE,IAAI,CAAC;IAClB,8DAA8D;IAC9D,SAAS,EAAE,IAAI,CAAC;CACjB;AAED;;;;;;;GAOG;AACH,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,oDAAoD;IACpD,WAAW,EAAE,IAAI,CAAC;IAClB,SAAS,EAAE,IAAI,CAAC;IAChB,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;;;GAGG;AACH,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;AAmDD,4DAA4D;AAC5D,wBAAgB,qBAAqB,CAAC,GAAG,OAAa,GAAG,aAAa,CAQrE;AAkCD,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;AAsED;;;;GAIG;AACH,wBAAsB,kBAAkB,CACtC,OAAO,EAAE,cAAc,EACvB,KAAK,GAAE,gBAAqB,GAC3B,OAAO,CAAC,iBAAiB,CAAC,CAwE5B"}
@@ -9,6 +9,7 @@ import { BillingAccount, BillingAccountCollection, BillingCloseKind, BillingLine
9
9
  import { Invoice } from '../models/Invoice.js';
10
10
  import { Address } from '../types/index.js';
11
11
  import { CreateCreditCheckoutInput } from './credits.js';
12
+ import { ScheduledBillingPeriod } from './cycles.js';
12
13
  import { ClosePeriodInput, PeriodCloseResult } from './period-close.js';
13
14
  import { BillingProvider, BillingProviderCheckoutSession } from './provider.js';
14
15
  /** Ledger accounts billing posts to, in the seller's books. */
@@ -73,6 +74,15 @@ export interface UpsertBillingAccountInput {
73
74
  paymentTermsDays?: number;
74
75
  /** Link an existing provider customer (for example from checkout). */
75
76
  providerCustomerId?: string;
77
+ /**
78
+ * Billing-cycle anchor (#3116): periods run monthly from this instant
79
+ * (anchor at signup/activation for no partial first period). `null` returns
80
+ * the payer to UTC calendar months; omitted leaves it unchanged. Changing it
81
+ * never bills time twice.
82
+ */
83
+ billingAnchorAt?: Date | null;
84
+ /** Prorate flat plans to the time they were active in a period (#3116). */
85
+ prorateFlatPlans?: boolean;
76
86
  }
77
87
  /** A synced account: its provider customer id is always present. */
78
88
  export interface SyncedBillingAccount {
@@ -133,8 +143,19 @@ export declare class BillingRuntime {
133
143
  * dies between creation and this save leaves an unused provider customer.
134
144
  */
135
145
  ensureProviderCustomer(account: BillingAccount): Promise<SyncedBillingAccount>;
136
- /** Close a billing period (default: the previous calendar month, UTC). */
146
+ /**
147
+ * Close billing periods. Without a period, each payer's last ended period
148
+ * on its own schedule (the previous UTC calendar month unless its account
149
+ * has a `billingAnchorAt`), so running it daily is safe. See
150
+ * {@link ClosePeriodInput}.
151
+ */
137
152
  closePeriod(input?: ClosePeriodInput): Promise<PeriodCloseResult>;
153
+ /**
154
+ * The payer's billing period containing `at` (default now) on its account's
155
+ * schedule — for example to show the next invoice date. A payer without an
156
+ * account is on calendar months.
157
+ */
158
+ billingPeriodFor(payerTenantId: string, at?: Date): Promise<ScheduledBillingPeriod>;
138
159
  getInvoice(invoiceId: string): Promise<Invoice>;
139
160
  /** Take the close's lease; returns the token, or null if another holds it. */
140
161
  acquireCloseLease(closeId: string, now?: Date): Promise<string | null>;
@@ -1 +1 @@
1
- {"version":3,"file":"runtime.d.ts","sourceRoot":"","sources":["../../src/billing/runtime.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"runtime.d.ts","sourceRoot":"","sources":["../../src/billing/runtime.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AACH,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,0BAA0B,CAAC;AACjE,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,qCAAqC,CAAC;AAE7E,OAAO,EAAE,iBAAiB,EAAE,MAAM,6BAA6B,CAAC;AAChE,OAAO,EACL,2BAA2B,EAC3B,KAAK,yBAAyB,EAC9B,sBAAsB,EACtB,mBAAmB,EACnB,sBAAsB,EACtB,wBAAwB,EACxB,0BAA0B,EAC1B,4BAA4B,EAC7B,MAAM,mCAAmC,CAAC;AAE3C,OAAO,EAAE,kBAAkB,EAAE,MAAM,sCAAsC,CAAC;AAC1E,OAAO,EAAE,iBAAiB,EAAE,MAAM,qCAAqC,CAAC;AACxE,OAAO,EAAE,yBAAyB,EAAE,MAAM,6CAA6C,CAAC;AACxF,OAAO,EACL,KAAK,cAAc,EACnB,wBAAwB,EACxB,KAAK,gBAAgB,EACrB,2BAA2B,EAC3B,4BAA4B,EAC5B,KAAK,eAAe,EACrB,MAAM,sBAAsB,CAAC;AAC9B,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,sBAAsB,CAAC;AACpD,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,mBAAmB,CAAC;AACjD,OAAO,EACL,KAAK,yBAAyB,EAE/B,MAAM,cAAc,CAAC;AACtB,OAAO,EAEL,KAAK,sBAAsB,EAC5B,MAAM,aAAa,CAAC;AAErB,OAAO,EACL,KAAK,gBAAgB,EAErB,KAAK,iBAAiB,EACvB,MAAM,mBAAmB,CAAC;AAC3B,OAAO,KAAK,EACV,eAAe,EACf,8BAA8B,EAC/B,MAAM,eAAe,CAAC;AAGvB,+DAA+D;AAC/D,MAAM,WAAW,qBAAqB;IACpC,+DAA+D;IAC/D,WAAW,EAAE,MAAM,CAAC;IACpB,oDAAoD;IACpD,gBAAgB,EAAE,MAAM,CAAC;IACzB,2DAA2D;IAC3D,YAAY,EAAE,MAAM,CAAC;IACrB,qDAAqD;IACrD,aAAa,EAAE,MAAM,CAAC;IACtB,2DAA2D;IAC3D,sBAAsB,EAAE,MAAM,CAAC;CAChC;AAED,iEAAiE;AACjE,MAAM,WAAW,mBAAmB;IAClC,cAAc,EAAE,MAAM,CAAC;IACvB,aAAa,EAAE,MAAM,CAAC;IACtB,gBAAgB,EAAE,MAAM,CAAC;IACzB,SAAS,EAAE,MAAM,CAAC;IAClB,QAAQ,EAAE,eAAe,CAAC;IAC1B,QAAQ,EAAE,eAAe,CAAC;IAC1B;;;OAGG;IACH,EAAE,EAAE,iBAAiB,CAAC;CACvB;AAED;;;;GAIG;AACH,MAAM,MAAM,iBAAiB,GAAG,CAC9B,MAAM,EAAE,mBAAmB,KACxB,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;AAE1B,MAAM,WAAW,qBAAsB,SAAQ,gBAAgB;IAC7D,uCAAuC;IACvC,cAAc,EAAE,MAAM,CAAC;IACvB,IAAI,EAAE,gBAAgB,CAAC;IACvB,QAAQ,EAAE,eAAe,CAAC;IAC1B,0EAA0E;IAC1E,oBAAoB,EAAE,yBAAyB,CAAC;IAChD,MAAM,EAAE,qBAAqB,CAAC;IAC9B,6CAA6C;IAC7C,mBAAmB,CAAC,EAAE,MAAM,CAAC;IAC7B,eAAe,CAAC,EAAE,iBAAiB,CAAC;IACpC,wEAAwE;IACxE,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,gDAAgD;IAChD,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB;AAED,MAAM,WAAW,yBAAyB;IACxC,aAAa,EAAE,MAAM,CAAC;IACtB,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,oEAAoE;IACpE,cAAc,CAAC,EAAE,OAAO,CAAC;IACzB,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,YAAY,CAAC,EAAE,OAAO,CAAC;IACvB,uBAAuB,CAAC,EAAE,MAAM,CAAC;IACjC,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,sEAAsE;IACtE,kBAAkB,CAAC,EAAE,MAAM,CAAC;IAC5B;;;;;OAKG;IACH,eAAe,CAAC,EAAE,IAAI,GAAG,IAAI,CAAC;IAC9B,2EAA2E;IAC3E,gBAAgB,CAAC,EAAE,OAAO,CAAC;CAC5B;AAED,oEAAoE;AACpE,MAAM,WAAW,oBAAoB;IACnC,OAAO,EAAE,cAAc,CAAC;IACxB,kBAAkB,EAAE,MAAM,CAAC;IAC3B,YAAY,EAAE,OAAO,CAAC;CACvB;AAID;;;;;;;;;GASG;AACH,qBAAa,cAAc;IAevB,QAAQ,CAAC,EAAE,EAAE,iBAAiB;IAC9B,QAAQ,CAAC,QAAQ,EAAE,wBAAwB;IAC3C,QAAQ,CAAC,MAAM,EAAE,4BAA4B;IAC7C,QAAQ,CAAC,OAAO,EAAE,2BAA2B;IAC7C,QAAQ,CAAC,SAAS,EAAE,kBAAkB;IACtC,QAAQ,CAAC,QAAQ,EAAE,iBAAiB;IACpC,QAAQ,CAAC,SAAS,EAAE,yBAAyB;IAC7C,QAAQ,CAAC,QAAQ,EAAE,iBAAiB;IACpC,QAAQ,CAAC,OAAO,EAAE,sBAAsB;IACxC,QAAQ,CAAC,WAAW,EAAE,2BAA2B;IACjD,QAAQ,CAAC,aAAa,EAAE,sBAAsB;IAC9C,QAAQ,CAAC,KAAK,EAAE,mBAAmB;IACnC,QAAQ,CAAC,aAAa,EAAE,4BAA4B;IACpD,QAAQ,CAAC,KAAK,EAAE,0BAA0B;IAC1C,QAAQ,CAAC,QAAQ,EAAE,wBAAwB;IA5B7C,QAAQ,CAAC,cAAc,EAAE,MAAM,CAAC;IAChC,QAAQ,CAAC,IAAI,EAAE,gBAAgB,CAAC;IAChC,QAAQ,CAAC,QAAQ,EAAE,eAAe,CAAC;IACnC,QAAQ,CAAC,oBAAoB,EAAE,yBAAyB,CAAC;IACzD,QAAQ,CAAC,MAAM,EAAE,qBAAqB,CAAC;IACvC,QAAQ,CAAC,mBAAmB,EAAE,MAAM,CAAC;IACrC,QAAQ,CAAC,eAAe,CAAC,EAAE,iBAAiB,CAAC;IAC7C,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B,2EAA2E;IAC3E,QAAQ,CAAC,aAAa,EAAE,MAAM,CAAC;IAE/B,OAAO;WA+CM,MAAM,CAAC,OAAO,EAAE,qBAAqB,GAAG,OAAO,CAAC,cAAc,CAAC;IAuCtE,UAAU,CAAC,aAAa,EAAE,MAAM,GAAG,OAAO,CAAC,cAAc,GAAG,IAAI,CAAC;IAIvE,OAAO,CAAC,SAAS;IAQjB;;;;OAIG;IACG,aAAa,CACjB,KAAK,EAAE,yBAAyB,GAC/B,OAAO,CAAC,cAAc,CAAC;IA2E1B;;;;OAIG;IACG,sBAAsB,CAC1B,OAAO,EAAE,cAAc,GACtB,OAAO,CAAC,oBAAoB,CAAC;IA0ChC;;;;;OAKG;IACH,WAAW,CAAC,KAAK,GAAE,gBAAqB,GAAG,OAAO,CAAC,iBAAiB,CAAC;IAIrE;;;;OAIG;IACG,gBAAgB,CACpB,aAAa,EAAE,MAAM,EACrB,EAAE,GAAE,IAAiB,GACpB,OAAO,CAAC,sBAAsB,CAAC;IAK5B,UAAU,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC;IAQrD,8EAA8E;IACxE,iBAAiB,CACrB,OAAO,EAAE,MAAM,EACf,GAAG,OAAa,GACf,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC;IAoBnB,iBAAiB,CAAC,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IActE;;;;;;;;OAQG;IACG,aAAa,CACjB,OAAO,EAAE,MAAM,EACf,SAAS,EAAE,MAAM,GAChB,OAAO,CAAC;QACT,QAAQ,EAAE,OAAO,CAAC;QAClB,OAAO,EAAE,MAAM,CAAC;QAChB,IAAI,EAAE,MAAM,CAAC;QACb,IAAI,CAAC,EAAE,MAAM,CAAC;KACf,CAAC;IAsBF,wEAAwE;IACxE,aAAa,CAAC,KAAK,SAAK,GAAG,OAAO,CAAC,MAAM,CAAC;IAQ1C;;;;OAIG;IACH,oBAAoB,CAClB,KAAK,EAAE,yBAAyB,GAC/B,OAAO,CAAC,8BAA8B,CAAC;IAI1C,2EAA2E;IAC3E,MAAM,CAAC,CAAC,EAAE,SAAS,EAAE,MAAM,OAAO,CAAC,CAAC,CAAC,GAAG,OAAO,CAAC,CAAC,CAAC;CAGnD"}
@@ -26,6 +26,8 @@ export declare function majorToMinorUnits(amount: number, currency: string): num
26
26
  export declare function deterministicId(parts: string[]): Promise<string>;
27
27
  /** Validate and lower-case a tenant UUID. */
28
28
  export declare function canonicalTenantId(id: string, label?: string): string;
29
+ /** Whether `id` is a tenant UUID (any case). */
30
+ export declare function isTenantId(id: string): boolean;
29
31
  /** Lower-case a possibly-empty tenant id for comparison. */
30
32
  export declare function tenantKey(id: string | null | undefined): string;
31
33
  //# sourceMappingURL=units.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"units.d.ts","sourceRoot":"","sources":["../../src/billing/units.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAIH,yEAAyE;AACzE,wBAAgB,iBAAiB,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,CAQ1D;AAED,6EAA6E;AAC7E,wBAAgB,yBAAyB,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,CAOlE;AAED,gEAAgE;AAChE,wBAAgB,iBAAiB,CAAC,MAAM,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,MAAM,CAO1E;AAED;;;;GAIG;AACH,wBAAgB,iBAAiB,CAAC,MAAM,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,MAAM,CAY1E;AAED;;;;GAIG;AACH,wBAAsB,eAAe,CAAC,KAAK,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,MAAM,CAAC,CAetE;AAKD,6CAA6C;AAC7C,wBAAgB,iBAAiB,CAAC,EAAE,EAAE,MAAM,EAAE,KAAK,SAAc,GAAG,MAAM,CAKzE;AAED,4DAA4D;AAC5D,wBAAgB,SAAS,CAAC,EAAE,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,GAAG,MAAM,CAE/D"}
1
+ {"version":3,"file":"units.d.ts","sourceRoot":"","sources":["../../src/billing/units.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAIH,yEAAyE;AACzE,wBAAgB,iBAAiB,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,CAQ1D;AAED,6EAA6E;AAC7E,wBAAgB,yBAAyB,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,CAOlE;AAED,gEAAgE;AAChE,wBAAgB,iBAAiB,CAAC,MAAM,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,MAAM,CAO1E;AAED;;;;GAIG;AACH,wBAAgB,iBAAiB,CAAC,MAAM,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,MAAM,CAY1E;AAED;;;;GAIG;AACH,wBAAsB,eAAe,CAAC,KAAK,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,MAAM,CAAC,CAetE;AAKD,6CAA6C;AAC7C,wBAAgB,iBAAiB,CAAC,EAAE,EAAE,MAAM,EAAE,KAAK,SAAc,GAAG,MAAM,CAKzE;AAED,gDAAgD;AAChD,wBAAgB,UAAU,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAE9C;AAED,4DAA4D;AAC5D,wBAAgB,SAAS,CAAC,EAAE,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,GAAG,MAAM,CAE/D"}
@@ -43,10 +43,13 @@ function canonicalTenantId(id, label = "Tenant ID") {
43
43
  if (typeof id !== "string" || !UUID_PATTERN.test(id)) throw new Error(`${label} must be a UUID.`);
44
44
  return id.toLowerCase();
45
45
  }
46
+ function isTenantId(id) {
47
+ return typeof id === "string" && UUID_PATTERN.test(id);
48
+ }
46
49
  function tenantKey(id) {
47
50
  return id ? String(id).toLowerCase() : "";
48
51
  }
49
52
  //#endregion
50
- export { minorToMajorUnits as a, majorToMinorUnits as i, currencyMinorUnitExponent as n, normalizeCurrency as o, deterministicId as r, tenantKey as s, canonicalTenantId as t };
53
+ export { majorToMinorUnits as a, tenantKey as c, isTenantId as i, currencyMinorUnitExponent as n, minorToMajorUnits as o, deterministicId as r, normalizeCurrency as s, canonicalTenantId as t };
51
54
 
52
- //# sourceMappingURL=units--tTn2ps8.js.map
55
+ //# sourceMappingURL=units-Bk_o7kRV.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"units--tTn2ps8.js","names":[],"sources":["../../src/billing/units.ts"],"sourcesContent":["/**\n * Money-unit and identity helpers for billing-period close (#3060).\n *\n * Commerce stores money as integer minor units. `@happyvertical/accounting`\n * takes and returns currency *major* units and converts to the provider's own\n * representation itself, so the only conversion this package performs is the\n * ISO 4217 one: minor units ÷ 10^exponent.\n */\n\nconst CURRENCY_PATTERN = /^[A-Z]{3}$/;\n\n/** Upper-case, validate, and return an ISO 4217-shaped currency code. */\nexport function normalizeCurrency(currency: string): string {\n const code = String(currency ?? '')\n .trim()\n .toUpperCase();\n if (!CURRENCY_PATTERN.test(code)) {\n throw new Error(`Currency '${currency}' must be a three-letter code.`);\n }\n return code;\n}\n\n/** The ISO 4217 minor-unit exponent of a currency (2 for USD, 0 for JPY). */\nexport function currencyMinorUnitExponent(currency: string): number {\n const code = normalizeCurrency(currency);\n const digits = new Intl.NumberFormat('en', {\n style: 'currency',\n currency: code,\n }).resolvedOptions().maximumFractionDigits;\n return typeof digits === 'number' ? digits : 2;\n}\n\n/** Integer minor units → major units (`1999` USD → `19.99`). */\nexport function minorToMajorUnits(amount: number, currency: string): number {\n if (!Number.isSafeInteger(amount)) {\n throw new Error(\n `Amount ${amount} must be a safe integer number of minor units.`,\n );\n }\n return amount / 10 ** currencyMinorUnitExponent(currency);\n}\n\n/**\n * Major units → integer minor units. Rejects a value that is not a whole\n * number of minor units instead of rounding it: a provider amount that does\n * not round-trip exactly means the two sides disagree about the currency.\n */\nexport function majorToMinorUnits(amount: number, currency: string): number {\n if (!Number.isFinite(amount)) {\n throw new Error(`Provider amount ${amount} is not a finite number.`);\n }\n const scaled = amount * 10 ** currencyMinorUnitExponent(currency);\n const minor = Math.round(scaled);\n if (Math.abs(scaled - minor) > 1e-6 || !Number.isSafeInteger(minor)) {\n throw new Error(\n `Provider amount ${amount} ${normalizeCurrency(currency)} is not a whole number of minor units.`,\n );\n }\n return minor;\n}\n\n/**\n * A stable UUID derived from its parts (SHA-256, version/variant bits set).\n * Deterministic ids are what make every period-close write replay-safe: a\n * retry recomputes the same identity instead of creating a second row.\n */\nexport async function deterministicId(parts: string[]): Promise<string> {\n const bytes = new TextEncoder().encode(JSON.stringify(parts));\n const digest = new Uint8Array(await crypto.subtle.digest('SHA-256', bytes));\n const uuid = digest.slice(0, 16);\n uuid[6] = (uuid[6] & 0x0f) | 0x50;\n uuid[8] = (uuid[8] & 0x3f) | 0x80;\n const hex = Array.from(uuid, (byte) => byte.toString(16).padStart(2, '0'));\n const joined = hex.join('');\n return [\n joined.slice(0, 8),\n joined.slice(8, 12),\n joined.slice(12, 16),\n joined.slice(16, 20),\n joined.slice(20),\n ].join('-');\n}\n\nconst UUID_PATTERN =\n /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;\n\n/** Validate and lower-case a tenant UUID. */\nexport function canonicalTenantId(id: string, label = 'Tenant ID'): string {\n if (typeof id !== 'string' || !UUID_PATTERN.test(id)) {\n throw new Error(`${label} must be a UUID.`);\n }\n return id.toLowerCase();\n}\n\n/** Lower-case a possibly-empty tenant id for comparison. */\nexport function tenantKey(id: string | null | undefined): string {\n return id ? String(id).toLowerCase() : '';\n}\n"],"mappings":";AASA,IAAM,mBAAmB;AAGlB,SAAS,kBAAkB,UAA0B;CAC1D,MAAM,OAAO,OAAO,YAAY,EAAE,CAAA,CAC/B,KAAK,CAAA,CACL,YAAY;CACf,IAAI,CAAC,iBAAiB,KAAK,IAAI,GAC7B,MAAM,IAAI,MAAM,aAAa,SAAQ,+BAAgC;CAEvE,OAAO;AACT;AAGO,SAAS,0BAA0B,UAA0B;CAClE,MAAM,OAAO,kBAAkB,QAAQ;CACvC,MAAM,SAAS,IAAI,KAAK,aAAa,MAAM;EACzC,OAAO;EACP,UAAU;CACZ,CAAC,CAAA,CAAE,gBAAgB,CAAA,CAAE;CACrB,OAAO,OAAO,WAAW,WAAW,SAAS;AAC/C;AAGO,SAAS,kBAAkB,QAAgB,UAA0B;CAC1E,IAAI,CAAC,OAAO,cAAc,MAAM,GAC9B,MAAM,IAAI,MACR,UAAU,OAAM,+CAClB;CAEF,OAAO,SAAS,MAAM,0BAA0B,QAAQ;AAC1D;AAOO,SAAS,kBAAkB,QAAgB,UAA0B;CAC1E,IAAI,CAAC,OAAO,SAAS,MAAM,GACzB,MAAM,IAAI,MAAM,mBAAmB,OAAM,yBAA0B;CAErE,MAAM,SAAS,SAAS,MAAM,0BAA0B,QAAQ;CAChE,MAAM,QAAQ,KAAK,MAAM,MAAM;CAC/B,IAAI,KAAK,IAAI,SAAS,KAAK,IAAI,QAAQ,CAAC,OAAO,cAAc,KAAK,GAChE,MAAM,IAAI,MACR,mBAAmB,OAAM,GAAI,kBAAkB,QAAQ,EAAC,uCAC1D;CAEF,OAAO;AACT;AAOA,eAAsB,gBAAgB,OAAkC;CACtE,MAAM,QAAQ,IAAI,YAAY,CAAA,CAAE,OAAO,KAAK,UAAU,KAAK,CAAC;CAE5D,MAAM,OAAO,IADM,WAAW,MAAM,OAAO,OAAO,OAAO,WAAW,KAAK,CAC5D,CAAA,CAAO,MAAM,GAAG,EAAE;CAC/B,KAAK,KAAM,KAAK,KAAK,KAAQ;CAC7B,KAAK,KAAM,KAAK,KAAK,KAAQ;CAE7B,MAAM,SADM,MAAM,KAAK,OAAO,SAAS,KAAK,SAAS,EAAE,CAAA,CAAE,SAAS,GAAG,GAAG,CACzD,CAAA,CAAI,KAAK,EAAE;CAC1B,OAAO;EACL,OAAO,MAAM,GAAG,CAAC;EACjB,OAAO,MAAM,GAAG,EAAE;EAClB,OAAO,MAAM,IAAI,EAAE;EACnB,OAAO,MAAM,IAAI,EAAE;EACnB,OAAO,MAAM,EAAE;CACjB,CAAA,CAAE,KAAK,GAAG;AACZ;AAEA,IAAM,eACJ;AAGK,SAAS,kBAAkB,IAAY,QAAQ,aAAqB;CACzE,IAAI,OAAO,OAAO,YAAY,CAAC,aAAa,KAAK,EAAE,GACjD,MAAM,IAAI,MAAM,GAAG,MAAK,iBAAkB;CAE5C,OAAO,GAAG,YAAY;AACxB;AAGO,SAAS,UAAU,IAAuC;CAC/D,OAAO,KAAK,OAAO,EAAE,CAAA,CAAE,YAAY,IAAI;AACzC"}
1
+ {"version":3,"file":"units-Bk_o7kRV.js","names":[],"sources":["../../src/billing/units.ts"],"sourcesContent":["/**\n * Money-unit and identity helpers for billing-period close (#3060).\n *\n * Commerce stores money as integer minor units. `@happyvertical/accounting`\n * takes and returns currency *major* units and converts to the provider's own\n * representation itself, so the only conversion this package performs is the\n * ISO 4217 one: minor units ÷ 10^exponent.\n */\n\nconst CURRENCY_PATTERN = /^[A-Z]{3}$/;\n\n/** Upper-case, validate, and return an ISO 4217-shaped currency code. */\nexport function normalizeCurrency(currency: string): string {\n const code = String(currency ?? '')\n .trim()\n .toUpperCase();\n if (!CURRENCY_PATTERN.test(code)) {\n throw new Error(`Currency '${currency}' must be a three-letter code.`);\n }\n return code;\n}\n\n/** The ISO 4217 minor-unit exponent of a currency (2 for USD, 0 for JPY). */\nexport function currencyMinorUnitExponent(currency: string): number {\n const code = normalizeCurrency(currency);\n const digits = new Intl.NumberFormat('en', {\n style: 'currency',\n currency: code,\n }).resolvedOptions().maximumFractionDigits;\n return typeof digits === 'number' ? digits : 2;\n}\n\n/** Integer minor units → major units (`1999` USD → `19.99`). */\nexport function minorToMajorUnits(amount: number, currency: string): number {\n if (!Number.isSafeInteger(amount)) {\n throw new Error(\n `Amount ${amount} must be a safe integer number of minor units.`,\n );\n }\n return amount / 10 ** currencyMinorUnitExponent(currency);\n}\n\n/**\n * Major units → integer minor units. Rejects a value that is not a whole\n * number of minor units instead of rounding it: a provider amount that does\n * not round-trip exactly means the two sides disagree about the currency.\n */\nexport function majorToMinorUnits(amount: number, currency: string): number {\n if (!Number.isFinite(amount)) {\n throw new Error(`Provider amount ${amount} is not a finite number.`);\n }\n const scaled = amount * 10 ** currencyMinorUnitExponent(currency);\n const minor = Math.round(scaled);\n if (Math.abs(scaled - minor) > 1e-6 || !Number.isSafeInteger(minor)) {\n throw new Error(\n `Provider amount ${amount} ${normalizeCurrency(currency)} is not a whole number of minor units.`,\n );\n }\n return minor;\n}\n\n/**\n * A stable UUID derived from its parts (SHA-256, version/variant bits set).\n * Deterministic ids are what make every period-close write replay-safe: a\n * retry recomputes the same identity instead of creating a second row.\n */\nexport async function deterministicId(parts: string[]): Promise<string> {\n const bytes = new TextEncoder().encode(JSON.stringify(parts));\n const digest = new Uint8Array(await crypto.subtle.digest('SHA-256', bytes));\n const uuid = digest.slice(0, 16);\n uuid[6] = (uuid[6] & 0x0f) | 0x50;\n uuid[8] = (uuid[8] & 0x3f) | 0x80;\n const hex = Array.from(uuid, (byte) => byte.toString(16).padStart(2, '0'));\n const joined = hex.join('');\n return [\n joined.slice(0, 8),\n joined.slice(8, 12),\n joined.slice(12, 16),\n joined.slice(16, 20),\n joined.slice(20),\n ].join('-');\n}\n\nconst UUID_PATTERN =\n /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;\n\n/** Validate and lower-case a tenant UUID. */\nexport function canonicalTenantId(id: string, label = 'Tenant ID'): string {\n if (typeof id !== 'string' || !UUID_PATTERN.test(id)) {\n throw new Error(`${label} must be a UUID.`);\n }\n return id.toLowerCase();\n}\n\n/** Whether `id` is a tenant UUID (any case). */\nexport function isTenantId(id: string): boolean {\n return typeof id === 'string' && UUID_PATTERN.test(id);\n}\n\n/** Lower-case a possibly-empty tenant id for comparison. */\nexport function tenantKey(id: string | null | undefined): string {\n return id ? String(id).toLowerCase() : '';\n}\n"],"mappings":";AASA,IAAM,mBAAmB;AAGlB,SAAS,kBAAkB,UAA0B;CAC1D,MAAM,OAAO,OAAO,YAAY,EAAE,CAAA,CAC/B,KAAK,CAAA,CACL,YAAY;CACf,IAAI,CAAC,iBAAiB,KAAK,IAAI,GAC7B,MAAM,IAAI,MAAM,aAAa,SAAQ,+BAAgC;CAEvE,OAAO;AACT;AAGO,SAAS,0BAA0B,UAA0B;CAClE,MAAM,OAAO,kBAAkB,QAAQ;CACvC,MAAM,SAAS,IAAI,KAAK,aAAa,MAAM;EACzC,OAAO;EACP,UAAU;CACZ,CAAC,CAAA,CAAE,gBAAgB,CAAA,CAAE;CACrB,OAAO,OAAO,WAAW,WAAW,SAAS;AAC/C;AAGO,SAAS,kBAAkB,QAAgB,UAA0B;CAC1E,IAAI,CAAC,OAAO,cAAc,MAAM,GAC9B,MAAM,IAAI,MACR,UAAU,OAAM,+CAClB;CAEF,OAAO,SAAS,MAAM,0BAA0B,QAAQ;AAC1D;AAOO,SAAS,kBAAkB,QAAgB,UAA0B;CAC1E,IAAI,CAAC,OAAO,SAAS,MAAM,GACzB,MAAM,IAAI,MAAM,mBAAmB,OAAM,yBAA0B;CAErE,MAAM,SAAS,SAAS,MAAM,0BAA0B,QAAQ;CAChE,MAAM,QAAQ,KAAK,MAAM,MAAM;CAC/B,IAAI,KAAK,IAAI,SAAS,KAAK,IAAI,QAAQ,CAAC,OAAO,cAAc,KAAK,GAChE,MAAM,IAAI,MACR,mBAAmB,OAAM,GAAI,kBAAkB,QAAQ,EAAC,uCAC1D;CAEF,OAAO;AACT;AAOA,eAAsB,gBAAgB,OAAkC;CACtE,MAAM,QAAQ,IAAI,YAAY,CAAA,CAAE,OAAO,KAAK,UAAU,KAAK,CAAC;CAE5D,MAAM,OAAO,IADM,WAAW,MAAM,OAAO,OAAO,OAAO,WAAW,KAAK,CAC5D,CAAA,CAAO,MAAM,GAAG,EAAE;CAC/B,KAAK,KAAM,KAAK,KAAK,KAAQ;CAC7B,KAAK,KAAM,KAAK,KAAK,KAAQ;CAE7B,MAAM,SADM,MAAM,KAAK,OAAO,SAAS,KAAK,SAAS,EAAE,CAAA,CAAE,SAAS,GAAG,GAAG,CACzD,CAAA,CAAI,KAAK,EAAE;CAC1B,OAAO;EACL,OAAO,MAAM,GAAG,CAAC;EACjB,OAAO,MAAM,GAAG,EAAE;EAClB,OAAO,MAAM,IAAI,EAAE;EACnB,OAAO,MAAM,IAAI,EAAE;EACnB,OAAO,MAAM,EAAE;CACjB,CAAA,CAAE,KAAK,GAAG;AACZ;AAEA,IAAM,eACJ;AAGK,SAAS,kBAAkB,IAAY,QAAQ,aAAqB;CACzE,IAAI,OAAO,OAAO,YAAY,CAAC,aAAa,KAAK,EAAE,GACjD,MAAM,IAAI,MAAM,GAAG,MAAK,iBAAkB;CAE5C,OAAO,GAAG,YAAY;AACxB;AAGO,SAAS,WAAW,IAAqB;CAC9C,OAAO,OAAO,OAAO,YAAY,aAAa,KAAK,EAAE;AACvD;AAGO,SAAS,UAAU,IAAuC;CAC/D,OAAO,KAAK,OAAO,EAAE,CAAA,CAAE,YAAY,IAAI;AACzC"}