mirror of
https://github.com/inventree/InvenTree
synced 2024-08-30 18:33:04 +00:00
Merge pull request #1029 from SchrodingersGat/sales-order-permissions
Sales order permissions
This commit is contained in:
commit
279b50d977
@ -22,7 +22,7 @@ from django.views.generic.base import TemplateView
|
||||
from part.models import Part, PartCategory
|
||||
from stock.models import StockLocation, StockItem
|
||||
from common.models import InvenTreeSetting, ColorTheme
|
||||
from users.models import check_user_role
|
||||
from users.models import check_user_role, RuleSet
|
||||
|
||||
from .forms import DeleteForm, EditUserForm, SetPasswordForm, ColorThemeSelectForm
|
||||
from .helpers import str2bool
|
||||
@ -147,7 +147,13 @@ class InvenTreeRoleMixin(PermissionRequiredMixin):
|
||||
for required in roles_required:
|
||||
|
||||
(role, permission) = required.split('.')
|
||||
|
||||
if role not in RuleSet.RULESET_NAMES:
|
||||
raise ValueError(f"Role '{role}' is not a valid role")
|
||||
|
||||
if permission not in RuleSet.RULESET_PERMISSIONS:
|
||||
raise ValueError(f"Permission '{permission}' is not a valid permission")
|
||||
|
||||
# Return False if the user does not have *any* of the required roles
|
||||
if not check_user_role(user, role, permission):
|
||||
return False
|
||||
|
@ -41,19 +41,21 @@ src="{% static 'img/blank_image.png' %}"
|
||||
</h4>
|
||||
<div class='btn-row'>
|
||||
<div class='btn-group action-buttons'>
|
||||
<button type='button' class='btn btn-default' id='build-edit' title='Edit Build'>
|
||||
{% if roles.build.change %}
|
||||
<button type='button' class='btn btn-default' id='build-edit' title='{% trans "Edit Build" %}'>
|
||||
<span class='fas fa-edit icon-green'/>
|
||||
</button>
|
||||
{% if build.is_active %}
|
||||
<button type='button' class='btn btn-default' id='build-complete' title="Complete Build">
|
||||
<button type='button' class='btn btn-default' id='build-complete' title='{% trans "Complete Build" %}'>
|
||||
<span class='fas fa-tools'/>
|
||||
</button>
|
||||
<button type='button' class='btn btn-default btn-glyph' id='build-cancel' title='Cancel Build'>
|
||||
<button type='button' class='btn btn-default btn-glyph' id='build-cancel' title='{% trans "Cancel Build" %}'>
|
||||
<span class='fas fa-times-circle icon-red'/>
|
||||
</button>
|
||||
{% endif %}
|
||||
{% if build.status == BuildStatus.CANCELLED %}
|
||||
<button type='button' class='btn btn-default btn-glyph' id='build-delete' title='Delete Build'>
|
||||
{% endif %}
|
||||
{% if build.status == BuildStatus.CANCELLED and roles.build.delete %}
|
||||
<button type='button' class='btn btn-default btn-glyph' id='build-delete' title='{% trans "Delete Build" %}'>
|
||||
<span class='fas fa-trash-alt icon-red'/>
|
||||
</button>
|
||||
{% endif %}
|
||||
|
@ -4,6 +4,7 @@ from __future__ import unicode_literals
|
||||
from django.test import TestCase
|
||||
from django.urls import reverse
|
||||
from django.contrib.auth import get_user_model
|
||||
from django.contrib.auth.models import Group
|
||||
|
||||
from rest_framework.test import APITestCase
|
||||
from rest_framework import status
|
||||
@ -30,6 +31,20 @@ class BuildTestSimple(TestCase):
|
||||
User.objects.create_user('testuser', 'test@testing.com', 'password')
|
||||
|
||||
self.user = User.objects.get(username='testuser')
|
||||
|
||||
g = Group.objects.create(name='builders')
|
||||
self.user.groups.add(g)
|
||||
|
||||
for rule in g.rule_sets.all():
|
||||
if rule.name == 'build':
|
||||
rule.can_change = True
|
||||
rule.can_add = True
|
||||
rule.can_delete = True
|
||||
|
||||
rule.save()
|
||||
|
||||
g.save()
|
||||
|
||||
self.client.login(username='testuser', password='password')
|
||||
|
||||
def test_build_objects(self):
|
||||
@ -94,7 +109,20 @@ class TestBuildAPI(APITestCase):
|
||||
def setUp(self):
|
||||
# Create a user for auth
|
||||
User = get_user_model()
|
||||
User.objects.create_user('testuser', 'test@testing.com', 'password')
|
||||
user = User.objects.create_user('testuser', 'test@testing.com', 'password')
|
||||
|
||||
g = Group.objects.create(name='builders')
|
||||
user.groups.add(g)
|
||||
|
||||
for rule in g.rule_sets.all():
|
||||
if rule.name == 'build':
|
||||
rule.can_change = True
|
||||
rule.can_add = True
|
||||
rule.can_delete = True
|
||||
|
||||
rule.save()
|
||||
|
||||
g.save()
|
||||
|
||||
self.client.login(username='testuser', password='password')
|
||||
|
||||
@ -131,7 +159,20 @@ class TestBuildViews(TestCase):
|
||||
|
||||
# Create a user
|
||||
User = get_user_model()
|
||||
User.objects.create_user('username', 'user@email.com', 'password')
|
||||
user = User.objects.create_user('username', 'user@email.com', 'password')
|
||||
|
||||
g = Group.objects.create(name='builders')
|
||||
user.groups.add(g)
|
||||
|
||||
for rule in g.rule_sets.all():
|
||||
if rule.name == 'build':
|
||||
rule.can_change = True
|
||||
rule.can_add = True
|
||||
rule.can_delete = True
|
||||
|
||||
rule.save()
|
||||
|
||||
g.save()
|
||||
|
||||
self.client.login(username='username', password='password')
|
||||
|
||||
|
@ -17,16 +17,18 @@ from . import forms
|
||||
from stock.models import StockLocation, StockItem
|
||||
|
||||
from InvenTree.views import AjaxUpdateView, AjaxCreateView, AjaxDeleteView
|
||||
from InvenTree.views import InvenTreeRoleMixin
|
||||
from InvenTree.helpers import str2bool, ExtractSerialNumbers
|
||||
from InvenTree.status_codes import BuildStatus
|
||||
|
||||
|
||||
class BuildIndex(ListView):
|
||||
class BuildIndex(InvenTreeRoleMixin, ListView):
|
||||
""" View for displaying list of Builds
|
||||
"""
|
||||
model = Build
|
||||
template_name = 'build/index.html'
|
||||
context_object_name = 'builds'
|
||||
role_required = 'build.view'
|
||||
|
||||
def get_queryset(self):
|
||||
""" Return all Build objects (order by date, newest first) """
|
||||
@ -56,6 +58,7 @@ class BuildCancel(AjaxUpdateView):
|
||||
ajax_form_title = _('Cancel Build')
|
||||
context_object_name = 'build'
|
||||
form_class = forms.CancelBuildForm
|
||||
role_required = 'build.change'
|
||||
|
||||
def post(self, request, *args, **kwargs):
|
||||
""" Handle POST request. Mark the build status as CANCELLED """
|
||||
@ -94,6 +97,7 @@ class BuildAutoAllocate(AjaxUpdateView):
|
||||
context_object_name = 'build'
|
||||
ajax_form_title = _('Allocate Stock')
|
||||
ajax_template_name = 'build/auto_allocate.html'
|
||||
role_required = 'build.change'
|
||||
|
||||
def get_context_data(self, *args, **kwargs):
|
||||
""" Get the context data for form rendering. """
|
||||
@ -147,6 +151,7 @@ class BuildUnallocate(AjaxUpdateView):
|
||||
form_class = forms.ConfirmBuildForm
|
||||
ajax_form_title = _("Unallocate Stock")
|
||||
ajax_template_name = "build/unallocate.html"
|
||||
form_required = 'build.change'
|
||||
|
||||
def post(self, request, *args, **kwargs):
|
||||
|
||||
@ -184,6 +189,7 @@ class BuildComplete(AjaxUpdateView):
|
||||
context_object_name = "build"
|
||||
ajax_form_title = _("Complete Build")
|
||||
ajax_template_name = "build/complete.html"
|
||||
role_required = 'build.change'
|
||||
|
||||
def get_form(self):
|
||||
""" Get the form object.
|
||||
@ -325,6 +331,7 @@ class BuildNotes(UpdateView):
|
||||
context_object_name = 'build'
|
||||
template_name = 'build/notes.html'
|
||||
model = Build
|
||||
role_required = 'build.view'
|
||||
|
||||
fields = ['notes']
|
||||
|
||||
@ -342,9 +349,11 @@ class BuildNotes(UpdateView):
|
||||
|
||||
class BuildDetail(DetailView):
|
||||
""" Detail view of a single Build object. """
|
||||
|
||||
model = Build
|
||||
template_name = 'build/detail.html'
|
||||
context_object_name = 'build'
|
||||
role_required = 'build.view'
|
||||
|
||||
def get_context_data(self, **kwargs):
|
||||
|
||||
@ -363,6 +372,7 @@ class BuildAllocate(DetailView):
|
||||
model = Build
|
||||
context_object_name = 'build'
|
||||
template_name = 'build/allocate.html'
|
||||
role_required = ['build.change']
|
||||
|
||||
def get_context_data(self, **kwargs):
|
||||
""" Provide extra context information for the Build allocation page """
|
||||
@ -392,6 +402,7 @@ class BuildCreate(AjaxCreateView):
|
||||
form_class = forms.EditBuildForm
|
||||
ajax_form_title = _('Start new Build')
|
||||
ajax_template_name = 'modal_form.html'
|
||||
role_required = 'build.add'
|
||||
|
||||
def get_initial(self):
|
||||
""" Get initial parameters for Build creation.
|
||||
@ -427,6 +438,7 @@ class BuildUpdate(AjaxUpdateView):
|
||||
context_object_name = 'build'
|
||||
ajax_form_title = _('Edit Build Details')
|
||||
ajax_template_name = 'modal_form.html'
|
||||
role_required = 'build.change'
|
||||
|
||||
def get_data(self):
|
||||
return {
|
||||
@ -440,6 +452,7 @@ class BuildDelete(AjaxDeleteView):
|
||||
model = Build
|
||||
ajax_template_name = 'build/delete_build.html'
|
||||
ajax_form_title = _('Delete Build')
|
||||
role_required = 'build.delete'
|
||||
|
||||
|
||||
class BuildItemDelete(AjaxDeleteView):
|
||||
@ -451,6 +464,7 @@ class BuildItemDelete(AjaxDeleteView):
|
||||
ajax_template_name = 'build/delete_build_item.html'
|
||||
ajax_form_title = _('Unallocate Stock')
|
||||
context_object_name = 'item'
|
||||
role_required = 'build.delete'
|
||||
|
||||
def get_data(self):
|
||||
return {
|
||||
@ -465,6 +479,7 @@ class BuildItemCreate(AjaxCreateView):
|
||||
form_class = forms.EditBuildItemForm
|
||||
ajax_template_name = 'build/create_build_item.html'
|
||||
ajax_form_title = _('Allocate new Part')
|
||||
role_required = 'build.add'
|
||||
|
||||
part = None
|
||||
available_stock = None
|
||||
@ -618,6 +633,7 @@ class BuildItemEdit(AjaxUpdateView):
|
||||
ajax_template_name = 'modal_form.html'
|
||||
form_class = forms.EditBuildItemForm
|
||||
ajax_form_title = _('Edit Stock Allocation')
|
||||
role_required = 'build.change'
|
||||
|
||||
def get_data(self):
|
||||
return {
|
||||
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@ -32,29 +32,31 @@ src="{% static 'img/blank_image.png' %}"
|
||||
<p>
|
||||
<div class='btn-row'>
|
||||
<div class='btn-group action-buttons'>
|
||||
<button type='button' class='btn btn-default' id='edit-order' title='Edit order information'>
|
||||
{% if roles.purchase_order.change %}
|
||||
<button type='button' class='btn btn-default' id='edit-order' title='{% trans "Edit order information" %}'>
|
||||
<span class='fas fa-edit icon-green'></span>
|
||||
</button>
|
||||
<button type='button' class='btn btn-default' id='export-order' title='Export order to file'>
|
||||
<span class='fas fa-file-download'></span>
|
||||
</button>
|
||||
{% if order.status == PurchaseOrderStatus.PENDING and order.lines.count > 0 %}
|
||||
<button type='button' class='btn btn-default' id='place-order' title='Place order'>
|
||||
<button type='button' class='btn btn-default' id='place-order' title='{% trans "Place order" %}'>
|
||||
<span class='fas fa-paper-plane icon-blue'></span>
|
||||
</button>
|
||||
{% elif order.status == PurchaseOrderStatus.PLACED %}
|
||||
<button type='button' class='btn btn-default' id='receive-order' title='Receive items'>
|
||||
<button type='button' class='btn btn-default' id='receive-order' title='{% trans "Receive items" %}'>
|
||||
<span class='fas fa-clipboard-check'></span>
|
||||
</button>
|
||||
<button type='button' class='btn btn-default' id='complete-order' title='Mark order as complete'>
|
||||
<button type='button' class='btn btn-default' id='complete-order' title='{% trans "Mark order as complete" %}'>
|
||||
<span class='fas fa-check-circle'></span>
|
||||
</button>
|
||||
{% endif %}
|
||||
{% if order.status == PurchaseOrderStatus.PENDING or order.status == PurchaseOrderStatus.PLACED %}
|
||||
<button type='button' class='btn btn-default' id='cancel-order' title='Cancel order'>
|
||||
<button type='button' class='btn btn-default' id='cancel-order' title='{% trans "Cancel order" %}'>
|
||||
<span class='fas fa-times-circle icon-red'></span>
|
||||
</button>
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
<button type='button' class='btn btn-default' id='export-order' title='{% trans "Export order to file" %}'>
|
||||
<span class='fas fa-file-download'></span>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</p>
|
||||
|
@ -28,9 +28,11 @@
|
||||
<div class='col-sm-6'>
|
||||
<h4>{% trans "Order Notes" %}</h4>
|
||||
</div>
|
||||
{% if roles.purchase_order.change %}
|
||||
<div class='col-sm-6'>
|
||||
<button title='{% trans "Edit notes" %}' class='btn btn-default action-button float-right' id='edit-notes'><span class='fas fa-edit'></span></button>
|
||||
</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
<hr>
|
||||
<div class='panel panel-default'>
|
||||
|
@ -14,7 +14,6 @@
|
||||
|
||||
{% include "attachment_table.html" with attachments=order.attachments.all %}
|
||||
|
||||
|
||||
{% endblock %}
|
||||
|
||||
{% block js_ready %}
|
||||
|
@ -12,7 +12,7 @@
|
||||
<hr>
|
||||
|
||||
<div id='order-toolbar-buttons' class='btn-group' style='float: right;'>
|
||||
{% if order.status == PurchaseOrderStatus.PENDING %}
|
||||
{% if order.status == PurchaseOrderStatus.PENDING and roles.purchase_order.change %}
|
||||
<button type='button' class='btn btn-default' id='new-po-line'>{% trans "Add Line Item" %}</button>
|
||||
{% endif %}
|
||||
</div>
|
||||
@ -209,12 +209,12 @@ $("#po-table").inventreeTable({
|
||||
|
||||
var pk = row.pk;
|
||||
|
||||
{% if order.status == PurchaseOrderStatus.PENDING %}
|
||||
{% if order.status == PurchaseOrderStatus.PENDING and roles.purchase_order.delete %}
|
||||
html += makeIconButton('fa-edit icon-blue', 'button-line-edit', pk, '{% trans "Edit line item" %}');
|
||||
html += makeIconButton('fa-trash-alt icon-red', 'button-line-delete', pk, '{% trans "Delete line item" %}');
|
||||
{% endif %}
|
||||
|
||||
{% if order.status == PurchaseOrderStatus.PLACED %}
|
||||
{% if order.status == PurchaseOrderStatus.PLACED and roles.purchase_order.change %}
|
||||
if (row.received < row.quantity) {
|
||||
html += makeIconButton('fa-clipboard-check', 'button-line-receive', pk, '{% trans "Receive line item" %}');
|
||||
}
|
||||
|
@ -14,7 +14,9 @@ InvenTree | {% trans "Purchase Orders" %}
|
||||
|
||||
<div id='table-buttons'>
|
||||
<div class='button-toolbar container-fluid' style='float: right;'>
|
||||
{% if roles.purchase_order.add %}
|
||||
<button class='btn btn-primary' type='button' id='po-create' title='{% trans "Create new purchase order" %}'>{% trans "New Purchase Order" %}</button>
|
||||
{% endif %}
|
||||
<div class='filter-list' id='filter-list-purchaseorder'>
|
||||
<!-- An empty div in which the filter list will be constructed -->
|
||||
</div>
|
||||
|
@ -41,12 +41,10 @@ src="{% static 'img/blank_image.png' %}"
|
||||
<p>{{ order.description }}</p>
|
||||
<div class='btn-row'>
|
||||
<div class='btn-group action-buttons'>
|
||||
{% if roles.sales_order.change %}
|
||||
<button type='button' class='btn btn-default' id='edit-order' title='Edit order information'>
|
||||
<span class='fas fa-edit icon-green'></span>
|
||||
</button>
|
||||
<button type='button' class='btn btn-default' id='packing-list' title='{% trans "Packing List" %}'>
|
||||
<span class='fas fa-clipboard-list'></span>
|
||||
</button>
|
||||
{% if order.status == SalesOrderStatus.PENDING %}
|
||||
<button type='button' class='btn btn-default' id='ship-order' title='{% trans "Ship order" %}'>
|
||||
<span class='fas fa-paper-plane icon-blue'></span>
|
||||
@ -55,6 +53,10 @@ src="{% static 'img/blank_image.png' %}"
|
||||
<span class='fas fa-times-circle icon-red'></span>
|
||||
</button>
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
<button type='button' disabled='' class='btn btn-default' id='packing-list' title='{% trans "Packing List" %}'>
|
||||
<span class='fas fa-clipboard-list'></span>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
{% endblock %}
|
||||
|
@ -14,7 +14,9 @@ InvenTree | {% trans "Sales Orders" %}
|
||||
|
||||
<div id='table-buttons'>
|
||||
<div class='button-toolbar container-fluid' style='float: right;'>
|
||||
{% if roles.sales_order.add %}
|
||||
<button class='btn btn-primary' type='button' id='so-create' title='{% trans "Create new sales order" %}'>{% trans "New Sales Order" %}</button>
|
||||
{% endif %}
|
||||
<div class='filter-list' id='filter-list-salesorder'>
|
||||
<!-- An empty div in which the filter list will be constructed -->
|
||||
</div>
|
||||
|
@ -6,6 +6,7 @@ from __future__ import unicode_literals
|
||||
from django.test import TestCase
|
||||
from django.urls import reverse
|
||||
from django.contrib.auth import get_user_model
|
||||
from django.contrib.auth.models import Group
|
||||
|
||||
from InvenTree.status_codes import PurchaseOrderStatus
|
||||
|
||||
@ -32,7 +33,21 @@ class OrderViewTestCase(TestCase):
|
||||
|
||||
# Create a user
|
||||
User = get_user_model()
|
||||
User.objects.create_user('username', 'user@email.com', 'password')
|
||||
user = User.objects.create_user('username', 'user@email.com', 'password')
|
||||
|
||||
# Ensure that the user has the correct permissions!
|
||||
g = Group.objects.create(name='orders')
|
||||
user.groups.add(g)
|
||||
|
||||
for rule in g.rule_sets.all():
|
||||
if rule.name in ['purchase_order', 'sales_order']:
|
||||
rule.can_change = True
|
||||
rule.can_add = True
|
||||
rule.can_delete = True
|
||||
|
||||
rule.save()
|
||||
|
||||
g.save()
|
||||
|
||||
self.client.login(username='username', password='password')
|
||||
|
||||
|
@ -28,19 +28,22 @@ from . import forms as order_forms
|
||||
|
||||
from InvenTree.views import AjaxView, AjaxCreateView, AjaxUpdateView, AjaxDeleteView
|
||||
from InvenTree.helpers import DownloadFile, str2bool
|
||||
from InvenTree.views import InvenTreeRoleMixin
|
||||
|
||||
from InvenTree.status_codes import PurchaseOrderStatus, SalesOrderStatus, StockStatus
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class PurchaseOrderIndex(ListView):
|
||||
class PurchaseOrderIndex(InvenTreeRoleMixin, ListView):
|
||||
""" List view for all purchase orders """
|
||||
|
||||
model = PurchaseOrder
|
||||
template_name = 'order/purchase_orders.html'
|
||||
context_object_name = 'orders'
|
||||
|
||||
role_required = 'purchase_order.view'
|
||||
|
||||
def get_queryset(self):
|
||||
""" Retrieve the list of purchase orders,
|
||||
ensure that the most recent ones are returned first. """
|
||||
@ -55,19 +58,21 @@ class PurchaseOrderIndex(ListView):
|
||||
return ctx
|
||||
|
||||
|
||||
class SalesOrderIndex(ListView):
|
||||
class SalesOrderIndex(InvenTreeRoleMixin, ListView):
|
||||
|
||||
model = SalesOrder
|
||||
template_name = 'order/sales_orders.html'
|
||||
context_object_name = 'orders'
|
||||
role_required = 'sales_order.view'
|
||||
|
||||
|
||||
class PurchaseOrderDetail(DetailView):
|
||||
class PurchaseOrderDetail(InvenTreeRoleMixin, DetailView):
|
||||
""" Detail view for a PurchaseOrder object """
|
||||
|
||||
context_object_name = 'order'
|
||||
queryset = PurchaseOrder.objects.all().prefetch_related('lines')
|
||||
template_name = 'order/purchase_order_detail.html'
|
||||
role_required = 'purchase_order.view'
|
||||
|
||||
def get_context_data(self, **kwargs):
|
||||
ctx = super().get_context_data(**kwargs)
|
||||
@ -75,12 +80,13 @@ class PurchaseOrderDetail(DetailView):
|
||||
return ctx
|
||||
|
||||
|
||||
class SalesOrderDetail(DetailView):
|
||||
class SalesOrderDetail(InvenTreeRoleMixin, DetailView):
|
||||
""" Detail view for a SalesOrder object """
|
||||
|
||||
context_object_name = 'order'
|
||||
queryset = SalesOrder.objects.all().prefetch_related('lines')
|
||||
template_name = 'order/sales_order_detail.html'
|
||||
role_required = 'sales_order.view'
|
||||
|
||||
|
||||
class PurchaseOrderAttachmentCreate(AjaxCreateView):
|
||||
@ -92,6 +98,7 @@ class PurchaseOrderAttachmentCreate(AjaxCreateView):
|
||||
form_class = order_forms.EditPurchaseOrderAttachmentForm
|
||||
ajax_form_title = _("Add Purchase Order Attachment")
|
||||
ajax_template_name = "modal_form.html"
|
||||
role_required = 'purchase_order.add'
|
||||
|
||||
def post_save(self, **kwargs):
|
||||
self.object.user = self.request.user
|
||||
@ -139,6 +146,7 @@ class SalesOrderAttachmentCreate(AjaxCreateView):
|
||||
model = SalesOrderAttachment
|
||||
form_class = order_forms.EditSalesOrderAttachmentForm
|
||||
ajax_form_title = _('Add Sales Order Attachment')
|
||||
role_required = 'sales_order.add'
|
||||
|
||||
def post_save(self, **kwargs):
|
||||
self.object.user = self.request.user
|
||||
@ -174,6 +182,7 @@ class PurchaseOrderAttachmentEdit(AjaxUpdateView):
|
||||
model = PurchaseOrderAttachment
|
||||
form_class = order_forms.EditPurchaseOrderAttachmentForm
|
||||
ajax_form_title = _("Edit Attachment")
|
||||
role_required = 'purchase_order.change'
|
||||
|
||||
def get_data(self):
|
||||
return {
|
||||
@ -195,6 +204,7 @@ class SalesOrderAttachmentEdit(AjaxUpdateView):
|
||||
model = SalesOrderAttachment
|
||||
form_class = order_forms.EditSalesOrderAttachmentForm
|
||||
ajax_form_title = _("Edit Attachment")
|
||||
role_required = 'sales_order.change'
|
||||
|
||||
def get_data(self):
|
||||
return {
|
||||
@ -216,6 +226,7 @@ class PurchaseOrderAttachmentDelete(AjaxDeleteView):
|
||||
ajax_form_title = _("Delete Attachment")
|
||||
ajax_template_name = "order/delete_attachment.html"
|
||||
context_object_name = "attachment"
|
||||
role_required = 'purchase_order.delete'
|
||||
|
||||
def get_data(self):
|
||||
return {
|
||||
@ -230,6 +241,7 @@ class SalesOrderAttachmentDelete(AjaxDeleteView):
|
||||
ajax_form_title = _("Delete Attachment")
|
||||
ajax_template_name = "order/delete_attachment.html"
|
||||
context_object_name = "attachment"
|
||||
role_required = 'sales_order.delete'
|
||||
|
||||
def get_data(self):
|
||||
return {
|
||||
@ -237,12 +249,13 @@ class SalesOrderAttachmentDelete(AjaxDeleteView):
|
||||
}
|
||||
|
||||
|
||||
class PurchaseOrderNotes(UpdateView):
|
||||
class PurchaseOrderNotes(InvenTreeRoleMixin, UpdateView):
|
||||
""" View for updating the 'notes' field of a PurchaseOrder """
|
||||
|
||||
context_object_name = 'order'
|
||||
template_name = 'order/order_notes.html'
|
||||
model = PurchaseOrder
|
||||
role_required = 'purchase_order.view'
|
||||
|
||||
fields = ['notes']
|
||||
|
||||
@ -259,12 +272,13 @@ class PurchaseOrderNotes(UpdateView):
|
||||
return ctx
|
||||
|
||||
|
||||
class SalesOrderNotes(UpdateView):
|
||||
class SalesOrderNotes(InvenTreeRoleMixin, UpdateView):
|
||||
""" View for editing the 'notes' field of a SalesORder """
|
||||
|
||||
context_object_name = 'order'
|
||||
template_name = 'order/sales_order_notes.html'
|
||||
model = SalesOrder
|
||||
role_required = 'sales_order.view'
|
||||
|
||||
fields = ['notes']
|
||||
|
||||
@ -286,6 +300,7 @@ class PurchaseOrderCreate(AjaxCreateView):
|
||||
model = PurchaseOrder
|
||||
ajax_form_title = _("Create Purchase Order")
|
||||
form_class = order_forms.EditPurchaseOrderForm
|
||||
role_required = 'purchase_order.add'
|
||||
|
||||
def get_initial(self):
|
||||
initials = super().get_initial().copy()
|
||||
@ -317,6 +332,7 @@ class SalesOrderCreate(AjaxCreateView):
|
||||
model = SalesOrder
|
||||
ajax_form_title = _("Create Sales Order")
|
||||
form_class = order_forms.EditSalesOrderForm
|
||||
role_required = 'sales_order.add'
|
||||
|
||||
def get_initial(self):
|
||||
initials = super().get_initial().copy()
|
||||
@ -347,6 +363,7 @@ class PurchaseOrderEdit(AjaxUpdateView):
|
||||
model = PurchaseOrder
|
||||
ajax_form_title = _('Edit Purchase Order')
|
||||
form_class = order_forms.EditPurchaseOrderForm
|
||||
role_required = 'purchase_order.change'
|
||||
|
||||
def get_form(self):
|
||||
|
||||
@ -367,6 +384,7 @@ class SalesOrderEdit(AjaxUpdateView):
|
||||
model = SalesOrder
|
||||
ajax_form_title = _('Edit Sales Order')
|
||||
form_class = order_forms.EditSalesOrderForm
|
||||
role_required = 'sales_order.change'
|
||||
|
||||
def get_form(self):
|
||||
form = super().get_form()
|
||||
@ -384,6 +402,7 @@ class PurchaseOrderCancel(AjaxUpdateView):
|
||||
ajax_form_title = _('Cancel Order')
|
||||
ajax_template_name = 'order/order_cancel.html'
|
||||
form_class = order_forms.CancelPurchaseOrderForm
|
||||
role_required = 'purchase_order.change'
|
||||
|
||||
def post(self, request, *args, **kwargs):
|
||||
""" Mark the PO as 'CANCELLED' """
|
||||
@ -417,6 +436,7 @@ class SalesOrderCancel(AjaxUpdateView):
|
||||
ajax_form_title = _("Cancel sales order")
|
||||
ajax_template_name = "order/sales_order_cancel.html"
|
||||
form_class = order_forms.CancelSalesOrderForm
|
||||
role_required = 'sales_order.change'
|
||||
|
||||
def post(self, request, *args, **kwargs):
|
||||
|
||||
@ -451,6 +471,7 @@ class PurchaseOrderIssue(AjaxUpdateView):
|
||||
ajax_form_title = _('Issue Order')
|
||||
ajax_template_name = "order/order_issue.html"
|
||||
form_class = order_forms.IssuePurchaseOrderForm
|
||||
role_required = 'purchase_order.change'
|
||||
|
||||
def post(self, request, *args, **kwargs):
|
||||
""" Mark the purchase order as 'PLACED' """
|
||||
@ -486,6 +507,7 @@ class PurchaseOrderComplete(AjaxUpdateView):
|
||||
ajax_template_name = "order/order_complete.html"
|
||||
ajax_form_title = _("Complete Order")
|
||||
context_object_name = 'order'
|
||||
role_required = 'purchase_order.change'
|
||||
|
||||
def get_context_data(self):
|
||||
|
||||
@ -520,6 +542,7 @@ class SalesOrderShip(AjaxUpdateView):
|
||||
context_object_name = 'order'
|
||||
ajax_template_name = 'order/sales_order_ship.html'
|
||||
ajax_form_title = _('Ship Order')
|
||||
role_required = 'sales_order.change'
|
||||
|
||||
def post(self, request, *args, **kwargs):
|
||||
|
||||
@ -563,6 +586,7 @@ class PurchaseOrderExport(AjaxView):
|
||||
"""
|
||||
|
||||
model = PurchaseOrder
|
||||
role_required = 'purchase_order.view'
|
||||
|
||||
def get(self, request, *args, **kwargs):
|
||||
|
||||
@ -594,6 +618,7 @@ class PurchaseOrderReceive(AjaxUpdateView):
|
||||
form_class = order_forms.ReceivePurchaseOrderForm
|
||||
ajax_form_title = _("Receive Parts")
|
||||
ajax_template_name = "order/receive_parts.html"
|
||||
role_required = 'purchase_order.change'
|
||||
|
||||
# Where the parts will be going (selected in POST request)
|
||||
destination = None
|
||||
@ -779,6 +804,11 @@ class OrderParts(AjaxView):
|
||||
ajax_form_title = _("Order Parts")
|
||||
ajax_template_name = 'order/order_wizard/select_parts.html'
|
||||
|
||||
role_required = [
|
||||
'part.view',
|
||||
'purchase_order.change',
|
||||
]
|
||||
|
||||
# List of Parts we wish to order
|
||||
parts = []
|
||||
suppliers = []
|
||||
@ -1085,6 +1115,7 @@ class POLineItemCreate(AjaxCreateView):
|
||||
context_object_name = 'line'
|
||||
form_class = order_forms.EditPurchaseOrderLineItemForm
|
||||
ajax_form_title = _('Add Line Item')
|
||||
role_required = 'purchase_order.add'
|
||||
|
||||
def post(self, request, *arg, **kwargs):
|
||||
|
||||
@ -1199,6 +1230,7 @@ class SOLineItemCreate(AjaxCreateView):
|
||||
context_order_name = 'line'
|
||||
form_class = order_forms.EditSalesOrderLineItemForm
|
||||
ajax_form_title = _('Add Line Item')
|
||||
role_required = 'sales_order.add'
|
||||
|
||||
def get_form(self, *args, **kwargs):
|
||||
|
||||
@ -1250,6 +1282,7 @@ class SOLineItemEdit(AjaxUpdateView):
|
||||
model = SalesOrderLineItem
|
||||
form_class = order_forms.EditSalesOrderLineItemForm
|
||||
ajax_form_title = _('Edit Line Item')
|
||||
role_required = 'sales_order.change'
|
||||
|
||||
def get_form(self):
|
||||
form = super().get_form()
|
||||
@ -1268,6 +1301,7 @@ class POLineItemEdit(AjaxUpdateView):
|
||||
form_class = order_forms.EditPurchaseOrderLineItemForm
|
||||
ajax_template_name = 'modal_form.html'
|
||||
ajax_form_title = _('Edit Line Item')
|
||||
role_required = 'purchase_order.change'
|
||||
|
||||
def get_form(self):
|
||||
form = super().get_form()
|
||||
@ -1285,7 +1319,8 @@ class POLineItemDelete(AjaxDeleteView):
|
||||
model = PurchaseOrderLineItem
|
||||
ajax_form_title = _('Delete Line Item')
|
||||
ajax_template_name = 'order/po_lineitem_delete.html'
|
||||
|
||||
role_required = 'purchase_order.delete'
|
||||
|
||||
def get_data(self):
|
||||
return {
|
||||
'danger': _('Deleted line item'),
|
||||
@ -1297,6 +1332,7 @@ class SOLineItemDelete(AjaxDeleteView):
|
||||
model = SalesOrderLineItem
|
||||
ajax_form_title = _("Delete Line Item")
|
||||
ajax_template_name = "order/so_lineitem_delete.html"
|
||||
role_required = 'sales_order.delete'
|
||||
|
||||
def get_data(self):
|
||||
return {
|
||||
@ -1310,6 +1346,7 @@ class SalesOrderAllocationCreate(AjaxCreateView):
|
||||
model = SalesOrderAllocation
|
||||
form_class = order_forms.EditSalesOrderAllocationForm
|
||||
ajax_form_title = _('Allocate Stock to Order')
|
||||
role_required = 'sales_order.add'
|
||||
|
||||
def get_initial(self):
|
||||
initials = super().get_initial().copy()
|
||||
@ -1379,6 +1416,7 @@ class SalesOrderAllocationEdit(AjaxUpdateView):
|
||||
model = SalesOrderAllocation
|
||||
form_class = order_forms.EditSalesOrderAllocationForm
|
||||
ajax_form_title = _('Edit Allocation Quantity')
|
||||
role_required = 'sales_order.change'
|
||||
|
||||
def get_form(self):
|
||||
form = super().get_form()
|
||||
@ -1396,3 +1434,4 @@ class SalesOrderAllocationDelete(AjaxDeleteView):
|
||||
ajax_form_title = _("Remove allocation")
|
||||
context_object_name = 'allocation'
|
||||
ajax_template_name = "order/so_allocation_delete.html"
|
||||
role_required = 'sales_order.delete'
|
||||
|
@ -36,6 +36,10 @@ class RuleSet(models.Model):
|
||||
choice[0] for choice in RULESET_CHOICES
|
||||
]
|
||||
|
||||
RULESET_PERMISSIONS = [
|
||||
'view', 'add', 'change', 'delete',
|
||||
]
|
||||
|
||||
RULESET_MODELS = {
|
||||
'admin': [
|
||||
'auth_group',
|
||||
|
Loading…
Reference in New Issue
Block a user