-
-
Notifications
You must be signed in to change notification settings - Fork 730
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
Fix bug in inventory management page #2893
Fix bug in inventory management page #2893
Conversation
b6ad422
to
d17e503
Compare
I see there's a field called variant_override.permission_revoked_at which is a date when the VO permission was revoked. I believe this issue is related to this field and not to deleted products. |
1cbef29
to
ce4430b
Compare
so, after testing deletion of permissions I realised VOs permissions were not being revoked on delete. So, I added a new commit to revoke permissions on VOs when permission is deleted. Simple fix to a complex problem. I believe this fixes the original issue completely. We just need to run some migration to revoke all VOs that have no permissions. |
So, this PR needs:
|
ce4430b
to
dadc56c
Compare
…es are revoked when permission is deleted
dadc56c
to
d375bb8
Compare
All done, this PR is ready for review and test. |
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.
Nice.
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.
Good work! Really nice to see your deep understanding. I just learned how permissions are modelled. :-D
I have some suggestions how to improve the migration, but that shouldn't block an S2 issue. So I'm approving it. 👍
def up | ||
# This process was executed when the permission_revoked_at colum was created (see AddPermissionRevokedAtToVariantOverrides) | ||
# It needs to be repeated due to #2739 | ||
variant_override_hubs = Enterprise.where(id: VariantOverride.all.map(&:hub_id).uniq) |
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.
It's good practice to declare ActiveRecord models used in the migration again so that the migration is independent from changes in the model code. Example: https://coderwall.com/p/zav1dg/using-models-in-rails-migrations
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.
You probably just took it from the previous migration, but this call is a bit clearer and more efficient:
variant_override_hubs = Enterprise.where(id: VariantOverride.all.map(&:hub_id).uniq) | |
variant_override_hubs = Enterprise.where(id: VariantOverride.uniq.pluck(:hub_id)) |
It also enables ActiveRecord to nest the VariantOverride query within the Enterprise query instead of making two queries.
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.
yeah, this was copy pasted from the original revoked_at code. I tested it with an example.
It would probably be better writing SQL, correct? Things like this will break in the future if these things are removed from the model :
"hub.relationships_as_child.with_permission"
Hmm. what do I do? Is there an easy fix? Can I ignore this for now? We will have to look at it when/if it breaks in the future.
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 the pluck lesson!
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.
Sorry to be late but I totally missed this PR. My concern is that VariantOverride.all
can potentially blow up some instance's DB. That turns into a SELECT
without WHERE
constraints thus, selecting the whole table 💥 I suggest we process them in chunks.
We can check if Canada (the only instance affected?) has just few variant overrides and run it there but we'll need to fix it before we run it in other instances.
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.
ok, do you think this query can blow a database? "select id from variant_overrides;"
Canada has 908 entries.
Anyway, I can re-write, can you please guide me here. What's the proper way of doing this?
|
||
variant_override_hubs.each do |hub| | ||
permitting_producer_ids = hub.relationships_as_child | ||
.with_permission(:create_variant_overrides).map(&:parent_id) |
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.
Another good use of pluck
:
.with_permission(:create_variant_overrides).map(&:parent_id) | |
.with_permission(:create_variant_overrides).pluck(:parent_id) |
Staged on https://staging.openfoodnetwork.org.au/. |
Thank you @luisramos0 for such a detailed test scenario. I'm amazed by the work done, kudos! Here are my testing notes : |
Lets ship this one directly to Canada :-D |
def up | ||
# This process was executed when the permission_revoked_at colum was created (see AddPermissionRevokedAtToVariantOverrides) | ||
# It needs to be repeated due to #2739 | ||
variant_override_hubs = Enterprise.where(id: VariantOverride.all.map(&:hub_id).uniq) |
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.
Sorry to be late but I totally missed this PR. My concern is that VariantOverride.all
can potentially blow up some instance's DB. That turns into a SELECT
without WHERE
constraints thus, selecting the whole table 💥 I suggest we process them in chunks.
We can check if Canada (the only instance affected?) has just few variant overrides and run it there but we'll need to fix it before we run it in other instances.
This commit makes use of three ActiveRecord features: 1. Using `select` instead of `all.map` enables ActiveRecord to nest one select into the other, resulting in one more efficient query instead of two. 2. Using `find_each` saves memory by loading records in batches. https://api.rubyonrails.org/classes/ActiveRecord/Batches.html#method-i-find_each 3. Using `pluck` creates only an array, avoiding loading all the other columns of the records into objects. Running this on the current Canadian database, fixes the following variant overrides: ``` [] [] [] [] [] [] [925, 924, 966, 965] [] [] [] [] [462, 863, 464, 822, 949, 947, 944, 939, 942, 946, 945, 943, 438, 937, 938, 941, 940, 467, 952, 875, 453, 953, 454, 951, 487, 460, 457, 528, 527, 486, 459, 458, 461, 529, 530, 950, 642, 384, 380, 643, 385, 381, 644, 386, 382, 960, 959, 379, 640, 377, 375, 532, 639, 376, 374, 646, 390, 389, 637, 406, 408, 647, 391, 393, 633, 396, 400, 398, 645, 388, 387, 648, 394, 392, 536, 632, 399, 397, 395, 634, 403, 401, 635, 404, 402, 636, 407, 405, 535, 534, 638, 410, 409, 948, 533, 537, 531, 877, 880, 894, 893, 672, 671, 673, 674, 703, 714, 715, 716, 717, 862, 864, 879, 876, 865, 881, 878, 463, 954, 866, 823, 957, 958, 955, 956, 899, 897] [] [969] ```
@sauloperez @luisramos0 I added another commit addressing all the potential performance issues. The commit contains explanations for all changes. Since this is a database migration that doesn't change any staging data, we don't need to stage this again. I'm tempted to deploy it to the Canadian server, but I would like the approval from @sauloperez. I tested this with the Canadian data and the migration runs without error. But I'm not able to re-produce the issue with the current data. I can save prices without any problem (as super admin). So I'm not sure how to test this. |
It's not obvious to replicate. You can follow the test case above in a version without the fix. Another option is to run something like "update variant_override set permission_revoked_at = null where hub_id = X" |
@sauloperez I used the |
Yes, AFAIK that's what it does. It might not be the most known AR's feature but I find it essential for data migrations. There's also the option to go deeper into AR and use find_in_batches. I've had the need to use it a few times. |
Hi all, @mkllnk deployed this to Aus production today and I'm wondering if it could be related to a bug that's been reported this evening. A user has said .... "I just went in and checked my inventory and random inventory amounts have been loaded for the 236 products I have loaded on the system." If you have a chance to look into this that would be most appreciated @sauloperez or @luisramos0 . If it's a bug it could effect more users, so good to catch early. Thanks |
I dont think it can be related as here we are updating permissions only. We are not changing stock levels. The only possibility I can see is that in this PR we are changing the permissions and revoked inventory items are excluded from the default query scope. So, any query or update to inventory items will not include revoked inventory items (inventory items = variant overrides). But how can that make "stock levels random"? I'd create a new issue for that @sstead |
ok, in order to connect this with stock management I tried some permissions related scenarios. we have a problem. first, this PR will always be correct. It's just making data consistent in the database. second, the problem I'll describe will only happen for enterprises that had broken permissions, i.e., they were selling products for which they didn't have permissions to "manage inventory". Explanation: What this PR is doing is revoking permissions on inventory items. The problem is that these inventory items can be on the hubs shopfront and they can still be bought even after this PR. Validation Before we move to a solution we need to validate that what I am talking about is what is happening in AUS. I cant access the server. We need to check if this user's enterprise has some variant_overrides revoked or if another enterprise has revoked variant_overrides of its products. If this explanation is correct there must be some of these in the DB for this user. Quick workaround in AUS: lets see how many variant overrides have permission_revoked_at != nil in AUS. I believe making this field nil for all entries is a valid shortcut. We can then rebuild this data from the permissions with the migration in this PR. Current Release: we have to revert this PR from master and the current release until we have a solution for this problem. Solution: if a producer revokes permissions for a hub to manage inventory, all the products disappear from the hubs shopfront. is this possible/valid? or do we need to consider mixed cases between permissions to "manage inventory" and "add to order cycle"? what does it mean when a hub can "add to order cycle" but cannot "manage inventory". Is this a valid usage case? |
@luisramos0 , In the case of our user, I don't think revoked permissions is the problem. This user is a farm shop, selling only her own products- there are no permissions. She is using Inventory to set her stock levels (probably without needing to- she could just as easily not use Inventory). Has the user sold much stock in the last few days? - She's had 5 orders in the last 24 hours. |
Hum... @sstead is this possible that the user did a mistake? She put some stock for the wrong products? I just don't see how this PR could have had such impact... and it is a very possible human mistake in what you describe... @luisramos0 about your solution, I'm not sure about the need to separate the "add to order cycle" and "add to inventory" permission and don't see any reason why a supplier would give one and not the other. Weither the hub add a commission through enterprise fee, or override product prices and stock is not really the producer business, I mean if the hub doesn't have a calculated margin why couldn't he just setup the price she wants to sell the products? But today, technically if you revoke permission to add to inventory, but keep permission to add to order cycle, products can still be listed in OC and appear in shop, it's just that hub can't override info through inventories. I don't think we need to revert then, right? Or can there be a problem with the fact that the user uses herself the inventory for her own catalog? Is there any permission involved to manage own inventory that could have been impacted? Could it be a form of conflict? The inventory is linked to her shop, and I guess there should be some default permission between the shop of a producer and her own product catalog... ? Even if they have the same name and are technically the same agent id in the system...? |
@myriamboure This is exactly the problem I have confirmed. You are saying it's a feature. If it's a feature, it's a feature this PR fixed. If this is correct, no need for workaround or revert. Unless we find something else. @sstead as a producer I have tried to give myself permissions to manage my own inventory but the inventory management page didnt show up anything. So, I am not sure what do you mean by managing own stock in inventory... what permissions are in place, can you share a screen shot? Probably better to open a new issue. |
I think it is correct and we don't need to do anything else. @luisramos0 you just need to be a producer with a "own shop" package, normally in inventory you should see your own products... well AFAK... let's see what @sstead says. Agree about opening a new issue. |
hi people - there is absolutely no way I can get my head around this at the moment. What I need to know is what it means for the user whose inventory levels all changed? @luisramos0 @myriamboure @sstead ? |
I've opened a new issue here - #2960 I don't think it was user error - she thoroughly checked items before opening OC, and products that haven't been in season for months suddenly had >0 on hand. Sorry I don't have time to get my head into this PR right now- but from a quick scan I don't think there are any 'revoked' permissions here. It could just be something funny relating to an enterprise who is a farm shop doing overrides on their own products- no permission in place, the system just lets a shop do overrides on itself. For now the user has updated the invenotry levels back to what they should be and hasn't reported any more issues today. |
What? Why?
Closes #2739
Initially I thought this happened where permissions to change existing variant overrides of deleted products were checked. The initial commit (now removed from this PR) was making the inventory page ignore variant overrides of deleted products.
After further investigation I concluded the problem was when permissions were deleted but variant overrides were not revoked (after discovering the field variant_override.permission_revoked_at :-)).
This PR is:
What should we test?
Inventory page and permissions.
Test adapted from a comment in #2739:
After this fix is installed in any live instance, the result of this query should be empty (the migration will do this part of the job) and should remain empty forever (the fix will do this part of the job) ;-)
select distinct hub.id, hub.name, supplier.id, supplier.name from variant_overrides vo, spree_variants v, spree_products p, enterprises hub, enterprises supplier where vo.variant_id = v.id and hub.id = vo.hub_id and supplier.id = p.supplier_id and v.product_id = p.id and vo.hub_id != p.supplier_id and (p.supplier_id, vo.hub_id) not in (select er.parent_id, er.child_id from enterprise_relationships er, enterprise_relationship_permissions erp where er.id = erp.enterprise_relationship_id and erp.name = 'create_variant_overrides') order by hub.id;
Release notes
Changelog Category: Fixed
Fix broken inventory page. When a producer deletes a permission for a hub to add producer's products to the hub's inventory, the hub's inventory items are now being correctly updated with a revoked stamp that will not break the inventory page anymore.
How is this related to the Spree upgrade?
Not related.