diff --git a/InvenTree/InvenTree/models.py b/InvenTree/InvenTree/models.py index 35ed5ccc0c..acfdad80fc 100644 --- a/InvenTree/InvenTree/models.py +++ b/InvenTree/InvenTree/models.py @@ -2,6 +2,7 @@ from __future__ import unicode_literals from django.db import models from django.contrib.contenttypes.models import ContentType +from rest_framework.exceptions import ValidationError class Company(models.Model): @@ -150,7 +151,7 @@ class InvenTreeTree(models.Model): pass # Parent cannot be set to same ID (this would cause looping) elif val == self.id: - return + raise ValidationError("Category cannot set itself as parent") # Null parent is OK elif val is None: pass @@ -158,7 +159,7 @@ class InvenTreeTree(models.Model): else: kids = self.getUniqueChildren() if val in kids: - return + raise ValidationError("Category cannot set a child as parent") # Prohibit certain characters from tree node names elif attrname == 'name': diff --git a/InvenTree/InvenTree/urls.py b/InvenTree/InvenTree/urls.py index e50470dc1c..a81134e48f 100644 --- a/InvenTree/InvenTree/urls.py +++ b/InvenTree/InvenTree/urls.py @@ -8,6 +8,7 @@ from stock.urls import stock_urls, stock_loc_urls, stock_track_urls from project.urls import prj_urls, prj_part_urls, prj_cat_urls, prj_run_urls from supplier.urls import cust_urls, manu_urls, supplier_part_urls, price_break_urls, supplier_urls from track.urls import unique_urls, part_track_urls +from users.urls import user_urls admin.site.site_header = "InvenTree Admin" @@ -40,6 +41,9 @@ apipatterns = [ url(r'^project-category/', include(prj_cat_urls)), url(r'^project-part/', include(prj_part_urls)), url(r'^project-run/', include(prj_run_urls)), + + # User URLs + url(r'^user/', include(user_urls)), ] urlpatterns = [ diff --git a/InvenTree/stock/models.py b/InvenTree/stock/models.py index 877661dd7f..c4be02eb63 100644 --- a/InvenTree/stock/models.py +++ b/InvenTree/stock/models.py @@ -2,6 +2,7 @@ from __future__ import unicode_literals from django.utils.translation import ugettext as _ from django.db import models from django.core.validators import MinValueValidator +from django.contrib.auth.models import User from supplier.models import SupplierPart from part.models import Part @@ -29,6 +30,7 @@ class StockItem(models.Model): # last time the stock was checked / counted stocktake_date = models.DateField(blank=True, null=True) + stocktake_user = models.ForeignKey(User, on_delete=models.SET_NULL, blank=True, null=True) review_needed = models.BooleanField(default=False) @@ -63,7 +65,7 @@ class StockItem(models.Model): infinite = models.BooleanField(default=False) - def stocktake(self, count): + def stocktake(self, count, user): """ Perform item stocktake. When the quantity of an item is counted, record the date of stocktake @@ -76,27 +78,7 @@ class StockItem(models.Model): self.quantity = count self.stocktake_date = datetime.now().date() - self.save() - - def take_stock(self, amount): - """ Take items from stock - This function can be called by initiating a ProjectRun, - or by manually taking the items from the stock location - """ - - if self.infinite: - return - - amount = int(amount) - if amount < 0: - raise ValueError("Stock amount must be positive") - - q = self.quantity - amount - - if q < 0: - q = 0 - - self.quantity = q + self.stocktake_user = user self.save() def add_stock(self, amount): @@ -119,6 +101,9 @@ class StockItem(models.Model): self.quantity = q self.save() + def take_stock(self, amount): + self.add_stock(-amount) + def __str__(self): return "{n} x {part} @ {loc}".format( n=self.quantity, diff --git a/InvenTree/stock/serializers.py b/InvenTree/stock/serializers.py index e73be8531b..fc0c6979fe 100644 --- a/InvenTree/stock/serializers.py +++ b/InvenTree/stock/serializers.py @@ -18,6 +18,7 @@ class StockItemSerializer(serializers.HyperlinkedModelSerializer): 'notes', 'updated', 'stocktake_date', + 'stocktake_user', 'review_needed', 'expected_arrival') diff --git a/InvenTree/stock/views.py b/InvenTree/stock/views.py index 26d6aa1e74..4dab2f4546 100644 --- a/InvenTree/stock/views.py +++ b/InvenTree/stock/views.py @@ -62,7 +62,7 @@ class StockStocktakeEndpoint(generics.UpdateAPIView): def update(self, request, *args, **kwargs): object = self.get_object() - object.stocktake(request.data['quantity']) + object.stocktake(request.data['quantity'], request.user) serializer = self.get_serializer(object) diff --git a/InvenTree/users/__init__.py b/InvenTree/users/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/InvenTree/users/admin.py b/InvenTree/users/admin.py new file mode 100644 index 0000000000..b12fa73f94 --- /dev/null +++ b/InvenTree/users/admin.py @@ -0,0 +1,3 @@ +# -*- coding: utf-8 -*- +# from __future__ import unicode_literals +# from django.contrib import admin diff --git a/InvenTree/users/apps.py b/InvenTree/users/apps.py new file mode 100644 index 0000000000..251989770b --- /dev/null +++ b/InvenTree/users/apps.py @@ -0,0 +1,8 @@ +# -*- coding: utf-8 -*- +from __future__ import unicode_literals + +from django.apps import AppConfig + + +class UsersConfig(AppConfig): + name = 'users' diff --git a/InvenTree/users/models.py b/InvenTree/users/models.py new file mode 100644 index 0000000000..40a96afc6f --- /dev/null +++ b/InvenTree/users/models.py @@ -0,0 +1 @@ +# -*- coding: utf-8 -*- diff --git a/InvenTree/users/serializers.py b/InvenTree/users/serializers.py new file mode 100644 index 0000000000..01ce8f44b3 --- /dev/null +++ b/InvenTree/users/serializers.py @@ -0,0 +1,14 @@ +from rest_framework import serializers +from django.contrib.auth.models import User + + +class UserSerializer(serializers.HyperlinkedModelSerializer): + """ Serializer for a User + """ + + class Meta: + model = User + fields = ('username', + 'first_name', + 'last_name', + 'email',) diff --git a/InvenTree/users/tests.py b/InvenTree/users/tests.py new file mode 100644 index 0000000000..57c7c1fe6b --- /dev/null +++ b/InvenTree/users/tests.py @@ -0,0 +1,4 @@ +# -*- coding: utf-8 -*- +# from __future__ import unicode_literals + +# from django.test import TestCase diff --git a/InvenTree/users/urls.py b/InvenTree/users/urls.py new file mode 100644 index 0000000000..046cab9428 --- /dev/null +++ b/InvenTree/users/urls.py @@ -0,0 +1,9 @@ +from django.conf.urls import url + +from . import views + +user_urls = [ + url(r'^(?P[0-9]+)/?$', views.UserDetail.as_view(), name='user-detail'), + + url(r'^$', views.UserList.as_view()), +] diff --git a/InvenTree/users/views.py b/InvenTree/users/views.py new file mode 100644 index 0000000000..20fee70caa --- /dev/null +++ b/InvenTree/users/views.py @@ -0,0 +1,17 @@ +from rest_framework import generics, permissions +from django.contrib.auth.models import User +from .serializers import UserSerializer + + +class UserDetail(generics.RetrieveAPIView): + + queryset = User.objects.all() + serializer_class = UserSerializer + permission_classes = (permissions.IsAuthenticatedOrReadOnly,) + + +class UserList(generics.ListAPIView): + + queryset = User.objects.all() + serializer_class = UserSerializer + permission_classes = (permissions.IsAuthenticatedOrReadOnly,)