allotment

package
v1.46.21 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Jul 3, 2026 License: MIT Imports: 6 Imported by: 0

Documentation

Overview

Package allotment grants a plan's recurring monthly included-usage credit to a tenant's prepaid balance.

Design (decomplected from the rest of billing):

  • The included monthly allotment is granted as an ordinary, tag-scoped, expiring Deposit transaction — the SAME mechanism as billing/credit's welcome credit. It therefore flows through TallyTransactions → balance → available with NO new balance-computation path, and the Hanzo gateway's prepaid balance gate (available > 0) honors it transparently. Usage withdrawals burn the deposit down; overage draws down purchased balance / is billed via the payment processor.

  • Non-accumulating: each grant expires at the end of its UTC month, so an unused remainder does not roll over. TallyTransactions already excludes expired deposits, so expiry needs no extra gate logic.

  • Idempotent per (user, period): the deposit is tagged with a period-scoped tag ("included-credit:YYYY-MM"). Re-running the grant for the same user in the same month is a safe no-op, which makes the monthly scheduler and any manual re-trigger naturally exactly-once.

The dollar amount per plan is catalog-derived (see billing.IncludedMonthlyCents, sourced from @hanzo/plans limits.includedCreditUsd). This package never hardcodes plan economics — callers pass the resolved cents in.

Index

Constants

View Source
const Kind = "iam-user"

Kind is the destination kind for IAM-bound balance transactions.

View Source
const TagPrefix = "included-credit"

TagPrefix is the stable prefix for monthly-allotment deposit tags. The full tag is TagPrefix + ":" + period (e.g. "included-credit:2026-06").

Variables

This section is empty.

Functions

func GrantedCents

func GrantedCents(db *datastore.Datastore, user string, at time.Time, test bool) int64

GrantedCents returns the total included-allotment credit currently granted to `user` for the UTC month containing `at` (sum of non-voided period-tagged deposits). Zero when none granted. Used by the rollup to report the included amount actually on the balance, independent of the catalog.

func Period

func Period(t time.Time) string

Period returns the canonical period key for a time, in UTC ("YYYY-MM").

func PeriodEnd

func PeriodEnd(t time.Time) time.Time

PeriodEnd returns the first instant of the month AFTER t's month (UTC). A deposit with this ExpiresAt is fully available for the whole of t's month and is excluded from balance the moment the next month begins.

func Tag

func Tag(t time.Time) string

Tag returns the period-scoped grant tag for a given time.

Types

type Result

type Result struct {
	Granted       bool   `json:"granted"`
	Reason        string `json:"reason,omitempty"`
	TransactionId string `json:"transactionId,omitempty"`
	AmountCents   int64  `json:"amountCents"`
	Period        string `json:"period"`
	Tag           string `json:"tag"`
}

Result describes the outcome of a grant attempt.

func Grant

func Grant(db *datastore.Datastore, user, plan string, cents int64, at time.Time, test bool) (Result, error)

Grant idempotently grants `cents` of included monthly usage credit to `user` for the UTC month containing `at`. It is a no-op (Granted=false) when:

  • cents <= 0 (plan has no included allotment), or
  • a grant for the same (user, period) already exists.

The check-and-create runs inside a datastore transaction so concurrent schedulers cannot double-grant. `test` marks the deposit test-only (mirrors the org.Live convention used elsewhere in billing).

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL