Merge remote-tracking branch 'inventree/master'

This commit is contained in:
Oliver Walters 2021-03-02 22:08:33 +11:00
commit ab53764c81
9 changed files with 164 additions and 196 deletions

View File

@ -58,8 +58,10 @@ class RolePermission(permissions.BasePermission):
# Extract the model name associated with this request # Extract the model name associated with this request
model = view.serializer_class.Meta.model model = view.serializer_class.Meta.model
# And the specific database table app_label = model._meta.app_label
table = model._meta.db_table model_name = model._meta.model_name
table = f"{app_label}_{model_name}"
except AttributeError: except AttributeError:
# We will assume that if the serializer class does *not* have a Meta, # We will assume that if the serializer class does *not* have a Meta,
# then we don't need a permission # then we don't need a permission

View File

@ -16,7 +16,7 @@ from django.urls import reverse_lazy
from django.contrib.auth.mixins import PermissionRequiredMixin from django.contrib.auth.mixins import PermissionRequiredMixin
from django.views import View from django.views import View
from django.views.generic import UpdateView, CreateView, FormView from django.views.generic import ListView, DetailView, CreateView, FormView, DeleteView, UpdateView
from django.views.generic.base import TemplateView from django.views.generic.base import TemplateView
from part.models import Part, PartCategory from part.models import Part, PartCategory
@ -113,14 +113,39 @@ class InvenTreeRoleMixin(PermissionRequiredMixin):
""" """
Permission class based on user roles, not user 'permissions'. Permission class based on user roles, not user 'permissions'.
To specify which role is required for the mixin, There are a number of ways that the permissions can be specified for a view:
set the class attribute 'role_required' to something like the following:
role_required = 'part.add' 1. Specify the 'role_required' attribute (e.g. part.change)
role_required = [ 2. Specify the 'permission_required' attribute (e.g. part.change_bomitem)
'part.change', (Note: This is the "normal" django-esque way of doing this)
'build.add', 3. Do nothing. The mixin will attempt to "guess" what permission you require:
] a) If there is a queryset associated with the View, we have the model!
b) The *type* of View tells us the permission level (e.g. AjaxUpdateView = change)
c) 1 + 1 = 3
d) Use the combination of model + permission as we would in 2)
1. Specify the 'role_required' attribute
=====================================
To specify which role is required for the mixin,
set the class attribute 'role_required' to something like the following:
role_required = 'part.add'
role_required = [
'part.change',
'build.add',
]
2. Specify the 'permission_required' attribute
===========================================
To specify a particular low-level permission,
set the class attribute 'permission_required' to something like:
permission_required = 'company.delete_company'
3. Do Nothing
==========
See above.
""" """
# By default, no roles are required # By default, no roles are required
@ -132,10 +157,6 @@ class InvenTreeRoleMixin(PermissionRequiredMixin):
Determine if the current user has specified permissions Determine if the current user has specified permissions
""" """
if self.permission_required:
# Ignore role-based permissions
return super().has_permission()
roles_required = [] roles_required = []
if type(self.role_required) is str: if type(self.role_required) is str:
@ -163,9 +184,80 @@ class InvenTreeRoleMixin(PermissionRequiredMixin):
if not check_user_role(user, role, permission): if not check_user_role(user, role, permission):
return False return False
# If a permission_required is specified, use that!
if self.permission_required:
# Ignore role-based permissions
return super().has_permission()
# Ok, so at this point we have not explicitly require a "role" or a "permission"
# Instead, we will use the model to introspect the data we need
model = getattr(self, 'model', None)
if not model:
queryset = getattr(self, 'queryset', None)
if queryset is not None:
model = queryset.model
# We were able to introspect a database model
if model is not None:
app_label = model._meta.app_label
model_name = model._meta.model_name
table = f"{app_label}_{model_name}"
permission = self.get_permission_class()
if not permission:
raise AttributeError(f"permission_class not defined for {type(self).__name__}")
# Check if the user has the required permission
return RuleSet.check_table_permission(user, table, permission)
# We did not fail any required checks # We did not fail any required checks
return True return True
def get_permission_class(self):
"""
Return the 'permission_class' required for the current View.
Must be one of:
- view
- change
- add
- delete
This can either be explicitly defined, by setting the
'permission_class' attribute,
or it can be "guessed" by looking at the type of class
"""
perm = getattr(self, 'permission_class', None)
# Permission is specified by the class itself
if perm:
return perm
# Otherwise, we will need to have a go at guessing...
permission_map = {
AjaxView: 'view',
ListView: 'view',
DetailView: 'view',
UpdateView: 'change',
DeleteView: 'delete',
AjaxUpdateView: 'change',
AjaxCreateView: 'add',
}
for view_class in permission_map.keys():
if issubclass(type(self), view_class):
return permission_map[view_class]
return None
class AjaxMixin(InvenTreeRoleMixin): class AjaxMixin(InvenTreeRoleMixin):
""" AjaxMixin provides basic functionality for rendering a Django form to JSON. """ AjaxMixin provides basic functionality for rendering a Django form to JSON.

View File

