Merge pull request #1064 from eeintech/company_permissions

Company permissions
This commit is contained in:
Oliver 2020-10-23 13:20:59 +11:00 committed by GitHub
commit cd4cb12937
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
12 changed files with 74 additions and 7 deletions

View File

@ -128,9 +128,13 @@ class InvenTreeRoleMixin(PermissionRequiredMixin):
def has_permission(self): def has_permission(self):
""" """
Determine if the current user 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:

View File

@ -23,23 +23,27 @@ InvenTree | {% trans "Company" %} - {{ company.name }}
<hr> <hr>
<h4> <h4>
{{ company.name }} {{ company.name }}
{% if user.is_staff and roles.company.change %} {% if user.is_staff and perms.company.change_company %}
<a href="{% url 'admin:company_company_change' company.pk %}"><span title="{% trans 'Admin view' %}" class='fas fa-user-shield'></span></a> <a href="{% url 'admin:company_company_change' company.pk %}"><span title="{% trans 'Admin view' %}" class='fas fa-user-shield'></span></a>
{% endif %} {% endif %}
</h4> </h4>
<p>{{ company.description }}</p> <p>{{ company.description }}</p>
<div class='btn-group action-buttons'> <div class='btn-group action-buttons'>
{% if company.is_supplier %} {% if company.is_supplier and roles.purchase_order.add %}
<button type='button' class='btn btn-default' id='company-order-2' title='Create purchase order'> <button type='button' class='btn btn-default' id='company-order-2' title='Create purchase order'>
<span class='fas fa-shopping-cart'/> <span class='fas fa-shopping-cart'/>
</button> </button>
{% endif %} {% endif %}
{% if perms.company.change_company %}
<button type='button' class='btn btn-default' id='company-edit' title='Edit company information'> <button type='button' class='btn btn-default' id='company-edit' title='Edit company information'>
<span class='fas fa-edit icon-green'/> <span class='fas fa-edit icon-green'/>
</button> </button>
{% endif %}
{% if perms.company.delete_company %}
<button type='button' class='btn btn-default' id='company-delete' title='Delete company'> <button type='button' class='btn btn-default' id='company-delete' title='Delete company'>
<span class='fas fa-trash-alt icon-red'/> <span class='fas fa-trash-alt icon-red'/>
</button> </button>
{% endif %}
</div> </div>
{% endblock %} {% endblock %}

View File

@ -9,17 +9,25 @@
<hr> <hr>
{% if roles.purchase_order.change %}
<div id='button-toolbar' class='btn-group'> <div id='button-toolbar' class='btn-group'>
{% if roles.purchase_order.add %}
<button class="btn btn-success" id='part-create' title='{% trans "Create new supplier part" %}'>{% trans "New Supplier Part" %}</button> <button class="btn btn-success" id='part-create' title='{% trans "Create new supplier part" %}'>{% trans "New Supplier Part" %}</button>
{% endif %}
<div class="dropdown" style="float: right;"> <div class="dropdown" style="float: right;">
<button class="btn btn-primary dropdown-toggle" type="button" data-toggle="dropdown">{% trans "Options" %} <button class="btn btn-primary dropdown-toggle" type="button" data-toggle="dropdown">{% trans "Options" %}
<span class="caret"></span></button> <span class="caret"></span></button>
<ul class="dropdown-menu"> <ul class="dropdown-menu">
{% if roles.purchase_order.add %}
<li><a href='#' id='multi-part-order' title='{% trans "Order parts" %}'>{% trans "Order Parts" %}</a></li> <li><a href='#' id='multi-part-order' title='{% trans "Order parts" %}'>{% trans "Order Parts" %}</a></li>
{% endif %}
{% if roles.purchase_order.delete %}
<li><a href='#' id='multi-part-delete' title='{% trans "Delete parts" %}'>{% trans "Delete Parts" %}</a></li> <li><a href='#' id='multi-part-delete' title='{% trans "Delete parts" %}'>{% trans "Delete Parts" %}</a></li>
{% endif %}
</ul> </ul>
</div> </div>
</div> </div>
{% endif %}
<table class='table table-striped table-condensed' id='part-table' data-toolbar='#button-toolbar'> <table class='table table-striped table-condensed' id='part-table' data-toolbar='#button-toolbar'>
</table> </table>

