Merge remote-tracking branch 'inventree/master'

This commit is contained in:
Oliver Walters 2020-10-08 14:01:04 +11:00
commit 8ffb7a7ced
8 changed files with 152 additions and 51 deletions

View File

@ -7,6 +7,8 @@ Provides extra global data to all templates.
from InvenTree.status_codes import SalesOrderStatus, PurchaseOrderStatus from InvenTree.status_codes import SalesOrderStatus, PurchaseOrderStatus
from InvenTree.status_codes import BuildStatus, StockStatus from InvenTree.status_codes import BuildStatus, StockStatus
from users.models import RuleSet
def status_codes(request): def status_codes(request):
@ -38,22 +40,31 @@ def user_roles(request):
roles = { roles = {
} }
for group in user.groups.all(): if user.is_superuser:
for rule in group.rule_sets.all(): for ruleset in RuleSet.RULESET_MODELS.keys():
roles[ruleset] = {
'view': True,
'add': True,
'change': True,
'delete': True,
}
else:
for group in user.groups.all():
for rule in group.rule_sets.all():
# Ensure the role name is in the dict # Ensure the role name is in the dict
if rule.name not in roles: if rule.name not in roles:
roles[rule.name] = { roles[rule.name] = {
'view': user.is_superuser, 'view': user.is_superuser,
'add': user.is_superuser, 'add': user.is_superuser,
'change': user.is_superuser, 'change': user.is_superuser,
'delete': user.is_superuser 'delete': user.is_superuser
} }
# Roles are additive across groups # Roles are additive across groups
roles[rule.name]['view'] |= rule.can_view roles[rule.name]['view'] |= rule.can_view
roles[rule.name]['add'] |= rule.can_add roles[rule.name]['add'] |= rule.can_add
roles[rule.name]['change'] |= rule.can_change roles[rule.name]['change'] |= rule.can_change
roles[rule.name]['delete'] |= rule.can_delete roles[rule.name]['delete'] |= rule.can_delete
return {'roles': roles} return {'roles': roles}

View File

@ -11,14 +11,16 @@
<h4>{% trans "Stock Tracking Information" %}</h4> <h4>{% trans "Stock Tracking Information" %}</h4>
<hr> <hr>
<div id='table-toolbar'> {% if roles.stock.change %}
<div id='table-toolbar'>
<div class='btn-group'> <div class='btn-group'>
<button class='btn btn-success' type='button' title='New tracking entry' id='new-entry'>New Entry</button> <button class='btn btn-success' type='button' title='New tracking entry' id='new-entry'>New Entry</button>
</div> </div>
</div> </div>
{% endif %}
<table class='table table-condensed table-striped' id='track-table' data-toolbar='#table-toolbar'> <table class='table table-condensed table-striped' id='track-table' data-toolbar='#table-toolbar'>
</table> </table>
{% endblock %} {% endblock %}
{% block js_ready %} {% block js_ready %}

View File

