mirror of
https://github.com/inventree/InvenTree
synced 2024-08-30 18:33:04 +00:00
Updated templates and a lot of manual testing
This commit is contained in:
parent
9eace09e0e
commit
b6135fda74
@ -145,3 +145,22 @@ def get_color_theme_css(username):
|
|||||||
inventree_css_static_url = os.path.join(settings.STATIC_URL, inventree_css_sheet)
|
inventree_css_static_url = os.path.join(settings.STATIC_URL, inventree_css_sheet)
|
||||||
|
|
||||||
return inventree_css_static_url
|
return inventree_css_static_url
|
||||||
|
|
||||||
|
|
||||||
|
@register.simple_tag()
|
||||||
|
def authorized_owners(group):
|
||||||
|
""" Return authorized owners """
|
||||||
|
|
||||||
|
owners = []
|
||||||
|
|
||||||
|
try:
|
||||||
|
for owner in group.get_users(include_group=True):
|
||||||
|
owners.append(owner.owner)
|
||||||
|
except AttributeError:
|
||||||
|
# group is None
|
||||||
|
pass
|
||||||
|
except TypeError:
|
||||||
|
# group.get_users returns None
|
||||||
|
pass
|
||||||
|
|
||||||
|
return owners
|
||||||
|
@ -9,12 +9,15 @@
|
|||||||
{% include "stock/tabs.html" with tab="tracking" %}
|
{% include "stock/tabs.html" with tab="tracking" %}
|
||||||
|
|
||||||
{% setting_object 'STOCK_OWNERSHIP_CONTROL' as owner_control %}
|
{% setting_object 'STOCK_OWNERSHIP_CONTROL' as owner_control %}
|
||||||
|
{% if owner_control.value == "True" %}
|
||||||
|
{% authorized_owners item.owner as owners %}
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
<h4>{% trans "Stock Tracking Information" %}</h4>
|
<h4>{% trans "Stock Tracking Information" %}</h4>
|
||||||
<hr>
|
<hr>
|
||||||
|
|
||||||
<!-- Check permissions and owner -->
|
<!-- Check permissions and owner -->
|
||||||
{% if owner_control.value == "False" or owner_control.value == "True" and item.owner == user %}
|
{% if owner_control.value == "False" or owner_control.value == "True" and user in owners %}
|
||||||
{% if roles.stock.change and not item.is_building %}
|
{% if roles.stock.change and not item.is_building %}
|
||||||
<div id='table-toolbar'>
|
<div id='table-toolbar'>
|
||||||
<div class='btn-group'>
|
<div class='btn-group'>
|
||||||
|
@ -16,6 +16,15 @@ InvenTree | {% trans "Stock Item" %} - {{ item }}
|
|||||||
{% include 'stock/loc_link.html' with location=item.location %}
|
{% include 'stock/loc_link.html' with location=item.location %}
|
||||||
|
|
||||||
{% setting_object 'STOCK_OWNERSHIP_CONTROL' as owner_control %}
|
{% 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 the owner 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'>
|
||||||
@ -31,12 +40,6 @@ InvenTree | {% trans "Stock Item" %} - {{ item }}
|
|||||||
</div>
|
</div>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
|
||||||
{% if owner_control.value == "True" and not item.owner == user and not user.is_superuser %}
|
|
||||||
<div class='alert alert-block alert-info'>
|
|
||||||
{% trans "You are not the owner of this item. This stock item cannot be edited." %}<br>
|
|
||||||
</div>
|
|
||||||
{% endif %}
|
|
||||||
|
|
||||||
{% if item.hasRequiredTests and not item.passedAllRequiredTests %}
|
{% if item.hasRequiredTests and not item.passedAllRequiredTests %}
|
||||||
<div class='alert alert-block alert-danger'>
|
<div class='alert alert-block alert-danger'>
|
||||||
{% trans "This stock item has not passed all required tests" %}
|
{% trans "This stock item has not passed all required tests" %}
|
||||||
@ -78,6 +81,9 @@ InvenTree | {% trans "Stock Item" %} - {{ item }}
|
|||||||
{% block page_data %}
|
{% block page_data %}
|
||||||
|
|
||||||
{% setting_object 'STOCK_OWNERSHIP_CONTROL' as owner_control %}
|
{% setting_object 'STOCK_OWNERSHIP_CONTROL' as owner_control %}
|
||||||
|
{% if owner_control.value == "True" %}
|
||||||
|
{% authorized_owners item.owner as owners %}
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
<h3>
|
<h3>
|
||||||
{% trans "Stock Item" %}
|
{% trans "Stock Item" %}
|
||||||
@ -144,7 +150,7 @@ InvenTree | {% trans "Stock Item" %} - {{ item }}
|
|||||||
{% endif %}
|
{% endif %}
|
||||||
<!-- Stock adjustment menu -->
|
<!-- Stock adjustment menu -->
|
||||||
<!-- Check permissions and owner -->
|
<!-- Check permissions and owner -->
|
||||||
{% if owner_control.value == "False" or owner_control.value == "True" and item.owner == user or user.is_superuser %}
|
{% 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-default dropdown-toggle' type='button' data-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-default dropdown-toggle' type='button' data-toggle='dropdown'><span class='fas fa-boxes'></span> <span class='caret'></span></button>
|
||||||
|
@ -5,11 +5,14 @@
|
|||||||
{% block content %}
|
{% block content %}
|
||||||
|
|
||||||
{% setting_object 'STOCK_OWNERSHIP_CONTROL' as owner_control %}
|
{% setting_object 'STOCK_OWNERSHIP_CONTROL' as owner_control %}
|
||||||
|
{% if owner_control.value == "True" %}
|
||||||
|
{% authorized_owners location.owner as owners %}
|
||||||
|
|
||||||
{% if location and owner_control.value == "True" and not location.owner in user.groups.all and not user.is_superuser %}
|
{% if location and not user in owners and not user.is_superuser %}
|
||||||
<div class='alert alert-block alert-info'>
|
<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>
|
{% trans "You are not in the list of owners of this location. This stock location cannot be edited." %}<br>
|
||||||
</div>
|
</div>
|
||||||
|
{% endif %}
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
|
||||||
<div class='row'>
|
<div class='row'>
|
||||||
@ -27,7 +30,7 @@
|
|||||||
<p>{% trans "All stock items" %}</p>
|
<p>{% trans "All stock items" %}</p>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
<div class='btn-group action-buttons' role='group'>
|
<div class='btn-group action-buttons' role='group'>
|
||||||
{% if owner_control.value == "False" or owner_control.value == "True" and location.owner in user.groups.all or user.is_superuser or not location %}
|
{% if owner_control.value == "False" or owner_control.value == "True" and user in owners or user.is_superuser or not location %}
|
||||||
{% if roles.stock.add %}
|
{% if roles.stock.add %}
|
||||||
<button class='btn btn-default' id='location-create' title='{% trans "Create new stock location" %}'>
|
<button class='btn btn-default' id='location-create' title='{% trans "Create new stock location" %}'>
|
||||||
<span class='fas fa-plus-circle icon-green'/>
|
<span class='fas fa-plus-circle icon-green'/>
|
||||||
@ -45,7 +48,7 @@
|
|||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
<!-- Check permissions and owner -->
|
<!-- Check permissions and owner -->
|
||||||
{% if owner_control.value == "False" or owner_control.value == "True" and location.owner in user.groups.all or user.is_superuser %}
|
{% if owner_control.value == "False" or owner_control.value == "True" and user in owners or user.is_superuser %}
|
||||||
{% if roles.stock.change %}
|
{% if roles.stock.change %}
|
||||||
<div class='btn-group'>
|
<div class='btn-group'>
|
||||||
<button id='stock-actions' title='{% trans "Stock actions" %}' class='btn btn-default dropdown-toggle' type='button' data-toggle='dropdown'><span class='fas fa-boxes'></span> <span class='caret'></span></button>
|
<button id='stock-actions' title='{% trans "Stock actions" %}' class='btn btn-default dropdown-toggle' type='button' data-toggle='dropdown'><span class='fas fa-boxes'></span> <span class='caret'></span></button>
|
||||||
|
@ -166,13 +166,59 @@ class StockLocationEdit(AjaxUpdateView):
|
|||||||
|
|
||||||
stock_ownership_control = InvenTreeSetting.get_setting('STOCK_OWNERSHIP_CONTROL')
|
stock_ownership_control = InvenTreeSetting.get_setting('STOCK_OWNERSHIP_CONTROL')
|
||||||
if stock_ownership_control:
|
if stock_ownership_control:
|
||||||
if self.object.get_children():
|
authorized_owners = self.object.owner.get_users()
|
||||||
for child in self.object.get_children():
|
print(f'{authorized_owners=}')
|
||||||
child.owner = self.object.owner
|
|
||||||
child.save()
|
# Update children locations
|
||||||
|
children_locations = self.object.get_children()
|
||||||
|
for child in children_locations:
|
||||||
|
# Check if current owner is subset of new owner
|
||||||
|
if child.owner and authorized_owners:
|
||||||
|
if child.owner in authorized_owners:
|
||||||
|
continue
|
||||||
|
|
||||||
|
child.owner = self.object.owner
|
||||||
|
child.save()
|
||||||
|
|
||||||
|
# Update stock items
|
||||||
|
stock_items = self.object.get_stock_items()
|
||||||
|
print(f'{stock_items=}')
|
||||||
|
for stock_item in stock_items:
|
||||||
|
# Check if current owner is subset of new owner
|
||||||
|
if stock_item.owner and authorized_owners:
|
||||||
|
if stock_item.owner in authorized_owners:
|
||||||
|
print(f'{stock_item.owner} is authorized')
|
||||||
|
continue
|
||||||
|
|
||||||
|
print(f'Updating stock item {stock_item} owner')
|
||||||
|
stock_item.owner = self.object.owner
|
||||||
|
stock_item.save()
|
||||||
|
|
||||||
return self.object
|
return self.object
|
||||||
|
|
||||||
|
def validate(self, item, form):
|
||||||
|
""" Check that owner is set if stock ownership control is enabled """
|
||||||
|
|
||||||
|
parent = form.cleaned_data.get('parent', None)
|
||||||
|
|
||||||
|
owner = form.cleaned_data.get('owner', None)
|
||||||
|
|
||||||
|
# Is ownership control enabled?
|
||||||
|
stock_ownership_control = InvenTreeSetting.get_setting('STOCK_OWNERSHIP_CONTROL')
|
||||||
|
|
||||||
|
if stock_ownership_control:
|
||||||
|
if not owner and not self.request.user.is_superuser:
|
||||||
|
form.add_error('owner', _('Owner is required (ownership control is enabled)'))
|
||||||
|
else:
|
||||||
|
try:
|
||||||
|
if parent.owner:
|
||||||
|
if parent.owner != owner:
|
||||||
|
error = f'Owner requires to be equivalent to parent\'s owner ({parent.owner})'
|
||||||
|
form.add_error('owner', error)
|
||||||
|
except AttributeError:
|
||||||
|
# No parent
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
class StockLocationQRCode(QRCodeView):
|
class StockLocationQRCode(QRCodeView):
|
||||||
""" View for displaying a QR code for a StockLocation object """
|
""" View for displaying a QR code for a StockLocation object """
|
||||||
@ -1288,6 +1334,18 @@ class StockAdjust(AjaxView, FormMixin):
|
|||||||
|
|
||||||
count += 1
|
count += 1
|
||||||
|
|
||||||
|
# Is ownership control enabled?
|
||||||
|
stock_ownership_control = InvenTreeSetting.get_setting('STOCK_OWNERSHIP_CONTROL')
|
||||||
|
|
||||||
|
if stock_ownership_control:
|
||||||
|
# Fetch destination owner
|
||||||
|
destination_owner = destination.owner
|
||||||
|
|
||||||
|
if destination_owner:
|
||||||
|
# Update owner
|
||||||
|
item.owner = destination_owner
|
||||||
|
item.save()
|
||||||
|
|
||||||
if count == 0:
|
if count == 0:
|
||||||
return _('No items were moved')
|
return _('No items were moved')
|
||||||
|
|
||||||
@ -1361,12 +1419,18 @@ class StockItemEdit(AjaxUpdateView):
|
|||||||
if not stock_ownership_control:
|
if not stock_ownership_control:
|
||||||
form.fields['owner'].widget = HiddenInput()
|
form.fields['owner'].widget = HiddenInput()
|
||||||
else:
|
else:
|
||||||
location_owner = location.owner
|
try:
|
||||||
|
location_owner = location.owner
|
||||||
|
except AttributeError:
|
||||||
|
location_owner = None
|
||||||
|
|
||||||
# Check if location has owner
|
# Check if location has owner
|
||||||
if location_owner:
|
if location_owner:
|
||||||
|
form.fields['owner'].initial = location_owner
|
||||||
|
|
||||||
# Check location owner type and filter
|
# Check location owner type and filter
|
||||||
if type(location_owner.owner) is Group:
|
if type(location_owner.owner) is Group:
|
||||||
queryset = location_owner.get_users()
|
queryset = location_owner.get_users(include_group=True)
|
||||||
if self.request.user in queryset:
|
if self.request.user in queryset:
|
||||||
form.fields['owner'].initial = self.request.user
|
form.fields['owner'].initial = self.request.user
|
||||||
form.fields['owner'].queryset = queryset
|
form.fields['owner'].queryset = queryset
|
||||||
@ -1374,6 +1438,25 @@ class StockItemEdit(AjaxUpdateView):
|
|||||||
form.fields['owner'].disabled = True
|
form.fields['owner'].disabled = True
|
||||||
form.fields['owner'].initial = location_owner
|
form.fields['owner'].initial = location_owner
|
||||||
|
|
||||||
|
try:
|
||||||
|
item_owner = item.owner
|
||||||
|
except AttributeError:
|
||||||
|
item_owner = None
|
||||||
|
|
||||||
|
# Check if item has owner
|
||||||
|
if item_owner:
|
||||||
|
form.fields['owner'].initial = item_owner
|
||||||
|
|
||||||
|
# Check location owner type and filter
|
||||||
|
if type(item_owner.owner) is Group:
|
||||||
|
queryset = item_owner.get_users(include_group=True)
|
||||||
|
if self.request.user in queryset:
|
||||||
|
form.fields['owner'].initial = self.request.user
|
||||||
|
form.fields['owner'].queryset = queryset
|
||||||
|
elif type(item_owner.owner) is User:
|
||||||
|
form.fields['owner'].disabled = True
|
||||||
|
form.fields['owner'].initial = item_owner
|
||||||
|
|
||||||
return form
|
return form
|
||||||
|
|
||||||
def validate(self, item, form):
|
def validate(self, item, form):
|
||||||
@ -1384,8 +1467,9 @@ class StockItemEdit(AjaxUpdateView):
|
|||||||
# Is ownership control enabled?
|
# Is ownership control enabled?
|
||||||
stock_ownership_control = InvenTreeSetting.get_setting('STOCK_OWNERSHIP_CONTROL')
|
stock_ownership_control = InvenTreeSetting.get_setting('STOCK_OWNERSHIP_CONTROL')
|
||||||
|
|
||||||
if not owner and stock_ownership_control:
|
if stock_ownership_control:
|
||||||
form.add_error('owner', _('Owner is required (ownership control is enabled)'))
|
if not owner and not self.request.user.is_superuser:
|
||||||
|
form.add_error('owner', _('Owner is required (ownership control is enabled)'))
|
||||||
|
|
||||||
|
|
||||||
class StockItemConvert(AjaxUpdateView):
|
class StockItemConvert(AjaxUpdateView):
|
||||||
@ -1495,7 +1579,7 @@ class StockLocationCreate(AjaxCreateView):
|
|||||||
stock_ownership_control = InvenTreeSetting.get_setting('STOCK_OWNERSHIP_CONTROL')
|
stock_ownership_control = InvenTreeSetting.get_setting('STOCK_OWNERSHIP_CONTROL')
|
||||||
|
|
||||||
if stock_ownership_control:
|
if stock_ownership_control:
|
||||||
if not owner:
|
if not owner and not self.request.user.is_superuser:
|
||||||
form.add_error('owner', _('Owner is required (ownership control is enabled)'))
|
form.add_error('owner', _('Owner is required (ownership control is enabled)'))
|
||||||
else:
|
else:
|
||||||
try:
|
try:
|
||||||
@ -1716,7 +1800,11 @@ class StockItemCreate(AjaxCreateView):
|
|||||||
if not stock_ownership_control:
|
if not stock_ownership_control:
|
||||||
form.fields['owner'].widget = HiddenInput()
|
form.fields['owner'].widget = HiddenInput()
|
||||||
else:
|
else:
|
||||||
location_owner = location.owner
|
try:
|
||||||
|
location_owner = location.owner
|
||||||
|
except AttributeError:
|
||||||
|
location_owner = None
|
||||||
|
|
||||||
if location_owner:
|
if location_owner:
|
||||||
# Check location owner type and filter
|
# Check location owner type and filter
|
||||||
if type(location_owner.owner) is Group:
|
if type(location_owner.owner) is Group:
|
||||||
@ -1848,7 +1936,7 @@ class StockItemCreate(AjaxCreateView):
|
|||||||
|
|
||||||
if stock_ownership_control:
|
if stock_ownership_control:
|
||||||
# Check if owner is set
|
# Check if owner is set
|
||||||
if not owner:
|
if not owner and not self.request.user.is_superuser:
|
||||||
form.add_error('owner', _('Owner is required (ownership control is enabled)'))
|
form.add_error('owner', _('Owner is required (ownership control is enabled)'))
|
||||||
return
|
return
|
||||||
|
|
||||||
|
@ -2,6 +2,9 @@
|
|||||||
{% load inventree_extras %}
|
{% load inventree_extras %}
|
||||||
|
|
||||||
{% setting_object 'STOCK_OWNERSHIP_CONTROL' as owner_control %}
|
{% setting_object 'STOCK_OWNERSHIP_CONTROL' as owner_control %}
|
||||||
|
{% if owner_control.value == "True" %}
|
||||||
|
{% authorized_owners location.owner as owners %}
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
<div id='button-toolbar'>
|
<div id='button-toolbar'>
|
||||||
<div class='button-toolbar container-fluid' style='float: right;'>
|
<div class='button-toolbar container-fluid' style='float: right;'>
|
||||||
@ -12,7 +15,7 @@
|
|||||||
{% if read_only %}
|
{% if read_only %}
|
||||||
{% else %}
|
{% else %}
|
||||||
<!-- Check permissions and owner -->
|
<!-- Check permissions and owner -->
|
||||||
{% if owner_control.value == "False" or owner_control.value == "True" and location.owner in user.groups.all or user.is_superuser %}
|
{% if owner_control.value == "False" or owner_control.value == "True" and user in owners or user.is_superuser %}
|
||||||
{% if roles.stock.add %}
|
{% if roles.stock.add %}
|
||||||
<button class="btn btn-success" id='item-create'>
|
<button class="btn btn-success" id='item-create'>
|
||||||
<span class='fas fa-plus-circle'></span> {% trans "New Stock Item" %}
|
<span class='fas fa-plus-circle'></span> {% trans "New Stock Item" %}
|
||||||
|
@ -3,7 +3,7 @@
|
|||||||
from django.contrib.auth.models import User, Group, Permission
|
from django.contrib.auth.models import User, Group, Permission
|
||||||
from django.contrib.contenttypes.fields import GenericForeignKey
|
from django.contrib.contenttypes.fields import GenericForeignKey
|
||||||
from django.contrib.contenttypes.models import ContentType
|
from django.contrib.contenttypes.models import ContentType
|
||||||
from django.db.models import UniqueConstraint
|
from django.db.models import UniqueConstraint, Q
|
||||||
from django.db.utils import IntegrityError
|
from django.db.utils import IntegrityError
|
||||||
from django.db import models
|
from django.db import models
|
||||||
from django.utils.translation import gettext_lazy as _
|
from django.utils.translation import gettext_lazy as _
|
||||||
@ -112,6 +112,7 @@ class RuleSet(models.Model):
|
|||||||
'report_reportasset',
|
'report_reportasset',
|
||||||
'report_testreport',
|
'report_testreport',
|
||||||
'part_partstar',
|
'part_partstar',
|
||||||
|
'users_owner',
|
||||||
|
|
||||||
# Third-party tables
|
# Third-party tables
|
||||||
'error_report_error',
|
'error_report_error',
|
||||||
@ -433,14 +434,23 @@ class Owner(models.Model):
|
|||||||
except IntegrityError:
|
except IntegrityError:
|
||||||
return None
|
return None
|
||||||
|
|
||||||
def get_users(self):
|
def get_users(self, include_group=False):
|
||||||
|
|
||||||
owner_users = None
|
owner_users = None
|
||||||
|
|
||||||
if type(self.owner) is Group:
|
if type(self.owner) is Group:
|
||||||
users = User.objects.filter(groups__name=self.owner.name)
|
users = User.objects.filter(groups__name=self.owner.name)
|
||||||
owner_users = Owner.objects.filter(owner_id__in=users,
|
|
||||||
owner_type=ContentType.objects.get_for_model(User).id)
|
if include_group:
|
||||||
|
query = Q(owner_id__in=users, owner_type=ContentType.objects.get_for_model(User).id) | \
|
||||||
|
Q(owner_id=self.owner.id, owner_type=ContentType.objects.get_for_model(Group).id)
|
||||||
|
else:
|
||||||
|
query = Q(owner_id__in=users, owner_type=ContentType.objects.get_for_model(User).id)
|
||||||
|
|
||||||
|
owner_users = Owner.objects.filter(query)
|
||||||
|
|
||||||
|
elif type(self.owner) is User:
|
||||||
|
owner_users = [self]
|
||||||
|
|
||||||
return owner_users
|
return owner_users
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user