-
-
Notifications
You must be signed in to change notification settings - Fork 725
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[Spree Upgrade] Subs - Extend Order cleanly for subscriptions #3012
[Spree Upgrade] Subs - Extend Order cleanly for subscriptions #3012
Conversation
@@ -0,0 +1,14 @@ | |||
# Used to prevent payments on subscriptions from being processed in the normal way. | |||
# Payments are skipped until after the order cycle has closed. | |||
module OrderSubscriptionsExtensions |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Dear reviewers,
This file introduces a new structure. I simply didn't know where to put this file. It is not a Concern, but an Extension. It is very tightly coupled to Spree::Order and Subscription logic. So it doesn't fit into lib
. It's not a service and it's not a model on its own. Is this the right place?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The name OrderSubscriptionsExtensions implies we can add more to this module. Modules and classes should have single responsibility and as such I'd name the module to what it is doing here and nothing else: OrderSubscriptionsPaymentRequired or OrderSubscriptionsProcessPayments.
re /extensions, I'd do an effort not to create another type of file in the codebase, it adds complexity that we should avoid.
I dont think it would be perfect, but I think it'd be better than this extension: a concern with a alias_method_chain on payment_required? or better, process_payments.
I am sure @sauloperez will be thinking about spree hooks. The right solution for this would be to patch spree code to add a "before_process_payments" hook and then make this change in ofn code reimplementing the hook.
Personally, I'd go for the alias_method_chain on process_payments inside a concern.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I am sure @sauloperez will be thinking about spree hooks
I'm too foreseeable . That is exactly what I though right after reading the description. I tend to dislike alias_method_chain
for what I shared in #3009 (comment).
The right solution for this would be to patch spree code to add a "before_process_payments" hook and then make this change in ofn code reimplementing the hook.
Then, why not this? or any other extension hook we think best fits here?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
With "The right solution" I meant "the solution that @sauloperez thinks is right" :-)
I think we have to explore option 4 below. Try to remove subscriptions code from order.
Orders belonging to subscriptions get completed without payment. That requires overriding Spree's functionality. Here we move this customisation into its own file and override a different method to make it less invasive and compatible with Spree 2. In Spree 2, an order in payment state without pending orders is invalid. Instead we skip the payment state by not requiring a payment for automatically generated orders until the order cycle is closed.
re "Orders belonging to subscriptions get completed without payment." |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Interesting challenge we have here.
@@ -0,0 +1,14 @@ | |||
# Used to prevent payments on subscriptions from being processed in the normal way. | |||
# Payments are skipped until after the order cycle has closed. | |||
module OrderSubscriptionsExtensions |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The name OrderSubscriptionsExtensions implies we can add more to this module. Modules and classes should have single responsibility and as such I'd name the module to what it is doing here and nothing else: OrderSubscriptionsPaymentRequired or OrderSubscriptionsProcessPayments.
re /extensions, I'd do an effort not to create another type of file in the codebase, it adds complexity that we should avoid.
I dont think it would be perfect, but I think it'd be better than this extension: a concern with a alias_method_chain on payment_required? or better, process_payments.
I am sure @sauloperez will be thinking about spree hooks. The right solution for this would be to patch spree code to add a "before_process_payments" hook and then make this change in ofn code reimplementing the hook.
Personally, I'd go for the alias_method_chain on process_payments inside a concern.
Injecting a new "pending" payment object is basically what happens on normal orders, right? It's not a payment as such, more like a placeholder that says "this can be paid in the future". It seems like a good idea to follow the same process. Or is the issue that the payment method hasn't been chosen at that point, so a pending payment can't be created? |
@luisramos0 @Matt-Yorkley Thank you for your great feedback. It makes me look at the bigger picture again. The Spree modelIf payment is not required:
If payments are required:
The special need of subscriptionsSubscriptions place an order and advance it to This model aligns with conventional veggie box deliveries on a weekly or fortnightly basis. Customers don't want to get charged without confirmation. If they don't change the order after they got notified when the order cycle opened, we see that as consent. It avoids double charging and therefore transaction fees. Most customers also prefer being charged later than earlier. But I'm also realising now that this looks very different from a CSA perspective. People pay the farmer early and get what the farmer can provide. Changes may be possible through additional orders with additional charges, cancelling orders, refunding or dealing with account credit. But discussing this logic needs to go through a broader inception phase. Possible implementations
What do you think now? Do you have a preference or other good ideas? |
Great analysis @mkllnk we should move this to a wiki page :-) After reading your analysis, I think we cannot change OFN core orders workflow just because of subscriptions. IMO there should be no reference to subscriptions on ofn orders code. |
This discussion and solution may take us some time. I think we should focus on core spree upgrade and leave subscriptions for later. Maybe just move this into #2953 |
I was thinking of cash payments for example, that can be present on a completed order even though the payment hasn't been made yet. The enterprise user can click the "capture" button once it's been paid to trigger the payment state changing. |
You literally read my mind! I think we have to make the effort to stop using this word. Let's talk about OOP instead. I don't know the inner details of subscriptions but in my mind I see a |
@sauloperez yes, that is that possibility
|
@luisramos0 asked:
The actual requirements were the following use case:
Rob did think a lot about how to achieve this. We could have created incomplete orders at the beginning of the order cycle. But incomplete orders don't reserve stock levels. So if we want to model that an order is actually placed and the stock is reserved for the user, a complete order seems reasonable. Postponing this issueI will move this PR and #2771 (which is blocked by this) to the non-core epic #2953. A proper solution seems a bit more complicated and I guess we can leave the current override of A better solutionI totally agree with avoiding overrides. Yes for good object oriented design. I'm not sure polymorphism is the right word for the solution here. I'm assuming that we still want a completed order and delay the payment. Spree processes payments in payment methods. The cash payment method allows to check out without paying. Rob always saw Stripe as requirement for subscriptions, because it allows capturing the money automatically. But maybe we need a subscription payment method that decorates another payment method. It can contain the logic of delaying the payment while the order cycle is open. But once it's closed, it just calls the associated payment method. This type of composition could avoid overrides and separate the code better. But it may well be that there are some unknown obstacles that make this really difficult. Worth a try after the upgrade? |
i like your line of thought Maikel! i wonder how the "cash payment method allows to check out without paying" is implemented... |
I like it too |
@luisramos0 Have a look at: It basically has a capture method returning |
@luisramos0 We deferred this to phase 2. Now we are in phase 2 and I just had a look at it again. What do you think we should do with these pull requests now? The current implementation seems to work. In this pull request and #2771 I thought I could improve our way of overriding and make it more compliant with Spree 2. You and Pau pointed out that it's still overriding core logic for subscriptions and that it's not ideal. I agree. But I also don't see a reasonable way of implementing our ideal solution. I see three ways forward: 1 - We close these pull requests and leave everything as it is. It works. The comment about obsolete code in the decorator code may be confusing though. openfoodnetwork/app/models/spree/order_decorator.rb Lines 327 to 344 in 32846af
2 - I incorporate your feedback about not creating a new extension and we go with this pull request. It's not ideal but I think that it's better than what we have at the moment. We see the separation of core code and subscriptions as separate issue out of scope. 3 - We invest more time to try and separate subscriptions and core logic. I suspect that it may not be possible with current Spree code and that we either need to override something or start defining our own models because subscriptions require something that is restricted in the Spree world. |
Given where we are with the upgrade and looking at this code again, I'd go for option 2. I dont mind the extension but I'd put those 2 short methods in the order_decorator itself. But if you prefer to keep the extension it's fine (I'd call it OrderSubscriptionsPaymentsExtension). So, if you rename the extension (or better imo, if you move the methods to order_decorator), I am ok with going ahead with this PR. It's not perfect but definitely better than what it was. Otherwise, I tend more to option 1 than option 3. |
Okay, I had another go at this. I realised several things:
@luisramos0 Have a look at https://github.com/openfoodfoundation/openfoodnetwork/compare/2-0-stable...mkllnk:2520-spree2-order-subscription?expand=1. Should I open a new pull request and close this one and #2771? I think that an extension would have been cleaner but I went with your preference of using the decorator now. We will see what the next Spree upgrade requires. 😉 |
yeah, that's it. awesome! yes, it's not so clean to have them in the order_decorator, but it makes it more obvious we need to take this out of here soon :-) |
What? Why?
Part of #2520. It unblocks #2771.
Orders belonging to subscriptions get completed without payment. That
requires overriding Spree's functionality. Here we move this
customisation into its own file and override a different method to make
it less invasive and compatible with Spree 2.
In Spree 2, an order in payment state without pending payments is invalid.
Instead we skip the payment state by not requiring a payment for
automatically generated orders until the order cycle is closed.
This is the change that comes with Spree 2:
What should we test?
Release notes
Changed: Payment processing logic has been prepared for future software updates.
Changelog Category: Changed
How is this related to the Spree upgrade?
It makes our code more compatible with Spree 2.