@ -60,10 +60,17 @@ InvenTree | {% trans "Stock Item" %} - {{ item }}
</h3> </h3>
<hr> <hr>
<h4> <h4>
{% if roles.part.view %}
<a href='{% url "part-detail" item.part.pk %}'>
{% endif %}
{{ item.part.full_name}}
{% if roles.part.view %}
</a>
{% endif %}
{% if item.serialized %} {% if item.serialized %}
<a href='{% url "part-detail" item.part.pk %}'>{{ item.part.full_name}}</a> # {{ item.serial }} # {{ item.serial }}
{% else %} {% else %}
<a href='{% url "part-detail" item.part.pk %}'>{{ item.part.full_name }}</a> &times {% decimal item.quantity %} &times {% decimal item.quantity %}
{% endif %} {% endif %}
{% if user.is_staff and roles.stock.change %} {% if user.is_staff and roles.stock.change %}
<a href="{% url 'admin:stock_stockitem_change' item.pk %}"><span title="{% trans 'Admin view' %}" class='fas fa-user-shield'></span></a> <a href="{% url 'admin:stock_stockitem_change' item.pk %}"><span title="{% trans 'Admin view' %}" class='fas fa-user-shield'></span></a>
@ -82,14 +89,17 @@ InvenTree | {% trans "Stock Item" %} - {{ item }}
<ul class='dropdown-menu' role='menu'> <ul class='dropdown-menu' role='menu'>
<li><a href='#' id='show-qr-code'><span class='fas fa-qrcode'></span> {% trans "Show QR Code" %}</a></li> <li><a href='#' id='show-qr-code'><span class='fas fa-qrcode'></span> {% trans "Show QR Code" %}</a></li>
<li><a href='#' id='print-label'><span class='fas fa-tag'></span> {% trans "Print Label" %}</a></li> <li><a href='#' id='print-label'><span class='fas fa-tag'></span> {% trans "Print Label" %}</a></li>
{% if item.uid %} {% if roles.stock.change %}
<li><a href='#' id='unlink-barcode'><span class='fas fa-unlink'></span> {% trans "Unlink Barcode" %}</a></li> {% if item.uid %}
{% else %} <li><a href='#' id='unlink-barcode'><span class='fas fa-unlink'></span> {% trans "Unlink Barcode" %}</a></li>
<li><a href='#' id='link-barcode'><span class='fas fa-link'></span> {% trans "Link Barcode" %}</a></li> {% else %}
<li><a href='#' id='link-barcode'><span class='fas fa-link'></span> {% trans "Link Barcode" %}</a></li>\
{% endif %}
{% endif %} {% endif %}
</ul> </ul>
</div> </div>
<!-- Stock adjustment menu --> <!-- Stock adjustment menu -->
{% if roles.stock.change %}
<div class='btn-group'> <div class='btn-group'>
<button id='stock-options' 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-options' 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>
<ul class='dropdown-menu' role='menu'> <ul class='dropdown-menu' role='menu'>
@ -117,21 +127,27 @@ InvenTree | {% trans "Stock Item" %} - {{ item }}
{% endif %} {% endif %}
</ul> </ul>
</div> </div>
{% endif %}
<!-- Edit stock item --> <!-- Edit stock item -->
{% if roles.stock.change %}
<div class='btn-group'> <div class='btn-group'>
<button id='stock-edit-actions' title='{% trans "Stock actions" %}' class='btn btn-default dropdown-toggle' type='button' data-toggle='dropdown'><span class='fas fa-tools'></span> <span class='caret'></span></button> <button id='stock-edit-actions' title='{% trans "Stock actions" %}' class='btn btn-default dropdown-toggle' type='button' data-toggle='dropdown'><span class='fas fa-tools'></span> <span class='caret'></span></button>
<ul class='dropdown-menu' role='menu'> <ul class='dropdown-menu' role='menu'>
{% if item.part.has_variants %} {% if item.part.has_variants %}
<li><a href='#' id='stock-convert' title='{% trans "Convert to variant" %}'><span class='fas fa-screwdriver'></span> {% trans "Convert to variant" %}</a></li> <li><a href='#' id='stock-convert' title='{% trans "Convert to variant" %}'><span class='fas fa-screwdriver'></span> {% trans "Convert to variant" %}</a></li>
{% endif %} {% endif %}
{% if roles.stock.add %}
<li><a href='#' id='stock-duplicate' title='{% trans "Duplicate stock item" %}'><span class='fas fa-copy'></span> {% trans "Duplicate stock item" %}</a></li> <li><a href='#' id='stock-duplicate' title='{% trans "Duplicate stock item" %}'><span class='fas fa-copy'></span> {% trans "Duplicate stock item" %}</a></li>
{% endif %}
<li><a href='#' id='stock-edit' title='{% trans "Edit stock item" %}'><span class='fas fa-edit icon-blue'></span> {% trans "Edit stock item" %}</a></li> <li><a href='#' id='stock-edit' title='{% trans "Edit stock item" %}'><span class='fas fa-edit icon-blue'></span> {% trans "Edit stock item" %}</a></li>
{% if item.can_delete or user.is_staff %} {% if user.is_staff or roles.stock.delete %}
<li><a href='#' id='stock-delete' title='{% trans "Delete stock item" %}'><span class='fas fa-trash-alt icon-red'></span> {% trans "Delete stock item" %}</a></li> {% if item.can_delete %}
<li><a href='#' id='stock-delete' title='{% trans "Delete stock item" %}'><span class='fas fa-trash-alt icon-red'></span> {% trans "Delete stock item" %}</a></li>
{% endif %}
{% endif %} {% endif %}
</ul> </ul>
</div> </div>
{% endif %}
<button type='button' class='btn btn-default' id='stock-test-report' title='{% trans "Generate test report" %}'> <button type='button' class='btn btn-default' id='stock-test-report' title='{% trans "Generate test report" %}'>
<span class='fas fa-file-invoice'/> <span class='fas fa-file-invoice'/>
</button> </button>
@ -147,7 +163,13 @@ InvenTree | {% trans "Stock Item" %} - {{ item }}
<td><span class='fas fa-shapes'></span></td> <td><span class='fas fa-shapes'></span></td>
<td>{% trans "Base Part" %}</td> <td>{% trans "Base Part" %}</td>
<td> <td>
<a href="{% url 'part-stock' item.part.id %}">{{ item.part.full_name }} {% if roles.part.view %}
<a href="{% url 'part-stock' item.part.id %}">
{% endif %}
{{ item.part.full_name }}
{% if roles.part.view %}
</a>
{% endif %}
</td> </td>
</tr> </tr>
{% if item.serialized %} {% if item.serialized %}

