diff --git a/InvenTree/build/migrations/0024_auto_20201201_1023.py b/InvenTree/build/migrations/0024_auto_20201201_1023.py
new file mode 100644
index 0000000000..fde4114af5
--- /dev/null
+++ b/InvenTree/build/migrations/0024_auto_20201201_1023.py
@@ -0,0 +1,20 @@
+# Generated by Django 3.0.7 on 2020-11-30 23:23
+
+from django.db import migrations
+import django.db.models.deletion
+import mptt.fields
+
+
+class Migration(migrations.Migration):
+
+ dependencies = [
+ ('build', '0023_auto_20201110_0911'),
+ ]
+
+ operations = [
+ migrations.AlterField(
+ model_name='build',
+ name='parent',
+ field=mptt.fields.TreeForeignKey(blank=True, help_text='BuildOrder to which this build is allocated', null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='children', to='build.Build', verbose_name='Parent Build'),
+ ),
+ ]
diff --git a/InvenTree/build/models.py b/InvenTree/build/models.py
index a18471ccc6..8616e11b2a 100644
--- a/InvenTree/build/models.py
+++ b/InvenTree/build/models.py
@@ -83,9 +83,10 @@ class Build(MPTTModel):
help_text=_('Brief description of the build')
)
+ # TODO - Perhaps delete the build "tree"
parent = TreeForeignKey(
'self',
- on_delete=models.DO_NOTHING,
+ on_delete=models.SET_NULL,
blank=True, null=True,
related_name='children',
verbose_name=_('Parent Build'),
diff --git a/InvenTree/gunicorn.conf.py b/InvenTree/gunicorn.conf.py
index aeee2a366b..0e5eee75f9 100644
--- a/InvenTree/gunicorn.conf.py
+++ b/InvenTree/gunicorn.conf.py
@@ -3,3 +3,6 @@ import multiprocessing
bind = "0.0.0.0:8000"
workers = multiprocessing.cpu_count() * 2 + 1
+
+max_requests = 1000
+max_requests_jitter = 50
diff --git a/InvenTree/stock/templates/stock/location.html b/InvenTree/stock/templates/stock/location.html
index 632219dc0a..fef3428373 100644
--- a/InvenTree/stock/templates/stock/location.html
+++ b/InvenTree/stock/templates/stock/location.html
@@ -99,7 +99,6 @@
-
{% if location and location.children.all|length > 0 %}
{% include 'stock/location_list.html' with children=location.children.all collapse_id="locations" %}
@@ -110,6 +109,7 @@
{% include "stock_table.html" %}
+
{% endblock %}
diff --git a/InvenTree/stock/views.py b/InvenTree/stock/views.py
index 175a06ae80..18c05f100b 100644
--- a/InvenTree/stock/views.py
+++ b/InvenTree/stock/views.py
@@ -1292,6 +1292,7 @@ class StockItemEdit(AjaxUpdateView):
# If the part cannot be purchased, hide the supplier_part field
if not item.part.purchaseable:
form.fields['supplier_part'].widget = HiddenInput()
+ form.fields['purchase_price'].widget = HiddenInput()
else:
query = form.fields['supplier_part'].queryset
query = query.filter(part=item.part.id)
@@ -1505,6 +1506,9 @@ class StockItemCreate(AjaxCreateView):
form.rebuild_layout()
+ if not part.purchaseable:
+ form.fields['purchase_price'].widget = HiddenInput()
+
# Hide the 'part' field (as a valid part is selected)
# form.fields['part'].widget = HiddenInput()
diff --git a/InvenTree/users/admin.py b/InvenTree/users/admin.py
index 4614e5bc4c..29496d02a7 100644
--- a/InvenTree/users/admin.py
+++ b/InvenTree/users/admin.py
@@ -87,6 +87,64 @@ class RoleGroupAdmin(admin.ModelAdmin):
RuleSetInline,
]
+ list_display = ('name', 'admin', 'part', 'stock', 'build', 'purchase_order', 'sales_order')
+
+ def get_rule_set(self, obj, rule_set_type):
+ ''' Return list of permissions for the given ruleset '''
+
+ # Get all rulesets associated to object
+ rule_sets = RuleSet.objects.filter(group=obj.pk)
+
+ # Select ruleset based on type
+ for rule_set in rule_sets:
+ if rule_set.name == rule_set_type:
+ break
+
+ def append_permission_level(permission_level, next_level):
+ if not permission_level:
+ return next_level
+
+ if permission_level[:-1].endswith('|'):
+ permission_level += next_level
+ else:
+ permission_level += ' | ' + next_level
+
+ return permission_level
+
+ permission_level = ''
+
+ if rule_set.can_view:
+ permission_level = append_permission_level(permission_level, 'V')
+
+ if rule_set.can_add:
+ permission_level = append_permission_level(permission_level, 'A')
+
+ if rule_set.can_change:
+ permission_level = append_permission_level(permission_level, 'C')
+
+ if rule_set.can_delete:
+ permission_level = append_permission_level(permission_level, 'D')
+
+ return permission_level
+
+ def admin(self, obj):
+ return self.get_rule_set(obj, 'admin')
+
+ def part(self, obj):
+ return self.get_rule_set(obj, 'part')
+
+ def stock(self, obj):
+ return self.get_rule_set(obj, 'stock')
+
+ def build(self, obj):
+ return self.get_rule_set(obj, 'build')
+
+ def purchase_order(self, obj):
+ return self.get_rule_set(obj, 'purchase_order')
+
+ def sales_order(self, obj):
+ return self.get_rule_set(obj, 'sales_order')
+
def get_formsets_with_inlines(self, request, obj=None):
for inline in self.get_inline_instances(request, obj):
# Hide RuleSetInline in the 'Add role' view