View File

@ -12,12 +12,13 @@ InvenTree | {% trans "Supplier List" %}
<h3>{{ title }}</h3> <h3>{{ title }}</h3>
<hr> <hr>
{% if pagetype == 'manufacturers' and roles.purchase_order.add or pagetype == 'suppliers' and roles.purchase_order.add or pagetype == 'customers' and roles.sales_order.add %}
<div id='button-toolbar'> <div id='button-toolbar'>
<div class='btn-group'> <div class='btn-group'>
<button type='button' class="btn btn-success" id='new-company'>{{ button_text }}</button> <button type='button' class="btn btn-success" id='new-company'>{{ button_text }}</button>
</div> </div>
</div> </div>
{% endif %}
<table class='table table-striped' id='company-table' data-toolbar='#button-toolbar'> <table class='table table-striped' id='company-table' data-toolbar='#button-toolbar'>
</table> </table>

View File

@ -9,6 +9,7 @@
<h4>{% trans "Purchase Orders" %}</h4> <h4>{% trans "Purchase Orders" %}</h4>
<hr> <hr>
{% if roles.purchase_order.add %}
<div id='button-bar'> <div id='button-bar'>
<div class='button-toolbar container-fluid' style='float: right;'> <div class='button-toolbar container-fluid' style='float: right;'>
<button class='btn btn-primary' type='button' id='company-order2' title='{% trans "Create new purchase order" %}'>{% trans "New Purchase Order" %}</button> <button class='btn btn-primary' type='button' id='company-order2' title='{% trans "Create new purchase order" %}'>{% trans "New Purchase Order" %}</button>
@ -17,6 +18,7 @@
</div> </div>
</div> </div>
</div> </div>
{% endif %}
<table class='table table-striped table-condensed po-table' id='purchase-order-table' data-toolbar='#button-bar'> <table class='table table-striped table-condensed po-table' id='purchase-order-table' data-toolbar='#button-bar'>
</table> </table>

View File

@ -9,6 +9,7 @@
<h4>{% trans "Sales Orders" %}</h4> <h4>{% trans "Sales Orders" %}</h4>
<hr> <hr>
{% if roles.sales_order.add %}
<div id='button-bar'> <div id='button-bar'>
<div class='button-toolbar container-fluid' style='float: right;'> <div class='button-toolbar container-fluid' style='float: right;'>
<button class='btn btn-primary' type='button' id='new-sales-order' title='{% trans "Create new sales order" %}'>{% trans "New Sales Order" %}</button> <button class='btn btn-primary' type='button' id='new-sales-order' title='{% trans "Create new sales order" %}'>{% trans "New Sales Order" %}</button>
@ -17,6 +18,7 @@
</div> </div>
</div> </div>
</div> </div>
{% endif %}
<table class='table table-striped table-condensed po-table' id='sales-order-table' data-toolbar='#button-bar'> <table class='table table-striped table-condensed po-table' id='sales-order-table' data-toolbar='#button-bar'>
</table> </table>

View File

