Support for Drupal 7 is ending on 5 January 2025—it’s time to migrate to Drupal 10! Learn about the many benefits of Drupal 10 and find migration tools in our resource center.
Is there an existing way for an end user to cancel their recurring order (i.e. Subscription)? Or is this something that needs to be implemented on a case-by-case basis?
Comment | File | Size | Author |
---|---|---|---|
#20 | cl_rules_set_status.jpg | 40.35 KB | jweirather |
Comments
Comment #1
dave bruns CreditAttribution: dave bruns commentedI'm wondering the same thing. Assuming a monthly subscription product, how does a user see when the license will renew and cancel the renewal / subscription if they like?
If there's nothing in the UI that currently allows cancellation, what exactly needs to happen in code to cause a monthly subscription product to be cancelled, so that the license is revoked and all future billing is terminated?
Note: there is some discussion about scheduling cancellations here: https://www.drupal.org/node/2247703
Comment #2
Jody LynnI believe that on /admin/commerce/licenses/list an admin can change a license status to Revoked to cancel it. End users may just need to be instructed to contact customer service to cancel.
Comment #3
aytee CreditAttribution: aytee commentedJody Lynn - you are correct. However, I wanted a way for the end user to cancel their own subscription.
I wrote a small module that invoked the rules component to cancel the order, which cancels the subscription
Comment #4
Kazanir CreditAttribution: Kazanir commentedJody is correct for the time being. Everyone's user interface desire around order cancellation is quite different and so an implement-your-own model is probably best for now.
Code-wise, there are 2 facets to this:
1. If a license is set to a status other than
COMMERCE_LICENSE_ACTIVE
(i.e. revoked or suspended), it will not be renewed onto a new order at the end of a billing cycle. This is the equivalent of cancelling your cell phone plan. Important to note is that if you only do this part, post-paid plans will still be charged for their usage during the current billing cycle when the cycle closes.2. If you also manually close a billing cycle (i.e. set
$cycle->status = 0
and save the cycle), then the order will not be closed properly when the billing cycle ends, and thus will not be charged at all. (Typically we also set the$order->status
to canceled when we do this for clarity.) This prevents existing charges on a post-paid plan from being charged, which is useful in situations where a customer has placed an order in error and you don't want to charge them anything at all.Let me know if this helps or if anyone has additional questions.
Comment #5
capfive CreditAttribution: capfive commentedCan you please elaborate on this aytee? I am in need of user triggered cancellation, where would i put this code? in custom module? does it need a fucntion to run with it?
And does this allow the user to cancel thier order which in turn cancels their subscription?
Comment #6
capfive CreditAttribution: capfive commentedComment #7
daveparrish CreditAttribution: daveparrish commented@capfive
It looks like 'rules_commerce_order_status_canceled' rule comes from commerce_backoffice which you may not have enabled. If I understand @Kazanir's comment correctly, all that needs to be done is to change the relevant COMMERCE_LICENSE_ACTIVE license to COMMERCE_LICENSE_SUSPENDED.
Comment #8
eleuthere CreditAttribution: eleuthere commentedHi guys,
I have two questions :
- How do I precisely do to let a user cancel an order renewal ? Which files do I create ?
- How can I help to make that feature standard ?
cu
Comment #9
capfive CreditAttribution: capfive commentedI'm a little new to all this rule stuff, would be great to get a detailed how-to like @eleuthere is asking for :)
i.e do i create a rule in CMS? or is it code in the module?
I think it should be standard that if a user cancel's their account, that the license is revoked/canceled as well, how can you continue to use the license if they do not have an account on the site?
Comment #10
agileadamLike others here, I am in need of a way to let users cancel their own licenses.
My plan is to call (with custom code) the rules actions defined in this patch: #2470467: Rules actions for revoke/suspend. More specifically, I'll create a menu callback (hook_menu()) that will handle a few arguments (user id, order number); the callback will perform some validation on the arguments and ask the user to confirm their intention to "cancel" their subscription/license/plan/whatever. If they continue to submit the form, it'll then call the suspend or revoke rules action function.
I'm assuming the rules actions defined in that patch will eventually make it into commerce_license, so I'd rather make use of those (by invoking them) than write my own functions to remove/suspend licenses. It's not that they're complicated, but rather that it'd be good to standardize this a bit. Time will tell where that patch goes...
Anyone have any opinions on this approach?
UPDATE: While thinking about this some more, I realized I actually want to show the "Cancel" link alongside a product (which is a "Plan" in my site; "basic" or "premium" for example), if the user has a license for that product. To accommodate this, my callback will use the user id and the product ID (not the order ID). I'd then be revoking/suspending whatever license exists for the product+user combo (if any). This site only allows a user to maintain a single license at any given time, so I don't have to worry about suspending the wrong license/order.
This is still all just experimentation and exploration, so I'll save you the play-by-play comments unless I come up with something I think would be helpful.
Comment #11
eleuthere CreditAttribution: eleuthere commentedI don't know how to do this but I like well built and reusable stuff.
I'm writing a tutorial/howto about selling roles with commerce from a "Commons" distribution starting point.
It's here : https://www.drupal.org/node/2482277
I'd be happy to apply patches or test dev versions of any module and complete my tutorial to contribute make thing operational, reliable and clear for anyone to use.
Tell me.
Comment #12
agileadamHey all,
I had to spend some time on this to come up with a quick solution. If I had the time to plan and create a new module that'd be more universal, I would. Unfortunately it's not in the cards for this one. Also, as it's been said before, each person's needs and implementation will probably be quite different.
Anyhow, I threw up a quick blog post to hopefully provide some direction to some of you: http://agileadam.com/2015/05/allowing-users-to-cancel-their-own-commerce...
This is not production-ready code, but check it out.
Comment #13
daveparrish CreditAttribution: daveparrish commented@agileadam,
Thank you for the post. I implement a cancel button almost the same way you did for a project I am working on. A solution like that would probably make for a good contrib module. I put my cancel button in the user profile page, but I like replacing the "Add to cart" button with the "Cancel Membership" button.
Comment #14
agileadamAs I wrote some code yesterday I thought about a contrib module that would provide:
If people agreed on what they wanted I'm sure we could come up with something.
Comment #15
eleuthere CreditAttribution: eleuthere commentedHi,
Beyond the immediate difficulty, there is site maintainability : what if we have to apply patches after the next module upgrade ? I wrote a small module just to delete an text area in a form. It's not very difficult...if you find examples and explainations...
Selling roles or files or streams is not selling hardware. What if a user byes twice the same license ? Do you refund ? It's useless workload. It could be interesting not to propose a user to bye a license of an already running type.
or for the same product or... I don't know which condition. Buyable products may depends on running licenses. Could it be managed with rules ? The idea to alter the "Add to cart" button to switch the action depending on conditions like running licenses is astucious. Could it be used more generally ?
But maybe this is not the right place to launch a specification talk...
Comment #16
wesjones CreditAttribution: wesjones commentedAnother non-coding option is to clone the view "Licenses". Then just customize that view for the user to revoke their own licenses.
I removed all the Bulk Operations except revoke. I removed the user field and commerce product field. I removed the filter criteria. I also stole a few ideas from the orders view like the path and contextual filters. Then set the permissions to "View own licenses". I also removed the relationships under advanced.
Comment #17
agileadamwesoccer2003, that's an interesting approach. I like it.
Comment #18
agileadamOkay folks, I decided it's probably best to create a contrib module (and documentation) for this stuff, just to get the ball rolling.
Please read the documentation and then have a look at the module.
I'll let the documentation explain what I did, rather than re-explain it here.
NOTE: there are plenty of TODOs in the code, which you can browse at http://cgit.drupalcode.org/commerce_license_cancel/commit/?id=523286b
Comment #19
jweirather CreditAttribution: jweirather commentedIf I'm reading these comments (#4, #7) correctly, we have the option to cancel licenses by setting a data value in rules, where the data value is the "status" of the license?
Commerce License handles it from there?
Although a specific rule would be prettier, the data value route still simplifies the matter for me (versus a whole new custem module, etc).
Comment #20
jweirather CreditAttribution: jweirather commentedExpanding on my previous comment: it appears I am able to set the Commerce License status via rules, using "set a data value". See attached image.
In my install a user can have multiple independent licenses, so revoking or suspending all licenses on an order (as in the patch) would be a problem, or require much voodoo.
Assuming "set a data value" works and Commerce License then cancels the recurring order at the appropriate time, I expect I should also be able to use a flag of some kind to fire the rule, like for example, a flag which a user can only flag and not unflag (so it disappears after one-time use). Such a flag would then be exposed to the rest of the UI, views, panels, etc...
I'd have to assume that if these concepts do work they address many use cases?
Comment #21
bjlewis2 CreditAttribution: bjlewis2 at Modules Unraveled commentedDefinitely need a way for a user to cancel their membership as well... I'll checkout the contrib in #18...
Comment #22
jweirather CreditAttribution: jweirather commentedThanks to @agileadam for the forms based contribution.
Also, you may be able to set something up using flag/rules.
Comment #23
Andrew Jamieson CreditAttribution: Andrew Jamieson commentedI have tried the module in #18 and it doesn't seem to work. I get a success message when cancelling the order but they are not being cancelled?
Comment #24
agileadam@Andrew,
Throw an issue into the queue for commerce_license_cancel and I'll have a look.
Comment #25
arthur_drupal CreditAttribution: arthur_drupal commentedHere is my view for the end user, with a menu link. Hope it can help.
Comment #26
arthur_drupal CreditAttribution: arthur_drupal commentedI had to implement this hook in order to let end user "view" own license :
Comment #27
loudpixels CreditAttribution: loudpixels commentedHi arthur_drupal,
I would also like to show my users their license ... possible directly on their account page.
Could you please send additional information about implementing your hook?
Excuse my ignorance but how do I use this code? where to save it?
Any pointers would be a great help! Thanks!
Comment #28
wizonesolutionsI'm gonna close this as working as designed — people need to make their own implementations of this. I'll be sharing one when I am done with it.
A note to people who come here because they have scheduled a cancellation in code and it's not actually changing the license, but it is removing the billing cycle — don't use
COMMERCE_LICENSE_REVOKED
in code. I suggestCOMMERCE_LICENSE_EXPIRED
. If you useCOMMERCE_LICENSE_REVOKED
,commerce_license_billing_collect_charges()
will exclude the license outright, and the license will get removed from the order when it refreshes (and it does this prior to renewal). Basically, things will get into a messed-up state, and the user will still have an active license without any recurring order or billing cycle to ensure payment, expiration, etc.