diff --git a/InvenTree/InvenTree/urls.py b/InvenTree/InvenTree/urls.py
index 19723bb6bb..d750b6388c 100644
--- a/InvenTree/InvenTree/urls.py
+++ b/InvenTree/InvenTree/urls.py
@@ -1,8 +1,21 @@
from django.conf.urls import url, include
from django.contrib import admin
+from rest_framework import status
+from rest_framework.response import Response
+from rest_framework.decorators import api_view
+
admin.site.site_header = "InvenTree Admin"
+
+@api_view()
+def Inventree404(self):
+ """ Supplied URL is invalid
+ """
+ content = {'detail': 'Malformed API URL'}
+ return Response(content, status=status.HTTP_404_NOT_FOUND)
+
+
urlpatterns = [
url(r'^stock/', include('stock.urls')),
url(r'^part/', include('part.urls')),
@@ -10,5 +23,8 @@ 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'))
+ url(r'^auth/', include('rest_framework.urls', namespace='rest_framework')),
+
+ # Any other URL
+ url(r'', Inventree404)
]
diff --git a/InvenTree/part/templates/part/category.html b/InvenTree/part/templates/part/category.html
deleted file mode 100644
index 8e999ea96c..0000000000
--- a/InvenTree/part/templates/part/category.html
+++ /dev/null
@@ -1,21 +0,0 @@
-{# Construct the category path #}
-Category/
-{% for path_item in category.parentpath %}
-{{ path_item.name }}/
-{% endfor %}
-
-{{ category.name }}
-
-
Children:
-{% for child in children %}
-{{ child.name }}
-{% endfor %}
-
-
-
-Parts:
-
-
-{% for part in category.part_set.all %}
-{{ part.name }}
-{% endfor %}
diff --git a/InvenTree/part/templates/part/categorylist.html b/InvenTree/part/templates/part/categorylist.html
deleted file mode 100644
index c4c62ba58b..0000000000
--- a/InvenTree/part/templates/part/categorylist.html
+++ /dev/null
@@ -1,8 +0,0 @@
-Top Level Part Categories:
-
-{% for category in categories %}
-
-
-{{ category.name }}
-
-{% endfor %}
\ No newline at end of file
diff --git a/InvenTree/part/templates/part/detail.html b/InvenTree/part/templates/part/detail.html
deleted file mode 100644
index 8055f46023..0000000000
--- a/InvenTree/part/templates/part/detail.html
+++ /dev/null
@@ -1,4 +0,0 @@
-{{part}}
-
-
-Category: {{ part.category }}
\ No newline at end of file
diff --git a/InvenTree/part/views.py b/InvenTree/part/views.py
index 711df899f8..da9cb5ab4a 100644
--- a/InvenTree/part/views.py
+++ b/InvenTree/part/views.py
@@ -61,10 +61,7 @@ class PartFilter(django_filters.rest_framework.FilterSet):
class PartList(generics.ListCreateAPIView):
- """ Display a list of parts, with optional filters
- Filters are specified in the url, e.g.
- /part/?category=127
- /part/?min_stock=100
+ """ List of parts, with optional filters
"""
def get_queryset(self):
diff --git a/InvenTree/stock/templates/stock/index.html b/InvenTree/stock/templates/stock/index.html
deleted file mode 100644
index 234cd000dc..0000000000
--- a/InvenTree/stock/templates/stock/index.html
+++ /dev/null
@@ -1,8 +0,0 @@
-Warehouses:
-
-{% for warehouse in warehouse %}
-
-
-{{ warehouse.name }}
-
-{% endfor %}
\ No newline at end of file
diff --git a/InvenTree/supplier/serializers.py b/InvenTree/supplier/serializers.py
new file mode 100644
index 0000000000..3635a93a72
--- /dev/null
+++ b/InvenTree/supplier/serializers.py
@@ -0,0 +1,42 @@
+from rest_framework import serializers
+
+from .models import Supplier, SupplierPart, SupplierPriceBreak
+
+
+class SupplierSerializer(serializers.ModelSerializer):
+
+ class Meta:
+ model = Supplier
+ fields = '__all__'
+
+
+class SupplierPartSerializer(serializers.ModelSerializer):
+
+ price_breaks = serializers.PrimaryKeyRelatedField(many=True, read_only=True)
+
+ class Meta:
+ model = SupplierPart
+ fields = ['pk',
+ 'part',
+ 'supplier',
+ 'SKU',
+ 'manufacturer',
+ 'MPN',
+ 'URL',
+ 'description',
+ 'single_price',
+ 'packaging',
+ 'multiple',
+ 'minimum',
+ 'price_breaks',
+ 'lead_time']
+
+
+class SupplierPriceBreakSerializer(serializers.ModelSerializer):
+
+ class Meta:
+ model = SupplierPriceBreak
+ fields = ['pk',
+ 'part',
+ 'quantity',
+ 'cost']
diff --git a/InvenTree/supplier/templates/supplier/detail.html b/InvenTree/supplier/templates/supplier/detail.html
deleted file mode 100644
index 709ba79248..0000000000
--- a/InvenTree/supplier/templates/supplier/detail.html
+++ /dev/null
@@ -1 +0,0 @@
-{{ supplier }}
\ No newline at end of file
diff --git a/InvenTree/supplier/urls.py b/InvenTree/supplier/urls.py
index 5490b22d87..10fbe8f230 100644
--- a/InvenTree/supplier/urls.py
+++ b/InvenTree/supplier/urls.py
@@ -1,11 +1,30 @@
-from django.conf.urls import url
+from django.conf.urls import url, include
from . import views
-urlpatterns = [
-
- # Display details of a supplier
- url(r'^(?P[0-9]+)/$', views.supplierDetail, name='detail'),
-
- url(r'^$', views.index, name='index')
+partpatterns = [
+ url(r'^(?P[0-9]+)/?$', views.SupplierPartDetail.as_view()),
+
+ url(r'^\?*[^/]*/?$', views.SupplierPartList.as_view())
+]
+
+pricepatterns = [
+ url(r'^(?P[0-9]+)/?$', views.SupplierPriceBreakDetail.as_view()),
+
+ url(r'^\?*[^/]*/?$', views.SupplierPriceBreakList.as_view())
+]
+
+urlpatterns = [
+
+ # Supplier part information
+ url(r'part/?', include(partpatterns)),
+
+ # Supplier price information
+ url(r'price/?', include(pricepatterns)),
+
+ # Display details of a supplier
+ url(r'^(?P[0-9]+)/?$', views.SupplierDetail.as_view()),
+
+ # List suppliers
+ url(r'^\?*[^/]*/?$', views.SupplierList.as_view())
]
diff --git a/InvenTree/supplier/views.py b/InvenTree/supplier/views.py
index edfd3883be..e6fa2e628b 100644
--- a/InvenTree/supplier/views.py
+++ b/InvenTree/supplier/views.py
@@ -1,15 +1,74 @@
-from django.shortcuts import render, get_object_or_404
-from django.http import HttpResponse
+from rest_framework import generics, permissions
-from .models import Supplier
+from .models import Supplier, SupplierPart, SupplierPriceBreak
+from .serializers import SupplierSerializer
+from .serializers import SupplierPartSerializer
+from .serializers import SupplierPriceBreakSerializer
-def index(request):
- return HttpResponse("This is the suppliers page")
+class SupplierDetail(generics.RetrieveUpdateDestroyAPIView):
+
+ queryset = Supplier.objects.all()
+ serializer_class = SupplierSerializer
+ permission_classes = (permissions.IsAuthenticatedOrReadOnly,)
-def supplierDetail(request, supplier_id):
- supplier = get_object_or_404(Supplier, pk=supplier_id)
-
- return render(request, 'supplier/detail.html',
- {'supplier': supplier})
+class SupplierList(generics.ListCreateAPIView):
+
+ queryset = Supplier.objects.all()
+ serializer_class = SupplierSerializer
+ permission_classes = (permissions.IsAuthenticatedOrReadOnly,)
+
+
+class SupplierPartDetail(generics.RetrieveUpdateDestroyAPIView):
+
+ queryset = SupplierPart.objects.all()
+ serializer_class = SupplierPartSerializer
+ permission_classes = (permissions.IsAuthenticatedOrReadOnly,)
+
+
+class SupplierPartList(generics.ListCreateAPIView):
+
+ serializer_class = SupplierPartSerializer
+ permission_classes = (permissions.IsAuthenticatedOrReadOnly,)
+
+ def get_queryset(self):
+ parts = SupplierPart.objects.all()
+ params = self.request.query_params
+
+ supplier_id = params.get('supplier', None)
+ if supplier_id:
+ parts = parts.filter(supplier=supplier_id)
+
+ part_id = params.get('part', None)
+ if part_id:
+ parts = parts.filter(part=part_id)
+
+ manu_id = params.get('manufacturer', None)
+ if manu_id:
+ parts = parts.filter(manufacturer=manu_id)
+
+ return parts
+
+
+class SupplierPriceBreakDetail(generics.RetrieveUpdateDestroyAPIView):
+
+ queryset = SupplierPriceBreak.objects.all()
+ serializer_class = SupplierPriceBreakSerializer
+ permission_classes = (permissions.IsAuthenticatedOrReadOnly,)
+
+
+class SupplierPriceBreakList(generics.ListCreateAPIView):
+
+ def get_queryset(self):
+ prices = SupplierPriceBreak.objects.all()
+ params = self.request.query_params
+
+ part_id = params.get('part', None)
+ if part_id:
+ prices = prices.filter(part=part_id)
+
+ return prices
+
+ serializer_class = SupplierPriceBreakSerializer
+ permission_classes = (permissions.IsAuthenticatedOrReadOnly,)