@ -18,19 +18,27 @@ src="{% static 'img/blank_image.png' %}"
{% block page_data %} {% block page_data %}
<h3>{% trans "Supplier Part" %}</h3> <h3>{% trans "Supplier Part" %}</h3>
<p>{{ part.supplier.name }} - {{ part.SKU }}</p> <p>{{ part.supplier.name }} - {{ part.SKU }}</p>
{% if roles.purchase_order.change %}
<div class='btn-row'> <div class='btn-row'>
<div class='btn-group action-buttons' role='group'> <div class='btn-group action-buttons' role='group'>
{% if roles.purchase_order.add %}
<button type='button' class='btn btn-default btn-glyph' id='order-part' title='{% trans "Order part" %}'> <button type='button' class='btn btn-default btn-glyph' id='order-part' title='{% trans "Order part" %}'>
<span class='fas fa-shopping-cart'></span> <span class='fas fa-shopping-cart'></span>
</button> </button>
{% endif %}
<button type='button' class='btn btn-default btn-glyph' id='edit-part' title='{% trans "Edit supplier part" %}'> <button type='button' class='btn btn-default btn-glyph' id='edit-part' title='{% trans "Edit supplier part" %}'>
<span class='fas fa-edit icon-green'/> <span class='fas fa-edit icon-green'/>
</button> </button>
{% if roles.purchase_order.delete %}
<button type='button' class='btn btn-default btn-glyph' id='delete-part' title='{% trans "Delete supplier part" %}'> <button type='button' class='btn btn-default btn-glyph' id='delete-part' title='{% trans "Delete supplier part" %}'>
<span class='fas fa-trash-alt icon-red'/> <span class='fas fa-trash-alt icon-red'/>
</button> </button>
{% endif %}
</div> </div>
</div> </div>
{% endif %}
{% endblock %} {% endblock %}
{% block page_details %} {% block page_details %}

View File

@ -10,11 +10,13 @@
<hr> <hr>
{% if roles.purchase_order.add %}
<div id='button-bar'> <div id='button-bar'>
<div class='btn-group'> <div class='btn-group'>
<button class='btn btn-primary' type='button' id='order-part2' title='Order part'>Order Part</button> <button class='btn btn-primary' type='button' id='order-part2' title='Order part'>Order Part</button>
</div> </div>
</div> </div>
{% endif %}
<table class='table table-striped table-condensed po-table' id='purchase-order-table' data-toolbar='#button-bar'> <table class='table table-striped table-condensed po-table' id='purchase-order-table' data-toolbar='#button-bar'>
</table> </table>

View File

@ -11,9 +11,11 @@
<hr> <hr>
{% if roles.purchase_order.add %}
<div id='price-break-toolbar' class='btn-group'> <div id='price-break-toolbar' class='btn-group'>
<button class='btn btn-primary' id='new-price-break' type='button'>{% trans "Add Price Break" %}</button> <button class='btn btn-primary' id='new-price-break' type='button'>{% trans "Add Price Break" %}</button>
</div> </div>
{% endif %}
<table class='table table-striped table-condensed' id='price-break-table' data-toolbar='#price-break-toolbar'> <table class='table table-striped table-condensed' id='price-break-table' data-toolbar='#price-break-toolbar'>
</table> </table>

View File

