Live subscriptions and lifecycle – system description

The subscription table and its relations, saving, state changes, writing item limits onto users, credit and cancellation, and the overnight lifecycle run.

Overview

Management of live subscriptions belonging to users and clients. Table names carry the installation's own prefix in the database.

Data model

TableRole
subscriptionsubscription: user, client, plan, state (trial, active, past_due, suspended, canceled, expired), cycle, seats, trial end, period end, cancel at period end
subscription_itemindividual items of the subscription with limits
subscription_accountthe user's credit account and home client
subscription_eventstate log
payment_transactionpayment transactions
subscription_creditcredit ledger

Saving and state changes

  1. Form: canAction(edit); save: canSave. Plan required; for a new subscription an existing user and an active plan; the client only within content permission; the billing company only from getBillableCompanies() (otherwise silently left out).
  2. New subscription: ensure the user's account row (ensureAccount), billing company, then Dlbtpayment::startTrial() (7 days).
  3. Existing: saveSubscription(), billing company, cache flush.
  4. Items: saveItems() by delete and rewrite, then materialiseLimits() – writes the item limit onto the owner user's EXISTING assignment row.
  5. setstate: Dlbtpayment::setState() (+ state log + syncGrants()); for trial, active, past_due syncClientPlan() for every user of the client.

Item choice (item, SYSTEM): the function list offers only active functions classified SUBSCRIPTION; plantemplate returns a plan's legacy content items. The item and limit blocks appear with item or edit, and limit or edit; as these are SYSTEM keys, the real restriction is edit.

Credit, cancellation, deletion

  • credit: Dlbtcredit::grant(), returns the new balance; account_id > 0, amount > 0.
  • cancel: Dlbtpayment::requestCancel(), at period end or immediately; errors not_found, already_ended.
  • delete: blocked by a payment transaction (error_in_use); otherwise physical deletion with the state log.
  • autocomplete: findUsers(), at most 8 hits, empty without edit.

Background job: subscription_lifecycle

Global seed job in the catalog-side cron queue processor. Steps: Dlbtpayment::runLifecycle() (expired trial with cancellation → expired; expired trial or period → charge, success active, failure past_due; lasting non-payment → suspended; cancelled with expired period → closed), then Dlbtbilling::applyPendingPlans() (due downgrades) and Dlbtbilling::invoiceMonthlyUsage() (monthly overage invoice). Log prefix: subscription_lifecycle.

Permissions and limitations

  • list: UNMAPPED; item, limit: SYSTEM; edit, add, credit, cancel, delete, debug: not classified.
  • The list shows every subscription without content scope.
  • credit does not check the account's content scope.