kopia lustrzana https://github.com/longclawshop/longclaw
Separate shipping models and address and register with modeladmin
rodzic
e2c6a7b8bf
commit
8b9867b740
|
|
@ -1,20 +0,0 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
# Generated by Django 1.10.4 on 2017-02-07 20:53
|
||||
from __future__ import unicode_literals
|
||||
|
||||
from django.db import migrations
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('basket', '0001_initial'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.RenameField(
|
||||
model_name='basketitem',
|
||||
old_name='product',
|
||||
new_name='variant',
|
||||
),
|
||||
]
|
||||
|
|
@ -7,9 +7,8 @@ from rest_framework.decorators import api_view, permission_classes
|
|||
from rest_framework import permissions, status
|
||||
from rest_framework.response import Response
|
||||
from longclaw.basket.utils import get_basket_items, destroy_basket
|
||||
from longclaw.orders.models import Order, OrderItem, Address
|
||||
from longclaw.checkout.models import ShippingCountry
|
||||
from longclaw.checkout import serializers
|
||||
from longclaw.orders.models import Order, OrderItem
|
||||
from longclaw.shipping.models import Address
|
||||
from longclaw.checkout.utils import PaymentError
|
||||
from longclaw import settings
|
||||
|
||||
|
|
@ -95,7 +94,6 @@ def capture_payment(request):
|
|||
)
|
||||
order_item.save()
|
||||
|
||||
|
||||
try:
|
||||
gateway.create_payment(request, float(total)+postage)
|
||||
# Once the order has been successfully taken, we can empty the basket
|
||||
|
|
@ -108,70 +106,3 @@ def capture_payment(request):
|
|||
response = Response(data={"message": err.message, "order_id": order.id},
|
||||
status=status.HTTP_400_BAD_REQUEST)
|
||||
return response
|
||||
|
||||
class InvalidShippingRate(Exception):
|
||||
pass
|
||||
|
||||
class InvalidShippingCountry(Exception):
|
||||
pass
|
||||
|
||||
def get_shipping_cost(country_code, option):
|
||||
try:
|
||||
obj = ShippingCountry.objects.get(country_code=country_code)
|
||||
if option == 'standard':
|
||||
return {"rate": obj.standard_rate,
|
||||
"description": obj.standard_rate_description,
|
||||
"carrier": obj.standard_rate_carrier}
|
||||
elif option == 'premium':
|
||||
return {"rate": obj.premium_rate,
|
||||
"description": obj.premium_rate_description,
|
||||
"carrier": obj.premium_rate_carrier}
|
||||
else:
|
||||
raise InvalidShippingRate
|
||||
|
||||
except ShippingCountry.DoesNotExist:
|
||||
if settings.DEFAULT_SHIPPING_ENABLED:
|
||||
return {"rate": settings.DEFAULT_SHIPPING_RATE,
|
||||
"description": "Standard shipping to rest of world",
|
||||
"carrier": settings.DEFAULT_SHIPPING_CARRIER}
|
||||
else:
|
||||
raise InvalidShippingCountry
|
||||
|
||||
|
||||
|
||||
@api_view(['GET'])
|
||||
@permission_classes({permissions.AllowAny})
|
||||
def shipping_cost(request):
|
||||
''' Returns the shipping cost for a given country
|
||||
If the shipping cost for the given country has not been set, it will
|
||||
fallback to the default shipping cost if it has been enabled in the app
|
||||
settings
|
||||
'''
|
||||
try:
|
||||
code = request.query_params.get('country_code')
|
||||
except AttributeError:
|
||||
return Response(data={"message": "No country code supplied"},
|
||||
status=status.HTTP_400_BAD_REQUEST)
|
||||
|
||||
option = request.query_params.get('shipping_option', 'standard')
|
||||
try:
|
||||
data = get_shipping_cost(code, option)
|
||||
response = Response(data=data, status=status.HTTP_200_OK)
|
||||
except InvalidShippingRate:
|
||||
response = Response(data={"message": "Shipping option {} is invalid".format(option)},
|
||||
status=status.HTTP_400_BAD_REQUEST)
|
||||
except InvalidShippingCountry:
|
||||
response = Response(data={"message": "Shipping to {} is not available".format(code)},
|
||||
status=status.HTTP_400_BAD_REQUEST)
|
||||
|
||||
return response
|
||||
|
||||
|
||||
@api_view(["GET"])
|
||||
@permission_classes([permissions.AllowAny])
|
||||
def get_shipping_countries(request):
|
||||
''' Get all shipping countries
|
||||
'''
|
||||
queryset = ShippingCountry.objects.all()
|
||||
serializer = serializers.ShippingCountrySerializer(queryset, many=True)
|
||||
return Response(data=serializer.data, status=status.HTTP_200_OK)
|
||||
|
|
|
|||
|
|
@ -0,0 +1,18 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
# Generated by Django 1.10.4 on 2017-02-11 16:32
|
||||
from __future__ import unicode_literals
|
||||
|
||||
from django.db import migrations
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('checkout', '0001_initial'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.DeleteModel(
|
||||
name='ShippingCountry',
|
||||
),
|
||||
]
|
||||
|
|
@ -1,17 +0,0 @@
|
|||
from django.db import models
|
||||
|
||||
class ShippingCountry(models.Model):
|
||||
''' Standard and premimum rate shipping for
|
||||
individual countries.
|
||||
'''
|
||||
country_code = models.CharField(max_length=3, primary_key=True)
|
||||
country_name = models.CharField(max_length=32)
|
||||
standard_rate = models.DecimalField(max_digits=12, decimal_places=2)
|
||||
standard_rate_carrier = models.CharField(max_length=64, default="Royal Mail")
|
||||
standard_rate_description = models.CharField(max_length=128,
|
||||
default="Royal Mail standard shipping")
|
||||
premium_rate = models.DecimalField(max_digits=12, decimal_places=2)
|
||||
premium_rate_carrier = models.CharField(max_length=64, default="Royal Mail")
|
||||
premium_rate_description = models.CharField(max_length=128,
|
||||
default="Royal Mail tracked and signed for")
|
||||
|
||||
|
|
@ -1,12 +0,0 @@
|
|||
from rest_framework import serializers
|
||||
|
||||
from longclaw.products.serializers import ProductVariantSerializer
|
||||
from longclaw.checkout.models import ShippingCountry
|
||||
|
||||
class ShippingCountrySerializer(serializers.ModelSerializer):
|
||||
|
||||
class Meta:
|
||||
model = ShippingCountry
|
||||
fields = "__all__"
|
||||
|
||||
|
||||
|
|
@ -2,9 +2,6 @@ from django.conf.urls import url
|
|||
from longclaw.checkout import api
|
||||
|
||||
urlpatterns = [
|
||||
url(r'shipping/$',
|
||||
api.shipping_cost,
|
||||
name='shipping'),
|
||||
url(r'payment/$',
|
||||
api.capture_payment,
|
||||
name='payment'),
|
||||
|
|
|
|||
|
|
@ -0,0 +1,30 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
# Generated by Django 1.10.4 on 2017-02-11 16:32
|
||||
from __future__ import unicode_literals
|
||||
|
||||
from django.db import migrations, models
|
||||
import django.db.models.deletion
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('shipping', '__first__'),
|
||||
('orders', '0002_order_shipping_rate'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AlterField(
|
||||
model_name='order',
|
||||
name='billing_address',
|
||||
field=models.ForeignKey(blank=True, on_delete=django.db.models.deletion.CASCADE, related_name='orders_billing_address', to='shipping.Address'),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='order',
|
||||
name='shipping_address',
|
||||
field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='orders_shipping_address', to='shipping.Address'),
|
||||
),
|
||||
migrations.DeleteModel(
|
||||
name='Address',
|
||||
),
|
||||
]
|
||||
|
|
@ -1,26 +1,6 @@
|
|||
from django.db import models
|
||||
from wagtail.wagtailadmin.edit_handlers import FieldPanel, InlinePanel
|
||||
from longclaw.settings import PRODUCT_VARIANT_MODEL, DEFAULT_SHIPPING_RATE
|
||||
|
||||
class Address(models.Model):
|
||||
name = models.CharField(max_length=64)
|
||||
line_1 = models.CharField(max_length=128)
|
||||
line_2 = models.CharField(max_length=128, blank=True)
|
||||
city = models.CharField(max_length=64)
|
||||
postcode = models.CharField(max_length=10)
|
||||
country = models.CharField(max_length=32)
|
||||
|
||||
panels = [
|
||||
FieldPanel('name'),
|
||||
FieldPanel('line_1'),
|
||||
FieldPanel('line_2'),
|
||||
FieldPanel('city'),
|
||||
FieldPanel('postcode'),
|
||||
FieldPanel('country')
|
||||
]
|
||||
|
||||
def __str__(self):
|
||||
return "{}, {}, {}".format(self.name, self.city, self.country)
|
||||
from longclaw.shipping.models import Address
|
||||
|
||||
class Order(models.Model):
|
||||
SUBMITTED = 1
|
||||
|
|
|
|||
|
|
@ -1,13 +1,8 @@
|
|||
from django.apps import apps
|
||||
from rest_framework import serializers
|
||||
from longclaw.orders.models import Order, OrderItem, Address
|
||||
from longclaw.orders.models import Order, OrderItem
|
||||
from longclaw.products.serializers import ProductVariantSerializer
|
||||
|
||||
class AddressSerializer(serializers.ModelSerializer):
|
||||
|
||||
class Meta:
|
||||
model = Address
|
||||
fields = "__all__"
|
||||
from longclaw.shipping.serializers import AddressSerializer
|
||||
|
||||
class OrderItemSerializer(serializers.ModelSerializer):
|
||||
|
||||
|
|
|
|||
|
|
@ -1,31 +0,0 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
# Generated by Django 1.10.4 on 2017-02-07 20:53
|
||||
from __future__ import unicode_literals
|
||||
|
||||
from django.db import migrations
|
||||
import django_extensions.db.fields
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('products', '0001_initial'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.RenameField(
|
||||
model_name='productimage',
|
||||
old_name='page',
|
||||
new_name='product',
|
||||
),
|
||||
migrations.RenameField(
|
||||
model_name='productvariant',
|
||||
old_name='page',
|
||||
new_name='product',
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='productvariant',
|
||||
name='slug',
|
||||
field=django_extensions.db.fields.AutoSlugField(blank=True, editable=False, populate_from=('product', 'ref'), separator=''),
|
||||
),
|
||||
]
|
||||
|
|
@ -12,12 +12,13 @@ from wagtail.wagtailimages.edit_handlers import ImageChooserPanel
|
|||
from wagtail.wagtailsearch import index
|
||||
|
||||
class ProductIndex(Page):
|
||||
pass
|
||||
subpage_types = ('products.Product',)
|
||||
|
||||
class ProductTag(TaggedItemBase):
|
||||
content_object = ParentalKey('Product', related_name='tagged_items')
|
||||
|
||||
class Product(Page):
|
||||
parent_page_types = ['products.ProductIndex']
|
||||
description = RichTextField()
|
||||
tags = ClusterTaggableManager(through=ProductTag, blank=True)
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1,72 @@
|
|||
from rest_framework.decorators import api_view, permission_classes
|
||||
from rest_framework import permissions, status
|
||||
from rest_framework.response import Response
|
||||
from longclaw.shipping import serializers, models
|
||||
from longclaw import settings
|
||||
|
||||
class InvalidShippingRate(Exception):
|
||||
pass
|
||||
|
||||
class InvalidShippingCountry(Exception):
|
||||
pass
|
||||
|
||||
def get_shipping_cost(country_code, option):
|
||||
try:
|
||||
obj = models.ShippingCountry.objects.get(country_code=country_code)
|
||||
if option == 'standard':
|
||||
return {"rate": obj.standard_rate,
|
||||
"description": obj.standard_rate_description,
|
||||
"carrier": obj.standard_rate_carrier}
|
||||
elif option == 'premium':
|
||||
return {"rate": obj.premium_rate,
|
||||
"description": obj.premium_rate_description,
|
||||
"carrier": obj.premium_rate_carrier}
|
||||
else:
|
||||
raise InvalidShippingRate
|
||||
|
||||
except models.ShippingCountry.DoesNotExist:
|
||||
if settings.DEFAULT_SHIPPING_ENABLED:
|
||||
return {"rate": settings.DEFAULT_SHIPPING_RATE,
|
||||
"description": "Standard shipping to rest of world",
|
||||
"carrier": settings.DEFAULT_SHIPPING_CARRIER}
|
||||
else:
|
||||
raise InvalidShippingCountry
|
||||
|
||||
|
||||
|
||||
@api_view(['GET'])
|
||||
@permission_classes({permissions.AllowAny})
|
||||
def shipping_cost(request):
|
||||
''' Returns the shipping cost for a given country
|
||||
If the shipping cost for the given country has not been set, it will
|
||||
fallback to the default shipping cost if it has been enabled in the app
|
||||
settings
|
||||
'''
|
||||
try:
|
||||
code = request.query_params.get('country_code')
|
||||
except AttributeError:
|
||||
return Response(data={"message": "No country code supplied"},
|
||||
status=status.HTTP_400_BAD_REQUEST)
|
||||
|
||||
option = request.query_params.get('shipping_option', 'standard')
|
||||
try:
|
||||
data = get_shipping_cost(code, option)
|
||||
response = Response(data=data, status=status.HTTP_200_OK)
|
||||
except InvalidShippingRate:
|
||||
response = Response(data={"message": "Shipping option {} is invalid".format(option)},
|
||||
status=status.HTTP_400_BAD_REQUEST)
|
||||
except InvalidShippingCountry:
|
||||
response = Response(data={"message": "Shipping to {} is not available".format(code)},
|
||||
status=status.HTTP_400_BAD_REQUEST)
|
||||
|
||||
return response
|
||||
|
||||
|
||||
@api_view(["GET"])
|
||||
@permission_classes([permissions.AllowAny])
|
||||
def shipping_countries(request):
|
||||
''' Get all shipping countries
|
||||
'''
|
||||
queryset = models.ShippingCountry.objects.all()
|
||||
serializer = serializers.ShippingCountrySerializer(queryset, many=True)
|
||||
return Response(data=serializer.data, status=status.HTTP_200_OK)
|
||||
|
|
@ -0,0 +1,5 @@
|
|||
from django.apps import AppConfig
|
||||
|
||||
|
||||
class ShippingConfig(AppConfig):
|
||||
name = 'shipping'
|
||||
|
|
@ -0,0 +1,47 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
# Generated by Django 1.10.4 on 2017-02-11 16:39
|
||||
from __future__ import unicode_literals
|
||||
|
||||
from django.db import migrations, models
|
||||
import django.db.models.deletion
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
initial = True
|
||||
|
||||
dependencies = [
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.CreateModel(
|
||||
name='Address',
|
||||
fields=[
|
||||
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||
('name', models.CharField(max_length=64)),
|
||||
('line_1', models.CharField(max_length=128)),
|
||||
('line_2', models.CharField(blank=True, max_length=128)),
|
||||
('city', models.CharField(max_length=64)),
|
||||
('postcode', models.CharField(max_length=10)),
|
||||
('country', models.CharField(max_length=32)),
|
||||
],
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name='ShippingCountry',
|
||||
fields=[
|
||||
('country_code', models.CharField(max_length=3, primary_key=True, serialize=False)),
|
||||
('country_name', models.CharField(max_length=32)),
|
||||
],
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name='ShippingRate',
|
||||
fields=[
|
||||
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||
('name', models.CharField(max_length=32)),
|
||||
('rate', models.DecimalField(decimal_places=2, max_digits=12)),
|
||||
('carrier', models.CharField(max_length=64)),
|
||||
('description', models.CharField(max_length=128)),
|
||||
('shipping_country', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='shipping_rates', to='shipping.ShippingCountry')),
|
||||
],
|
||||
),
|
||||
]
|
||||
|
|
@ -0,0 +1,41 @@
|
|||
from django.db import models
|
||||
from wagtail.wagtailadmin.edit_handlers import FieldPanel, InlinePanel
|
||||
|
||||
class Address(models.Model):
|
||||
name = models.CharField(max_length=64)
|
||||
line_1 = models.CharField(max_length=128)
|
||||
line_2 = models.CharField(max_length=128, blank=True)
|
||||
city = models.CharField(max_length=64)
|
||||
postcode = models.CharField(max_length=10)
|
||||
country = models.CharField(max_length=32)
|
||||
|
||||
panels = [
|
||||
FieldPanel('name'),
|
||||
FieldPanel('line_1'),
|
||||
FieldPanel('line_2'),
|
||||
FieldPanel('city'),
|
||||
FieldPanel('postcode'),
|
||||
FieldPanel('country')
|
||||
]
|
||||
|
||||
def __str__(self):
|
||||
return "{}, {}, {}".format(self.name, self.city, self.country)
|
||||
|
||||
class ShippingCountry(models.Model):
|
||||
''' Standard and premimum rate shipping for
|
||||
individual countries.
|
||||
'''
|
||||
country_code = models.CharField(max_length=3, primary_key=True)
|
||||
country_name = models.CharField(max_length=32)
|
||||
|
||||
class Meta:
|
||||
verbose_name_plural = "shipping countries"
|
||||
|
||||
class ShippingRate(models.Model):
|
||||
|
||||
name = models.CharField(max_length=32)
|
||||
rate = models.DecimalField(max_digits=12, decimal_places=2)
|
||||
carrier = models.CharField(max_length=64)
|
||||
description = models.CharField(max_length=128)
|
||||
shipping_country = models.ForeignKey(ShippingCountry, related_name="shipping_rates")
|
||||
|
||||
|
|
@ -0,0 +1,24 @@
|
|||
from rest_framework import serializers
|
||||
from longclaw.shipping.models import Address, ShippingCountry, ShippingRate
|
||||
|
||||
class AddressSerializer(serializers.ModelSerializer):
|
||||
|
||||
class Meta:
|
||||
model = Address
|
||||
fields = "__all__"
|
||||
|
||||
class ShippingRateSerializer(serializers.ModelSerializer):
|
||||
|
||||
class Meta:
|
||||
model = ShippingRate
|
||||
fields = "__all__"
|
||||
|
||||
class ShippingCountrySerializer(serializers.ModelSerializer):
|
||||
|
||||
shipping_rates = ShippingRateSerializer(many=True)
|
||||
|
||||
class Meta:
|
||||
model = ShippingCountry
|
||||
fields = "__all__"
|
||||
|
||||
|
||||
|
|
@ -0,0 +1,11 @@
|
|||
from django.conf.urls import url
|
||||
from longclaw.shipping import api
|
||||
|
||||
urlpatterns = [
|
||||
url(r'shipping/cost/$',
|
||||
api.shipping_cost,
|
||||
name='shipping_cost'),
|
||||
url(r'shipping/countries/$',
|
||||
api.shipping_countries,
|
||||
name="shipping_countries")
|
||||
]
|
||||
|
|
@ -0,0 +1,16 @@
|
|||
from wagtail.contrib.modeladmin.options import (
|
||||
ModelAdmin, modeladmin_register
|
||||
)
|
||||
|
||||
from longclaw.shipping.models import ShippingCountry
|
||||
|
||||
class ShippingCountryModelAdmin(ModelAdmin):
|
||||
model = ShippingCountry
|
||||
menu_order = 200
|
||||
menu_icon = 'site'
|
||||
add_to_settings_menu = False
|
||||
exclude_from_explorer = False
|
||||
list_display = ('country_name', 'country_code')
|
||||
inspect_view_enabled = True
|
||||
|
||||
modeladmin_register(ShippingCountryModelAdmin)
|
||||
Ładowanie…
Reference in New Issue