diff --git a/InvenTree/stock/models.py b/InvenTree/stock/models.py
index 42cc5b9f7a..64b47da6d3 100644
--- a/InvenTree/stock/models.py
+++ b/InvenTree/stock/models.py
@@ -63,6 +63,43 @@ class StockLocation(InvenTreeTree):
help_text=_('Select Owner'),
related_name='stock_locations')
+ def get_location_owner(self):
+ """
+ Get the closest "owner" for this location.
+
+ Start at this location, and traverse "up" the location tree until we find an owner
+ """
+
+ for loc in self.get_ancestors(include_self=True, ascending=True):
+ if loc.owner is not None:
+ return loc.owner
+
+ return None
+
+ def check_ownership(self, user):
+ """
+ Check if the user "owns" (is one of the owners of) the location.
+ """
+
+ # Superuser accounts automatically "own" everything
+ if user.is_superuser:
+ return True
+
+ ownership_enabled = common.models.InvenTreeSetting.get_setting('STOCK_OWNERSHIP_CONTROL')
+
+ if not ownership_enabled:
+ # Location ownership function is not enabled, so return True
+ return True
+
+ owner = self.get_location_owner()
+
+ if owner is None:
+ # No owner set, for this location or any location above
+ # So, no ownership checks to perform!
+ return True
+
+ return user in owner.get_related_owners(include_group=True)
+
def get_absolute_url(self):
return reverse('stock-location-detail', kwargs={'pk': self.id})
@@ -614,6 +651,48 @@ class StockItem(MPTTModel):
help_text=_('Select Owner'),
related_name='stock_items')
+ def get_item_owner(self):
+ """
+ Return the closest "owner" for this StockItem.
+
+ - If the item has an owner set, return that
+ - If the item is "in stock", check the StockLocation
+ - Otherwise, return None
+ """
+
+ if self.owner is not None:
+ return self.owner
+
+ if self.in_stock and self.location is not None:
+ loc_owner = self.location.get_location_owner()
+
+ if loc_owner:
+ return loc_owner
+
+ return None
+
+ def check_ownership(self, user):
+ """
+ Check if the user "owns" (or is one of the owners of) the item
+ """
+
+ # Superuser accounts automatically "own" everything
+ if user.is_superuser:
+ return True
+
+ ownership_enabled = common.models.InvenTreeSetting.get_setting('STOCK_OWNERSHIP_CONTROL')
+
+ if not ownership_enabled:
+ # Location ownership function is not enabled, so return True
+ return True
+
+ owner = self.get_item_owner()
+
+ if owner is None:
+ return True
+
+ return user in owner.get_related_owners(include_group=True)
+
def is_stale(self):
"""
Returns True if this Stock item is "stale".
diff --git a/InvenTree/stock/templates/stock/item.html b/InvenTree/stock/templates/stock/item.html
index f42a768069..113fefb9b1 100644
--- a/InvenTree/stock/templates/stock/item.html
+++ b/InvenTree/stock/templates/stock/item.html
@@ -18,18 +18,11 @@
{% trans "Stock Tracking Information" %}
{% include "spacer.html" %}
- {% setting_object 'STOCK_OWNERSHIP_CONTROL' as owner_control %}
- {% if owner_control.value == "True" %}
- {% authorized_owners item.owner as owners %}
- {% endif %}
-
- {% if owner_control.value == "False" or owner_control.value == "True" and user in owners %}
- {% if roles.stock.change and not item.is_building %}
+ {% if user_owns_item and roles.stock.change and not item.is_building %}
{% endif %}
- {% endif %}
diff --git a/InvenTree/stock/templates/stock/item_base.html b/InvenTree/stock/templates/stock/item_base.html
index 9979468357..c52d101afb 100644
--- a/InvenTree/stock/templates/stock/item_base.html
+++ b/InvenTree/stock/templates/stock/item_base.html
@@ -59,14 +59,7 @@
-
-
-{% setting_object 'STOCK_OWNERSHIP_CONTROL' as owner_control %}
-{% if owner_control.value == "True" %}
- {% authorized_owners item.owner as owners %}
-{% endif %}
-
-{% if owner_control.value == "False" or owner_control.value == "True" and user in owners or user.is_superuser %}
+{% if user_owns_item %}
{% if roles.stock.change and not item.is_building %}
@@ -219,24 +212,8 @@
-{% setting_object 'STOCK_OWNERSHIP_CONTROL' as owner_control %}
-{% if owner_control.value == "True" %}
- {% authorized_owners item.owner as owners %}
-{% endif %}
-
- {% setting_object 'STOCK_OWNERSHIP_CONTROL' as owner_control %}
- {% if owner_control.value == "True" %}
- {% authorized_owners item.owner as owners %}
-
- {% if not user in owners and not user.is_superuser %}
-
- {% trans "You are not in the list of owners of this item. This stock item cannot be edited." %}
-
{% trans "This stock item is in production and cannot be edited." %}
@@ -419,11 +396,18 @@
{% endif %}
- {% if item.owner %}
+ {% if ownership_enabled and item_owner %}
{% trans "Owner" %}
-
{{ item.owner }}
+
+ {{ item_owner }}
+ {% if not user_owns_item %}
+
+ {% trans "Read only" %}
+
+ {% endif %}
+
{% endif %}
diff --git a/InvenTree/stock/templates/stock/location.html b/InvenTree/stock/templates/stock/location.html
index 39b9faedb4..4c98db529b 100644
--- a/InvenTree/stock/templates/stock/location.html
+++ b/InvenTree/stock/templates/stock/location.html
@@ -20,6 +20,7 @@
{% endblock %}
{% block actions %}
+
{% if location and user.is_staff and roles.stock_location.change %}
{% url 'admin:stock_stocklocation_change' location.pk as url %}
@@ -38,7 +39,7 @@
-{% if owner_control.value == "False" or owner_control.value == "True" and user in owners or user.is_superuser %}
+{% if user_owns_location %}
{% if roles.stock.change %}