mirror of
https://github.com/inventree/InvenTree.git
synced 2025-04-28 11:36:44 +00:00
Merge pull request #2676 from SchrodingersGat/location-permission-fix
Stock location template fix
This commit is contained in:
commit
c882d1f89b
@ -63,6 +63,43 @@ class StockLocation(InvenTreeTree):
|
|||||||
help_text=_('Select Owner'),
|
help_text=_('Select Owner'),
|
||||||
related_name='stock_locations')
|
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):
|
def get_absolute_url(self):
|
||||||
return reverse('stock-location-detail', kwargs={'pk': self.id})
|
return reverse('stock-location-detail', kwargs={'pk': self.id})
|
||||||
|
|
||||||
@ -614,6 +651,48 @@ class StockItem(MPTTModel):
|
|||||||
help_text=_('Select Owner'),
|
help_text=_('Select Owner'),
|
||||||
related_name='stock_items')
|
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):
|
def is_stale(self):
|
||||||
"""
|
"""
|
||||||
Returns True if this Stock item is "stale".
|
Returns True if this Stock item is "stale".
|
||||||
|
@ -18,18 +18,11 @@
|
|||||||
<h4>{% trans "Stock Tracking Information" %}</h4>
|
<h4>{% trans "Stock Tracking Information" %}</h4>
|
||||||
{% include "spacer.html" %}
|
{% include "spacer.html" %}
|
||||||
<div class='btn-group' role='group'>
|
<div class='btn-group' role='group'>
|
||||||
{% setting_object 'STOCK_OWNERSHIP_CONTROL' as owner_control %}
|
{% if user_owns_item and roles.stock.change and not item.is_building %}
|
||||||
{% if owner_control.value == "True" %}
|
|
||||||
{% authorized_owners item.owner as owners %}
|
|
||||||
{% endif %}
|
|
||||||
<!-- Check permissions and owner -->
|
|
||||||
{% if owner_control.value == "False" or owner_control.value == "True" and user in owners %}
|
|
||||||
{% if roles.stock.change and not item.is_building %}
|
|
||||||
<button class='btn btn-success' type='button' title='New tracking entry' id='new-entry'>
|
<button class='btn btn-success' type='button' title='New tracking entry' id='new-entry'>
|
||||||
<span class='fas fa-plus-circle'></span> {% trans "New Entry" %}
|
<span class='fas fa-plus-circle'></span> {% trans "New Entry" %}
|
||||||
</button>
|
</button>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
{% endif %}
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -59,14 +59,7 @@
|
|||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
<!-- Stock adjustment menu -->
|
<!-- Stock adjustment menu -->
|
||||||
<!-- Check permissions and owner -->
|
{% if user_owns_item %}
|
||||||
|
|
||||||
{% 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 roles.stock.change and not item.is_building %}
|
{% if roles.stock.change and not item.is_building %}
|
||||||
<div class='btn-group'>
|
<div class='btn-group'>
|
||||||
<button id='stock-actions' title='{% trans "Stock adjustment actions" %}' class='btn btn-outline-secondary dropdown-toggle' type='button' data-bs-toggle='dropdown'><span class='fas fa-boxes'></span> <span class='caret'></span></button>
|
<button id='stock-actions' title='{% trans "Stock adjustment actions" %}' class='btn btn-outline-secondary dropdown-toggle' type='button' data-bs-toggle='dropdown'><span class='fas fa-boxes'></span> <span class='caret'></span></button>
|
||||||
@ -219,24 +212,8 @@
|
|||||||
</tr>
|
</tr>
|
||||||
</table>
|
</table>
|
||||||
|
|
||||||
{% setting_object 'STOCK_OWNERSHIP_CONTROL' as owner_control %}
|
|
||||||
{% if owner_control.value == "True" %}
|
|
||||||
{% authorized_owners item.owner as owners %}
|
|
||||||
{% endif %}
|
|
||||||
|
|
||||||
<div class='info-messages'>
|
<div class='info-messages'>
|
||||||
|
|
||||||
{% 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 %}
|
|
||||||
<div class='alert alert-block alert-info'>
|
|
||||||
{% trans "You are not in the list of owners of this item. This stock item cannot be edited." %}<br>
|
|
||||||
</div>
|
|
||||||
{% endif %}
|
|
||||||
{% endif %}
|
|
||||||
|
|
||||||
{% if item.is_building %}
|
{% if item.is_building %}
|
||||||
<div class='alert alert-block alert-info'>
|
<div class='alert alert-block alert-info'>
|
||||||
{% trans "This stock item is in production and cannot be edited." %}<br>
|
{% trans "This stock item is in production and cannot be edited." %}<br>
|
||||||
@ -419,11 +396,18 @@
|
|||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
{% if item.owner %}
|
{% if ownership_enabled and item_owner %}
|
||||||
<tr>
|
<tr>
|
||||||
<td><span class='fas fa-users'></span></td>
|
<td><span class='fas fa-users'></span></td>
|
||||||
<td>{% trans "Owner" %}</td>
|
<td>{% trans "Owner" %}</td>
|
||||||
<td>{{ item.owner }}</td>
|
<td>
|
||||||
|
{{ item_owner }}
|
||||||
|
{% if not user_owns_item %}
|
||||||
|
<span class='badge rounded-pill bg-warning badge-right' title='{% trans "You are not in the list of owners of this item. This stock item cannot be edited." %}'>
|
||||||
|
{% trans "Read only" %}
|
||||||
|
</span>
|
||||||
|
{% endif %}
|
||||||
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
</table>
|
</table>
|
||||||
|
@ -20,6 +20,7 @@
|
|||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|
||||||
{% block actions %}
|
{% block actions %}
|
||||||
|
|
||||||
<!-- Admin view -->
|
<!-- Admin view -->
|
||||||
{% if location and user.is_staff and roles.stock_location.change %}
|
{% if location and user.is_staff and roles.stock_location.change %}
|
||||||
{% url 'admin:stock_stocklocation_change' location.pk as url %}
|
{% url 'admin:stock_stocklocation_change' location.pk as url %}
|
||||||
@ -38,7 +39,7 @@
|
|||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
<!-- Check permissions and owner -->
|
<!-- Check permissions and owner -->
|
||||||
{% 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 %}
|
{% if roles.stock.change %}
|
||||||
<div class='btn-group' role='group'>
|
<div class='btn-group' role='group'>
|
||||||
<button id='stock-actions' title='{% trans "Stock actions" %}' class='btn btn-outline-secondary dropdown-toggle' type='button' data-bs-toggle='dropdown'>
|
<button id='stock-actions' title='{% trans "Stock actions" %}' class='btn btn-outline-secondary dropdown-toggle' type='button' data-bs-toggle='dropdown'>
|
||||||
@ -74,13 +75,11 @@
|
|||||||
{% endif %}
|
{% endif %}
|
||||||
{% endif %}
|
{% endif %}
|
||||||
{% endif %}
|
{% endif %}
|
||||||
{% if owner_control.value == "False" or owner_control.value == "True" and user in owners or user.is_superuser or not location %}
|
{% if user_owns_location and roles.stock_location.add %}
|
||||||
{% if roles.stock_location.add %}
|
|
||||||
<button class='btn btn-success' id='location-create' type='button' title='{% trans "Create new stock location" %}'>
|
<button class='btn btn-success' id='location-create' type='button' title='{% trans "Create new stock location" %}'>
|
||||||
<span class='fas fa-plus-circle'></span> {% trans "New Location" %}
|
<span class='fas fa-plus-circle'></span> {% trans "New Location" %}
|
||||||
</button>
|
</button>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
{% endif %}
|
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|
||||||
{% block details_left %}
|
{% block details_left %}
|
||||||
@ -106,23 +105,23 @@
|
|||||||
<td><em>{% trans "Top level stock location" %}</em></td>
|
<td><em>{% trans "Top level stock location" %}</em></td>
|
||||||
</tr>
|
</tr>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
{% if ownership_enabled and location_owner %}
|
||||||
|
<tr>
|
||||||
|
<td><span class='fas fa-users'></span></td>
|
||||||
|
<td>{% trans "Location Owner" %}</td>
|
||||||
|
<td>
|
||||||
|
{{ location_owner }}
|
||||||
|
{% if not user_owns_location %}
|
||||||
|
<span class='badge rounded-pill bg-warning badge-right' title='{% trans "You are not in the list of owners of this location. This stock location cannot be edited." %}'>
|
||||||
|
{% trans "Read only" %}
|
||||||
|
</span>
|
||||||
|
{% endif %}
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
{% endif %}
|
||||||
</table>
|
</table>
|
||||||
{% endblock details_left %}
|
{% endblock details_left %}
|
||||||
|
|
||||||
{% block details_below %}
|
|
||||||
{% setting_object 'STOCK_OWNERSHIP_CONTROL' as owner_control %}
|
|
||||||
{% if owner_control.value == "True" %}
|
|
||||||
{% authorized_owners location.owner as owners %}
|
|
||||||
|
|
||||||
{% if location and not user in owners and not user.is_superuser %}
|
|
||||||
<div class='alert alert-block alert-info'>
|
|
||||||
{% trans "You are not in the list of owners of this location. This stock location cannot be edited." %}<br>
|
|
||||||
</div>
|
|
||||||
{% endif %}
|
|
||||||
{% endif %}
|
|
||||||
|
|
||||||
{% endblock details_below %}
|
|
||||||
|
|
||||||
{% block details_right %}
|
{% block details_right %}
|
||||||
{% if location %}
|
{% if location %}
|
||||||
<table class='table table-striped table-condensed'>
|
<table class='table table-striped table-condensed'>
|
||||||
|
@ -63,6 +63,11 @@ class StockIndex(InvenTreeRoleMixin, ListView):
|
|||||||
context['loc_count'] = StockLocation.objects.count()
|
context['loc_count'] = StockLocation.objects.count()
|
||||||
context['stock_count'] = StockItem.objects.count()
|
context['stock_count'] = StockItem.objects.count()
|
||||||
|
|
||||||
|
# No 'ownership' checks are necessary for the top-level StockLocation view
|
||||||
|
context['user_owns_location'] = True
|
||||||
|
context['location_owner'] = None
|
||||||
|
context['ownership_enabled'] = common.models.InvenTreeSetting.get_setting('STOCK_OWNERSHIP_CONTROL')
|
||||||
|
|
||||||
return context
|
return context
|
||||||
|
|
||||||
|
|
||||||
@ -76,6 +81,16 @@ class StockLocationDetail(InvenTreeRoleMixin, DetailView):
|
|||||||
queryset = StockLocation.objects.all()
|
queryset = StockLocation.objects.all()
|
||||||
model = StockLocation
|
model = StockLocation
|
||||||
|
|
||||||
|
def get_context_data(self, **kwargs):
|
||||||
|
|
||||||
|
context = super().get_context_data(**kwargs)
|
||||||
|
|
||||||
|
context['ownership_enabled'] = common.models.InvenTreeSetting.get_setting('STOCK_OWNERSHIP_CONTROL')
|
||||||
|
context['location_owner'] = context['location'].get_location_owner()
|
||||||
|
context['user_owns_location'] = context['location'].check_ownership(self.request.user)
|
||||||
|
|
||||||
|
return context
|
||||||
|
|
||||||
|
|
||||||
class StockItemDetail(InvenTreeRoleMixin, DetailView):
|
class StockItemDetail(InvenTreeRoleMixin, DetailView):
|
||||||
"""
|
"""
|
||||||
@ -126,6 +141,10 @@ class StockItemDetail(InvenTreeRoleMixin, DetailView):
|
|||||||
# We only support integer serial number progression
|
# We only support integer serial number progression
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
data['ownership_enabled'] = common.models.InvenTreeSetting.get_setting('STOCK_OWNERSHIP_CONTROL')
|
||||||
|
data['item_owner'] = self.object.get_item_owner()
|
||||||
|
data['user_owns_item'] = self.object.check_ownership(self.request.user)
|
||||||
|
|
||||||
return data
|
return data
|
||||||
|
|
||||||
def get(self, request, *args, **kwargs):
|
def get(self, request, *args, **kwargs):
|
||||||
|
Loading…
x
Reference in New Issue
Block a user