From 6a88bdb37d467939eabf4ed3e58e0f6746aedcfc Mon Sep 17 00:00:00 2001 From: eeintech Date: Mon, 11 Jan 2021 12:56:40 -0500 Subject: [PATCH] StockLocation owner is now a GenericForeignKey that can be set to user or group models --- InvenTree/stock/forms.py | 25 +++++++++- .../migrations/0057_auto_20210107_1904.py | 27 ----------- InvenTree/stock/models.py | 27 +++++++++-- InvenTree/stock/views.py | 48 +++++++++++++++---- 4 files changed, 88 insertions(+), 39 deletions(-) delete mode 100644 InvenTree/stock/migrations/0057_auto_20210107_1904.py diff --git a/InvenTree/stock/forms.py b/InvenTree/stock/forms.py index 7659981ecd..97fc4fe69d 100644 --- a/InvenTree/stock/forms.py +++ b/InvenTree/stock/forms.py @@ -10,6 +10,7 @@ from django.forms.utils import ErrorDict from django.utils.translation import ugettext as _ from django.core.validators import MinValueValidator from django.core.exceptions import ValidationError +from django.contrib.auth.models import User, Group from mptt.fields import TreeNodeChoiceField @@ -85,15 +86,37 @@ class EditStockItemTestResultForm(HelperForm): class EditStockLocationForm(HelperForm): """ Form for editing a StockLocation """ + owner = forms.ChoiceField( + label=_('Owner'), + help_text=_('Select Owner') + ) + class Meta: model = StockLocation fields = [ 'name', 'parent', 'description', - 'owner', ] + def get_owner_choices(self): + + choices = [('', '-' * 10)] + + for group in Group.objects.all(): + choices.append((f'group_{group.name}', f'{group} (Group)')) + + for user in User.objects.all(): + choices.append((f'user_{user.username}', f'{user} (User)')) + + return choices + + def __init__(self, *args, **kwargs): + + super().__init__(*args, **kwargs) + + self.fields['owner'].choices = self.get_owner_choices() + class ConvertStockItemForm(HelperForm): """ diff --git a/InvenTree/stock/migrations/0057_auto_20210107_1904.py b/InvenTree/stock/migrations/0057_auto_20210107_1904.py deleted file mode 100644 index 9d2f2a533c..0000000000 --- a/InvenTree/stock/migrations/0057_auto_20210107_1904.py +++ /dev/null @@ -1,27 +0,0 @@ -# Generated by Django 3.0.7 on 2021-01-07 19:04 - -from django.conf import settings -from django.db import migrations, models -import django.db.models.deletion - - -class Migration(migrations.Migration): - - dependencies = [ - ('auth', '0011_update_proxy_permissions'), - migrations.swappable_dependency(settings.AUTH_USER_MODEL), - ('stock', '0056_stockitem_expiry_date'), - ] - - operations = [ - migrations.AddField( - model_name='stockitem', - name='owner', - field=models.ForeignKey(blank=True, help_text='Owner (User)', null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='owner_stockitems', to=settings.AUTH_USER_MODEL), - ), - migrations.AddField( - model_name='stocklocation', - name='owner', - field=models.ForeignKey(blank=True, help_text='Owner (Group)', null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='owner_stocklocations', to='auth.Group'), - ), - ] diff --git a/InvenTree/stock/models.py b/InvenTree/stock/models.py index acd505171c..596422ed9c 100644 --- a/InvenTree/stock/models.py +++ b/InvenTree/stock/models.py @@ -19,6 +19,8 @@ from django.core.validators import MinValueValidator from django.contrib.auth.models import User, Group from django.db.models.signals import pre_delete from django.dispatch import receiver +from django.contrib.contenttypes.fields import GenericForeignKey +from django.contrib.contenttypes.models import ContentType from markdownx.models import MarkdownxField @@ -47,9 +49,28 @@ class StockLocation(InvenTreeTree): Stock locations can be heirarchical as required """ - owner = models.ForeignKey(Group, on_delete=models.SET_NULL, blank=True, null=True, - help_text='Owner (Group)', - related_name='owner_stocklocations') + owner_type = models.ForeignKey(ContentType, on_delete=models.CASCADE, null=True, blank=True) + owner_id = models.PositiveIntegerField(null=True, blank=True) + owner = GenericForeignKey('owner_type', 'owner_id') + + def save(self, *args, **kwargs): + """ Custom save method to process StockLocation owner """ + + # Extract owner + try: + owner = kwargs.pop('owner') + except KeyError: + owner = '' + + # Set the owner + if owner.startswith('group'): + group_name = owner.replace('group_', '') + self.owner = Group.objects.get(name=group_name) + elif owner.startswith('user'): + user_name = owner.replace('user_', '') + self.owner = User.objects.get(username=user_name) + + super(StockLocation, self).save(*args, **kwargs) def get_absolute_url(self): return reverse('stock-location-detail', kwargs={'pk': self.id}) diff --git a/InvenTree/stock/views.py b/InvenTree/stock/views.py index 1af0585c39..2d9a417f39 100644 --- a/InvenTree/stock/views.py +++ b/InvenTree/stock/views.py @@ -11,7 +11,7 @@ from django.views.generic import DetailView, ListView, UpdateView from django.forms.models import model_to_dict from django.forms import HiddenInput from django.urls import reverse -from django.contrib.auth.models import User +from django.contrib.auth.models import User, Group from django.utils.translation import ugettext as _ @@ -125,6 +125,24 @@ class StockLocationEdit(AjaxUpdateView): ajax_form_title = _('Edit Stock Location') role_required = 'stock.change' + def get_owner_initial(self): + + initial = '' + + location = self.get_object() + + owner = location.owner + + if owner: + if type(owner) is Group: + group_name = owner.name + initial = f'group_{group_name}' + elif type(owner) is User: + user_name = owner.username + initial = f'user_{user_name}' + + return initial + def get_form(self): """ Customize form data for StockLocation editing. @@ -144,9 +162,12 @@ class StockLocationEdit(AjaxUpdateView): # Is ownership control enabled? stock_ownership_control = InvenTreeSetting.get_setting('STOCK_OWNERSHIP_CONTROL') + owner_initial = self.get_owner_initial() + if not stock_ownership_control: form.fields['owner'].widget = HiddenInput() else: + form.fields['owner'].initial = owner_initial if location.parent: form.fields['owner'].initial = location.parent.owner if not self.request.user.is_superuser: @@ -159,13 +180,21 @@ class StockLocationEdit(AjaxUpdateView): - update all children's owners with location's owner """ - self.object = form.save() + self.object = form.save(commit=False) + # parent = form.cleaned_data.get('parent', None) + stock_ownership_control = InvenTreeSetting.get_setting('STOCK_OWNERSHIP_CONTROL') - if self.object.get_children() and stock_ownership_control: - for child in self.object.get_children(): - child.owner = self.object.owner - child.save() + if stock_ownership_control: + owner = form.cleaned_data.get('owner', None) + self.object.save(**{'owner': owner}) + + if self.object.get_children(): + for child in self.object.get_children(): + child.owner = self.object.owner + child.save() + else: + self.object.save() return self.object @@ -1463,10 +1492,13 @@ class StockLocationCreate(AjaxCreateView): self.object = form.save(commit=False) parent = form.cleaned_data.get('parent', None) + owner = form.cleaned_data.get('owner', None) + if parent: self.object.owner = parent.owner - - self.object.save() + self.object.save() + else: + self.object.save(**{'owner': owner}) return self.object