diff --git a/InvenTree/InvenTree/urls.py b/InvenTree/InvenTree/urls.py index f4a6b74667..19723bb6bb 100644 --- a/InvenTree/InvenTree/urls.py +++ b/InvenTree/InvenTree/urls.py @@ -10,4 +10,5 @@ urlpatterns = [ url(r'^track/', include('track.urls')), url(r'^project/', include('project.urls')), url(r'^admin/', admin.site.urls), + url(r'^auth/', include('rest_framework.urls', namespace='rest_framework')) ] diff --git a/InvenTree/part/serializers.py b/InvenTree/part/serializers.py index 1ff66264e3..774815ac1a 100644 --- a/InvenTree/part/serializers.py +++ b/InvenTree/part/serializers.py @@ -44,10 +44,10 @@ class PartCategoryBriefSerializer(serializers.ModelSerializer): class PartCategoryDetailSerializer(serializers.ModelSerializer): # List of parts in this category - parts = PartSerializer(many=True) + parts = PartSerializer(many=True, read_only=True) # List of child categories under this one - children = PartCategoryBriefSerializer(many=True) + children = PartCategoryBriefSerializer(many=True, read_only=True) class Meta: model = PartCategory diff --git a/InvenTree/part/urls.py b/InvenTree/part/urls.py index de6c9c13a8..01db39c149 100644 --- a/InvenTree/part/urls.py +++ b/InvenTree/part/urls.py @@ -1,19 +1,45 @@ -from django.conf.urls import url +from django.conf.urls import url, include from . import views -urlpatterns = [ - # Single part detail - url(r'^(?P[0-9]+)/$', views.PartDetail.as_view()), - - # Part parameters list - url(r'^(?P[0-9]+)/parameters/$', views.PartParameters.as_view()), +""" URL patterns associated with part categories: +/category -> List all top-level categories +/category/ -> Detail view of given category +/category/new -> Create a new category +""" +categorypatterns = [ # Part category detail url(r'^category/(?P[0-9]+)/$', views.PartCategoryDetail.as_view()), # List of top-level categories - url(r'^category/$', views.PartCategoryList.as_view()), + url(r'^$', views.PartCategoryList.as_view()) +] + +""" URL patterns associated with a particular part: +/part/ -> Detail view of a given part +/part//parameters -> List parameters associated with a part +""" +partdetailpatterns = [ + # Single part detail + url(r'^$', views.PartDetail.as_view()), + + # View part parameters + url(r'parameters/$', views.PartParameters.as_view()) +] + +""" Top-level URL patterns for the Part app: +/part/ -> List all parts +/part/new -> Create a new part +/part/ -> (refer to partdetailpatterns) +/part/category -> (refer to categorypatterns) +""" +urlpatterns = [ + # Individual part + url(r'^(?P[0-9]+)/', include(partdetailpatterns)), + + # Part categories + url(r'^category/', views.PartCategoryList.as_view()), # List of all parts url(r'^$', views.PartList.as_view()) diff --git a/InvenTree/part/views.py b/InvenTree/part/views.py index dcd5ac54a3..55d5255789 100644 --- a/InvenTree/part/views.py +++ b/InvenTree/part/views.py @@ -1,4 +1,4 @@ -from rest_framework import generics +from rest_framework import generics, permissions from .models import PartCategory, Part, PartParameter from .serializers import PartSerializer @@ -6,37 +6,44 @@ from .serializers import PartCategoryDetailSerializer from .serializers import PartParameterSerializer -class PartDetail(generics.RetrieveAPIView): - +class PartDetail(generics.RetrieveUpdateDestroyAPIView): + """ Return information on a single part + """ queryset = Part.objects.all() serializer_class = PartSerializer + permission_classes = (permissions.IsAuthenticatedOrReadOnly,) -class PartParameters(generics.ListAPIView): - +class PartParameters(generics.ListCreateAPIView): + """ Return all parameters associated with a particular part + """ def get_queryset(self): part_id = self.kwargs['pk'] return PartParameter.objects.filter(part=part_id) serializer_class = PartParameterSerializer + permission_classes = (permissions.IsAuthenticatedOrReadOnly,) -class PartList(generics.ListAPIView): +class PartList(generics.ListCreateAPIView): queryset = Part.objects.all() serializer_class = PartSerializer + permission_classes = (permissions.IsAuthenticatedOrReadOnly,) -class PartCategoryDetail(generics.RetrieveAPIView): +class PartCategoryDetail(generics.RetrieveUpdateAPIView): """ Return information on a single PartCategory """ queryset = PartCategory.objects.all() serializer_class = PartCategoryDetailSerializer + permission_classes = (permissions.IsAuthenticatedOrReadOnly,) -class PartCategoryList(generics.ListAPIView): +class PartCategoryList(generics.ListCreateAPIView): """ Return a list of all top-level part categories. Categories are considered "top-level" if they do not have a parent """ queryset = PartCategory.objects.filter(parent=None) serializer_class = PartCategoryDetailSerializer + permission_classes = (permissions.IsAuthenticatedOrReadOnly,) diff --git a/InvenTree/project/models.py b/InvenTree/project/models.py index 1958540699..bf2bd42368 100644 --- a/InvenTree/project/models.py +++ b/InvenTree/project/models.py @@ -1,5 +1,5 @@ from __future__ import unicode_literals -from django.utils.translation import ugettext as _ +# from django.utils.translation import ugettext as _ from django.db import models @@ -47,6 +47,13 @@ class ProjectPart(models.Model): The overage is the number of extra parts that are generally used for a single run. """ + part = models.ForeignKey(Part, on_delete=models.CASCADE) + project = models.ForeignKey(Project, on_delete=models.CASCADE) + quantity = models.PositiveIntegerField(default=1) + + """ + # TODO - Add overage model fields + # Overage types OVERAGE_PERCENT = 0 OVERAGE_ABSOLUTE = 1 @@ -56,13 +63,11 @@ class ProjectPart(models.Model): OVERAGE_ABSOLUTE: _("Absolute") } - part = models.ForeignKey(Part, on_delete=models.CASCADE) - project = models.ForeignKey(Project, on_delete=models.CASCADE) - quantity = models.PositiveIntegerField(default=1) overage = models.FloatField(default=0) overage_type = models.PositiveIntegerField( default=OVERAGE_ABSOLUTE, choices=OVARAGE_CODES.items()) + """ # Set if the part is generated by the project, # rather than being consumed by the project diff --git a/InvenTree/project/serializers.py b/InvenTree/project/serializers.py index 0dae3f7cbd..dd9c9cb784 100644 --- a/InvenTree/project/serializers.py +++ b/InvenTree/project/serializers.py @@ -11,12 +11,10 @@ class ProjectPartSerializer(serializers.ModelSerializer): 'part', 'project', 'quantity', - 'overage', - 'overage_type', 'output') -class ProjectBriefSerializer(serializers.ModelSerializer): +class ProjectSerializer(serializers.ModelSerializer): """ Serializer for displaying brief overview of a project """ @@ -28,18 +26,6 @@ class ProjectBriefSerializer(serializers.ModelSerializer): 'category') -class ProjectDetailSerializer(serializers.ModelSerializer): - """ Serializer for detailed project information - """ - - class Meta: - model = Project - fields = ('pk', - 'name', - 'description', - 'category') - - class ProjectCategoryBriefSerializer(serializers.ModelSerializer): class Meta: @@ -49,9 +35,9 @@ class ProjectCategoryBriefSerializer(serializers.ModelSerializer): class ProjectCategoryDetailSerializer(serializers.ModelSerializer): - projects = ProjectBriefSerializer(many=True) + projects = ProjectSerializer(many=True, read_only=True) - children = ProjectCategoryBriefSerializer(many=True) + children = ProjectCategoryBriefSerializer(many=True, read_only=True) class Meta: model = ProjectCategory diff --git a/InvenTree/project/urls.py b/InvenTree/project/urls.py index 2758a64cc8..1dd0fba554 100644 --- a/InvenTree/project/urls.py +++ b/InvenTree/project/urls.py @@ -1,20 +1,39 @@ -from django.conf.urls import url +from django.conf.urls import url, include from . import views -urlpatterns = [ +""" URL patterns associated with project +/project/ -> Detail view of single project +/project//parts -> Detail all parts associated with project +""" +projectdetailpatterns = [ # Single project detail - url(r'^(?P[0-9]+)/$', views.ProjectDetail.as_view()), + url(r'^$', views.ProjectDetail.as_view()), # Parts associated with a project - url(r'^(?P[0-9]+)/parts$', views.ProjectPartsList.as_view()), + url(r'^parts/$', views.ProjectPartsList.as_view()), +] + +projectcategorypatterns = [ + # List of top-level project categories + url(r'^$', views.ProjectCategoryList.as_view()), + + # Detail of a single project category + url(r'^(?P[0-9]+)/$', views.ProjectCategoryDetail.as_view()), + + # Create a new category + url(r'^new/$', views.NewProjectCategory.as_view()) + +] + +urlpatterns = [ + + # Individual project URL + url(r'^(?P[0-9]+)/', include(projectdetailpatterns)), # List of all projects url(r'^$', views.ProjectList.as_view()), - # List of top-level project categories - url(r'^category/$', views.ProjectCategoryList.as_view()), - - # Detail of a single project category - url(r'^category/(?P[0-9]+)/$', views.ProjectCategoryDetail.as_view()) + # Project categories + url(r'^category/', include(projectcategorypatterns)), ] diff --git a/InvenTree/project/views.py b/InvenTree/project/views.py index 46a5fdb0c4..bb4d415139 100644 --- a/InvenTree/project/views.py +++ b/InvenTree/project/views.py @@ -1,38 +1,50 @@ -from rest_framework import generics +from rest_framework import generics, permissions from .models import ProjectCategory, Project, ProjectPart -from .serializers import ProjectBriefSerializer, ProjectDetailSerializer +from .serializers import ProjectSerializer from .serializers import ProjectCategoryDetailSerializer from .serializers import ProjectPartSerializer -class ProjectDetail(generics.RetrieveAPIView): +class ProjectDetail(generics.RetrieveUpdateAPIView): queryset = Project.objects.all() - serializer_class = ProjectDetailSerializer + serializer_class = ProjectSerializer + permission_classes = (permissions.IsAuthenticatedOrReadOnly,) -class ProjectList(generics.ListAPIView): +class ProjectList(generics.ListCreateAPIView): queryset = Project.objects.all() - serializer_class = ProjectBriefSerializer + serializer_class = ProjectSerializer + permission_classes = (permissions.IsAuthenticatedOrReadOnly,) -class ProjectCategoryDetail(generics.RetrieveAPIView): +class NewProjectCategory(generics.CreateAPIView): + """ Create a new Project Category + """ + serializer_class = ProjectCategoryDetailSerializer + permission_classes = (permissions.IsAuthenticatedOrReadOnly,) + + +class ProjectCategoryDetail(generics.RetrieveUpdateAPIView): queryset = ProjectCategory.objects.all() serializer_class = ProjectCategoryDetailSerializer + permission_classes = (permissions.IsAuthenticatedOrReadOnly,) -class ProjectCategoryList(generics.ListAPIView): +class ProjectCategoryList(generics.ListCreateAPIView): queryset = ProjectCategory.objects.filter(parent=None) serializer_class = ProjectCategoryDetailSerializer + permission_classes = (permissions.IsAuthenticatedOrReadOnly,) -class ProjectPartsList(generics.ListAPIView): +class ProjectPartsList(generics.ListCreateAPIView): serializer_class = ProjectPartSerializer + permission_classes = (permissions.IsAuthenticatedOrReadOnly,) def get_queryset(self): project_id = self.kwargs['pk'] diff --git a/InvenTree/stock/serializers.py b/InvenTree/stock/serializers.py index bf07dfa1de..0e06115d39 100644 --- a/InvenTree/stock/serializers.py +++ b/InvenTree/stock/serializers.py @@ -36,10 +36,10 @@ class LocationDetailSerializer(serializers.ModelSerializer): """ # List of all stock items in this location - items = StockItemSerializer(many=True) + items = StockItemSerializer(many=True, read_only=True) # List of all child locations under this one - children = LocationBriefSerializer(many=True) + children = LocationBriefSerializer(many=True, read_only=True) class Meta: model = StockLocation