Merchant & operations
Consolidated recurring billing
How Agovena combines due subscription renewals for one customer into a single order, payment and invoice, with prorated lines.
On this page
One renewal order for several subscriptions
When a customer has several active subscriptions that renew around the same time, Agovena can bill them together: one renewal order with one line per subscription, one payment and one invoice. This is Core recurring billing behavior. It runs inside php artisan agovena:process-subscription-renewals, which the scheduler starts every minute. There is nothing to install.
The logic is in SubscriptionService, ConsolidatedRenewalOrderBuilder and ConsolidatedBillingLine.
Which subscriptions are combined
Subscriptions are grouped when they share all of these:
- customer and customer email;
- currency;
- payment gateway;
- renewal mode;
- billing interval and interval count.
Within a group, a subscription is eligible when it is active or past_due, is not set to cancel at period end, has no pending renewal, and its next billing date falls within the consolidation window. A group is billed together only when it has at least two eligible subscriptions and at least one of them is due.
Subscriptions that do not qualify renew on their own, as before. Groups with manual renewal and subscriptions whose provider manages the subscription itself are never consolidated. Different currencies, gateways, intervals or interval counts always stay in separate orders.
Consolidation window
The window decides how far ahead a not-yet-due subscription can be pulled into the current order. Set it in Admin → Settings → Store under Consolidated billing window (days) (setting key subscription_consolidation_window_days), default 31. The field accepts 1 through 31 days, so a subscription with a much later billing date does not end up on the current invoice.
Prorated lines and the shared period
The earliest due date in the group becomes the due date of the order and the invoice. All subscriptions in the order get a new period that starts on that date.
A subscription that was due later has already been paid for the days between the earliest due date and its own due date. Its line price is reduced by those days:
billable unit amount = unit amount × (period days − days already paid) ÷ period days
The calculation uses integer minor units and rounds half up. If the days already paid cover the whole period, the line total is zero. Each order item stores its source in options_snapshot.consolidated_billing: source type and ID, due date, next period end, period days and days already paid.
Payment, invoice and audit
The order builder creates the order, its items, one pending payment and the invoice in one database transaction. The invoice takes over the order's due date. Agovena then attempts the renewal charge with the gateway's stored authorization, as for a single renewal. Without a reusable authorization the order stays payable and the usual past-due handling applies.
When the order is paid, all pending renewals linked to it are marked paid in one transaction and every subscription moves to the same aligned period.
Each run uses a deterministic idempotency key built from the customer, currency, gateway and every subscription ID with its due date. A concurrent or repeated scheduler run therefore finds the existing order instead of creating a second one. The audit log records billing.renewal_consolidated with the order number, number of sources, due date and total amount.
Check the result
Open the renewal order in Admin → Orders. Check that each line matches a subscription, that the prorated amounts make sense for the dates involved, and that the invoice due date equals the earliest due date. Read orders, payments, and fulfillment for the rest of the order workflow.