Key Concepts and terminology
Please notice that we use the terms "Subscription Job" somewhat loosely along this document, meaning some code related to subscriptions that achieves a specific, repetitive task. Do not mistake with the very specific meaning the term "Job" has in either Broadleaf's Scheduled Jobs and Events module, or in scheduling frameworks in general.
Domain
Primary Order: This is the base Order that is referenced by a Subscription. This order allows the Subscription to keep track of Order Items, pricing, etc. A Primary Order is tied to a Subscription during checkout of a Subscription Product.
Secondary Order: This is an Order used to keep track of attempted transactions performed by the recurring bill job.
Subscription Product: This is referring to a Product that has been marked as "Is Subscription".
Subscription Status
A good part of the work done by the Subscription Jobs consists in simply maintain the appropriate status for subscription records. Built-in statuses are:
- Active: the status of a subscription when it is first created, and it is apt to be used in upcoming billing cycles.
- Pending: a marker status used when the payment method associated with a subscription has expired, or certain other problems occurred during the billing process.
- Suspended: Used when a severe payment error occurred, or the tender associated with a subscription is expired and past its grace period.
- Due: a subscription whose billing cycle has arrived, and is ready to be billed.
- Canceled: an action taken by the user. Completely ignored by the Subscription jobs.
- Soft Declined: a status indicating that some recoverable payment error occurred, and billing should be reattempted on that subscription.
Jobs
Again, these "Subscription Jobs" represent a group of classes to accomplish a task, rather than a "Job" in the strict traditional, sense of a scheduling interface. Therefore, when reviewing the code, do not look for one specific class file bearing the name of each of the subtitles below, but rather, for groups of related classes. For example, for the "AutoSuspend" job, look for Subscription*AutoSuspend*EventConsumer, Subscription*AutoSuspend*Thread, BatchSubscription*AutoSuspend*Service, etc.
Current Subscription Jobs are:
Auto Pending:
Traverses a number of subscription records, and adequately marks them as "pending" taking into account their status and tender's expiration date, if the tender is expired but within the grace period indicated in days by the system property subscriptions.grace.periodAuto Suspend:
Same as pending, but takes a more drastic action (marking as "suspended") if the expiration date is prior to the current, less the subscriptions.grace.periodMark As Due:
Traverses active subscriptions with adequate nextBillingDate, and marks them as "Due" (i.e., ready to be billed). This should be be a lightweight, updating job to be run as often as possible, and its idea is to alleviate logic from the payment workflow.Payment:
A job that runs a number of "due" subscription records to Subscriptions' custom payment workflow. As it runs a whole workflow with many activities, this is by far the most resource-intensive of all jobs, and the most likely to present problems when running in a multi-threaded environment.Tender Expiration Warning:
A job that traverses subscription records whose tenders' expiration dates are near expiration by at the amount of days indicated by the subscriptions.expiration.notice.length system property.
Then, this job notifies the corresponding customer(s) accordingly, bear in mind how long ago the last notification was issued, and checking if it falls within the re-notification window period indicated by the global property subscriptions.expiration.notification.nonrepeat.period.
This state diagram illustrates the possible transitions between different subscription statuses.
Batches and threads
All Subscription Jobs are prepared to run over very large Subscription recordsets (we designed the Subscription Jobs with an average of 212,000 billing transactions in mind). In order to perform well, these jobs need to process many records at a time, and devote more that one thread to accomplish those processes in parallel.
Both the batch size and the amount of threads are individually configurable for each job.
Notifications
Upon completion, all Subscription Job emit some sort of notification to the customers who signed up for each subscription. Out-of-the-box, this module just provides an interface and a dummy service implementation, either for multiple (a batch of) customers, or an individual customer.
The types of notifications being covered at the moment are:
- SUSPENSION_MESSAGE : issued by the Autosuspend job, when the customer's tender is past the expiration date, plus a configurable grace period.
- SET_TO_PENDING_MESSAGE: issued by the Autosuspend job, when the customer's tender is past the expiration date, but still within the grace period
- TENDER_EXPIRING: issued by the TenderExpirationWarning job, when the customer's tender is about to expire, a configurable amount of days in advance.
- SUBSCRIPTION_PAYMENT: issued by the Subscription Payment (billing) job, after a successful payment workflow on a specific subscription.
Two more notification types are not produced by automated jobs, but require user or admin interaction:
- CANCELLATION_MESSAGE
- REACTIVATION_MESSAGE
when subscriptions are cancelled and reactivated, respectively.