@ -6,6 +6,7 @@ from __future__ import unicode_literals
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
from .models import SupplierPart from .models import SupplierPart
@ -25,7 +26,24 @@ class CompanyViewTest(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

@ -14,6 +14,7 @@ from django.forms import HiddenInput
from InvenTree.views import AjaxCreateView, AjaxUpdateView, AjaxDeleteView from InvenTree.views import AjaxCreateView, AjaxUpdateView, AjaxDeleteView
from InvenTree.helpers import str2bool from InvenTree.helpers import str2bool
from InvenTree.views import InvenTreeRoleMixin
from common.models import Currency from common.models import Currency
@ -29,7 +30,7 @@ from .forms import EditSupplierPartForm
from .forms import EditPriceBreakForm from .forms import EditPriceBreakForm
class CompanyIndex(ListView): class CompanyIndex(InvenTreeRoleMixin, ListView):
""" View for displaying list of companies """ View for displaying list of companies
""" """
@ -37,6 +38,7 @@ class CompanyIndex(ListView):
template_name = 'company/index.html' template_name = 'company/index.html'
context_object_name = 'companies' context_object_name = 'companies'
paginate_by = 50 paginate_by = 50
permission_required = 'company.view_company'
def get_context_data(self, **kwargs): def get_context_data(self, **kwargs):
@ -116,8 +118,8 @@ class CompanyNotes(UpdateView):
context_object_name = 'company' context_object_name = 'company'
template_name = 'company/notes.html' template_name = 'company/notes.html'
model = Company model = Company
fields = ['notes'] fields = ['notes']
permission_required = 'company.view_company'
def get_success_url(self): def get_success_url(self):
return reverse('company-notes', kwargs={'pk': self.get_object().id}) return reverse('company-notes', kwargs={'pk': self.get_object().id})
@ -137,6 +139,7 @@ class CompanyDetail(DetailView):
template_name = 'company/detail.html' template_name = 'company/detail.html'
queryset = Company.objects.all() queryset = Company.objects.all()
model = Company model = Company
permission_required = 'company.view_company'
def get_context_data(self, **kwargs): def get_context_data(self, **kwargs):
ctx = super().get_context_data(**kwargs) ctx = super().get_context_data(**kwargs)
@ -150,6 +153,7 @@ class CompanyImage(AjaxUpdateView):
ajax_template_name = 'modal_form.html' ajax_template_name = 'modal_form.html'
ajax_form_title = _('Update Company Image') ajax_form_title = _('Update Company Image')
form_class = CompanyImageForm form_class = CompanyImageForm
permission_required = 'company.change_company'
def get_data(self): def get_data(self):
return { return {
@ -164,6 +168,7 @@ class CompanyEdit(AjaxUpdateView):
context_object_name = 'company' context_object_name = 'company'
ajax_template_name = 'modal_form.html' ajax_template_name = 'modal_form.html'
ajax_form_title = _('Edit Company') ajax_form_title = _('Edit Company')
permission_required = 'company.change_company'
def get_data(self): def get_data(self):
return { return {
@ -177,6 +182,7 @@ class CompanyCreate(AjaxCreateView):
context_object_name = 'company' context_object_name = 'company'
form_class = EditCompanyForm form_class = EditCompanyForm
ajax_template_name = 'modal_form.html' ajax_template_name = 'modal_form.html'
permission_required = 'company.add_company'
def get_form_title(self): def get_form_title(self):
@ -230,6 +236,7 @@ class CompanyDelete(AjaxDeleteView):
ajax_template_name = 'company/delete.html' ajax_template_name = 'company/delete.html'
ajax_form_title = _('Delete Company') ajax_form_title = _('Delete Company')
context_object_name = 'company' context_object_name = 'company'
permission_required = 'company.delete_company'
def get_data(self): def get_data(self):
return { return {
@ -243,6 +250,7 @@ class SupplierPartDetail(DetailView):
template_name = 'company/supplier_part_detail.html' template_name = 'company/supplier_part_detail.html'
context_object_name = 'part' context_object_name = 'part'
queryset = SupplierPart.objects.all() queryset = SupplierPart.objects.all()
permission_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)
@ -258,6 +266,7 @@ 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'
class SupplierPartCreate(AjaxCreateView): class SupplierPartCreate(AjaxCreateView):
@ -268,6 +277,7 @@ class SupplierPartCreate(AjaxCreateView):
ajax_template_name = 'modal_form.html' ajax_template_name = 'modal_form.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 get_form(self): def get_form(self):
""" Create Form instance to create a new SupplierPart object. """ Create Form instance to create a new SupplierPart object.
@ -327,6 +337,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'
parts = [] parts = []
@ -398,6 +409,7 @@ 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 {
@ -440,6 +452,7 @@ 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):
@ -455,3 +468,4 @@ 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

@ -13,9 +13,11 @@
<h4>{% trans "Sales Order Items" %}</h4> <h4>{% trans "Sales Order Items" %}</h4>
{% if roles.sales_order.change %}
<div id='order-toolbar-buttons' class='btn-group' style='float: right;'> <div id='order-toolbar-buttons' class='btn-group' style='float: right;'>
<button type='button' class='btn btn-default' id='new-so-line'>{% trans "Add Line Item" %}</button> <button type='button' class='btn btn-default' id='new-so-line'>{% trans "Add Line Item" %}</button>
</div> </div>
{% endif %}
<table class='table table-striped table-condensed' id='so-lines-table' data-toolbar='#order-toolbar-buttons'> <table class='table table-striped table-condensed' id='so-lines-table' data-toolbar='#order-toolbar-buttons'>