Files
member-console/internal/billing/querier.go
T
cgalo5758 dd3962990b Adopt entity keys and add invoice numbers
Replace the entity slugs on organizations, workspaces, resource pools,
and
plan ladders with nullable `key` columns and add keys to products,
prices,
and entitlement sets. Rename `providers.slug` to `provider` and add
partial
unique indexes for system and org role names.

Assign invoice numbers per billing account from a gapless transactional
counter; Stripe's number moves to the invoice mapping as an external
reference.

Seeds, fixtures, and the operator lookup address rows by key, and the
returning-login resync no longer blanks a display name when the IdP
sends
no `name` claim.
2026-08-29 20:12:04 -05:00

324 lines
22 KiB
Go

// Code generated by sqlc. DO NOT EDIT.
// versions:
// sqlc v1.29.0
package billing
import (
"context"
"database/sql"
)
type Querier interface {
// Setup-checklist existence probe.
AnyActivePrice(ctx context.Context) (bool, error)
// Setup-checklist existence probe.
AnyProduct(ctx context.Context) (bool, error)
// Setup-checklist existence probe.
AnyPublishedProduct(ctx context.Context) (bool, error)
// Setup-checklist existence probe: a ladder delivers only through its rank-0
// tier, so "ladder exists" alone is not the step.
AnyRankZeroTier(ctx context.Context) (bool, error)
// Webhook-primary closeout: when a subscription actually ends (Stripe fires
// customer.subscription.deleted at period end), mark its still-pending scheduled
// changes applied so the intent ledger reflects what happened.
ApplyScheduledChangesForSubscription(ctx context.Context, subscriptionID string) error
// The transactional, gapless counter invoice-numbers D1 specifies: the
// account's next_invoice_number is incremented and the prior value
// returned in the same statement, so the caller runs this inside the same
// transaction that inserts the invoice row (invoice.finalized projection).
// Never a Postgres sequence — a sequence burns values on rollback, and this
// counter must not: a projection that fails after this call rolls back
// with the transaction, leaving the counter exactly where it was. Row
// locking is implicit in the UPDATE and serializes only within one
// account.
AssignNextInvoiceNumber(ctx context.Context, billingAccountID string) (int32, error)
CancelScheduledChange(ctx context.Context, scheduledChangeID string) (SubscriptionScheduledChange, error)
// First half of the make-default handshake; run in the same transaction as
// MarkDefaultPrice (clear before set, so the partial unique index never sees
// two defaults for one product).
ClearDefaultPrice(ctx context.Context, productID string) error
// Both halves of the operator overview's Monthly recurring caption in one
// read: 'active' and 'trialing' are the two statuses that mean the
// subscription is presently owed service (the pair operator_billing.go
// treats as live), but only active ones contribute money, so the caption
// needs them separately.
CountLiveSubscriptionsByStatus(ctx context.Context) (CountLiveSubscriptionsByStatusRow, error)
// Receivables headline for the operator landing surface. `open` is the only
// actionable non-terminal invoice status (design/billing/model.md): draft is
// not yet issued, and paid/void/uncollectible/refunded are settled or written
// off. A count, not a balance sum — currency is per-row, and a cross-currency
// sum would be a number the tile could not stand behind.
CountOpenInvoices(ctx context.Context) (int64, error)
// Operator overview tile: the size of the live catalog. Counts only
// lifecycle_status='published' — drafts are work in progress and retired
// products are history, so neither belongs in a "what we sell today" number.
CountPublishedProducts(ctx context.Context) (int64, error)
// Operator catalog overview (ux-ia-naming 2.1): how many published products
// are a tier on some plan ladder, vs. off-ladder. A product counts once even
// when it is shared across more than one ladder (DISTINCT).
CountPublishedTierProducts(ctx context.Context) (int64, error)
CreateBillingAccount(ctx context.Context, arg CreateBillingAccountParams) (Account, error)
// invoice_number is the platform-assigned reference number (invoice-numbers
// D1-D3): the caller assigns it via AssignNextInvoiceNumber (billing_accounts.sql)
// in the same transaction, inside the invoice.finalized projection, and
// passes the formatted result here. Drafts pass NULL/invalid
// (chk_invoices_issued_have_number allows a NULL number only when status is
// 'draft').
CreateInvoice(ctx context.Context, arg CreateInvoiceParams) (Invoice, error)
CreateInvoiceLineItem(ctx context.Context, arg CreateInvoiceLineItemParams) (InvoiceLineItem, error)
CreatePayment(ctx context.Context, arg CreatePaymentParams) (Payment, error)
CreatePaymentMethod(ctx context.Context, arg CreatePaymentMethodParams) (PaymentMethod, error)
// `key` is the optional declarative address (entity-keys §3), root-scoped.
// The operator create form asks for a name only, so a UI-created ladder
// leaves it NULL; a seed or a configuration loader supplies it.
CreatePlanLadder(ctx context.Context, arg CreatePlanLadderParams) (PlanLadder, error)
// Appends the tier at the end of the ladder: rank self-assigns to MAX+1 in the
// INSERT itself (no read-then-write race). Reorder keeps ranks contiguous
// 0..N-1, so MAX+1 == COUNT; operators position tiers by drag-and-drop.
CreatePlanLadderTier(ctx context.Context, arg CreatePlanLadderTierParams) (PlanLadderTier, error)
// The first price a product gets becomes its default automatically (there is
// nothing else to offer members); subsequent prices are created non-default
// and promoted explicitly via Clear/MarkDefaultPrice. The NOT EXISTS probe
// also self-heals a product that somehow lost its default: the next price
// created becomes it. The partial unique index
// (idx_prices_one_default_per_product) backstops concurrent creation races.
//
// `key` is the optional declarative address (entity-keys §3), unique within
// the product because a price is a child of one. Stripe's `lookup_key` is
// the same idea on the same entity. The operator create form does not
// collect one, so a UI-created price leaves it NULL.
CreatePrice(ctx context.Context, arg CreatePriceParams) (Price, error)
// `key` is the optional declarative address (entity-keys §3), root-scoped.
// Product names deliberately carry no uniqueness constraint (two ladders may
// each have a "Pro"), which is exactly why a caller outside the database
// needs a key to name one row. The operator create form does not collect
// one, so a UI-created product leaves it NULL.
CreateProduct(ctx context.Context, arg CreateProductParams) (Product, error)
CreateScheduledChange(ctx context.Context, arg CreateScheduledChangeParams) (SubscriptionScheduledChange, error)
CreateSubscription(ctx context.Context, arg CreateSubscriptionParams) (Subscription, error)
CreateSubscriptionChange(ctx context.Context, arg CreateSubscriptionChangeParams) (SubscriptionChange, error)
CreateSubscriptionItem(ctx context.Context, arg CreateSubscriptionItemParams) (SubscriptionItem, error)
// Handlers must refuse to deactivate the default price (members would lose
// the purchase path); the is_default guard here backstops that rule.
DeactivatePrice(ctx context.Context, priceID string) (Price, error)
DeletePlanLadder(ctx context.Context, planLadderID string) error
DeleteTier(ctx context.Context, arg DeleteTierParams) error
// Idempotent tier membership for a seed (entity-keys §6 as amended by §9 A1:
// a seed ensures a row exists and never overwrites one). A tier has no key of
// its own: it is a relationship, and its identity is the pair (§2 class E),
// which is also its primary key. Rank self-assigns to MAX+1 exactly as
// CreatePlanLadderTier does, so a caller inserting tiers in ascending order
// gets 0..N-1; a second run conflicts on the pair and does nothing, leaving
// an operator's own reordering alone.
EnsurePlanLadderTier(ctx context.Context, arg EnsurePlanLadderTierParams) error
GetBillingAccountByID(ctx context.Context, billingAccountID string) (Account, error)
GetDefaultPriceByProduct(ctx context.Context, productID string) (Price, error)
GetInvoiceByID(ctx context.Context, invoiceID string) (Invoice, error)
GetInvoiceLineItemsByInvoiceID(ctx context.Context, invoiceID string) ([]InvoiceLineItem, error)
GetInvoicesByBillingAccountID(ctx context.Context, billingAccountID string) ([]Invoice, error)
// Most recent invoice for a billing account (any status). Used by the
// per-org composite's billing-summary section.
GetLatestInvoiceByBillingAccountID(ctx context.Context, billingAccountID string) (Invoice, error)
// Most recent subscription for a billing account (any status). Used by the
// per-org composite's billing-summary section.
GetLatestSubscriptionByBillingAccountID(ctx context.Context, billingAccountID string) (Subscription, error)
// Sum of (amount_due - amount_paid) across invoices with status='open' — the
// only actionable non-terminal invoice status per design/billing/model.md.
// Returns 0 if no open invoices exist.
GetOutstandingBalanceByBillingAccountID(ctx context.Context, billingAccountID string) (int64, error)
GetPaymentByID(ctx context.Context, paymentID string) (Payment, error)
GetPaymentMethodByID(ctx context.Context, paymentMethodID string) (PaymentMethod, error)
GetPaymentMethodsByBillingAccountID(ctx context.Context, billingAccountID string) ([]PaymentMethod, error)
GetPaymentsByInvoiceID(ctx context.Context, invoiceID string) ([]Payment, error)
GetPlanLadderByID(ctx context.Context, planLadderID string) (PlanLadder, error)
// Root key resolver (entity-keys §5). uq_plan_ladders_key guarantees at most
// one row matches.
GetPlanLadderByKey(ctx context.Context, key sql.NullString) (PlanLadder, error)
GetPrice(ctx context.Context, priceID string) (Price, error)
// Child key resolver (entity-keys §5): the declarative address of a price is
// its product's key plus its own. uq_prices_product_id_key guarantees at
// most one row matches.
GetPriceByProductAndKey(ctx context.Context, arg GetPriceByProductAndKeyParams) (Price, error)
GetProductByID(ctx context.Context, productID string) (Product, error)
// Root key resolver (entity-keys §5). uq_products_key guarantees at most one
// row matches -- unlike GetProductByName, whose column has no unique
// constraint at all.
GetProductByKey(ctx context.Context, key sql.NullString) (Product, error)
// Diagnostics view (migration 00006): independent structural dimensions per
// product. Readiness reads set_present and billing_shape.
GetProductShape(ctx context.Context, productID string) (CoreProductShape, error)
GetScheduledChangeByID(ctx context.Context, scheduledChangeID string) (SubscriptionScheduledChange, error)
GetSubscriptionByID(ctx context.Context, subscriptionID string) (Subscription, error)
GetSubscriptionChangesBySubscriptionID(ctx context.Context, subscriptionID string) ([]SubscriptionChange, error)
GetSubscriptionItemByID(ctx context.Context, subscriptionItemID string) (SubscriptionItem, error)
GetSubscriptionItemsBySubscriptionID(ctx context.Context, subscriptionID string) ([]SubscriptionItem, error)
GetSubscriptionsByBillingAccountID(ctx context.Context, billingAccountID string) ([]Subscription, error)
GetTier(ctx context.Context, arg GetTierParams) (PlanLadderTier, error)
GetTierByLadderRank(ctx context.Context, arg GetTierByLadderRankParams) (PlanLadderTier, error)
ListActiveProducts(ctx context.Context) ([]Product, error)
ListActiveScheduledChangesBySubscription(ctx context.Context, subscriptionID string) ([]SubscriptionScheduledChange, error)
ListAllProducts(ctx context.Context) ([]Product, error)
ListBillingAccountsByOrgID(ctx context.Context, orgID string) ([]Account, error)
// Operator billing-accounts view, paged and searched (operator-list-scale
// UX-4; operator-billing-views D8). No status facet: core.accounts.status
// carries no CHECK-enforced vocabulary and operator-list-scale's "Status
// filters exist where a status vocabulary exists" requirement does not
// name accounts, so this query offers search + pagination only.
//
// sqlc.narg(q): NULL matches every row; set, a case-insensitive substring
// match against the account's own name, or its organization via
// sqlc.narg(org_ids) (design D3: "billing: organization name plus the
// view's leading identifier"). Organization-name search resolves through
// a pre-resolved ID array rather than a join to core.organizations: no
// existing internal/billing query crosses that module boundary
// (grep 'core\.' internal/billing/queries/ turns up none), so
// operator_billing.go's matchingOrgIDs resolves matching org IDs in Go and
// passes them here, mirroring the grants lane's product-name pattern.
// count(*) OVER() carries the true total for the filtered set (design D2).
ListBillingAccountsPage(ctx context.Context, arg ListBillingAccountsPageParams) ([]ListBillingAccountsPageRow, error)
// Sweeper backstop: due, not-yet-fired rows. Concurrency safety comes from the
// per-row claim (MarkScheduledChangeApplied), not row locking, so a plain read
// is sufficient.
ListDueScheduledChanges(ctx context.Context) ([]SubscriptionScheduledChange, error)
// Operator invoices view, paged/searched/filtered (operator-list-scale
// UX-4; operator-billing-views D5/D8). Carries ba.org_id so the handler can
// resolve and link the organization without a cross-module join (see
// billing_accounts.sql's ListBillingAccountsPage comment for why).
//
// sqlc.narg(q): NULL matches every row; set, a case-insensitive substring
// match against the billing account's name (the view's leading identifier
// pre-reorder), the invoice's own invoice_number (invoice-numbers D3/D4 --
// matches both the platform form and a grandfathered Stripe-format string,
// since both live in this column), or its organization via
// sqlc.narg(org_ids), pre-resolved in Go (operator_billing.go:
// matchingOrgIDs). sqlc.narg(invoice_ids): a search also matches an
// invoice whose stripe.invoice_mappings row carries a matching
// stripe_invoice_number (design D6) -- internal/billing has no query that
// joins the stripe schema (mirrors the org-name pattern above: no existing
// query crosses that module boundary either), so operator_billing.go
// resolves the matching invoice ids there
// (matchingInvoiceIDsByStripeNumber) and passes them in pre-resolved, the
// same shape as org_ids.
// sqlc.narg(status): NULL matches every status. The stored status
// vocabulary (design/data-model.md: draft, open, paid, void,
// uncollectible, refunded -- core.invoices carries no CHECK constraint,
// this is the documented closed set) matches exactly; the sentinel value
// 'overdue' instead selects the derived predicate design D5 defines --
// status = 'open' AND due_date IS NOT NULL AND due_date < now() -- so the
// Overdue filter's total is computed in SQL, never after LIMIT (the same
// predicate operator_billing.go's invoiceIsOverdue applies in Go for
// per-row presentation; a test pins their agreement).
// count(*) OVER() carries the true total for the filtered set (design D2).
ListInvoicesPage(ctx context.Context, arg ListInvoicesPageParams) ([]ListInvoicesPageRow, error)
ListLaddersByProduct(ctx context.Context, productID string) ([]ListLaddersByProductRow, error)
// Operator payments view, paged and searched (operator-list-scale UX-4;
// operator-billing-views D8). No status facet: the operator-list-scale
// spec's "Status filters exist where a status vocabulary exists"
// requirement enumerates grants/invoices/subscriptions/organizations, not
// payments, so this query offers search + pagination only. Carries
// ba.org_id so the handler can resolve and link the organization without a
// cross-module join (see billing_accounts.sql's ListBillingAccountsPage
// comment for why).
//
// sqlc.narg(q): NULL matches every row; set, a case-insensitive substring
// match against the billing account's name (the view's leading identifier
// pre-reorder) or its organization via sqlc.narg(org_ids), pre-resolved in
// Go (operator_billing.go: matchingOrgIDs).
// Joins to core.invoices (not left -- invoice_id is NOT NULL on
// core.payments) to carry invoice_number: invoice-numbers D3 puts the
// number in the title of this view's "View invoice" cross-reference.
// count(*) OVER() carries the true total for the filtered set (design D2).
ListPaymentsPage(ctx context.Context, arg ListPaymentsPageParams) ([]ListPaymentsPageRow, error)
ListPlanLadders(ctx context.Context) ([]PlanLadder, error)
// LEFT JOINs on purpose: a ladder whose rank-0 tier was deleted must still
// appear (product columns NULL) so surfaces that reference it — notably an
// org type's configured default — can show it as broken instead of silently
// dropping it from a dropdown and NULLing the stored value on save.
ListPlanLaddersWithRankZeroProduct(ctx context.Context) ([]ListPlanLaddersWithRankZeroProductRow, error)
ListPricesByProduct(ctx context.Context, productID string) ([]Price, error)
// Product duplicate-name warning (entity-keys): products may
// legitimately share a name (a "Pro" tier on two ladders), so
// core.products.name carries no uniqueness constraint -- this powers a live,
// non-blocking warning on the create/edit forms instead of a 422. Matches
// case-insensitively; when exclude_product_id is set (the edit form's own
// product), that product is excluded from its own duplicate check. LEFT
// JOINs the ladder tables so a matching product that is on no ladder still
// returns one row (ladder columns NULL); the caller groups rows by
// product_id in Go and collects each product's ladder names.
ListProductsByNameCI(ctx context.Context, arg ListProductsByNameCIParams) ([]ListProductsByNameCIRow, error)
// Plan products are those attached to a ladder via plan_ladder_tiers
// (Doc 31 Amendment #3); membership is the structural signal —
// display_category is presentation-only and never branched on.
ListPublicPlanProducts(ctx context.Context) ([]Product, error)
ListPublicProducts(ctx context.Context) ([]Product, error)
// Recent invoices for the operator landing activity timeline. Joins to
// core.accounts to resolve the org_id (same schema, safe for sqlc).
ListRecentInvoices(ctx context.Context, limit int32) ([]ListRecentInvoicesRow, error)
// Recent payments for the operator landing activity timeline. Joins to
// core.accounts to resolve the org_id (same schema, safe for sqlc).
ListRecentPayments(ctx context.Context, limit int32) ([]ListRecentPaymentsRow, error)
// Products that are a tier in more than one ladder (the many-to-many made
// legible for the operator topology overview). Returns one row per
// (shared product, ladder) membership, ordered for stable grouping in Go.
ListSharedTierProducts(ctx context.Context) ([]ListSharedTierProductsRow, error)
// Operator subscriptions view, paged/searched/filtered (operator-list-scale
// UX-4; operator-billing-views D8). Carries ba.org_id so the handler can
// resolve and link the organization without a cross-module join (see
// billing_accounts.sql's ListBillingAccountsPage comment for why).
//
// sqlc.narg(q): NULL matches every row; set, a case-insensitive substring
// match against the billing account's name (the view's leading identifier
// pre-reorder) or its organization via sqlc.narg(org_ids), pre-resolved in
// Go (operator_billing.go: matchingOrgIDs).
// sqlc.narg(status): NULL matches every status; set, an exact match
// against the subscription's CHECK-constrained status vocabulary
// (00010_schema_hardening.sql: chk_subscriptions_status_valid --
// incomplete, incomplete_expired, trialing, active, past_due, canceled,
// unpaid, paused).
// count(*) OVER() carries the true total for the filtered set (design D2).
ListSubscriptionsPage(ctx context.Context, arg ListSubscriptionsPageParams) ([]ListSubscriptionsPageRow, error)
ListTiersByLadder(ctx context.Context, planLadderID string) ([]PlanLadderTier, error)
ListTiersByLadderWithProducts(ctx context.Context, planLadderID string) ([]ListTiersByLadderWithProductsRow, error)
// Second half of the make-default handshake. Scoped to (price_id, product_id)
// so a stale/forged price ID from another product cannot be promoted; the
// is_active guard keeps a deactivated price from becoming the default.
MarkDefaultPrice(ctx context.Context, arg MarkDefaultPriceParams) (Price, error)
MarkPaymentMethodDetached(ctx context.Context, paymentMethodID string) error
// Idempotency guard / claim: the status transition scheduled->applied is the
// claim. A second firer (webhook vs sweeper) gets sql.ErrNoRows and no-ops.
MarkScheduledChangeApplied(ctx context.Context, scheduledChangeID string) (SubscriptionScheduledChange, error)
// Sets a single ladder's display order. Used by the topology reorder flow,
// which renumbers ladders to a contiguous sequence; sort_order is deliberately
// NOT writable via UpdatePlanLadder so editing a ladder never reorders it.
SetPlanLadderSortOrder(ctx context.Context, arg SetPlanLadderSortOrderParams) error
// The Monthly recurring headline, per currency — the caller displays the
// largest bucket and acknowledges the rest (cross-currency conversion is
// explicitly out of scope: issues.md). Monthly-normalized: month prices at
// face value, year at one-twelfth, each times item quantity. Active only —
// trialing subscriptions pay nothing today and counting their money would
// overstate.
SumMonthlyRecurringByCurrency(ctx context.Context) ([]SumMonthlyRecurringByCurrencyRow, error)
// Outstanding receivables for the Open invoices caption, per currency —
// the caller applies the same largest-bucket display rule as the Monthly
// recurring headline.
SumOpenInvoiceBalanceByCurrency(ctx context.Context) ([]SumOpenInvoiceBalanceByCurrencyRow, error)
// A new scheduled change (or an immediate action) supersedes any still-pending
// intent on the same subscription.
SupersedeActiveScheduledChanges(ctx context.Context, subscriptionID string) error
UpdateBillingAccountStatus(ctx context.Context, arg UpdateBillingAccountStatusParams) (Account, error)
UpdateInvoicePaid(ctx context.Context, arg UpdateInvoicePaidParams) (Invoice, error)
UpdateInvoiceStatus(ctx context.Context, arg UpdateInvoiceStatusParams) (Invoice, error)
UpdateInvoiceVoided(ctx context.Context, arg UpdateInvoiceVoidedParams) (Invoice, error)
UpdatePaymentMethodSafeFields(ctx context.Context, arg UpdatePaymentMethodSafeFieldsParams) (PaymentMethod, error)
UpdatePlanLadder(ctx context.Context, arg UpdatePlanLadderParams) (PlanLadder, error)
UpdateProduct(ctx context.Context, arg UpdateProductParams) (Product, error)
// Converge a core item row after an in-place Stripe price modification (paid->paid
// switch): the Stripe item id is unchanged but it now carries a new price/product.
UpdateSubscriptionItemPriceProduct(ctx context.Context, arg UpdateSubscriptionItemPriceProductParams) (SubscriptionItem, error)
UpdateSubscriptionStatus(ctx context.Context, arg UpdateSubscriptionStatusParams) (Subscription, error)
UpdateTierRank(ctx context.Context, arg UpdateTierRankParams) (PlanLadderTier, error)
}
var _ Querier = (*Queries)(nil)