View File

@ -18,9 +18,11 @@
<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'>
<button class='btn btn-default' id='location-create' title='{% trans "Create new stock location" %}'> {% if roles.stock.add %}
<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'/>
</button> </button>
{% endif %}
<!-- Barcode actions menu --> <!-- Barcode actions menu -->
{% if location %} {% if location %}
<div class='btn-group'> <div class='btn-group'>
@ -31,20 +33,24 @@
<li><a href='#' id='barcode-check-in'><span class='fas fa-arrow-right'></span> {% trans "Check-in Items" %}</a></li> <li><a href='#' id='barcode-check-in'><span class='fas fa-arrow-right'></span> {% trans "Check-in Items" %}</a></li>
</ul> </ul>
</div> </div>
<div class='btn-group'> {% if roles.stock.change %}
<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> <div class='btn-group'>
<ul class='dropdown-menu' role='menu'> <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>
<li><a href='#' id='location-count'><span class='fas fa-clipboard-list'></span> <ul class='dropdown-menu' role='menu'>
{% trans "Count stock" %}</a></li> <li><a href='#' id='location-count'><span class='fas fa-clipboard-list'></span>
</ul> {% trans "Count stock" %}</a></li>
</div> </ul>
<div class='btn-group'> </div>
<button id='location-actions' title='{% trans "Location actions" %}' class='btn btn-default dropdown-toggle' type='button' data-toggle="dropdown"><span class='fas fa-sitemap'></span> <span class='caret'></span></button> <div class='btn-group'>
<ul class='dropdown-menu' role='menu'> <button id='location-actions' title='{% trans "Location actions" %}' class='btn btn-default dropdown-toggle' type='button' data-toggle="dropdown"><span class='fas fa-sitemap'></span> <span class='caret'></span></button>
<li><a href='#' id='location-edit'><span class='fas fa-edit icon-green'></span> {% trans "Edit location" %}</a></li> <ul class='dropdown-menu' role='menu'>
<li><a href='#' id='location-delete'><span class='fas fa-trash-alt icon-red'></span> {% trans "Delete location" %}</a></li> <li><a href='#' id='location-edit'><span class='fas fa-edit icon-green'></span> {% trans "Edit location" %}</a></li>
</ul> {% if roles.stock.delete %}
</div> <li><a href='#' id='location-delete'><span class='fas fa-trash-alt icon-red'></span> {% trans "Delete location" %}</a></li>
{% endif %}
</ul>
</div>
{% endif %}
{% endif %} {% endif %}
</div> </div>
</div> </div>

