Voting starts in March for the Drupal Association Board election.
This is a documentation page for the Commerce License module.
- Enable the module and all of its dependencies (ctools, entity, entityreference, entity_bundle_plugin).
- Enable advancedqueue if you want to use remote (synchronizable) licenses.
- Enable a module that provides one or more license types. A commerce_license_example module is included that you can use for demonstration purposes.
- Go to admin/commerce/config/license and select the product and line item types that should be licensable. This will create the required fields.
Warning: You NEED to select at least one product type AND one line item type! If no line item types are selected, no licenses will be created during checkout.
- Add one or more products and select a license type and duration for each one
Commerce License Role
The commerce_license_role submodule allows roles to be licensed.
The customer receives the role referenced by the purchased license product. Changing $license->product_id (from "Basic Membership" to "Premium Membership", for instance) changes the owner's role.
- Go to admin/commerce/config/license/role and select the product types that will be used to sell the roles. This will create a commerce_license_role options field on each of the selected product types.
- Create a product, select the Role license type, then select the role that should be licensed.
The license is an entity that gets created on checkout, and represents the purchased right to access a resource. A license can be configurable, meaning that it has fields attached which are filled in by the customer (on the add to cart form or during checkout through a checkout pane).
The license is referenced from a line item through a commerce_license entityreference field.
Each line item can have its own licence.
When a line item gets created, the matching license will be created as well. The type of the license to create is determined by looking at the commerce_license_type field on the product.
If the line item gets deleted, its license gets deleted as well.
A license can have one of several statuses, all represented by constants mapping to a numeric value:
- COMMERCE_LICENSE_CREATED: The license was just created, and the order is still in checkout.
- COMMERCE_LICENSE_PENDING: (Remote licenses only) The order has been paid, the license is awaiting synchronization.
- COMMERCE_LICENSE_ACTIVE: The license is active and can be used.
- COMMERCE_LICENSE_EXPIRED: The license has expired.
- COMMERCE_LICENSE_REVOKED: The license has been revoked (due to an order cancellation, for instance).
The license has two timestamps, set when the license status is first changed to COMMERCE_LICENSE_ACTIVE:
- granted: The unix timestamp indicating when the license was granted (set to the current time at that moment).
- expires: The unix timestamp indicating when the license expires.
The commerce_license_duration field is looked up on the product, and if it's 0 (meaning "Unlimited"), the expires timestamp is set to 0, indicating that the license never expires.
If commerce_license_duration is set to a positive value (for example 3600, indicating it should last for an hour), that value is added to the current time and stored in the expires column.
Each license type (entity bundle) is a ctools plugin, represented by a class that inherits either CommerceLicenseBase (local licenses) or CommerceLicenseRemoteBase (remote licenses).
Each license type can define the fields it has by implementing the fields() method.
If missing, the fields and their instances will be created on the next cache clear.
See this blog post for more information.
Configurable license types
A license type is configurable if it returns TRUE from the isConfigurable() method.
Configurable license types define fields that should be filled-in by the customer before or during checkout. There are two ways to allow that:
1) Inline Entity Form
Each line item has a commerce_license reference field. Inline Entity Form allows the license fields
to be edited directly on the line item form ("add to cart" or "order add / edit" admin form).
If Inline Entity Form was already present when Commerce License was installed, the commerce_license reference field was already configured to use it. Otherwise, you will need to go to admin/commerce/config/line-items and click the "manage fields" link for your line item type. First you must change the widget for the "License" field to "Inline Entity Form - Commerce License".
After that, you need to click on the "edit" link for the "License" field, then look for the "Add to cart form settings" section, and click the "Include this field on Add to Cart forms for line items of this type" checkbox. Save your changes and the configurable fields should now appear on the add to cart form on your product display page.
2) "License Information" checkout pane
If enabled, this checkout pane will output a form for each configurable license present in the cart.
Both of these (Inline Entity Form and the checkout pane) call the same methods on the license type class to generate / validate / submit the license form.
Remote licenses types
A remote license type extends the CommerceLicenseRemoteBase base class, which implements the CommerceLicenseSynchronizableInterface.
Every remote license has a "sync_status" field that tracks the synchronization status (needs sync, synced, sync failed).
Once an order has been paid in full, all remote licenses are queued for synchronization and then processed by advancedqueue one by one. The queue worker calls the synchronize() method of each license type class, allowing it to contact the remote service and store the result.
The synchronization queue view at admin/commerce/licenses/sync-queue allows synchronizations to be tracked.
Checkout complete pane
The "License completion message" checkout pane outputs a pane for each found license, allowing
licenses to present the access details to the customer.
If a license hasn't been synchronized yet, the checkout pane refreshes itself until the synchronization happens. If the synchronization doesn't happen after 30 refreshes, it is marked as failed and the refresh is stopped.
For remote licenses, the synchronize method is only called when the synchronization queue is processed.
This means you need to configure your server to have a frequent cron-task that uses drush to process the queue.
You can configure the frequency at which the checkout completion pane refreshes as well as the total time that can elapse before the synchronization is marked as failed (and the refresh stops).
So this means you must configure the cron-task on your server to run more frequently than the time you configure for the total-time. That way the checkout-complete pane will continue to refresh and at some point during the total-time, the cron task will run and process the synchronization queue - at which point the pane will update with the user's license details.
The command your cron task needs to run is as follows:
drush -r /path/to/your/drupal/install -l http://yoursiteurl.com advancedqueue-process-queue commerce_license_synchronization
When cron runs, it takes the ids of all expired licenses (expires < REQUEST_TIME), and queues them.
The queue (advancedqueue if present, cron queue otherwise) then processes the licenses one by one, changing their status to COMMERCE_LICENSE_EXPIRED, allowing rules and hooks to respond to the save.
If the license is synchronizable, it is also queued for synchronization, allowing the remote service to be notified if needed.