The invoice shows the Receivables remittance block, as quotes do
The invoice dialog renders the same QuoteRemittanceBlock the quote preview uses, from the seller's Receivables details, while anything is owed. The Receivables ...
The invoice's remittance block reads exactly as the quote's
Same heading, labels and ACH Credit Only notice (signer.quote.remit), with the invoice-number reference kept beneath it.
Invoices print the Receivables ACH details exactly as quotes do
The PDF and the email now carry the quote's remittance block, word for word: - Remit payment to - payee (legal name) - bank - routing number (ABA) - account num...
Rebuild - the previous run could not reach data.forgejo.org to fetch actions/checkout
Change seats and licenses from a date, with the prorated charge previewed
Change seats & licenses opens a dialog to set: - seats and each add-on's licenses (per-user licenses follow the seats until typed over); - the date it takes e...
Endpoints for dated, prorated seat and license changes; the job applies them
New endpoints: - POST **************** - POST /subscriptions/{uid}/changes - GET /subscriptions/{uid}/changes - POST **************** The hourly billing job ap...
Seat and add-on license changes mid-period, on a chosen date, prorated
SubscriptionChangeService records a change to a live subscription's seats and add-on licenses effective on any date from today. It previews the exact prorated c...
Plain-language statuses everywhere; agreed add-on prices and a monthly discount in the order wizard
StatusChip (89 call sites) showed raw codes such as PENDING_APPROVAL; it now shows the dictionary's words (common.statusCodes), or the code read aloud for one i...
Pay by card on the invoice page
When the server offers it (platform-sold invoices with a balance), the invoice page shows Pay by card. It posts to /<locale>/i/<token>/pay, which sends the cust...
Invoice checkout sessions are unkeyed, like every checkout Session
A stable idempotency key would hand a returning customer the same, possibly expired, payment page ****************
Customers pay invoices by card online; a bank's SCA request reaches the customer
On invoices sold by the platform org (the only seller whose Stripe account it is): - the public invoice offers Pay by card: POST **************** opens a Stri...
Pay a subscription invoice by card on a Stripe-hosted page
Internal POST **************** creates a payment-mode Checkout session for the amount owed. It saves the card for future automatic charges when the customer has...
Track an invoice's pending online card payment
New nullable column **************** plus helpers to list and settle pending sessions idempotently (a payment carrying the same processor reference is never rec...
Negotiated add-on prices and a quote's discount carry into the subscription
Converting a quote now carries: - each add-on's agreed per-license price (when it differs from the catalog's) - the quote's or accepted option's discount, as a ...
Auto-renew and notes work on live subscriptions; card on file and charge card now
- The auto-renew switch sets the subscription's own renewal (it posted a field the draft-only order update ignored) and says when a non-renewing one ends. - N...
Cap only add-ons the organization holds
An add-on it does not hold is left to the existing entitlement gates, as before caps existed - paying organizations running a phone server without the add-on co...
The owners' invoice link opens on the workspace host the org can actually reach
Built internal.<domain> by hand, which OrgDomainRuleGuardTest forbids: an org whose own domain is not finished would get a link to a host that answers nothing. ...
Show licenses held and in use where mailboxes and extensions are assigned
Owner rule 2026-10-22: per-user add-ons bill the licenses purchased, and the licenses are the only limit on what may be in use. A LicenseUsageMeter ("4 of 10 li...
Quotes start subscriptions; offline acceptance; tenant orders; plain-language billing
- Quotes: "Add from subscription catalog" fills a row from the live plans/add-ons (name, monthly price, "per user / month" / "per 10 GB block / month") and ke...
Refuse a department or contact mailbox past the email licenses
Owner rule 2026-10-22: per-user add-ons bill the licenses purchased; how many mailboxes may be in use is limited only by them. Under a 3rd-party provider a depa...
Record offline acceptance, log prints, convert quotes into subscriptions
- POST **************** (SEND_QUOTES or MANAGE_QUOTES) - POST **************** (VIEW_QUOTES or MANAGE_QUOTES) - POST .../{uid}/convert takes an optional body (t...
Quotes convert into subscriptions; tenant orders never comp the seller
- A quote in a SUBSCRIPTION market, or whose accepted rows were filled from the subscription catalog, converts into a SubscriptionOrder (plan, seats from the ...
Refuse a mailbox past the organization's email licenses
Owner rule 2026-10-22: per-user add-ons bill the licenses purchased; how many mailboxes may be in use is limited only by them. Before a mailbox is put into use,...
Refuse a phone extension past the organization's licenses
Owner rule 2026-10-22: per-user add-ons bill the licenses purchased; how many extensions may be in use is limited only by them. Before an extension is put into ...
License usage and per-unit license checks for per-user add-ons
Owner rule 2026-10-22: every per-user add-on bills the licenses purchased, like seats; how many mailboxes or extensions may be in use is limited only by them. ...
Endpoints to set a subscription's auto-renew and an order's notes in any status
Turn renewal on or off for a live subscription; notes on any order
The console's auto-renew switch sent a field the draft-only order update did not have, so it never saved; and notes failed on any order past draft.
Approving a card order grants paid access too
AUTO_BILL orders waited for a Stripe checkout that subscription invoicing no longer uses; the ledger charges the saved card on each billing day instead.
Card customers are charged automatically on the billing day
For AUTO_BILL subscriptions the billing job charges each approved invoice to the customer's saved card on its billing day through BillingService's internal card...
Internal card endpoints for subscription invoice auto-charge
GET **************** and POST /charge, guarded by the shared X-Internal-Auth secret (constant-time compare; 403 without it). A charge is an off-session PaymentI...
Card auto-charge bookkeeping on subscription invoices
AUTO_BILL invoices are charged on their billing day once approved and retried every three days, up to four attempts. Each attempt is numbered before it is made ...
The billing job takes each subscription and invoice in its own transaction
Its first run raised Harmony's October invoice and lost it when one audit insert failed, because the whole prepare step was one transaction.
Subscription events store JSON states; billing steps run one row per transaction
**************** are jsonb, and every caller wrote a bare status like ACTIVE - an invalid JSON insert that rolled back whatever it was auditing (order activatio...
The POS proxy passes a PDF or an empty reply through instead of failing it as JSON
The invoice PDF and any 204 went through response.json() and became a 500.
Subscription billing console β invoice drawer, draft editor, payments, market invoicing
Invoices tab: plain-language rows (period, total, amount due, due date, status) open a drawer with the lines, totals, payments received, where and when it was s...
Stripe bills add-on licenses held, not mailboxes or extensions in use
Every add-on now takes its quantity from AddOnLicenses, the rule the order calculator and subscription invoices share: licenses bought, defaulting to the seat c...
Automatic subscription invoicing - drafts, owner review, email with PDF, payments, reminders
SubscriptionBillingJob (hourly, one pod, and at startup) runs the cycle: - raise each renewal invoice as a draft lead-days before its billing day - move subscri...
The customer's invoice, online β branded, printable, with a PDF download
/[locale]/i/[token] resolves the invoice server-side (token in a POST body, never a URL) and renders it in the seller's own name and colour, falling back to a n...
BILLING_INVOICE, gated on viewing subscription invoices
Raised by SecurityService to the selling organization's owners when a subscription invoice draft is waiting for review or a customer's invoice goes past due. Al...
License-based add-on pricing and a real subscription invoice lifecycle
One rule for add-on quantity (AddOnLicenses): every add-on bills the licenses PURCHASED, like seats - per-user add-ons default to the seat count, storage to the...
Background work uses three engine slots per pod and is sent as low priority
One background slot per pod left three of the engine's four streams idle during a dictionary sync. Background callers (a wait above the 100-second default: the ...
Four streams of four threads, and a lane that keeps one free for chat
Measured on the nodes' CPU class with the dictionary sync's own traffic (15-key chunks): one stream of eight threads did 1.5 keys/s, two of eight 1.8, four of f...
Read subscription invoices, events and agreements under the keys the server sends
The server answers invoices/invoice, events and agreements/agreement; posApi read subscriptionInvoices, subscriptionEvents and subscriptionAgreements, so the In...
Rebuild the Stripe mirror from Stripe nightly and on startup
Events older than 30 days cannot be fetched, so the September invoice and subscription events lost to the API-version mismatch are unrecoverable as events. Stri...
Catalog edits reach only the caller's organization; own-order callers cannot comp or price themselves
Every update and delete of a subscription plan, price, feature, add-on, bundle, volume discount, promotion or agreement template now checks that the row belongs...
Name the organization that owns a subscription catalog row
The catalog update/delete methods take a uid alone, so a caller holding the catalog right in any organization could edit another organization's plans, prices, a...
A missing locale file renders English instead of throwing
i18n/request.ts and message-locales.ts imported messages/<locale>.json bare, so a build made while the dictionary had no file for a locale turned that locale's ...
Like what you see shipping?
All of it arrives in your workspace on its own. Start on the free plan and read this page again in a month.