View File

@ -1,5 +1,6 @@
{% extends "collapse.html" %} {% extends "collapse.html" %}
{% if roles.stock.view %}
{% block collapse_title %} {% block collapse_title %}
Sub-Locations<span class='badge'>{{ children|length }}</span> Sub-Locations<span class='badge'>{{ children|length }}</span>
{% endblock %} {% endblock %}
@ -14,4 +15,5 @@ Sub-Locations<span class='badge'>{{ children|length }}</span>
</li> </li>
{% endfor %} {% endfor %}
</ul> </ul>
{% endblock %} {% endblock %}
{% endif %}

View File

@ -3,6 +3,7 @@
from django.test import TestCase from django.test import TestCase
from django.urls import reverse from django.urls import reverse
from django.contrib.auth import get_user_model from django.contrib.auth import get_user_model
from django.contrib.auth.models import Group
import json import json
@ -23,7 +24,24 @@ class StockViewTestCase(TestCase):
# Create a user # Create a user
User = get_user_model() User = get_user_model()
User.objects.create_user('username', 'user@email.com', 'password') self.user = User.objects.create_user(
username='username',
email='user@email.com',
password='password'
)
# Put the user into a group with the correct permissions
group = Group.objects.create(name='mygroup')
self.user.groups.add(group)
# Give the group *all* the permissions!
for rule in group.rule_sets.all():
rule.can_view = True
rule.can_change = True
rule.can_add = True
rule.can_delete = True
rule.save()
self.client.login(username='username', password='password') self.client.login(username='username', password='password')

View File