@ -28,7 +28,6 @@ class BuildIndex(InvenTreeRoleMixin, ListView):
model = Build model = Build
template_name = 'build/index.html' template_name = 'build/index.html'
context_object_name = 'builds' context_object_name = 'builds'
role_required = 'build.view'
def get_queryset(self): def get_queryset(self):
""" Return all Build objects (order by date, newest first) """ """ Return all Build objects (order by date, newest first) """
@ -58,7 +57,6 @@ class BuildCancel(AjaxUpdateView):
ajax_form_title = _('Cancel Build') ajax_form_title = _('Cancel Build')
context_object_name = 'build' context_object_name = 'build'
form_class = forms.CancelBuildForm form_class = forms.CancelBuildForm
role_required = 'build.change'
def validate(self, build, form, **kwargs): def validate(self, build, form, **kwargs):
@ -92,7 +90,6 @@ class BuildAutoAllocate(AjaxUpdateView):
context_object_name = 'build' context_object_name = 'build'
ajax_form_title = _('Allocate Stock') ajax_form_title = _('Allocate Stock')
ajax_template_name = 'build/auto_allocate.html' ajax_template_name = 'build/auto_allocate.html'
role_required = 'build.change'
def get_initial(self): def get_initial(self):
""" """
@ -181,7 +178,6 @@ class BuildOutputCreate(AjaxUpdateView):
form_class = forms.BuildOutputCreateForm form_class = forms.BuildOutputCreateForm
ajax_template_name = 'build/build_output_create.html' ajax_template_name = 'build/build_output_create.html'
ajax_form_title = _('Create Build Output') ajax_form_title = _('Create Build Output')
role_required = 'build.change'
def validate(self, build, form, **kwargs): def validate(self, build, form, **kwargs):
""" """
@ -280,6 +276,7 @@ class BuildOutputDelete(AjaxUpdateView):
model = Build model = Build
form_class = forms.BuildOutputDeleteForm form_class = forms.BuildOutputDeleteForm
ajax_form_title = _('Delete Build Output') ajax_form_title = _('Delete Build Output')
role_required = 'build.delete' role_required = 'build.delete'
def get_initial(self): def get_initial(self):
@ -340,7 +337,6 @@ class BuildUnallocate(AjaxUpdateView):
form_class = forms.UnallocateBuildForm form_class = forms.UnallocateBuildForm
ajax_form_title = _("Unallocate Stock") ajax_form_title = _("Unallocate Stock")
ajax_template_name = "build/unallocate.html" ajax_template_name = "build/unallocate.html"
role_required = 'build.change'
def get_initial(self): def get_initial(self):
@ -408,7 +404,7 @@ class BuildComplete(AjaxUpdateView):
model = Build model = Build
form_class = forms.CompleteBuildForm form_class = forms.CompleteBuildForm
role_required = 'build.change'
ajax_form_title = _('Complete Build Order') ajax_form_title = _('Complete Build Order')
ajax_template_name = 'build/complete.html' ajax_template_name = 'build/complete.html'
@ -444,7 +440,6 @@ class BuildOutputComplete(AjaxUpdateView):
context_object_name = "build" context_object_name = "build"
ajax_form_title = _("Complete Build Output") ajax_form_title = _("Complete Build Output")
ajax_template_name = "build/complete_output.html" ajax_template_name = "build/complete_output.html"
role_required = 'build.change'
def get_form(self): def get_form(self):
@ -579,13 +574,15 @@ class BuildOutputComplete(AjaxUpdateView):
} }
class BuildNotes(UpdateView): class BuildNotes(InvenTreeRoleMixin, UpdateView):
""" View for editing the 'notes' field of a Build object. """ View for editing the 'notes' field of a Build object.
""" """
context_object_name = 'build' context_object_name = 'build'
template_name = 'build/notes.html' template_name = 'build/notes.html'
model = Build model = Build
# Override the default permission role for this View
role_required = 'build.view' role_required = 'build.view'
fields = ['notes'] fields = ['notes']
@ -602,13 +599,12 @@ class BuildNotes(UpdateView):
return ctx return ctx
class BuildDetail(DetailView): class BuildDetail(InvenTreeRoleMixin, DetailView):
""" Detail view of a single Build object. """ """ Detail view of a single Build object. """
model = Build model = Build
template_name = 'build/detail.html' template_name = 'build/detail.html'
context_object_name = 'build' context_object_name = 'build'
role_required = 'build.view'
def get_context_data(self, **kwargs): def get_context_data(self, **kwargs):
@ -623,12 +619,11 @@ class BuildDetail(DetailView):
return ctx return ctx
class BuildAllocate(DetailView): class BuildAllocate(InvenTreeRoleMixin, DetailView):
""" View for allocating parts to a Build """ """ View for allocating parts to a Build """
model = Build model = Build
context_object_name = 'build' context_object_name = 'build'
template_name = 'build/allocate.html' template_name = 'build/allocate.html'
role_required = ['build.change']
def get_context_data(self, **kwargs): def get_context_data(self, **kwargs):
""" Provide extra context information for the Build allocation page """ """ Provide extra context information for the Build allocation page """
@ -652,13 +647,15 @@ class BuildAllocate(DetailView):
class BuildCreate(AjaxCreateView): class BuildCreate(AjaxCreateView):
""" View to create a new Build object """ """
View to create a new Build object
"""
model = Build model = Build
context_object_name = 'build' context_object_name = 'build'
form_class = forms.EditBuildForm form_class = forms.EditBuildForm
ajax_form_title = _('New Build Order') ajax_form_title = _('New Build Order')
ajax_template_name = 'modal_form.html' ajax_template_name = 'modal_form.html'
role_required = 'build.add'
def get_form(self): def get_form(self):
form = super().get_form() form = super().get_form()
@ -734,7 +731,6 @@ class BuildUpdate(AjaxUpdateView):
context_object_name = 'build' context_object_name = 'build'
ajax_form_title = _('Edit Build Order Details') ajax_form_title = _('Edit Build Order Details')
ajax_template_name = 'modal_form.html' ajax_template_name = 'modal_form.html'
role_required = 'build.change'
def get_form(self): def get_form(self):
@ -776,7 +772,6 @@ class BuildDelete(AjaxDeleteView):
model = Build model = Build
ajax_template_name = 'build/delete_build.html' ajax_template_name = 'build/delete_build.html'
ajax_form_title = _('Delete Build Order') ajax_form_title = _('Delete Build Order')
role_required = 'build.delete'
class BuildItemDelete(AjaxDeleteView): class BuildItemDelete(AjaxDeleteView):
@ -788,7 +783,6 @@ class BuildItemDelete(AjaxDeleteView):
ajax_template_name = 'build/delete_build_item.html' ajax_template_name = 'build/delete_build_item.html'
ajax_form_title = _('Unallocate Stock') ajax_form_title = _('Unallocate Stock')
context_object_name = 'item' context_object_name = 'item'
role_required = 'build.delete'
def get_data(self): def get_data(self):
return { return {
@ -805,7 +799,6 @@ class BuildItemCreate(AjaxCreateView):
form_class = forms.EditBuildItemForm form_class = forms.EditBuildItemForm
ajax_template_name = 'build/create_build_item.html' ajax_template_name = 'build/create_build_item.html'
ajax_form_title = _('Allocate stock to build output') ajax_form_title = _('Allocate stock to build output')
role_required = 'build.add'
# The output StockItem against which the allocation is being made # The output StockItem against which the allocation is being made
output = None output = None
@ -1021,7 +1014,6 @@ class BuildItemEdit(AjaxUpdateView):
ajax_template_name = 'build/edit_build_item.html' ajax_template_name = 'build/edit_build_item.html'
form_class = forms.EditBuildItemForm form_class = forms.EditBuildItemForm
ajax_form_title = _('Edit Stock Allocation') ajax_form_title = _('Edit Stock Allocation')
role_required = 'build.change'
def get_data(self): def get_data(self):
return { return {
@ -1055,7 +1047,6 @@ class BuildAttachmentCreate(AjaxCreateView):
model = BuildOrderAttachment model = BuildOrderAttachment
form_class = forms.EditBuildAttachmentForm form_class = forms.EditBuildAttachmentForm
ajax_form_title = _('Add Build Order Attachment') ajax_form_title = _('Add Build Order Attachment')
role_required = 'build.add'
def save(self, form, **kwargs): def save(self, form, **kwargs):
""" """
@ -1105,7 +1096,6 @@ class BuildAttachmentEdit(AjaxUpdateView):
model = BuildOrderAttachment model = BuildOrderAttachment
form_class = forms.EditBuildAttachmentForm form_class = forms.EditBuildAttachmentForm
ajax_form_title = _('Edit Attachment') ajax_form_title = _('Edit Attachment')
role_required = 'build.change'
def get_form(self): def get_form(self):
form = super().get_form() form = super().get_form()
@ -1127,7 +1117,6 @@ class BuildAttachmentDelete(AjaxDeleteView):
model = BuildOrderAttachment model = BuildOrderAttachment
ajax_form_title = _('Delete Attachment') ajax_form_title = _('Delete Attachment')
context_object_name = 'attachment' context_object_name = 'attachment'
role_required = 'build.delete'
def get_data(self): def get_data(self):
return { return {

View File

@ -269,7 +269,6 @@ class SupplierPartEdit(AjaxUpdateView):
form_class = EditSupplierPartForm form_class = EditSupplierPartForm
ajax_template_name = 'modal_form.html' ajax_template_name = 'modal_form.html'
ajax_form_title = _('Edit Supplier Part') ajax_form_title = _('Edit Supplier Part')
role_required = 'purchase_order.change'
def get_form(self): def get_form(self):
form = super().get_form() form = super().get_form()
@ -294,7 +293,6 @@ class SupplierPartCreate(AjaxCreateView):
ajax_template_name = 'company/supplier_part_create.html' ajax_template_name = 'company/supplier_part_create.html'
ajax_form_title = _('Create new Supplier Part') ajax_form_title = _('Create new Supplier Part')
context_object_name = 'part' context_object_name = 'part'
role_required = 'purchase_order.add'
def validate(self, part, form): def validate(self, part, form):
@ -413,6 +411,7 @@ class SupplierPartDelete(AjaxDeleteView):
success_url = '/supplier/' success_url = '/supplier/'
ajax_template_name = 'company/partdelete.html' ajax_template_name = 'company/partdelete.html'
ajax_form_title = _('Delete Supplier Part') ajax_form_title = _('Delete Supplier Part')
role_required = 'purchase_order.delete' role_required = 'purchase_order.delete'
parts = [] parts = []
@ -485,7 +484,6 @@ class PriceBreakCreate(AjaxCreateView):
form_class = EditPriceBreakForm form_class = EditPriceBreakForm
ajax_form_title = _('Add Price Break') ajax_form_title = _('Add Price Break')
ajax_template_name = 'modal_form.html' ajax_template_name = 'modal_form.html'
role_required = 'purchase_order.add'
def get_data(self): def get_data(self):
return { return {
@ -547,7 +545,6 @@ class PriceBreakEdit(AjaxUpdateView):
form_class = EditPriceBreakForm form_class = EditPriceBreakForm
ajax_form_title = _('Edit Price Break') ajax_form_title = _('Edit Price Break')
ajax_template_name = 'modal_form.html' ajax_template_name = 'modal_form.html'
role_required = 'purchase_order.change'
def get_form(self): def get_form(self):
@ -563,4 +560,3 @@ class PriceBreakDelete(AjaxDeleteView):
model = SupplierPriceBreak model = SupplierPriceBreak
ajax_form_title = _("Delete Price Break") ajax_form_title = _("Delete Price Break")
ajax_template_name = 'modal_delete_form.html' ajax_template_name = 'modal_delete_form.html'
role_required = 'purchase_order.delete'

View File

@ -44,8 +44,6 @@ class PurchaseOrderIndex(InvenTreeRoleMixin, ListView):
template_name = 'order/purchase_orders.html' template_name = 'order/purchase_orders.html'
context_object_name = 'orders' context_object_name = 'orders'
role_required = 'purchase_order.view'
def get_queryset(self): def get_queryset(self):
""" Retrieve the list of purchase orders, """ Retrieve the list of purchase orders,
ensure that the most recent ones are returned first. """ ensure that the most recent ones are returned first. """
@ -65,7 +63,6 @@ class SalesOrderIndex(InvenTreeRoleMixin, ListView):
model = SalesOrder model = SalesOrder
template_name = 'order/sales_orders.html' template_name = 'order/sales_orders.html'
context_object_name = 'orders' context_object_name = 'orders'
role_required = 'sales_order.view'
class PurchaseOrderDetail(InvenTreeRoleMixin, DetailView): class PurchaseOrderDetail(InvenTreeRoleMixin, DetailView):
@ -74,7 +71,6 @@ class PurchaseOrderDetail(InvenTreeRoleMixin, DetailView):
context_object_name = 'order' context_object_name = 'order'
queryset = PurchaseOrder.objects.all().prefetch_related('lines') queryset = PurchaseOrder.objects.all().prefetch_related('lines')
template_name = 'order/purchase_order_detail.html' template_name = 'order/purchase_order_detail.html'
role_required = 'purchase_order.view'
def get_context_data(self, **kwargs): def get_context_data(self, **kwargs):
ctx = super().get_context_data(**kwargs) ctx = super().get_context_data(**kwargs)
@ -88,7 +84,6 @@ class SalesOrderDetail(InvenTreeRoleMixin, DetailView):
context_object_name = 'order' context_object_name = 'order'
queryset = SalesOrder.objects.all().prefetch_related('lines') queryset = SalesOrder.objects.all().prefetch_related('lines')
template_name = 'order/sales_order_detail.html' template_name = 'order/sales_order_detail.html'
role_required = 'sales_order.view'
class PurchaseOrderAttachmentCreate(AjaxCreateView): class PurchaseOrderAttachmentCreate(AjaxCreateView):
@ -100,7 +95,6 @@ class PurchaseOrderAttachmentCreate(AjaxCreateView):
form_class = order_forms.EditPurchaseOrderAttachmentForm form_class = order_forms.EditPurchaseOrderAttachmentForm
ajax_form_title = _("Add Purchase Order Attachment") ajax_form_title = _("Add Purchase Order Attachment")
ajax_template_name = "modal_form.html" ajax_template_name = "modal_form.html"
role_required = 'purchase_order.add'
def save(self, form, **kwargs): def save(self, form, **kwargs):
@ -150,7 +144,6 @@ class SalesOrderAttachmentCreate(AjaxCreateView):
model = SalesOrderAttachment model = SalesOrderAttachment
form_class = order_forms.EditSalesOrderAttachmentForm form_class = order_forms.EditSalesOrderAttachmentForm
ajax_form_title = _('Add Sales Order Attachment') ajax_form_title = _('Add Sales Order Attachment')
role_required = 'sales_order.add'
def save(self, form, **kwargs): def save(self, form, **kwargs):
""" """
@ -191,7 +184,6 @@ class PurchaseOrderAttachmentEdit(AjaxUpdateView):
model = PurchaseOrderAttachment model = PurchaseOrderAttachment
form_class = order_forms.EditPurchaseOrderAttachmentForm form_class = order_forms.EditPurchaseOrderAttachmentForm
ajax_form_title = _("Edit Attachment") ajax_form_title = _("Edit Attachment")
role_required = 'purchase_order.change'
def get_data(self): def get_data(self):
return { return {
@ -213,7 +205,6 @@ class SalesOrderAttachmentEdit(AjaxUpdateView):
model = SalesOrderAttachment model = SalesOrderAttachment
form_class = order_forms.EditSalesOrderAttachmentForm form_class = order_forms.EditSalesOrderAttachmentForm
ajax_form_title = _("Edit Attachment") ajax_form_title = _("Edit Attachment")
role_required = 'sales_order.change'
def get_data(self): def get_data(self):
return { return {
@ -235,7 +226,6 @@ class PurchaseOrderAttachmentDelete(AjaxDeleteView):
ajax_form_title = _("Delete Attachment") ajax_form_title = _("Delete Attachment")
ajax_template_name = "order/delete_attachment.html" ajax_template_name = "order/delete_attachment.html"
context_object_name = "attachment" context_object_name = "attachment"
role_required = 'purchase_order.delete'
def get_data(self): def get_data(self):
return { return {
@ -250,7 +240,6 @@ class SalesOrderAttachmentDelete(AjaxDeleteView):
ajax_form_title = _("Delete Attachment") ajax_form_title = _("Delete Attachment")
ajax_template_name = "order/delete_attachment.html" ajax_template_name = "order/delete_attachment.html"
context_object_name = "attachment" context_object_name = "attachment"
role_required = 'sales_order.delete'
def get_data(self): def get_data(self):
return { return {
@ -264,6 +253,8 @@ class PurchaseOrderNotes(InvenTreeRoleMixin, UpdateView):
context_object_name = 'order' context_object_name = 'order'
template_name = 'order/order_notes.html' template_name = 'order/order_notes.html'
model = PurchaseOrder model = PurchaseOrder
# Override the default permission roles
role_required = 'purchase_order.view' role_required = 'purchase_order.view'
fields = ['notes'] fields = ['notes']
@ -311,7 +302,6 @@ class PurchaseOrderCreate(AjaxCreateView):
model = PurchaseOrder model = PurchaseOrder
ajax_form_title = _("Create Purchase Order") ajax_form_title = _("Create Purchase Order")
form_class = order_forms.EditPurchaseOrderForm form_class = order_forms.EditPurchaseOrderForm
role_required = 'purchase_order.add'
def get_initial(self): def get_initial(self):
initials = super().get_initial().copy() initials = super().get_initial().copy()
@ -347,7 +337,6 @@ class SalesOrderCreate(AjaxCreateView):
model = SalesOrder model = SalesOrder
ajax_form_title = _("Create Sales Order") ajax_form_title = _("Create Sales Order")
form_class = order_forms.EditSalesOrderForm form_class = order_forms.EditSalesOrderForm
role_required = 'sales_order.add'
def get_initial(self): def get_initial(self):
initials = super().get_initial().copy() initials = super().get_initial().copy()
@ -383,7 +372,6 @@ class PurchaseOrderEdit(AjaxUpdateView):
model = PurchaseOrder model = PurchaseOrder
ajax_form_title = _('Edit Purchase Order') ajax_form_title = _('Edit Purchase Order')
form_class = order_forms.EditPurchaseOrderForm form_class = order_forms.EditPurchaseOrderForm
role_required = 'purchase_order.change'
def get_form(self): def get_form(self):
@ -404,7 +392,6 @@ class SalesOrderEdit(AjaxUpdateView):
model = SalesOrder model = SalesOrder
ajax_form_title = _('Edit Sales Order') ajax_form_title = _('Edit Sales Order')
form_class = order_forms.EditSalesOrderForm form_class = order_forms.EditSalesOrderForm
role_required = 'sales_order.change'
def get_form(self): def get_form(self):
form = super().get_form() form = super().get_form()
@ -422,7 +409,6 @@ class PurchaseOrderCancel(AjaxUpdateView):
ajax_form_title = _('Cancel Order') ajax_form_title = _('Cancel Order')
ajax_template_name = 'order/order_cancel.html' ajax_template_name = 'order/order_cancel.html'
form_class = order_forms.CancelPurchaseOrderForm form_class = order_forms.CancelPurchaseOrderForm
role_required = 'purchase_order.change'
def validate(self, order, form, **kwargs): def validate(self, order, form, **kwargs):
@ -449,7 +435,6 @@ class SalesOrderCancel(AjaxUpdateView):
ajax_form_title = _("Cancel sales order") ajax_form_title = _("Cancel sales order")
ajax_template_name = "order/sales_order_cancel.html" ajax_template_name = "order/sales_order_cancel.html"
form_class = order_forms.CancelSalesOrderForm form_class = order_forms.CancelSalesOrderForm
role_required = 'sales_order.change'
def validate(self, order, form, **kwargs): def validate(self, order, form, **kwargs):
@ -476,7 +461,6 @@ class PurchaseOrderIssue(AjaxUpdateView):
ajax_form_title = _('Issue Order') ajax_form_title = _('Issue Order')
ajax_template_name = "order/order_issue.html" ajax_template_name = "order/order_issue.html"
form_class = order_forms.IssuePurchaseOrderForm form_class = order_forms.IssuePurchaseOrderForm
role_required = 'purchase_order.change'
def validate(self, order, form, **kwargs): def validate(self, order, form, **kwargs):
@ -506,7 +490,6 @@ class PurchaseOrderComplete(AjaxUpdateView):
ajax_template_name = "order/order_complete.html" ajax_template_name = "order/order_complete.html"
ajax_form_title = _("Complete Order") ajax_form_title = _("Complete Order")
context_object_name = 'order' context_object_name = 'order'
role_required = 'purchase_order.change'
def get_context_data(self): def get_context_data(self):
@ -543,7 +526,6 @@ class SalesOrderShip(AjaxUpdateView):
context_object_name = 'order' context_object_name = 'order'
ajax_template_name = 'order/sales_order_ship.html' ajax_template_name = 'order/sales_order_ship.html'
ajax_form_title = _('Ship Order') ajax_form_title = _('Ship Order')
role_required = 'sales_order.change'
def post(self, request, *args, **kwargs): def post(self, request, *args, **kwargs):
@ -587,6 +569,8 @@ class PurchaseOrderExport(AjaxView):
""" """
model = PurchaseOrder model = PurchaseOrder
# Specify role as we cannot introspect from "AjaxView"
role_required = 'purchase_order.view' role_required = 'purchase_order.view'
def get(self, request, *args, **kwargs): def get(self, request, *args, **kwargs):
@ -619,6 +603,8 @@ class PurchaseOrderReceive(AjaxUpdateView):
form_class = order_forms.ReceivePurchaseOrderForm form_class = order_forms.ReceivePurchaseOrderForm
ajax_form_title = _("Receive Parts") ajax_form_title = _("Receive Parts")
ajax_template_name = "order/receive_parts.html" ajax_template_name = "order/receive_parts.html"
# Specify role as we do not specify a Model against this view
role_required = 'purchase_order.change' role_required = 'purchase_order.change'
# Where the parts will be going (selected in POST request) # Where the parts will be going (selected in POST request)
@ -1117,7 +1103,6 @@ class POLineItemCreate(AjaxCreateView):
context_object_name = 'line' context_object_name = 'line'
form_class = order_forms.EditPurchaseOrderLineItemForm form_class = order_forms.EditPurchaseOrderLineItemForm
ajax_form_title = _('Add Line Item') ajax_form_title = _('Add Line Item')
role_required = 'purchase_order.add'
def validate(self, item, form, **kwargs): def validate(self, item, form, **kwargs):
@ -1201,7 +1186,6 @@ class SOLineItemCreate(AjaxCreateView):
context_order_name = 'line' context_order_name = 'line'
form_class = order_forms.EditSalesOrderLineItemForm form_class = order_forms.EditSalesOrderLineItemForm
ajax_form_title = _('Add Line Item') ajax_form_title = _('Add Line Item')
role_required = 'sales_order.add'
def get_form(self, *args, **kwargs): def get_form(self, *args, **kwargs):
@ -1253,7 +1237,6 @@ class SOLineItemEdit(AjaxUpdateView):
model = SalesOrderLineItem model = SalesOrderLineItem
form_class = order_forms.EditSalesOrderLineItemForm form_class = order_forms.EditSalesOrderLineItemForm
ajax_form_title = _('Edit Line Item') ajax_form_title = _('Edit Line Item')
role_required = 'sales_order.change'
def get_form(self): def get_form(self):
form = super().get_form() form = super().get_form()
@ -1272,7 +1255,6 @@ class POLineItemEdit(AjaxUpdateView):
form_class = order_forms.EditPurchaseOrderLineItemForm form_class = order_forms.EditPurchaseOrderLineItemForm
ajax_template_name = 'modal_form.html' ajax_template_name = 'modal_form.html'
ajax_form_title = _('Edit Line Item') ajax_form_title = _('Edit Line Item')
role_required = 'purchase_order.change'
def get_form(self): def get_form(self):
form = super().get_form() form = super().get_form()
@ -1290,7 +1272,6 @@ class POLineItemDelete(AjaxDeleteView):
model = PurchaseOrderLineItem model = PurchaseOrderLineItem
ajax_form_title = _('Delete Line Item') ajax_form_title = _('Delete Line Item')
ajax_template_name = 'order/po_lineitem_delete.html' ajax_template_name = 'order/po_lineitem_delete.html'
role_required = 'purchase_order.delete'
def get_data(self): def get_data(self):
return { return {
@ -1303,7 +1284,6 @@ class SOLineItemDelete(AjaxDeleteView):
model = SalesOrderLineItem model = SalesOrderLineItem
ajax_form_title = _("Delete Line Item") ajax_form_title = _("Delete Line Item")
ajax_template_name = "order/so_lineitem_delete.html" ajax_template_name = "order/so_lineitem_delete.html"
role_required = 'sales_order.delete'
def get_data(self): def get_data(self):
return { return {
@ -1317,7 +1297,6 @@ class SalesOrderAllocationCreate(AjaxCreateView):
model = SalesOrderAllocation model = SalesOrderAllocation
form_class = order_forms.EditSalesOrderAllocationForm form_class = order_forms.EditSalesOrderAllocationForm
ajax_form_title = _('Allocate Stock to Order') ajax_form_title = _('Allocate Stock to Order')
role_required = 'sales_order.add'
def get_initial(self): def get_initial(self):
initials = super().get_initial().copy() initials = super().get_initial().copy()
@ -1392,7 +1371,6 @@ class SalesOrderAllocationEdit(AjaxUpdateView):
model = SalesOrderAllocation model = SalesOrderAllocation
form_class = order_forms.EditSalesOrderAllocationForm form_class = order_forms.EditSalesOrderAllocationForm
ajax_form_title = _('Edit Allocation Quantity') ajax_form_title = _('Edit Allocation Quantity')
role_required = 'sales_order.change'
def get_form(self): def get_form(self):
form = super().get_form() form = super().get_form()
@ -1410,4 +1388,3 @@ class SalesOrderAllocationDelete(AjaxDeleteView):
ajax_form_title = _("Remove allocation") ajax_form_title = _("Remove allocation")
context_object_name = 'allocation' context_object_name = 'allocation'
ajax_template_name = "order/so_allocation_delete.html" ajax_template_name = "order/so_allocation_delete.html"
role_required = 'sales_order.delete'

View File

@ -57,8 +57,6 @@ class PartIndex(InvenTreeRoleMixin, ListView):
template_name = 'part/category.html' template_name = 'part/category.html'
context_object_name = 'parts' context_object_name = 'parts'
role_required = 'part.view'
def get_queryset(self): def get_queryset(self):
return Part.objects.all().select_related('category') return Part.objects.all().select_related('category')
@ -85,7 +83,6 @@ class PartRelatedCreate(AjaxCreateView):
form_class = part_forms.CreatePartRelatedForm form_class = part_forms.CreatePartRelatedForm
ajax_form_title = _("Add Related Part") ajax_form_title = _("Add Related Part")
ajax_template_name = "modal_form.html" ajax_template_name = "modal_form.html"
role_required = 'part.change'
def get_initial(self): def get_initial(self):
""" Set parent part as part_1 field """ """ Set parent part as part_1 field """
@ -141,6 +138,8 @@ class PartRelatedDelete(AjaxDeleteView):
model = PartRelated model = PartRelated
ajax_form_title = _("Delete Related Part") ajax_form_title = _("Delete Related Part")
context_object_name = "related" context_object_name = "related"
# Explicit role requirement
role_required = 'part.change' role_required = 'part.change'
@ -154,8 +153,6 @@ class PartAttachmentCreate(AjaxCreateView):
ajax_form_title = _("Add part attachment") ajax_form_title = _("Add part attachment")
ajax_template_name = "modal_form.html" ajax_template_name = "modal_form.html"
role_required = 'part.add'
def save(self, form, **kwargs): def save(self, form, **kwargs):
""" """
Record the user that uploaded this attachment Record the user that uploaded this attachment
@ -208,8 +205,6 @@ class PartAttachmentEdit(AjaxUpdateView):
ajax_template_name = 'modal_form.html' ajax_template_name = 'modal_form.html'
ajax_form_title = _('Edit attachment') ajax_form_title = _('Edit attachment')
role_required = 'part.change'
def get_data(self): def get_data(self):
return { return {
'success': _('Part attachment updated') 'success': _('Part attachment updated')
@ -246,8 +241,6 @@ class PartTestTemplateCreate(AjaxCreateView):
form_class = part_forms.EditPartTestTemplateForm form_class = part_forms.EditPartTestTemplateForm
ajax_form_title = _("Create Test Template") ajax_form_title = _("Create Test Template")
role_required = 'part.add'
def get_initial(self): def get_initial(self):
initials = super().get_initial() initials = super().get_initial()
@ -275,8 +268,6 @@ class PartTestTemplateEdit(AjaxUpdateView):
form_class = part_forms.EditPartTestTemplateForm form_class = part_forms.EditPartTestTemplateForm
ajax_form_title = _("Edit Test Template") ajax_form_title = _("Edit Test Template")
role_required = 'part.change'
def get_form(self): def get_form(self):
form = super().get_form() form = super().get_form()
@ -291,8 +282,6 @@ class PartTestTemplateDelete(AjaxDeleteView):
model = PartTestTemplate model = PartTestTemplate
ajax_form_title = _("Delete Test Template") ajax_form_title = _("Delete Test Template")
role_required = 'part.delete'
class PartSetCategory(AjaxUpdateView): class PartSetCategory(AjaxUpdateView):
""" View for settings the part category for multiple parts at once """ """ View for settings the part category for multiple parts at once """
@ -386,8 +375,6 @@ class MakePartVariant(AjaxCreateView):
ajax_form_title = _('Create Variant') ajax_form_title = _('Create Variant')
ajax_template_name = 'part/variant_part.html' ajax_template_name = 'part/variant_part.html'
role_required = 'part.add'
def get_part_template(self): def get_part_template(self):
return get_object_or_404(Part, id=self.kwargs['pk']) return get_object_or_404(Part, id=self.kwargs['pk'])
@ -468,8 +455,6 @@ class PartDuplicate(AjaxCreateView):
ajax_form_title = _("Duplicate Part") ajax_form_title = _("Duplicate Part")
ajax_template_name = "part/copy_part.html" ajax_template_name = "part/copy_part.html"
role_required = 'part.add'
def get_data(self): def get_data(self):
return { return {
'success': _('Copied part') 'success': _('Copied part')
@ -594,8 +579,6 @@ class PartCreate(AjaxCreateView):
ajax_form_title = _('Create New Part') ajax_form_title = _('Create New Part')
ajax_template_name = 'part/create_part.html' ajax_template_name = 'part/create_part.html'
role_required = 'part.add'
def get_data(self): def get_data(self):
return { return {
'success': _("Created new part"), 'success': _("Created new part"),
@ -772,8 +755,6 @@ class PartDetail(InvenTreeRoleMixin, DetailView):
queryset = Part.objects.all().select_related('category') queryset = Part.objects.all().select_related('category')
template_name = 'part/detail.html' template_name = 'part/detail.html'
role_required = 'part.view'
# Add in some extra context information based on query params # Add in some extra context information based on query params
def get_context_data(self, **kwargs): def get_context_data(self, **kwargs):
""" Provide extra context data to template """ Provide extra context data to template
@ -859,8 +840,6 @@ class PartImageUpload(AjaxUpdateView):
form_class = part_forms.PartImageForm form_class = part_forms.PartImageForm
role_required = 'part.change'
def get_data(self): def get_data(self):
return { return {
'success': _('Updated part image'), 'success': _('Updated part image'),
@ -874,8 +853,6 @@ class PartImageSelect(AjaxUpdateView):
ajax_template_name = 'part/select_image.html' ajax_template_name = 'part/select_image.html'
ajax_form_title = _('Select Part Image') ajax_form_title = _('Select Part Image')
role_required = 'part.change'
fields = [ fields = [
'image', 'image',
] ]
@ -917,8 +894,6 @@ class PartEdit(AjaxUpdateView):
ajax_form_title = _('Edit Part Properties') ajax_form_title = _('Edit Part Properties')
context_object_name = 'part' context_object_name = 'part'
role_required = 'part.change'
def get_form(self): def get_form(self):
""" Create form for Part editing. """ Create form for Part editing.
Overrides default get_form() method to limit the choices Overrides default get_form() method to limit the choices
@ -948,7 +923,6 @@ class BomDuplicate(AjaxUpdateView):
ajax_form_title = _('Duplicate BOM') ajax_form_title = _('Duplicate BOM')
ajax_template_name = 'part/bom_duplicate.html' ajax_template_name = 'part/bom_duplicate.html'
form_class = part_forms.BomDuplicateForm form_class = part_forms.BomDuplicateForm
role_required = 'part.change'
def get_form(self): def get_form(self):
@ -1002,8 +976,6 @@ class BomValidate(AjaxUpdateView):
context_object_name = 'part' context_object_name = 'part'
form_class = part_forms.BomValidateForm form_class = part_forms.BomValidateForm
role_required = 'part.change'
def get_context(self): def get_context(self):
return { return {
'part': self.get_object(), 'part': self.get_object(),
@ -1854,8 +1826,6 @@ class PartDelete(AjaxDeleteView):
ajax_form_title = _('Confirm Part Deletion') ajax_form_title = _('Confirm Part Deletion')
context_object_name = 'part' context_object_name = 'part'
role_required = 'part.delete'
success_url = '/part/' success_url = '/part/'
def get_data(self): def get_data(self):
@ -1977,9 +1947,9 @@ class PartPricing(AjaxView):
class PartParameterTemplateCreate(AjaxCreateView): class PartParameterTemplateCreate(AjaxCreateView):
""" View for creating a new PartParameterTemplate """ """
View for creating a new PartParameterTemplate
role_required = 'part.add' """
model = PartParameterTemplate model = PartParameterTemplate
form_class = part_forms.EditPartParameterTemplateForm form_class = part_forms.EditPartParameterTemplateForm
@ -1987,9 +1957,9 @@ class PartParameterTemplateCreate(AjaxCreateView):
class PartParameterTemplateEdit(AjaxUpdateView): class PartParameterTemplateEdit(AjaxUpdateView):
""" View for editing a PartParameterTemplate """ """
View for editing a PartParameterTemplate
role_required = 'part.change' """
model = PartParameterTemplate model = PartParameterTemplate
form_class = part_forms.EditPartParameterTemplateForm form_class = part_forms.EditPartParameterTemplateForm
@ -1999,8 +1969,6 @@ class PartParameterTemplateEdit(AjaxUpdateView):
class PartParameterTemplateDelete(AjaxDeleteView): class PartParameterTemplateDelete(AjaxDeleteView):
""" View for deleting an existing PartParameterTemplate """ """ View for deleting an existing PartParameterTemplate """
role_required = 'part.delete'
model = PartParameterTemplate model = PartParameterTemplate
ajax_form_title = _("Delete Part Parameter Template") ajax_form_title = _("Delete Part Parameter Template")
@ -2008,8 +1976,6 @@ class PartParameterTemplateDelete(AjaxDeleteView):
class PartParameterCreate(AjaxCreateView): class PartParameterCreate(AjaxCreateView):
""" View for creating a new PartParameter """ """ View for creating a new PartParameter """
role_required = 'part.add'
model = PartParameter model = PartParameter
form_class = part_forms.EditPartParameterForm form_class = part_forms.EditPartParameterForm
ajax_form_title = _('Create Part Parameter') ajax_form_title = _('Create Part Parameter')
@ -2060,8 +2026,6 @@ class PartParameterCreate(AjaxCreateView):
class PartParameterEdit(AjaxUpdateView): class PartParameterEdit(AjaxUpdateView):
""" View for editing a PartParameter """ """ View for editing a PartParameter """
role_required = 'part.change'
model = PartParameter model = PartParameter
form_class = part_forms.EditPartParameterForm form_class = part_forms.EditPartParameterForm
ajax_form_title = _('Edit Part Parameter') ajax_form_title = _('Edit Part Parameter')
@ -2076,8 +2040,6 @@ class PartParameterEdit(AjaxUpdateView):
class PartParameterDelete(AjaxDeleteView): class PartParameterDelete(AjaxDeleteView):
""" View for deleting a PartParameter """ """ View for deleting a PartParameter """
role_required = 'part.change'
model = PartParameter model = PartParameter
ajax_template_name = 'part/param_delete.html' ajax_template_name = 'part/param_delete.html'
ajax_form_title = _('Delete Part Parameter') ajax_form_title = _('Delete Part Parameter')
@ -2091,8 +2053,6 @@ class CategoryDetail(InvenTreeRoleMixin, DetailView):
queryset = PartCategory.objects.all().prefetch_related('children') queryset = PartCategory.objects.all().prefetch_related('children')
template_name = 'part/category_partlist.html' template_name = 'part/category_partlist.html'
role_required = ['part_category.view', 'part.view']
def get_context_data(self, **kwargs): def get_context_data(self, **kwargs):
context = super(CategoryDetail, self).get_context_data(**kwargs).copy() context = super(CategoryDetail, self).get_context_data(**kwargs).copy()
@ -2135,14 +2095,15 @@ class CategoryParametric(CategoryDetail):
class CategoryEdit(AjaxUpdateView): class CategoryEdit(AjaxUpdateView):
""" Update view to edit a PartCategory """ """
Update view to edit a PartCategory
"""
model = PartCategory model = PartCategory
form_class = part_forms.EditCategoryForm form_class = part_forms.EditCategoryForm
ajax_template_name = 'modal_form.html' ajax_template_name = 'modal_form.html'
ajax_form_title = _('Edit Part Category') ajax_form_title = _('Edit Part Category')
role_required = 'part_category.change'
def get_context_data(self, **kwargs): def get_context_data(self, **kwargs):
context = super(CategoryEdit, self).get_context_data(**kwargs).copy() context = super(CategoryEdit, self).get_context_data(**kwargs).copy()
@ -2173,15 +2134,16 @@ class CategoryEdit(AjaxUpdateView):
class CategoryDelete(AjaxDeleteView): class CategoryDelete(AjaxDeleteView):
""" Delete view to delete a PartCategory """ """
Delete view to delete a PartCategory
"""
model = PartCategory model = PartCategory
ajax_template_name = 'part/category_delete.html' ajax_template_name = 'part/category_delete.html'
ajax_form_title = _('Delete Part Category') ajax_form_title = _('Delete Part Category')
context_object_name = 'category' context_object_name = 'category'
success_url = '/part/' success_url = '/part/'
role_required = 'part_category.delete'
def get_data(self): def get_data(self):
return { return {
'danger': _('Part category was deleted'), 'danger': _('Part category was deleted'),
@ -2196,8 +2158,6 @@ class CategoryCreate(AjaxCreateView):
ajax_template_name = 'modal_form.html' ajax_template_name = 'modal_form.html'
form_class = part_forms.EditCategoryForm form_class = part_forms.EditCategoryForm
role_required = 'part_category.add'
def get_context_data(self, **kwargs): def get_context_data(self, **kwargs):
""" Add extra context data to template. """ Add extra context data to template.
@ -2236,8 +2196,6 @@ class CategoryCreate(AjaxCreateView):
class CategoryParameterTemplateCreate(AjaxCreateView): class CategoryParameterTemplateCreate(AjaxCreateView):
""" View for creating a new PartCategoryParameterTemplate """ """ View for creating a new PartCategoryParameterTemplate """
role_required = 'part_category.change'
model = PartCategoryParameterTemplate model = PartCategoryParameterTemplate
form_class = part_forms.EditCategoryParameterTemplateForm form_class = part_forms.EditCategoryParameterTemplateForm
ajax_form_title = _('Create Category Parameter Template') ajax_form_title = _('Create Category Parameter Template')
@ -2339,8 +2297,6 @@ class CategoryParameterTemplateCreate(AjaxCreateView):
class CategoryParameterTemplateEdit(AjaxUpdateView): class CategoryParameterTemplateEdit(AjaxUpdateView):
""" View for editing a PartCategoryParameterTemplate """ """ View for editing a PartCategoryParameterTemplate """
role_required = 'part_category.change'
model = PartCategoryParameterTemplate model = PartCategoryParameterTemplate
form_class = part_forms.EditCategoryParameterTemplateForm form_class = part_forms.EditCategoryParameterTemplateForm
ajax_form_title = _('Edit Category Parameter Template') ajax_form_title = _('Edit Category Parameter Template')
@ -2398,8 +2354,6 @@ class CategoryParameterTemplateEdit(AjaxUpdateView):
class CategoryParameterTemplateDelete(AjaxDeleteView): class CategoryParameterTemplateDelete(AjaxDeleteView):
""" View for deleting an existing PartCategoryParameterTemplate """ """ View for deleting an existing PartCategoryParameterTemplate """
role_required = 'part_category.change'
model = PartCategoryParameterTemplate model = PartCategoryParameterTemplate
ajax_form_title = _("Delete Category Parameter Template") ajax_form_title = _("Delete Category Parameter Template")
@ -2413,14 +2367,15 @@ class CategoryParameterTemplateDelete(AjaxDeleteView):
class BomItemCreate(AjaxCreateView): class BomItemCreate(AjaxCreateView):
""" Create view for making a new BomItem object """ """
Create view for making a new BomItem object
"""
model = BomItem model = BomItem
form_class = part_forms.EditBomItemForm form_class = part_forms.EditBomItemForm
ajax_template_name = 'modal_form.html' ajax_template_name = 'modal_form.html'
ajax_form_title = _('Create BOM Item') ajax_form_title = _('Create BOM Item')
role_required = 'part.add'
def get_form(self): def get_form(self):
""" Override get_form() method to reduce Part selection options. """ Override get_form() method to reduce Part selection options.
@ -2491,8 +2446,6 @@ class BomItemEdit(AjaxUpdateView):
ajax_template_name = 'modal_form.html' ajax_template_name = 'modal_form.html'
ajax_form_title = _('Edit BOM item') ajax_form_title = _('Edit BOM item')
role_required = 'part.change'
def get_form(self): def get_form(self):
""" Override get_form() method to filter part selection options """ Override get_form() method to filter part selection options
@ -2543,13 +2496,12 @@ class BomItemEdit(AjaxUpdateView):
class BomItemDelete(AjaxDeleteView): class BomItemDelete(AjaxDeleteView):
""" Delete view for removing BomItem """ """ Delete view for removing BomItem """
model = BomItem model = BomItem
ajax_template_name = 'part/bom-delete.html' ajax_template_name = 'part/bom-delete.html'
context_object_name = 'item' context_object_name = 'item'
ajax_form_title = _('Confim BOM item deletion') ajax_form_title = _('Confim BOM item deletion')
role_required = 'part.change'
class PartSalePriceBreakCreate(AjaxCreateView): class PartSalePriceBreakCreate(AjaxCreateView):
""" View for creating a sale price break for a part """ """ View for creating a sale price break for a part """
@ -2558,8 +2510,6 @@ class PartSalePriceBreakCreate(AjaxCreateView):
form_class = part_forms.EditPartSalePriceBreakForm form_class = part_forms.EditPartSalePriceBreakForm
ajax_form_title = _('Add Price Break') ajax_form_title = _('Add Price Break')
role_required = 'part.add'
def get_data(self): def get_data(self):
return { return {
'success': _('Added new price break') 'success': _('Added new price break')
@ -2608,8 +2558,6 @@ class PartSalePriceBreakEdit(AjaxUpdateView):
form_class = part_forms.EditPartSalePriceBreakForm form_class = part_forms.EditPartSalePriceBreakForm
ajax_form_title = _('Edit Price Break') ajax_form_title = _('Edit Price Break')
role_required = 'part.change'
def get_form(self): def get_form(self):
form = super().get_form() form = super().get_form()
@ -2624,5 +2572,3 @@ class PartSalePriceBreakDelete(AjaxDeleteView):
model = PartSellPriceBreak model = PartSellPriceBreak
ajax_form_title = _("Delete Price Break") ajax_form_title = _("Delete Price Break")
ajax_template_name = "modal_delete_form.html" ajax_template_name = "modal_delete_form.html"
role_required = 'part.delete'

View File

@ -45,9 +45,6 @@ stock_tracking_urls = [
# delete # delete
url(r'^(?P<pk>\d+)/delete', views.StockItemTrackingDelete.as_view(), name='stock-tracking-delete'), url(r'^(?P<pk>\d+)/delete', views.StockItemTrackingDelete.as_view(), name='stock-tracking-delete'),
# list
url('^.*$', views.StockTrackingIndex.as_view(), name='stock-tracking-list')
] ]
stock_urls = [ stock_urls = [

View File

@ -49,7 +49,6 @@ class StockIndex(InvenTreeRoleMixin, ListView):
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()
@ -75,7 +74,6 @@ class StockLocationDetail(InvenTreeRoleMixin, 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_location.view', 'stock.view']
class StockItemDetail(InvenTreeRoleMixin, DetailView): class StockItemDetail(InvenTreeRoleMixin, DetailView):
@ -87,7 +85,6 @@ class StockItemDetail(InvenTreeRoleMixin, 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(InvenTreeRoleMixin, UpdateView): class StockItemNotes(InvenTreeRoleMixin, UpdateView):
@ -96,6 +93,7 @@ class StockItemNotes(InvenTreeRoleMixin, UpdateView):
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' role_required = 'stock.view'
fields = ['notes'] fields = ['notes']
@ -123,7 +121,6 @@ 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_location.change'
def get_form(self): def get_form(self):
""" Customize form data for StockLocation editing. """ Customize form data for StockLocation editing.
@ -246,6 +243,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_location.view', 'stock.view'] role_required = ['stock_location.view', 'stock.view']
def get_qr_data(self): def get_qr_data(self):
@ -266,7 +264,6 @@ 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 save(self, form, **kwargs): def save(self, form, **kwargs):
""" Record the user that uploaded the attachment """ """ Record the user that uploaded the attachment """
@ -312,7 +309,6 @@ 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):
@ -331,7 +327,6 @@ 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 {
@ -348,7 +343,6 @@ 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 validate(self, item, form, **kwargs): def validate(self, item, form, **kwargs):
@ -382,7 +376,6 @@ 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 validate(self, item, form, **kwargs): def validate(self, item, form, **kwargs):
@ -412,6 +405,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'] role_required = ['stock.change', 'stock.delete']
def get_form(self): def get_form(self):
@ -448,7 +442,6 @@ 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 save(self, form, **kwargs): def save(self, form, **kwargs):
""" """
@ -489,7 +482,6 @@ 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):
@ -508,7 +500,6 @@ 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 StockExportOptions(AjaxView): class StockExportOptions(AjaxView):
@ -517,7 +508,6 @@ 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):
@ -665,7 +655,6 @@ 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
@ -1232,7 +1221,6 @@ 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.
@ -1343,7 +1331,6 @@ 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):
""" """
@ -1369,7 +1356,6 @@ 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_location.add'
def get_initial(self): def get_initial(self):
initials = super(StockLocationCreate, self).get_initial().copy() initials = super(StockLocationCreate, self).get_initial().copy()
@ -1462,7 +1448,6 @@ 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):
@ -1555,7 +1540,6 @@ 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):
""" """
@ -1880,7 +1864,6 @@ 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_location.delete'
class StockItemDelete(AjaxDeleteView): class StockItemDelete(AjaxDeleteView):
@ -1894,7 +1877,6 @@ 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):
@ -1906,18 +1888,6 @@ 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(InvenTreeRoleMixin, ListView):
"""
StockTrackingIndex provides a page to display StockItemTracking objects
"""
model = StockItemTracking
template_name = 'stock/tracking.html'
context_object_name = 'items'
role_required = 'stock.view'
class StockItemTrackingEdit(AjaxUpdateView): class StockItemTrackingEdit(AjaxUpdateView):
@ -1926,7 +1896,6 @@ 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):
@ -1936,7 +1905,6 @@ 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

@ -68,6 +68,7 @@ class RuleSet(models.Model):
'part_partparameter', 'part_partparameter',
'part_partrelated', 'part_partrelated',
'part_partstar', 'part_partstar',
'company_supplierpart',
], ],
'stock_location': [ 'stock_location': [
'stock_stocklocation', 'stock_stocklocation',
@ -94,11 +95,11 @@ class RuleSet(models.Model):
], ],
'purchase_order': [ 'purchase_order': [
'company_company', 'company_company',
'company_supplierpart',
'company_supplierpricebreak', 'company_supplierpricebreak',
'order_purchaseorder', 'order_purchaseorder',
'order_purchaseorderattachment', 'order_purchaseorderattachment',
'order_purchaseorderlineitem', 'order_purchaseorderlineitem',
'company_supplierpart',
], ],
'sales_order': [ 'sales_order': [
'company_company', 'company_company',
@ -342,7 +343,7 @@ def update_group_roles(group, debug=False):
content_type = ContentType.objects.get(app_label=app, model=model) content_type = ContentType.objects.get(app_label=app, model=model)
permission = Permission.objects.get(content_type=content_type, codename=perm) permission = Permission.objects.get(content_type=content_type, codename=perm)
except ContentType.DoesNotExist: except ContentType.DoesNotExist:
print(f"Error: Could not find permission matching '{permission_string}'") raise ValueError(f"Error: Could not find permission matching '{permission_string}'")
permission = None permission = None
return permission return permission