-
-
Notifications
You must be signed in to change notification settings - Fork 1.3k
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
Update order cancellation, sets inventory units to canceled #3781
Update order cancellation, sets inventory units to canceled #3781
Conversation
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.
Left a preliminary concern, also some specs seem to be failing.
core/app/models/spree/shipment.rb
Outdated
units_available, units_to_back_order = stock_location.fill_status(item.variant, item.quantity) | ||
|
||
inventory_units.canceled.limit(units_available).each(&:on_hand!) | ||
inventory_units.canceled.limit(units_to_back_order).each(&:backorder!) |
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.
Is canceling an order the only way to cancel an IU at the moment? Just wondering if other IUs can have the state canceled and they would be resumed, even if not part of the order cancelation.
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.
No, you are right, there are other places.
I have to pick only the canceled units for the variant reported on the manifest items.
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've used the line_item to be sure.
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.
BTW I'm double-checking this to be sure. Sorry for the message spam 🙇 .
Before this commit when an order was canceled the inventory units of the order will remain untouched. So there were canceled orders with inventory units with the state on_hand or backordered. This situation was not only inconsistent but can lead to subtle bugs with the stock management system. With this commit the inventory units related to an order are canceled when the order is canceled. When an order is resume we recalculate the state of the connected inventory units, based on the actual stocks available.
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.
Just left a question, overall I can't see any issues with this approach.
number_of_items_to_restore = item.states["on_hand"].to_i + item.states["backordered"].to_i | ||
|
||
if item.variant.should_track_inventory? | ||
units_available, units_to_back_order = stock_location.fill_status(item.variant, number_of_items_to_restore) |
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.
Are these variables filled with the current availability in the stock location, right?
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.
Exactly, this will update the inventory units state based on the current stock level.
This is why inside #after_resume I have to call #resume_inventory_units before unstocking the items. If you call #resume_inventory_units after the unstocking the states of the inventory units will be wrong.
There is a test covering this use-case to avoid regression.
shipment.resume! | ||
expect(shipment.state).to eq 'pending' | ||
end | ||
end | ||
|
||
context "when any inventory was already canceled" do |
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.
Thanks for adding this spec!
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.
Thanks to you for pointing out the edge case 🙇, I totally missed it!
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.
Thanks @stefano-sarioli !
@@ -34,6 +34,14 @@ module InventoryUnit | |||
event :cancel do | |||
transition to: :canceled, from: ::Spree::InventoryUnit::CANCELABLE_STATES.map(&:to_sym) | |||
end | |||
|
|||
event :on_hand do |
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'm not 100% sure about this event name.
Semantically speaking, event names should be verbs, as they actively change the state of an object. In this case, the action name is the same as the target state, and this may lead to some confusion too.
Also, there's the query method #can_on_hand? added automatically, which again does not make 100% sense to me.
What about changing the name to something like set_on_hand
or make_on_hand
? And if you find a better naming, just go for it.
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 agree with you, I was not convinced too by the name of that event but couldn't think of something better.
I like set_on_hand
proposed by you ❤️.
Sadly, as pointed out in the last comment of Kennyadsl, I'm probably going to close this PR to move the whole resume functionality out of Solidus.
Thanks a lot for your feedback, I'll note it down to use it when the work on the extracted functionality will start 🙏.
inventory_units.where.not(state: 'canceled').each(&:cancel!) | ||
end | ||
|
||
def resume_inventory_units |
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.
We discussed this within the core team. We think that resuming concerns should be moved into a separate PR. There are a lot of opinions on how resuming an order should work and probably none of them will work as the majority of stores expect (everyone wants to restock items in different ways, depending on if they are using Solidus to manage stocks, which itself has a lot of variables, or they are relying on an external system).
We are thinking to actually deprecate the Resume order functionality. It's not used a lot and gives us more headaches than the benefits it provides to stores (none of us can think of a single store that ever used this functionality). The way to go here is moving the current behavior into a legacy extension, and deprecate the functionality in core (removing the Resume button from the admin UI). WDYT?
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 agree with you, especially if it's an underused functionality.
My solution is far too general and makes a lot of assumptions about the stock management system.
I think that extracting the resume functionality into an external gem, maybe with this fix on it, would be the best solution.
Probably we can close this PR, I'll wait for the final decision about the resume functionality and will come back to contribute to that one as soon as it's ready.
Thank a lot for your feedback and consideration 🙏.
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 cancellation part of this PR is well done and something that we definitely need in core. Please don't close the PR but just remove the part that resumes the inventory units. 🙏
This PR fix #3719.
Before this commit when an order was canceled the inventory units
of the order will remain untouched. So there were canceled orders with
inventory units with the state on_hand or backordered.
This situation was not only inconsistent but can lead to subtle bugs
with the stock management system.
How to reproduce the bug:
This problem is caused by the fact that when the order is canceled, a movement is created to restock the stock_item correlated with the inventory_units. As soon as the stock_items get back to a positive value it will try to convert as much as possible back-ordered inventory units to on_hand.
With this commit the inventory units related to an order are canceled when the order is canceled.
When an order is resumed we recalculate the state of the connected
inventory units, based on the actual stocks available.
What do you think about this issue, and my solution?
I'm not sure that the testing is enough, probably I can add an E2E test, what do you think? any idea on what can be the best place to put this test?
Checklist: