def update_owners(self): from django.contrib.auth import get_user_model from django.contrib.auth.models import Group from users.models import Owner # Create group owners for group in Group.objects.all(): Owner.create(group) # Create user owners for user in get_user_model().objects.all(): Owner.create(user)
def update_owners(self): """Create an 'owner' object for each user and group instance""" from django.contrib.auth import get_user_model from django.contrib.auth.models import Group from users.models import Owner # Create group owners for group in Group.objects.all(): Owner.create(group) # Create user owners for user in get_user_model().objects.all(): Owner.create(user)
def test_overdue_notification(self): """Test overdue purchase order notification Ensure that a notification is sent when a PurchaseOrder becomes overdue """ po = PurchaseOrder.objects.get(pk=1) # Created by 'sam' po.created_by = get_user_model().objects.get(pk=4) # Responsible : 'Engineers' group responsible = Owner.create(obj=Group.objects.get(pk=2)) po.responsible = responsible # Target date = yesterday po.target_date = datetime.now().date() - timedelta(days=1) po.save() # Check for overdue purchase orders order.tasks.check_overdue_purchase_orders() for user_id in [2, 3, 4]: messages = common.models.NotificationMessage.objects.filter( category='order.overdue_purchase_order', user__id=user_id, ) self.assertTrue(messages.exists()) msg = messages.first() self.assertEqual(msg.target_object_id, 1) self.assertEqual(msg.name, 'Overdue Purchase Order')
def get_form(self): """ Customize form data for StockLocation editing. Limit the choices for 'parent' field to those which make sense. If ownership control is enabled and location has parent, disable owner field. """ form = super(AjaxUpdateView, self).get_form() location = self.get_object() # Remove any invalid choices for the 'parent' field parent_choices = StockLocation.objects.all() parent_choices = parent_choices.exclude( id__in=location.getUniqueChildren()) form.fields['parent'].queryset = parent_choices # Is ownership control enabled? stock_ownership_control = InvenTreeSetting.get_setting( 'STOCK_OWNERSHIP_CONTROL') if not stock_ownership_control: # Hide owner field form.fields['owner'].widget = HiddenInput() else: # Get location's owner location_owner = location.owner if location_owner: if location.parent: try: # If location has parent and owner: automatically select parent's owner parent_owner = location.parent.owner form.fields['owner'].initial = parent_owner except AttributeError: pass else: # If current owner exists: automatically select it form.fields['owner'].initial = location_owner # Update queryset or disable field (only if not admin) if not self.request.user.is_superuser: if type(location_owner.owner) is Group: user_as_owner = Owner.get_owner(self.request.user) queryset = location_owner.get_related_owners( include_group=True) if user_as_owner not in queryset: # Only owners or admin can change current owner form.fields['owner'].disabled = True else: form.fields['owner'].queryset = queryset return form
def test_owner(self): # Check that owner was created for user user_as_owner = Owner.get_owner(self.user) self.assertEqual(type(user_as_owner), Owner) # Check that owner was created for group group_as_owner = Owner.get_owner(self.group) self.assertEqual(type(group_as_owner), Owner) # Check name self.assertEqual(str(user_as_owner), 'testuser (user)') # Get related owners (user + group) related_owners = group_as_owner.get_related_owners(include_group=True) self.assertTrue(user_as_owner in related_owners) self.assertTrue(group_as_owner in related_owners) # Get related owners (only user) related_owners = group_as_owner.get_related_owners(include_group=False) self.assertTrue(user_as_owner in related_owners) self.assertFalse(group_as_owner in related_owners) # Get related owners on user related_owners = user_as_owner.get_related_owners() self.assertEqual(related_owners, [user_as_owner]) # Check owner matching owners = Owner.get_owners_matching_user(self.user) self.assertEqual(owners, [user_as_owner, group_as_owner]) # Delete user and verify owner was deleted too self.user.delete() user_as_owner = Owner.get_owner(self.user) self.assertEqual(user_as_owner, None) # Delete group and verify owner was deleted too self.group.delete() group_as_owner = Owner.get_owner(self.group) self.assertEqual(group_as_owner, None)
def filter_assigned_to_me(self, queryset, name, value): """Filter by orders which are assigned to the current user.""" value = str2bool(value) # Work out who "me" is! owners = Owner.get_owners_matching_user(self.request.user) if value: queryset = queryset.filter(responsible__in=owners) else: queryset = queryset.exclude(responsible__in=owners) return queryset
def test_overdue_notification(self): """Test overdue sales order notification""" self.order.created_by = get_user_model().objects.get(pk=3) self.order.responsible = Owner.create(obj=Group.objects.get(pk=2)) self.order.target_date = datetime.now().date() - timedelta(days=1) self.order.save() # Check for overdue sales orders order.tasks.check_overdue_sales_orders() messages = NotificationMessage.objects.filter( category='order.overdue_sales_order', ) self.assertEqual(len(messages), 2)
def test_owner(self): # Check that owner was created for user user_as_owner = Owner.get_owner(self.user) self.assertEqual(type(user_as_owner), Owner) # Check that owner was created for group group_as_owner = Owner.get_owner(self.group) self.assertEqual(type(group_as_owner), Owner) # Get related owners (user + group) related_owners = group_as_owner.get_related_owners(include_group=True) self.assertTrue(user_as_owner in related_owners) self.assertTrue(group_as_owner in related_owners) # Delete user and verify owner was deleted too self.user.delete() user_as_owner = Owner.get_owner(self.user) self.assertEqual(user_as_owner, None) # Delete group and verify owner was deleted too self.group.delete() group_as_owner = Owner.get_owner(self.group) self.assertEqual(group_as_owner, None)
def test_new_build_notification(self): """Test that a notification is sent when a new build is created""" Build.objects.create( reference='BO-9999', title='Some new build', part=self.assembly, quantity=5, issued_by=get_user_model().objects.get(pk=2), responsible=Owner.create(obj=Group.objects.get(pk=3))) # Two notifications should have been sent messages = common.models.NotificationMessage.objects.filter( category='build.new_build', ) self.assertEqual(messages.count(), 2) self.assertFalse(messages.filter(user__pk=2).exists()) self.assertTrue(messages.filter(user__pk=3).exists()) self.assertTrue(messages.filter(user__pk=4).exists())
def test_new_so_notification(self): """Test that a notification is sent when a new SalesOrder is created. - The responsible user should receive a notification - The creating user should *not* receive a notification """ SalesOrder.objects.create( customer=self.customer, reference='1234567', created_by=get_user_model().objects.get(pk=3), responsible=Owner.create(obj=Group.objects.get(pk=3))) messages = NotificationMessage.objects.filter( category='order.new_salesorder', ) # A notification should have been generated for user 4 (who is a member of group 3) self.assertTrue(messages.filter(user__pk=4).exists()) # However *no* notification should have been generated for the creating user self.assertFalse(messages.filter(user__pk=3).exists())
def test_new_po_notification(self): """Test that a notification is sent when a new PurchaseOrder is created - The responsible user(s) should receive a notification - The creating user should *not* receive a notification """ PurchaseOrder.objects.create( supplier=Company.objects.get(pk=1), reference='XYZABC', created_by=get_user_model().objects.get(pk=3), responsible=Owner.create(obj=get_user_model().objects.get(pk=4)), ) messages = common.models.NotificationMessage.objects.filter( category='order.new_purchaseorder', ) self.assertEqual(messages.count(), 1) # A notification should have been generated for user 4 (who is a member of group 3) self.assertTrue(messages.filter(user__pk=4).exists()) # However *no* notification should have been generated for the creating user self.assertFalse(messages.filter(user__pk=3).exists())
def test_owner_control(self): # Test stock location and item ownership from .models import StockLocation, StockItem from users.models import Owner user_group = self.user.groups.all()[0] user_group_owner = Owner.get_owner(user_group) new_user_group = self.new_user.groups.all()[0] new_user_group_owner = Owner.get_owner(new_user_group) user_as_owner = Owner.get_owner(self.user) new_user_as_owner = Owner.get_owner(self.new_user) test_location_id = 4 test_item_id = 11 # Enable ownership control self.enable_ownership() # Set ownership on existing location response = self.client.post(reverse('stock-location-edit', args=(test_location_id, )), { 'name': 'Office', 'owner': user_group_owner.pk }, HTTP_X_REQUESTED_WITH='XMLHttpRequest') self.assertContains(response, '"form_valid": true', status_code=200) # Set ownership on existing item (and change location) response = self.client.post(reverse('stock-item-edit', args=(test_item_id, )), { 'part': 1, 'status': StockStatus.OK, 'owner': user_as_owner.pk }, HTTP_X_REQUESTED_WITH='XMLHttpRequest') self.assertContains(response, '"form_valid": true', status_code=200) # Logout self.client.logout() # Login with new user self.client.login(username='******', password='******') # Test location edit response = self.client.post(reverse('stock-location-edit', args=(test_location_id, )), { 'name': 'Office', 'owner': new_user_group_owner.pk }, HTTP_X_REQUESTED_WITH='XMLHttpRequest') # Make sure the location's owner is unchanged location = StockLocation.objects.get(pk=test_location_id) self.assertEqual(location.owner, user_group_owner) # Test item edit response = self.client.post(reverse('stock-item-edit', args=(test_item_id, )), { 'part': 1, 'status': StockStatus.OK, 'owner': new_user_as_owner.pk }, HTTP_X_REQUESTED_WITH='XMLHttpRequest') # Make sure the item's owner is unchanged item = StockItem.objects.get(pk=test_item_id) self.assertEqual(item.owner, user_as_owner) # Create new parent location parent_location = { 'name': 'John Desk', 'description': 'John\'s desk', 'owner': new_user_group_owner.pk, } # Create new parent location response = self.client.post(reverse('stock-location-create'), parent_location, HTTP_X_REQUESTED_WITH='XMLHttpRequest') self.assertContains(response, '"form_valid": true', status_code=200) # Retrieve created location parent_location = StockLocation.objects.get( name=parent_location['name']) # Create new child location new_location = { 'name': 'Upper Left Drawer', 'description': 'John\'s desk - Upper left drawer', } # Try to create new location with neither parent or owner response = self.client.post(reverse('stock-location-create'), new_location, HTTP_X_REQUESTED_WITH='XMLHttpRequest') self.assertContains(response, '"form_valid": false', status_code=200) # Try to create new location with invalid owner new_location['parent'] = parent_location.id new_location['owner'] = user_group_owner.pk response = self.client.post(reverse('stock-location-create'), new_location, HTTP_X_REQUESTED_WITH='XMLHttpRequest') self.assertContains(response, '"form_valid": false', status_code=200) # Try to create new location with valid owner new_location['owner'] = new_user_group_owner.pk response = self.client.post(reverse('stock-location-create'), new_location, HTTP_X_REQUESTED_WITH='XMLHttpRequest') self.assertContains(response, '"form_valid": true', status_code=200) # Retrieve created location location_created = StockLocation.objects.get(name=new_location['name']) # Create new item new_item = { 'part': 25, 'location': location_created.pk, 'quantity': 123, 'status': StockStatus.OK, } # Try to create new item with no owner response = self.client.post(reverse('stock-item-create'), new_item, HTTP_X_REQUESTED_WITH='XMLHttpRequest') self.assertContains(response, '"form_valid": false', status_code=200) # Try to create new item with invalid owner new_item['owner'] = user_as_owner.pk response = self.client.post(reverse('stock-item-create'), new_item, HTTP_X_REQUESTED_WITH='XMLHttpRequest') self.assertContains(response, '"form_valid": false', status_code=200) # Try to create new item with valid owner new_item['owner'] = new_user_as_owner.pk response = self.client.post(reverse('stock-item-create'), new_item, HTTP_X_REQUESTED_WITH='XMLHttpRequest') self.assertContains(response, '"form_valid": true', status_code=200) # Logout self.client.logout() # Login with admin self.client.login(username='******', password='******') # Switch owner of location response = self.client.post(reverse('stock-location-edit', args=(location_created.pk, )), { 'name': new_location['name'], 'owner': user_group_owner.pk }, HTTP_X_REQUESTED_WITH='XMLHttpRequest') self.assertContains(response, '"form_valid": true', status_code=200) # Check that owner was updated for item in this location stock_item = StockItem.objects.all().last() self.assertEqual(stock_item.owner, user_group_owner)
def get_form(self): """ Get form for StockItem editing. Limit the choices for supplier_part """ form = super(AjaxUpdateView, self).get_form() # Hide the "expiry date" field if the feature is not enabled if not common.settings.stock_expiry_enabled(): form.fields['expiry_date'].widget = HiddenInput() item = self.get_object() # If the part cannot be purchased, hide the supplier_part field if not item.part.purchaseable: form.fields['supplier_part'].widget = HiddenInput() form.fields.pop('purchase_price') else: query = form.fields['supplier_part'].queryset query = query.filter(part=item.part.id) form.fields['supplier_part'].queryset = query # Hide the serial number field if it is not required if not item.part.trackable and not item.serialized: form.fields['serial'].widget = HiddenInput() location = item.location # Is ownership control enabled? stock_ownership_control = InvenTreeSetting.get_setting('STOCK_OWNERSHIP_CONTROL') if not stock_ownership_control: form.fields['owner'].widget = HiddenInput() else: try: location_owner = location.owner except AttributeError: location_owner = None # Check if location has owner if location_owner: form.fields['owner'].initial = location_owner # Check location's owner type and filter potential owners if type(location_owner.owner) is Group: user_as_owner = Owner.get_owner(self.request.user) queryset = location_owner.get_related_owners(include_group=True) if user_as_owner in queryset: form.fields['owner'].initial = user_as_owner form.fields['owner'].queryset = queryset elif type(location_owner.owner) is get_user_model(): # If location's owner is a user: automatically set owner field and disable it form.fields['owner'].disabled = True form.fields['owner'].initial = location_owner try: item_owner = item.owner except AttributeError: item_owner = None # Check if item has owner if item_owner: form.fields['owner'].initial = item_owner # Check item's owner type and filter potential owners if type(item_owner.owner) is Group: user_as_owner = Owner.get_owner(self.request.user) queryset = item_owner.get_related_owners(include_group=True) if user_as_owner in queryset: form.fields['owner'].initial = user_as_owner form.fields['owner'].queryset = queryset elif type(item_owner.owner) is get_user_model(): # If item's owner is a user: automatically set owner field and disable it form.fields['owner'].disabled = True form.fields['owner'].initial = item_owner return form
def get_form(self): """ Get form for StockItem creation. Overrides the default get_form() method to intelligently limit ForeignKey choices based on other selections """ form = super().get_form() # Hide the "expiry date" field if the feature is not enabled if not common.settings.stock_expiry_enabled(): form.fields['expiry_date'].widget = HiddenInput() part = self.get_part(form=form) if part is not None: # Add placeholder text for the serial number field form.field_placeholder['serial_numbers'] = part.getSerialNumberString() form.rebuild_layout() if not part.purchaseable: form.fields.pop('purchase_price') # Hide the 'part' field (as a valid part is selected) # form.fields['part'].widget = HiddenInput() # Trackable parts get special consideration: if part.trackable: form.fields['delete_on_deplete'].disabled = True else: form.fields['serial_numbers'].disabled = True # If the part is NOT purchaseable, hide the supplier_part field if not part.purchaseable: form.fields['supplier_part'].widget = HiddenInput() else: # Pre-select the allowable SupplierPart options parts = form.fields['supplier_part'].queryset parts = parts.filter(part=part.id) form.fields['supplier_part'].queryset = parts # If there is one (and only one) supplier part available, pre-select it all_parts = parts.all() if len(all_parts) == 1: # TODO - This does NOT work for some reason? Ref build.views.BuildItemCreate form.fields['supplier_part'].initial = all_parts[0].id else: # No Part has been selected! # We must not provide *any* options for SupplierPart form.fields['supplier_part'].queryset = SupplierPart.objects.none() form.fields['serial_numbers'].disabled = True # Otherwise if the user has selected a SupplierPart, we know what Part they meant! if form['supplier_part'].value() is not None: pass location = None try: loc_id = form['location'].value() location = StockLocation.objects.get(pk=loc_id) except StockLocation.DoesNotExist: pass except ValueError: pass # Is ownership control enabled? stock_ownership_control = InvenTreeSetting.get_setting('STOCK_OWNERSHIP_CONTROL') if not stock_ownership_control: form.fields['owner'].widget = HiddenInput() else: try: location_owner = location.owner except AttributeError: location_owner = None if location_owner: # Check location's owner type and filter potential owners if type(location_owner.owner) is Group: user_as_owner = Owner.get_owner(self.request.user) queryset = location_owner.get_related_owners() if user_as_owner in queryset: form.fields['owner'].initial = user_as_owner form.fields['owner'].queryset = queryset elif type(location_owner.owner) is get_user_model(): # If location's owner is a user: automatically set owner field and disable it form.fields['owner'].disabled = True form.fields['owner'].initial = location_owner return form