kopia lustrzana https://github.com/longclawshop/longclaw
Fixes #46
rodzic
03f929b3ab
commit
91a4106714
|
|
@ -1,100 +1,96 @@
|
|||
from django.apps import apps
|
||||
from django.db import transaction
|
||||
from rest_framework.decorators import api_view, permission_classes
|
||||
from rest_framework import permissions, status
|
||||
from rest_framework.decorators import detail_route, list_route
|
||||
from rest_framework import permissions, status, viewsets
|
||||
from rest_framework.response import Response
|
||||
from longclaw.longclawbasket.models import BasketItem
|
||||
from longclaw.longclawbasket.serializers import BasketItemSerializer
|
||||
from longclaw.longclawbasket import utils
|
||||
from longclaw.settings import PRODUCT_VARIANT_MODEL
|
||||
from longclaw.utils import ProductVariant
|
||||
|
||||
ProductVariant = apps.get_model(*PRODUCT_VARIANT_MODEL.split('.'))
|
||||
class BasketViewSet(viewsets.ModelViewSet):
|
||||
"""
|
||||
Viewset for interacting with a sessions 'basket' -
|
||||
``ProductVariants`` which have been marked for checkout.BaseException
|
||||
"""
|
||||
serializer_class = BasketItemSerializer
|
||||
permission_classes = (permissions.AllowAny, )
|
||||
|
||||
@api_view(["GET"])
|
||||
@permission_classes([permissions.AllowAny])
|
||||
def get_basket(request):
|
||||
''' Get all basket items
|
||||
'''
|
||||
items, _ = utils.get_basket_items(request)
|
||||
serializer = BasketItemSerializer(items, many=True)
|
||||
return Response(data=serializer.data, status=status.HTTP_200_OK)
|
||||
def get_queryset(self):
|
||||
items, _ = utils.get_basket_items(self.request)
|
||||
return items
|
||||
|
||||
@api_view(["GET"])
|
||||
@permission_classes([permissions.AllowAny])
|
||||
def get_item_count(request):
|
||||
'''
|
||||
Get quantity of a single item in the basket
|
||||
'''
|
||||
bid = utils.basket_id(request)
|
||||
item = ProductVariant.objects.get(id=request.GET["variant_id"])
|
||||
try:
|
||||
count = BasketItem.objects.get(basket_id=bid, variant=item).quantity
|
||||
except BasketItem.DoesNotExist:
|
||||
count = 0
|
||||
return Response(data={"quantity": count}, status=status.HTTP_200_OK)
|
||||
def create(self, request):
|
||||
"""
|
||||
Add an item to the basket
|
||||
"""
|
||||
variant_id = request.data.get("variant_id", None)
|
||||
|
||||
@transaction.atomic
|
||||
@api_view(["POST"])
|
||||
@permission_classes([permissions.AllowAny])
|
||||
def add_to_basket(request):
|
||||
'''
|
||||
Add an item to the basket
|
||||
'''
|
||||
variant = ProductVariant.objects.get(id=request.data["variant_id"])
|
||||
quantity = request.data.get("quantity", 1)
|
||||
if variant_id is not None:
|
||||
variant = ProductVariant.objects.get(id=variant_id)
|
||||
|
||||
items, bid = utils.get_basket_items(request)
|
||||
# Check if the variant is already in the basket
|
||||
in_basket = False
|
||||
for item in items:
|
||||
if item.variant.id == variant.id:
|
||||
item.increase_quantity(quantity)
|
||||
in_basket = True
|
||||
break
|
||||
if not in_basket:
|
||||
item = BasketItem(variant=variant, quantity=quantity, basket_id=bid)
|
||||
item.save()
|
||||
quantity = request.data.get("quantity", 1)
|
||||
items, bid = utils.get_basket_items(request)
|
||||
|
||||
items, _ = utils.get_basket_items(request)
|
||||
serializer = BasketItemSerializer(items, many=True)
|
||||
return Response(data=serializer.data,
|
||||
status=status.HTTP_201_CREATED)
|
||||
# Check if the variant is already in the basket
|
||||
in_basket = False
|
||||
for item in items:
|
||||
if item.variant.id == variant.id:
|
||||
item.increase_quantity(quantity)
|
||||
in_basket = True
|
||||
break
|
||||
if not in_basket:
|
||||
item = BasketItem(variant=variant, quantity=quantity, basket_id=bid)
|
||||
item.save()
|
||||
|
||||
@transaction.atomic
|
||||
@api_view(["POST"])
|
||||
@permission_classes([permissions.AllowAny])
|
||||
def remove_from_basket(request):
|
||||
'''
|
||||
Remove an item from the basket
|
||||
'''
|
||||
print(request.data["variant_id"])
|
||||
variant = ProductVariant.objects.get(id=request.data["variant_id"])
|
||||
quantity = request.data.get("quantity", 1)
|
||||
try:
|
||||
item = BasketItem.objects.get(basket_id=utils.basket_id(request), variant=variant)
|
||||
except BasketItem.DoesNotExist:
|
||||
return Response(data={"message": "Item does not exist in cart"},
|
||||
status=status.HTTP_400_BAD_REQUEST)
|
||||
serializer = BasketItemSerializer(self.get_queryset(), many=True)
|
||||
response = Response(data=serializer.data,
|
||||
status=status.HTTP_201_CREATED)
|
||||
|
||||
if quantity >= item.quantity:
|
||||
item.delete()
|
||||
else:
|
||||
item.decrease_quantity(quantity)
|
||||
else:
|
||||
response = Response(
|
||||
{"message": "Missing 'variant_id'"},
|
||||
status=status.HTTP_400_BAD_REQUEST)
|
||||
|
||||
items, _ = utils.get_basket_items(request)
|
||||
serializer = BasketItemSerializer(items, many=True)
|
||||
return Response(data=serializer.data,
|
||||
status=status.HTTP_201_CREATED)
|
||||
return response
|
||||
|
||||
@api_view(["GET"])
|
||||
@permission_classes([permissions.AllowAny])
|
||||
def basket_total_items(request):
|
||||
'''
|
||||
Get total number of items in the basket
|
||||
'''
|
||||
items, _ = utils.get_basket_items(request)
|
||||
n_total = 0
|
||||
for item in items:
|
||||
n_total += item.quantity
|
||||
def destroy(self, request, variant_id=None):
|
||||
'''
|
||||
Remove an item from the basket
|
||||
'''
|
||||
variant = ProductVariant.objects.get(id=variant_id)
|
||||
quantity = request.data.get("quantity", 1)
|
||||
try:
|
||||
item = BasketItem.objects.get(
|
||||
basket_id=utils.basket_id(request), variant=variant)
|
||||
item.decrease_quantity(quantity)
|
||||
|
||||
return Response(data={"quantity": n_total}, status=status.HTTP_200_OK)
|
||||
serializer = BasketItemSerializer(self.get_queryset(), many=True)
|
||||
return Response(data=serializer.data,
|
||||
status=status.HTTP_200_OK)
|
||||
|
||||
except BasketItem.DoesNotExist:
|
||||
return Response(data={"message": "Item does not exist in cart"},
|
||||
status=status.HTTP_400_BAD_REQUEST)
|
||||
|
||||
@list_route(methods=['get'])
|
||||
def total_items(self, request):
|
||||
'''
|
||||
Get total number of items in the basket
|
||||
'''
|
||||
n_total = 0
|
||||
for item in self.get_queryset():
|
||||
n_total += item.quantity
|
||||
|
||||
return Response(data={"quantity": n_total}, status=status.HTTP_200_OK)
|
||||
|
||||
@detail_route(methods=['get'])
|
||||
def item_count(self, request, variant_id=None):
|
||||
'''
|
||||
Get quantity of a single item in the basket
|
||||
'''
|
||||
bid = utils.basket_id(request)
|
||||
item = ProductVariant.objects.get(id=variant_id)
|
||||
try:
|
||||
count = BasketItem.objects.get(basket_id=bid, variant=item).quantity
|
||||
except BasketItem.DoesNotExist:
|
||||
count = 0
|
||||
return Response(data={"quantity": count}, status=status.HTTP_200_OK)
|
||||
|
|
|
|||
|
|
@ -1,3 +1,18 @@
|
|||
from django.test import TestCase
|
||||
from django.test.client import RequestFactory
|
||||
from longclaw.tests.utils import LongclawTestCase, BasketItemFactory
|
||||
from longclaw.longclawbasket.utils import basket_id
|
||||
|
||||
# Create your tests here.
|
||||
|
||||
class BasketTest(LongclawTestCase):
|
||||
|
||||
def setUp(self):
|
||||
request = RequestFactory().get('/')
|
||||
request.session = {}
|
||||
bid = basket_id(request)
|
||||
BasketItemFactory(basket_id=bid)
|
||||
|
||||
def test_get_basket(self):
|
||||
self.get_test('basket_list')
|
||||
|
||||
def test_basket_total_items(self):
|
||||
self.get_test('basket_total_items')
|
||||
|
|
|
|||
|
|
@ -3,22 +3,38 @@ from longclaw.longclawbasket import api
|
|||
from longclaw.longclawbasket import views
|
||||
from longclaw.settings import API_URL_PREFIX
|
||||
|
||||
basket_list = api.BasketViewSet.as_view({
|
||||
'get': 'list',
|
||||
'post': 'create'
|
||||
})
|
||||
|
||||
basket_detail = api.BasketViewSet.as_view({
|
||||
'delete': 'destroy'
|
||||
})
|
||||
|
||||
item_count = api.BasketViewSet.as_view({
|
||||
'get': 'item_count'
|
||||
})
|
||||
|
||||
total_items = api.BasketViewSet.as_view({
|
||||
'get': 'total_items'
|
||||
})
|
||||
|
||||
urlpatterns = [
|
||||
url(API_URL_PREFIX + r'add_to_basket/$',
|
||||
api.add_to_basket,
|
||||
name="add_to_basket"),
|
||||
url(API_URL_PREFIX + r'remove_from_basket/$',
|
||||
api.remove_from_basket,
|
||||
name="remove_from_basket"),
|
||||
url(API_URL_PREFIX + r'get_item_count/$',
|
||||
api.get_item_count,
|
||||
name="get_item_count"),
|
||||
url(API_URL_PREFIX + r'basket_total_items/$',
|
||||
api.basket_total_items,
|
||||
|
||||
url(API_URL_PREFIX + r'basket/$',
|
||||
basket_list,
|
||||
name='basket_list'),
|
||||
url(API_URL_PREFIX + r'basket/count',
|
||||
total_items,
|
||||
name="basket_total_items"),
|
||||
url(API_URL_PREFIX + r'get_basket/$',
|
||||
api.get_basket,
|
||||
name="get_basket"),
|
||||
url(API_URL_PREFIX + r'basket/(?P<variant_id>[0-9]+)/$',
|
||||
basket_detail,
|
||||
name='basket_detail'),
|
||||
url(API_URL_PREFIX + r'basket/(?P<variant_id>[0-9]+)/$',
|
||||
item_count,
|
||||
name='basket_item_count'),
|
||||
|
||||
url(r'basket/$',
|
||||
views.BasketView.as_view(),
|
||||
name="basket")
|
||||
|
|
|
|||
|
|
@ -1,9 +1,6 @@
|
|||
from django.apps import apps
|
||||
from rest_framework import serializers
|
||||
from longclaw.longclawproducts.models import Product
|
||||
from longclaw.settings import PRODUCT_VARIANT_MODEL
|
||||
|
||||
ProductVariant = apps.get_model(*PRODUCT_VARIANT_MODEL.split('.'))
|
||||
from longclaw.utils import ProductVariant
|
||||
|
||||
class ProductSerializer(serializers.ModelSerializer):
|
||||
|
||||
|
|
|
|||
|
|
@ -1,7 +1,5 @@
|
|||
import factory
|
||||
from django.core.urlresolvers import reverse
|
||||
from django.apps import apps
|
||||
from django.utils.text import slugify
|
||||
|
||||
from rest_framework.test import APITestCase
|
||||
from rest_framework import status
|
||||
|
|
@ -10,9 +8,7 @@ from wagtail_factories import PageFactory
|
|||
|
||||
from longclaw.longclawproducts.models import Product
|
||||
from longclaw.longclawbasket.models import BasketItem
|
||||
from longclaw.settings import PRODUCT_VARIANT_MODEL
|
||||
|
||||
ProductVariant = apps.get_model(*PRODUCT_VARIANT_MODEL.split('.'))
|
||||
from longclaw.utils import ProductVariant
|
||||
|
||||
class ProductFactory(PageFactory):
|
||||
''' Create a random Product
|
||||
|
|
@ -25,8 +21,8 @@ class ProductFactory(PageFactory):
|
|||
|
||||
@classmethod
|
||||
def _create(cls, model_class, *args, **kwargs):
|
||||
kwargs['parent'] = None
|
||||
return super(ProductFactory, cls)._create(model_class, *args, **kwargs)
|
||||
kwargs['parent'] = None
|
||||
return super(ProductFactory, cls)._create(model_class, *args, **kwargs)
|
||||
|
||||
class ProductVariantFactory(factory.django.DjangoModelFactory):
|
||||
|
||||
|
|
@ -34,7 +30,7 @@ class ProductVariantFactory(factory.django.DjangoModelFactory):
|
|||
model = ProductVariant
|
||||
|
||||
product = factory.SubFactory(ProductFactory)
|
||||
description = factory.Faker('text')
|
||||
description = factory.Faker('text')
|
||||
price = factory.Faker('pyfloat', positive=True, left_digits=2, right_digits=2)
|
||||
ref = factory.Faker('pystr', min_chars=3, max_chars=10)
|
||||
stock = factory.Faker('pyint')
|
||||
|
|
@ -58,7 +54,7 @@ class LongclawTestCase(APITestCase):
|
|||
urlkwargs (dict): The `kwargs` parameter to pass to the `reverse` function
|
||||
'''
|
||||
response = self.client.get(reverse(urlname, kwargs=urlkwargs), **kwargs)
|
||||
self.assertEquals(response.status_code, status.HTTP_200_OK)
|
||||
self.assertEqual(response.status_code, status.HTTP_200_OK)
|
||||
return response
|
||||
|
||||
def post_test(self, data, urlname, urlkwargs=None, **kwargs):
|
||||
|
|
@ -78,10 +74,10 @@ class LongclawTestCase(APITestCase):
|
|||
''' Submit a PATCH request and assert the response status code is 200
|
||||
'''
|
||||
response = self.client.patch(reverse(urlname, kwargs=urlkwargs), data, **kwargs)
|
||||
self.assertEquals(response.status_code, status.HTTP_200_OK)
|
||||
self.assertEqual(response.status_code, status.HTTP_200_OK)
|
||||
return response
|
||||
|
||||
def put_test(self, data, urlname, urlkwargs=None, **kwargs):
|
||||
response = self.client.put(reverse(urlname, kwargs=urlkwargs), data, **kwargs)
|
||||
self.assertEquals(response.status_code, status.HTTP_202_ACCEPTED)
|
||||
return response
|
||||
self.assertEqual(response.status_code, status.HTTP_202_ACCEPTED)
|
||||
return response
|
||||
|
|
|
|||
|
|
@ -0,0 +1,4 @@
|
|||
from django.apps import apps
|
||||
from longclaw.settings import PRODUCT_VARIANT_MODEL
|
||||
|
||||
ProductVariant = apps.get_model(*PRODUCT_VARIANT_MODEL.split('.'))
|
||||
Ładowanie…
Reference in New Issue