@ -17,6 +17,7 @@ from django.utils.translation import ugettext as _
from InvenTree.views import AjaxView from InvenTree.views import AjaxView
from InvenTree.views import AjaxUpdateView, AjaxDeleteView, AjaxCreateView from InvenTree.views import AjaxUpdateView, AjaxDeleteView, AjaxCreateView
from InvenTree.views import QRCodeView from InvenTree.views import QRCodeView
from InvenTree.views import InvenTreeRoleMixin
from InvenTree.forms import ConfirmForm from InvenTree.forms import ConfirmForm
from InvenTree.helpers import str2bool, DownloadFile, GetExportFormats from InvenTree.helpers import str2bool, DownloadFile, GetExportFormats
@ -36,12 +37,13 @@ from .admin import StockItemResource
from . import forms as StockForms from . import forms as StockForms
class StockIndex(ListView): class StockIndex(InvenTreeRoleMixin, ListView):
""" StockIndex view loads all StockLocation and StockItem object """ StockIndex view loads all StockLocation and StockItem object
""" """
model = StockItem model = StockItem
template_name = 'stock/location.html' template_name = 'stock/location.html'
context_obect_name = 'locations' context_obect_name = 'locations'
role_required = 'stock.view'
def get_context_data(self, **kwargs): def get_context_data(self, **kwargs):
context = super(StockIndex, self).get_context_data(**kwargs).copy() context = super(StockIndex, self).get_context_data(**kwargs).copy()
@ -58,7 +60,7 @@ class StockIndex(ListView):
return context return context
class StockLocationDetail(DetailView): class StockLocationDetail(InvenTreeRoleMixin, DetailView):
""" """
Detailed view of a single StockLocation object Detailed view of a single StockLocation object
""" """
@ -67,9 +69,10 @@ class StockLocationDetail(DetailView):
template_name = 'stock/location.html' template_name = 'stock/location.html'
queryset = StockLocation.objects.all() queryset = StockLocation.objects.all()
model = StockLocation model = StockLocation
role_required = 'stock.view'
class StockItemDetail(DetailView): class StockItemDetail(InvenTreeRoleMixin, DetailView):
""" """
Detailed view of a single StockItem object Detailed view of a single StockItem object
""" """
@ -78,14 +81,16 @@ class StockItemDetail(DetailView):
template_name = 'stock/item.html' template_name = 'stock/item.html'
queryset = StockItem.objects.all() queryset = StockItem.objects.all()
model = StockItem model = StockItem
role_required = 'stock.view'
class StockItemNotes(UpdateView): class StockItemNotes(InvenTreeRoleMixin, UpdateView):
""" View for editing the 'notes' field of a StockItem object """ """ View for editing the 'notes' field of a StockItem object """
context_object_name = 'item' context_object_name = 'item'
template_name = 'stock/item_notes.html' template_name = 'stock/item_notes.html'
model = StockItem model = StockItem
role_required = 'stock.view'
fields = ['notes'] fields = ['notes']
@ -112,6 +117,7 @@ class StockLocationEdit(AjaxUpdateView):
context_object_name = 'location' context_object_name = 'location'
ajax_template_name = 'modal_form.html' ajax_template_name = 'modal_form.html'
ajax_form_title = _('Edit Stock Location') ajax_form_title = _('Edit Stock Location')
role_required = 'stock.change'
def get_form(self): def get_form(self):
""" Customize form data for StockLocation editing. """ Customize form data for StockLocation editing.
@ -136,6 +142,7 @@ class StockLocationQRCode(QRCodeView):
""" View for displaying a QR code for a StockLocation object """ """ View for displaying a QR code for a StockLocation object """
ajax_form_title = _("Stock Location QR code") ajax_form_title = _("Stock Location QR code")
role_required = 'stock.view'
def get_qr_data(self): def get_qr_data(self):
""" Generate QR code data for the StockLocation """ """ Generate QR code data for the StockLocation """
@ -155,6 +162,7 @@ class StockItemAttachmentCreate(AjaxCreateView):
form_class = StockForms.EditStockItemAttachmentForm form_class = StockForms.EditStockItemAttachmentForm
ajax_form_title = _("Add Stock Item Attachment") ajax_form_title = _("Add Stock Item Attachment")
ajax_template_name = "modal_form.html" ajax_template_name = "modal_form.html"
role_required = 'stock.add'
def post_save(self, **kwargs): def post_save(self, **kwargs):
""" Record the user that uploaded the attachment """ """ Record the user that uploaded the attachment """
@ -199,6 +207,7 @@ class StockItemAttachmentEdit(AjaxUpdateView):
model = StockItemAttachment model = StockItemAttachment
form_class = StockForms.EditStockItemAttachmentForm form_class = StockForms.EditStockItemAttachmentForm
ajax_form_title = _("Edit Stock Item Attachment") ajax_form_title = _("Edit Stock Item Attachment")
role_required = 'stock.change'
def get_form(self): def get_form(self):
@ -217,6 +226,7 @@ class StockItemAttachmentDelete(AjaxDeleteView):
ajax_form_title = _("Delete Stock Item Attachment") ajax_form_title = _("Delete Stock Item Attachment")
ajax_template_name = "attachment_delete.html" ajax_template_name = "attachment_delete.html"
context_object_name = "attachment" context_object_name = "attachment"
role_required = 'stock.delete'
def get_data(self): def get_data(self):
return { return {
@ -233,6 +243,7 @@ class StockItemAssignToCustomer(AjaxUpdateView):
ajax_form_title = _("Assign to Customer") ajax_form_title = _("Assign to Customer")
context_object_name = "item" context_object_name = "item"
form_class = StockForms.AssignStockItemToCustomerForm form_class = StockForms.AssignStockItemToCustomerForm
role_required = 'stock.change'
def post(self, request, *args, **kwargs): def post(self, request, *args, **kwargs):
@ -270,6 +281,7 @@ class StockItemReturnToStock(AjaxUpdateView):
ajax_form_title = _("Return to Stock") ajax_form_title = _("Return to Stock")
context_object_name = "item" context_object_name = "item"
form_class = StockForms.ReturnStockItemForm form_class = StockForms.ReturnStockItemForm
role_required = 'stock.change'
def post(self, request, *args, **kwargs): def post(self, request, *args, **kwargs):
@ -303,6 +315,7 @@ class StockItemSelectLabels(AjaxView):
model = StockItem model = StockItem
ajax_form_title = _('Select Label Template') ajax_form_title = _('Select Label Template')
role_required = 'stock.view'
def get_form(self): def get_form(self):
@ -351,6 +364,8 @@ class StockItemPrintLabels(AjaxView):
label: Valid pk of a StockItemLabel template label: Valid pk of a StockItemLabel template
""" """
role_required = 'stock.view'
def get(self, request, *args, **kwargs): def get(self, request, *args, **kwargs):
label = request.GET.get('label', None) label = request.GET.get('label', None)
@ -387,6 +402,7 @@ class StockItemDeleteTestData(AjaxUpdateView):
model = StockItem model = StockItem
form_class = ConfirmForm form_class = ConfirmForm
ajax_form_title = _("Delete All Test Data") ajax_form_title = _("Delete All Test Data")
role_required = ['stock.change', 'stock.delete']
def get_form(self): def get_form(self):
return ConfirmForm() return ConfirmForm()
@ -422,6 +438,7 @@ class StockItemTestResultCreate(AjaxCreateView):
model = StockItemTestResult model = StockItemTestResult
form_class = StockForms.EditStockItemTestResultForm form_class = StockForms.EditStockItemTestResultForm
ajax_form_title = _("Add Test Result") ajax_form_title = _("Add Test Result")
role_required = 'stock.add'
def post_save(self, **kwargs): def post_save(self, **kwargs):
""" Record the user that uploaded the test result """ """ Record the user that uploaded the test result """
@ -459,6 +476,7 @@ class StockItemTestResultEdit(AjaxUpdateView):
model = StockItemTestResult model = StockItemTestResult
form_class = StockForms.EditStockItemTestResultForm form_class = StockForms.EditStockItemTestResultForm
ajax_form_title = _("Edit Test Result") ajax_form_title = _("Edit Test Result")
role_required = 'stock.change'
def get_form(self): def get_form(self):
@ -477,6 +495,7 @@ class StockItemTestResultDelete(AjaxDeleteView):
model = StockItemTestResult model = StockItemTestResult
ajax_form_title = _("Delete Test Result") ajax_form_title = _("Delete Test Result")
context_object_name = "result" context_object_name = "result"
role_required = 'stock.delete'
class StockItemTestReportSelect(AjaxView): class StockItemTestReportSelect(AjaxView):
@ -487,6 +506,7 @@ class StockItemTestReportSelect(AjaxView):
model = StockItem model = StockItem
ajax_form_title = _("Select Test Report Template") ajax_form_title = _("Select Test Report Template")
role_required = 'stock.view'
def get_form(self): def get_form(self):
@ -527,6 +547,7 @@ class StockItemTestReportDownload(AjaxView):
template - Valid PK of a TestReport template object template - Valid PK of a TestReport template object
""" """
role_required = 'stock.view'
def get(self, request, *args, **kwargs): def get(self, request, *args, **kwargs):
@ -554,6 +575,7 @@ class StockExportOptions(AjaxView):
model = StockLocation model = StockLocation
ajax_form_title = _('Stock Export Options') ajax_form_title = _('Stock Export Options')
form_class = StockForms.ExportOptionsForm form_class = StockForms.ExportOptionsForm
role_required = 'stock.view'
def post(self, request, *args, **kwargs): def post(self, request, *args, **kwargs):
@ -586,6 +608,7 @@ class StockExport(AjaxView):
""" """
model = StockItem model = StockItem
role_required = 'stock.view'
def get(self, request, *args, **kwargs): def get(self, request, *args, **kwargs):
@ -673,6 +696,7 @@ class StockItemQRCode(QRCodeView):
""" View for displaying a QR code for a StockItem object """ """ View for displaying a QR code for a StockItem object """
ajax_form_title = _("Stock Item QR Code") ajax_form_title = _("Stock Item QR Code")
role_required = 'stock.view'
def get_qr_data(self): def get_qr_data(self):
""" Generate QR code data for the StockItem """ """ Generate QR code data for the StockItem """
@ -699,6 +723,7 @@ class StockItemInstall(AjaxUpdateView):
form_class = StockForms.InstallStockForm form_class = StockForms.InstallStockForm
ajax_form_title = _('Install Stock Item') ajax_form_title = _('Install Stock Item')
ajax_template_name = "stock/item_install.html" ajax_template_name = "stock/item_install.html"
role_required = 'stock.change'
part = None part = None
@ -798,6 +823,7 @@ class StockItemUninstall(AjaxView, FormMixin):
ajax_template_name = 'stock/stock_uninstall.html' ajax_template_name = 'stock/stock_uninstall.html'
ajax_form_title = _('Uninstall Stock Items') ajax_form_title = _('Uninstall Stock Items')
form_class = StockForms.UninstallStockForm form_class = StockForms.UninstallStockForm
role_required = 'stock.change'
# List of stock items to uninstall (initially empty) # List of stock items to uninstall (initially empty)
stock_items = [] stock_items = []
@ -931,6 +957,7 @@ class StockAdjust(AjaxView, FormMixin):
ajax_form_title = _('Adjust Stock') ajax_form_title = _('Adjust Stock')
form_class = StockForms.AdjustStockForm form_class = StockForms.AdjustStockForm
stock_items = [] stock_items = []
role_required = 'stock.change'
def get_GET_items(self): def get_GET_items(self):
""" Return list of stock items initally requested using GET. """ Return list of stock items initally requested using GET.
@ -1251,6 +1278,7 @@ class StockItemEdit(AjaxUpdateView):
context_object_name = 'item' context_object_name = 'item'
ajax_template_name = 'modal_form.html' ajax_template_name = 'modal_form.html'
ajax_form_title = _('Edit Stock Item') ajax_form_title = _('Edit Stock Item')
role_required = 'stock.change'
def get_form(self): def get_form(self):
""" Get form for StockItem editing. """ Get form for StockItem editing.
@ -1287,6 +1315,7 @@ class StockItemConvert(AjaxUpdateView):
ajax_form_title = _('Convert Stock Item') ajax_form_title = _('Convert Stock Item')
ajax_template_name = 'stock/stockitem_convert.html' ajax_template_name = 'stock/stockitem_convert.html'
context_object_name = 'item' context_object_name = 'item'
role_required = 'stock.change'
def get_form(self): def get_form(self):
""" """
@ -1312,6 +1341,7 @@ class StockLocationCreate(AjaxCreateView):
context_object_name = 'location' context_object_name = 'location'
ajax_template_name = 'modal_form.html' ajax_template_name = 'modal_form.html'
ajax_form_title = _('Create new Stock Location') ajax_form_title = _('Create new Stock Location')
role_required = 'stock.add'
def get_initial(self): def get_initial(self):
initials = super(StockLocationCreate, self).get_initial().copy() initials = super(StockLocationCreate, self).get_initial().copy()
@ -1334,6 +1364,7 @@ class StockItemSerialize(AjaxUpdateView):
ajax_template_name = 'stock/item_serialize.html' ajax_template_name = 'stock/item_serialize.html'
ajax_form_title = _('Serialize Stock') ajax_form_title = _('Serialize Stock')
form_class = StockForms.SerializeStockForm form_class = StockForms.SerializeStockForm
role_required = 'stock.change'
def get_form(self): def get_form(self):
@ -1426,6 +1457,7 @@ class StockItemCreate(AjaxCreateView):
context_object_name = 'item' context_object_name = 'item'
ajax_template_name = 'modal_form.html' ajax_template_name = 'modal_form.html'
ajax_form_title = _('Create new Stock Item') ajax_form_title = _('Create new Stock Item')
role_required = 'stock.add'
def get_part(self, form=None): def get_part(self, form=None):
""" """
@ -1701,6 +1733,7 @@ class StockLocationDelete(AjaxDeleteView):
ajax_template_name = 'stock/location_delete.html' ajax_template_name = 'stock/location_delete.html'
context_object_name = 'location' context_object_name = 'location'
ajax_form_title = _('Delete Stock Location') ajax_form_title = _('Delete Stock Location')
role_required = 'stock.delete'
class StockItemDelete(AjaxDeleteView): class StockItemDelete(AjaxDeleteView):
@ -1714,6 +1747,7 @@ class StockItemDelete(AjaxDeleteView):
ajax_template_name = 'stock/item_delete.html' ajax_template_name = 'stock/item_delete.html'
context_object_name = 'item' context_object_name = 'item'
ajax_form_title = _('Delete Stock Item') ajax_form_title = _('Delete Stock Item')
role_required = 'stock.delete'
class StockItemTrackingDelete(AjaxDeleteView): class StockItemTrackingDelete(AjaxDeleteView):
@ -1725,9 +1759,10 @@ class StockItemTrackingDelete(AjaxDeleteView):
model = StockItemTracking model = StockItemTracking
ajax_template_name = 'stock/tracking_delete.html' ajax_template_name = 'stock/tracking_delete.html'
ajax_form_title = _('Delete Stock Tracking Entry') ajax_form_title = _('Delete Stock Tracking Entry')
role_required = 'stock.delete'
class StockTrackingIndex(ListView): class StockTrackingIndex(InvenTreeRoleMixin, ListView):
""" """
StockTrackingIndex provides a page to display StockItemTracking objects StockTrackingIndex provides a page to display StockItemTracking objects
""" """
@ -1735,6 +1770,7 @@ class StockTrackingIndex(ListView):
model = StockItemTracking model = StockItemTracking
template_name = 'stock/tracking.html' template_name = 'stock/tracking.html'
context_object_name = 'items' context_object_name = 'items'
role_required = 'stock.view'
class StockItemTrackingEdit(AjaxUpdateView): class StockItemTrackingEdit(AjaxUpdateView):
@ -1743,6 +1779,7 @@ class StockItemTrackingEdit(AjaxUpdateView):
model = StockItemTracking model = StockItemTracking
ajax_form_title = _('Edit Stock Tracking Entry') ajax_form_title = _('Edit Stock Tracking Entry')
form_class = StockForms.TrackingEntryForm form_class = StockForms.TrackingEntryForm
role_required = 'stock.change'
class StockItemTrackingCreate(AjaxCreateView): class StockItemTrackingCreate(AjaxCreateView):
@ -1752,6 +1789,7 @@ class StockItemTrackingCreate(AjaxCreateView):
model = StockItemTracking model = StockItemTracking
ajax_form_title = _("Add Stock Tracking Entry") ajax_form_title = _("Add Stock Tracking Entry")
form_class = StockForms.TrackingEntryForm form_class = StockForms.TrackingEntryForm
role_required = 'stock.add'
def post(self, request, *args, **kwargs): def post(self, request, *args, **kwargs):

View File

@ -1,10 +1,12 @@
{% load i18n %} {% load i18n %}
{% if roles.stock.change %}
<div id='attachment-buttons'> <div id='attachment-buttons'>
<div class='btn-group'> <div class='btn-group'>
<button type='button' class='btn btn-success' id='new-attachment'>{% trans "Add Attachment" %}</button> <button type='button' class='btn btn-success' id='new-attachment'>{% trans "Add Attachment" %}</button>
</div> </div>
</div> </div>
{% endif %}
<div class='dropzone' id='attachment-dropzone'> <div class='dropzone' id='attachment-dropzone'>
<table class='table table-striped table-condensed' data-toolbar='#attachment-buttons' id='attachment-table'> <table class='table table-striped table-condensed' data-toolbar='#attachment-buttons' id='attachment-table'>