This commit is contained in:
Nathan Chapman 2022-05-11 17:39:22 -06:00
parent 750afa6033
commit 60896a2835
8 changed files with 204 additions and 51 deletions

View File

@ -1 +1,65 @@
[{"model": "accounts.address", "pk": 1, "fields": {"first_name": "Nathan", "last_name": "Chapman", "street_address_1": "1504 N 230 E", "street_address_2": "", "city": "North Logan", "state": "UT", "postal_code": "84341"}}, {"model": "accounts.address", "pk": 2, "fields": {"first_name": "Nathan", "last_name": "Chapman", "street_address_1": "1125 W 400 N", "street_address_2": "", "city": "Logan", "state": "UT", "postal_code": "84321"}}, {"model": "accounts.user", "pk": 1, "fields": {"password": "pbkdf2_sha256$320000$VLksxVkUXOtoAEthHFi6DB$xj+81uh6NwPfZFP+7agf2UAJQZN89j5Wt38gUXeJ3z0=", "last_login": "2022-05-03T23:58:18.358Z", "is_superuser": true, "username": "nathanchapman", "first_name": "Nathan", "last_name": "Chapman", "email": "contact@nathanjchapman.com", "is_staff": true, "is_active": true, "date_joined": "2022-04-28T01:24:47.591Z", "default_shipping_address": 1, "default_billing_address": null, "groups": [], "user_permissions": [], "addresses": []}}, {"model": "accounts.user", "pk": 13, "fields": {"password": "pbkdf2_sha256$320000$L6WDkOMJwmkjR9OVsXfsIj$otr4goV5Tz5Hy5l24UkSYcH0L9Y5hDD89GKYD6LGcZo=", "last_login": null, "is_superuser": false, "username": "john", "first_name": "John", "last_name": "Doe", "email": "john@example.com", "is_staff": false, "is_active": true, "date_joined": "2022-05-04T00:00:11Z", "default_shipping_address": null, "default_billing_address": null, "groups": [], "user_permissions": [], "addresses": []}}] [{
"model": "accounts.address",
"pk": 1,
"fields": {
"first_name": "Nathan",
"last_name": "Chapman",
"street_address_1": "1504 N 230 E",
"street_address_2": "",
"city": "North Logan",
"state": "UT",
"postal_code": "84341"
}
}, {
"model": "accounts.address",
"pk": 2,
"fields": {
"first_name": "John",
"last_name": "Doe",
"street_address_1": "90415 Pollich Skyway",
"street_address_2": "",
"city": "Jaskolskiburgh",
"state": "MS",
"postal_code": "32715"
}
}, {
"model": "accounts.user",
"pk": 1,
"fields": {
"password": "pbkdf2_sha256$320000$VLksxVkUXOtoAEthHFi6DB$xj+81uh6NwPfZFP+7agf2UAJQZN89j5Wt38gUXeJ3z0=",
"last_login": "2022-05-03T23:58:18.358Z",
"is_superuser": true,
"username": "nathanchapman",
"first_name": "Nathan",
"last_name": "Chapman",
"email": "contact@nathanjchapman.com",
"is_staff": true,
"is_active": true,
"date_joined": "2022-04-28T01:24:47.591Z",
"default_shipping_address": 1,
"default_billing_address": null,
"groups": [],
"user_permissions": [],
"addresses": []
}
}, {
"model": "accounts.user",
"pk": 2,
"fields": {
"password": "pbkdf2_sha256$320000$L6WDkOMJwmkjR9OVsXfsIj$otr4goV5Tz5Hy5l24UkSYcH0L9Y5hDD89GKYD6LGcZo=",
"last_login": null,
"is_superuser": false,
"username": "johndoe",
"first_name": "John",
"last_name": "Doe",
"email": "john@example.com",
"is_staff": false,
"is_active": true,
"date_joined": "2022-05-04T00:00:11Z",
"default_shipping_address": 2,
"default_billing_address": null,
"groups": [],
"user_permissions": [],
"addresses": []
}
}]

View File

@ -27,11 +27,13 @@ from .weight import WeightUnits, zero_weight
logger = logging.getLogger(__name__) logger = logging.getLogger(__name__)
class ProductEncoder(DjangoJSONEncoder): class ProductEncoder(DjangoJSONEncoder):
def default(self, obj): def default(self, obj):
logger.info(f"\n{obj}\n") logger.info(f"\n{obj}\n")
return super().default(obj) return super().default(obj)
class ProductManager(models.Manager): class ProductManager(models.Manager):
def get_queryset(self): def get_queryset(self):
return super().get_queryset().annotate( return super().get_queryset().annotate(
@ -39,7 +41,6 @@ class ProductManager(models.Manager):
) )
class Product(models.Model): class Product(models.Model):
name = models.CharField(max_length=250) name = models.CharField(max_length=250)
subtitle = models.CharField(max_length=250, blank=True) subtitle = models.CharField(max_length=250, blank=True)
@ -52,7 +53,10 @@ class Product(models.Model):
null=True, null=True,
) )
weight = MeasurementField( weight = MeasurementField(
measurement=Weight, unit_choices=WeightUnits.CHOICES, blank=True, null=True measurement=Weight,
unit_choices=WeightUnits.CHOICES,
blank=True,
null=True
) )
visible_in_listings = models.BooleanField(default=False) visible_in_listings = models.BooleanField(default=False)
@ -105,11 +109,11 @@ class ProductPhoto(models.Model):
# img.save(self.image.path) # img.save(self.image.path)
class Coupon(models.Model): class Coupon(models.Model):
type = models.CharField( type = models.CharField(
max_length=20, choices=VoucherType.CHOICES, default=VoucherType.ENTIRE_ORDER max_length=20,
choices=VoucherType.CHOICES,
default=VoucherType.ENTIRE_ORDER
) )
name = models.CharField(max_length=255, null=True, blank=True) name = models.CharField(max_length=255, null=True, blank=True)
code = models.CharField(max_length=12, unique=True, db_index=True) code = models.CharField(max_length=12, unique=True, db_index=True)
@ -127,6 +131,7 @@ class Coupon(models.Model):
) )
products = models.ManyToManyField(Product, blank=True) products = models.ManyToManyField(Product, blank=True)
users = models.ManyToManyField(User, blank=True)
class Meta: class Meta:
ordering = ("code",) ordering = ("code",)
@ -143,8 +148,6 @@ class Coupon(models.Model):
return reverse('dashboard:coupon-detail', kwargs={'pk': self.pk}) return reverse('dashboard:coupon-detail', kwargs={'pk': self.pk})
class ShippingMethod(models.Model): class ShippingMethod(models.Model):
name = models.CharField(max_length=100) name = models.CharField(max_length=100)
type = models.CharField(max_length=30, choices=ShippingMethodType.CHOICES) type = models.CharField(max_length=30, choices=ShippingMethodType.CHOICES)
@ -183,7 +186,9 @@ class Order(models.Model):
null=True null=True
) )
status = models.CharField( status = models.CharField(
max_length=32, default=OrderStatus.UNFULFILLED, choices=OrderStatus.CHOICES max_length=32,
default=OrderStatus.UNFULFILLED,
choices=OrderStatus.CHOICES
) )
billing_address = models.ForeignKey( billing_address = models.ForeignKey(
Address, Address,
@ -207,7 +212,6 @@ class Order(models.Model):
on_delete=models.SET_NULL on_delete=models.SET_NULL
) )
coupon = models.ForeignKey( coupon = models.ForeignKey(
Coupon, Coupon,
related_name='orders', related_name='orders',
@ -228,7 +232,6 @@ class Order(models.Model):
default=0 default=0
) )
weight = MeasurementField( weight = MeasurementField(
measurement=Weight, measurement=Weight,
unit_choices=WeightUnits.CHOICES, unit_choices=WeightUnits.CHOICES,
@ -263,7 +266,6 @@ class Order(models.Model):
ordering = ('-created_at',) ordering = ('-created_at',)
class Transaction(models.Model): class Transaction(models.Model):
status = models.CharField( status = models.CharField(
max_length=32, max_length=32,
@ -342,4 +344,3 @@ class TrackingNumber(models.Model):
def __str__(self): def __str__(self):
return self.tracking_id return self.tracking_id

View File

@ -1,9 +1,11 @@
import os, time import os
import time
from selenium.webdriver.firefox.webdriver import WebDriver from selenium.webdriver.firefox.webdriver import WebDriver
from selenium.webdriver.common.keys import Keys from selenium.webdriver.common.keys import Keys
from selenium.common.exceptions import WebDriverException from selenium.common.exceptions import WebDriverException
from django.contrib.staticfiles.testing import StaticLiveServerTestCase from django.contrib.staticfiles.testing import StaticLiveServerTestCase
class HomeTests(StaticLiveServerTestCase): class HomeTests(StaticLiveServerTestCase):
fixtures = ['accounts.json', 'products.json'] fixtures = ['accounts.json', 'products.json']

View File

@ -573,6 +573,11 @@ article + article {
margin-top: 8rem; margin-top: 8rem;
} }
.error-view {
text-align: center;
margin: auto 0;
}
/* Product reviews /* Product reviews
========================================================================== */ ========================================================================== */
.review__list { .review__list {

View File

@ -1,4 +1,5 @@
import logging, json import logging
import json
from requests import ConnectionError from requests import ConnectionError
from django import forms from django import forms
from django.conf import settings from django.conf import settings
@ -14,13 +15,19 @@ from .tasks import contact_form_email
logger = logging.getLogger(__name__) logger = logging.getLogger(__name__)
class AddToCartForm(forms.Form): class AddToCartForm(forms.Form):
grind = forms.ChoiceField(choices=CoffeeGrind.GRIND_CHOICES) grind = forms.ChoiceField(choices=CoffeeGrind.GRIND_CHOICES)
quantity = forms.IntegerField(min_value=1, max_value=20, initial=1) quantity = forms.IntegerField(min_value=1, max_value=20, initial=1)
class UpdateCartItemForm(forms.Form): class UpdateCartItemForm(forms.Form):
quantity = forms.IntegerField(min_value=1, max_value=20, initial=1) quantity = forms.IntegerField(min_value=1, max_value=20, initial=1)
update = forms.BooleanField(required=False, initial=True, widget=forms.HiddenInput) update = forms.BooleanField(
required=False,
initial=True,
widget=forms.HiddenInput
)
class AddToSubscriptionForm(forms.Form): class AddToSubscriptionForm(forms.Form):
@ -83,7 +90,6 @@ class AddressForm(forms.Form):
'Could not connect to USPS, try again.' 'Could not connect to USPS, try again.'
) )
if 'Error' in validation.result['AddressValidateResponse']['Address']: if 'Error' in validation.result['AddressValidateResponse']['Address']:
error = validation.result['AddressValidateResponse']['Address']['Error']['Description'] error = validation.result['AddressValidateResponse']['Address']['Error']['Description']
raise ValidationError( raise ValidationError(
@ -97,6 +103,7 @@ class AddressForm(forms.Form):
'Could not find Zip5' 'Could not find Zip5'
) )
class OrderCreateForm(forms.ModelForm): class OrderCreateForm(forms.ModelForm):
email = forms.CharField(widget=forms.HiddenInput()) email = forms.CharField(widget=forms.HiddenInput())
first_name = forms.CharField(widget=forms.HiddenInput()) first_name = forms.CharField(widget=forms.HiddenInput())
@ -113,9 +120,11 @@ class OrderCreateForm(forms.ModelForm):
'shipping_total': forms.HiddenInput() 'shipping_total': forms.HiddenInput()
} }
class CouponApplyForm(forms.Form): class CouponApplyForm(forms.Form):
code = forms.CharField(label='Coupon code') code = forms.CharField(label='Coupon code')
class ContactForm(forms.Form): class ContactForm(forms.Form):
GOOGLE = 'Google Search' GOOGLE = 'Google Search'
SHOP = 'The coffee shop' SHOP = 'The coffee shop'

View File

@ -16,15 +16,16 @@ from storefront.cart import Cart
logger = logging.getLogger(__name__) logger = logging.getLogger(__name__)
class CartTest(TestCase):
def setUp(self):
self.client = Client()
self.factory = RequestFactory()
self.customer = User.objects.create_user( class CartTest(TestCase):
username='petertempler', email='peter@testing.com', password='peterspassword321' @classmethod
def setUpTestData(cls):
cls.customer = User.objects.create_user(
username='petertempler',
email='peter@testing.com',
password='peterspassword321'
) )
self.product = Product.objects.create( cls.product = Product.objects.create(
name='Dante\'s Tornado', name='Dante\'s Tornado',
description='Coffee', description='Coffee',
sku='23987', sku='23987',
@ -32,11 +33,15 @@ class CartTest(TestCase):
weight=Weight(oz=16), weight=Weight(oz=16),
visible_in_listings=True visible_in_listings=True
) )
self.order = Order.objects.create( cls.order = Order.objects.create(
customer=self.customer, customer=cls.customer,
total_net_amount=13.4 total_net_amount=13.4
) )
def setUp(self):
self.client = Client()
self.factory = RequestFactory()
self.client.force_login(self.customer) self.client.force_login(self.customer)
self.client.session['shipping_address'] = { self.client.session['shipping_address'] = {
'first_name': 'Nathan', 'first_name': 'Nathan',
@ -89,7 +94,10 @@ class CartTest(TestCase):
update_quantity=False update_quantity=False
) )
self.assertEqual(cart.cart[f'{self.product.id}']['variations'][CoffeeGrind.WHOLE]['quantity'], 1) self.assertEqual(
cart.cart[f'{self.product.id}']['variations'][CoffeeGrind.WHOLE]['quantity'],
1
)
self.assertEqual(len(cart), 1) self.assertEqual(len(cart), 1)
self.assertEqual(sum(cart.get_item_prices()), Decimal('13.4')) self.assertEqual(sum(cart.get_item_prices()), Decimal('13.4'))
self.assertEqual(cart.get_total_price(), Decimal('13.4')) self.assertEqual(cart.get_total_price(), Decimal('13.4'))
@ -100,7 +108,10 @@ class CartTest(TestCase):
grind=CoffeeGrind.WHOLE, grind=CoffeeGrind.WHOLE,
update_quantity=False update_quantity=False
) )
self.assertEqual(cart.cart[f'{self.product.id}']['variations'][CoffeeGrind.WHOLE]['quantity'], 2) self.assertEqual(
cart.cart[f'{self.product.id}']['variations'][CoffeeGrind.WHOLE]['quantity'],
2
)
self.assertEqual(len(cart), 2) self.assertEqual(len(cart), 2)
cart.add( cart.add(
@ -110,7 +121,10 @@ class CartTest(TestCase):
grind=CoffeeGrind.ESPRESSO, grind=CoffeeGrind.ESPRESSO,
update_quantity=False update_quantity=False
) )
self.assertEqual(cart.cart[f'{self.product.id}']['variations'][CoffeeGrind.ESPRESSO]['quantity'], 3) self.assertEqual(
cart.cart[f'{self.product.id}']['variations'][CoffeeGrind.ESPRESSO]['quantity'],
3
)
self.assertEqual(len(cart), 5) self.assertEqual(len(cart), 5)
self.assertEqual(cart.get_total_price(), Decimal('67')) self.assertEqual(cart.get_total_price(), Decimal('67'))
@ -128,7 +142,10 @@ class CartTest(TestCase):
grind=CoffeeGrind.WHOLE, grind=CoffeeGrind.WHOLE,
update_quantity=False update_quantity=False
) )
self.assertEqual(cart.cart[f'{self.product.id}']['variations'][CoffeeGrind.WHOLE]['quantity'], 3) self.assertEqual(
cart.cart[f'{self.product.id}']['variations'][CoffeeGrind.WHOLE]['quantity'],
3
)
cart.add( cart.add(
request, request,
@ -137,7 +154,10 @@ class CartTest(TestCase):
grind=CoffeeGrind.WHOLE, grind=CoffeeGrind.WHOLE,
update_quantity=True update_quantity=True
) )
self.assertEqual(cart.cart[f'{self.product.id}']['variations'][CoffeeGrind.WHOLE]['quantity'], 1) self.assertEqual(
cart.cart[f'{self.product.id}']['variations'][CoffeeGrind.WHOLE]['quantity'],
1
)
def test_cart_remove_item(self): def test_cart_remove_item(self):
cart_detail_url = reverse('storefront:cart-detail') cart_detail_url = reverse('storefront:cart-detail')
@ -172,6 +192,3 @@ class CartTest(TestCase):
update_quantity=False update_quantity=False
) )
self.assertEqual(cart.get_total_weight(), Decimal(48)) self.assertEqual(cart.get_total_weight(), Decimal(48))
def test_cart_(self):
pass

View File

@ -21,9 +21,9 @@ from . import RequestFaker
logger = logging.getLogger(__name__) logger = logging.getLogger(__name__)
class CreateOrderTest(TestCase): class CreateOrderTest(TestCase):
def setUp(self): @classmethod
self.client = Client() def setUpTestData(cls):
self.product = Product.objects.create( cls.product = Product.objects.create(
name='Decaf', name='Decaf',
description='Coffee', description='Coffee',
sku='23987', sku='23987',
@ -32,6 +32,10 @@ class CreateOrderTest(TestCase):
visible_in_listings=True visible_in_listings=True
) )
def setUp(self):
self.client = Client()
def test_build_request_body(self): def test_build_request_body(self):
product_list_url = reverse('storefront:product-list') product_list_url = reverse('storefront:product-list')
response = self.client.get(product_list_url, follow=True) response = self.client.get(product_list_url, follow=True)

View File

@ -6,10 +6,12 @@ from django.utils import timezone
from django.shortcuts import render, reverse, redirect, get_object_or_404 from django.shortcuts import render, reverse, redirect, get_object_or_404
from django.urls import reverse_lazy from django.urls import reverse_lazy
from django.core.mail import EmailMessage from django.core.mail import EmailMessage
from django.core.exceptions import ObjectDoesNotExist from django.core.exceptions import ObjectDoesNotExist, PermissionDenied
from django.http import JsonResponse, HttpResponseRedirect from django.http import JsonResponse, HttpResponseRedirect
from django.views.generic.base import RedirectView, TemplateView from django.views.generic.base import RedirectView, TemplateView
from django.views.generic.edit import FormView, CreateView, UpdateView, DeleteView, FormMixin from django.views.generic.edit import (
FormView, CreateView, UpdateView, DeleteView, FormMixin
)
from django.views.generic.detail import DetailView, SingleObjectMixin from django.views.generic.detail import DetailView, SingleObjectMixin
from django.views.generic.list import ListView from django.views.generic.list import ListView
from django.contrib.auth.decorators import login_required from django.contrib.auth.decorators import login_required
@ -25,17 +27,23 @@ from paypalcheckoutsdk.core import PayPalHttpClient, SandboxEnvironment
from accounts.models import User, Address from accounts.models import User, Address
from accounts.utils import get_or_create_customer from accounts.utils import get_or_create_customer
from accounts.forms import AddressForm as AccountAddressForm, CustomerUpdateForm from accounts.forms import (
AddressForm as AccountAddressForm, CustomerUpdateForm
)
from core.models import Product, Order, Transaction, OrderLine, Coupon from core.models import Product, Order, Transaction, OrderLine, Coupon
from core.forms import ShippingMethodForm from core.forms import ShippingMethodForm
from core import OrderStatus from core import OrderStatus
from .forms import AddToCartForm, UpdateCartItemForm, OrderCreateForm, AddressForm, CouponApplyForm, ContactForm from .forms import (
AddToCartForm, UpdateCartItemForm, OrderCreateForm,
AddressForm, CouponApplyForm, ContactForm
)
from .cart import Cart from .cart import Cart
from .payments import CaptureOrder from .payments import CaptureOrder
logger = logging.getLogger(__name__) logger = logging.getLogger(__name__)
class CartView(TemplateView): class CartView(TemplateView):
template_name = 'storefront/cart_detail.html' template_name = 'storefront/cart_detail.html'
@ -53,6 +61,7 @@ class CartView(TemplateView):
context['coupon_apply_form'] = CouponApplyForm() context['coupon_apply_form'] = CouponApplyForm()
return context return context
class CartAddProductView(SingleObjectMixin, FormView): class CartAddProductView(SingleObjectMixin, FormView):
model = Product model = Product
form_class = AddToCartForm form_class = AddToCartForm
@ -118,7 +127,7 @@ class CouponApplyView(FormView):
def form_valid(self, form): def form_valid(self, form):
today = timezone.localtime(timezone.now()).date() today = timezone.localtime(timezone.now()).date()
code = form.cleaned_data['code'] code = form.cleaned_data['code'].upper()
try: try:
coupon = Coupon.objects.get( coupon = Coupon.objects.get(
code__iexact=code, code__iexact=code,
@ -200,6 +209,7 @@ class CheckoutAddressView(FormView):
self.request.session['shipping_address'] = address self.request.session['shipping_address'] = address
return super().form_valid(form) return super().form_valid(form)
class OrderCreateView(CreateView): class OrderCreateView(CreateView):
model = Order model = Order
template_name = 'storefront/order_form.html' template_name = 'storefront/order_form.html'
@ -260,10 +270,11 @@ class OrderCreateView(CreateView):
return JsonResponse(data) return JsonResponse(data)
@csrf_exempt @csrf_exempt
@require_POST @require_POST
def paypal_order_transaction_capture(request, transaction_id): def paypal_order_transaction_capture(request, transaction_id):
if request.method =="POST": if request.method == "POST":
data = CaptureOrder().capture_order(transaction_id) data = CaptureOrder().capture_order(transaction_id)
cart = Cart(request) cart = Cart(request)
cart.clear() cart.clear()
@ -280,6 +291,7 @@ def paypal_order_transaction_capture(request, transaction_id):
else: else:
return JsonResponse({'details': 'invalid request'}) return JsonResponse({'details': 'invalid request'})
@csrf_exempt @csrf_exempt
@require_POST @require_POST
def paypal_webhook_endpoint(request): def paypal_webhook_endpoint(request):
@ -291,39 +303,66 @@ def paypal_webhook_endpoint(request):
class PaymentDoneView(TemplateView): class PaymentDoneView(TemplateView):
template_name = 'storefront/payment_done.html' template_name = 'storefront/payment_done.html'
class PaymentCanceledView(TemplateView): class PaymentCanceledView(TemplateView):
template_name = 'storefront/payment_canceled.html' template_name = 'storefront/payment_canceled.html'
class CustomerDetailView(LoginRequiredMixin, DetailView): class CustomerDetailView(UserPassesTestMixin, LoginRequiredMixin, DetailView):
model = User model = User
template_name = 'storefront/customer_detail.html' template_name = 'storefront/customer_detail.html'
context_object_name = 'customer' context_object_name = 'customer'
permission_denied_message = 'Not authorized.'
raise_exception = True
class CustomerUpdateView(LoginRequiredMixin, UpdateView): def test_func(self):
return self.request.user.pk == self.get_object().pk
class CustomerUpdateView(UserPassesTestMixin, LoginRequiredMixin, UpdateView):
model = User model = User
template_name = 'storefront/customer_form.html' template_name = 'storefront/customer_form.html'
context_object_name = 'customer' context_object_name = 'customer'
form_class = CustomerUpdateForm form_class = CustomerUpdateForm
permission_denied_message = 'Not authorized.'
raise_exception = True
def test_func(self):
return self.request.user.pk == self.get_object().pk
def get_success_url(self): def get_success_url(self):
return reverse('storefront:customer-detail', kwargs={'pk': self.object.pk}) return reverse(
'storefront:customer-detail', kwargs={'pk': self.object.pk}
)
class OrderDetailView(LoginRequiredMixin, DetailView): class OrderDetailView(UserPassesTestMixin, LoginRequiredMixin, DetailView):
model = Order model = Order
template_name = 'storefront/order_detail.html' template_name = 'storefront/order_detail.html'
pk_url_kwarg = 'order_pk' pk_url_kwarg = 'order_pk'
permission_denied_message = 'Not authorized.'
raise_exception = True
def test_func(self):
return self.request.user.pk == self.get_object().customer.pk
def get_context_data(self, **kwargs): def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs) context = super().get_context_data(**kwargs)
context['customer'] = User.objects.get(pk=self.kwargs['pk']) context['customer'] = User.objects.get(pk=self.kwargs['pk'])
return context return context
class CustomerAddressCreateView(LoginRequiredMixin, CreateView):
class CustomerAddressCreateView(
UserPassesTestMixin, LoginRequiredMixin, CreateView
):
model = Address model = Address
template_name = 'storefront/address_create_form.html' template_name = 'storefront/address_create_form.html'
form_class = AccountAddressForm form_class = AccountAddressForm
permission_denied_message = 'Not authorized.'
raise_exception = True
def test_func(self):
return self.request.user.pk == self.kwargs['pk']
def get_context_data(self, **kwargs): def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs) context = super().get_context_data(**kwargs)
@ -338,13 +377,23 @@ class CustomerAddressCreateView(LoginRequiredMixin, CreateView):
return super().form_valid(form) return super().form_valid(form)
def get_success_url(self): def get_success_url(self):
return reverse('storefront:customer-detail', kwargs={'pk': self.kwargs['pk']}) return reverse(
'storefront:customer-detail', kwargs={'pk': self.kwargs['pk']}
)
class CustomerAddressUpdateView(LoginRequiredMixin, UpdateView):
class CustomerAddressUpdateView(
UserPassesTestMixin, LoginRequiredMixin, UpdateView
):
model = Address model = Address
pk_url_kwarg = 'address_pk' pk_url_kwarg = 'address_pk'
template_name = 'storefront/address_form.html' template_name = 'storefront/address_form.html'
form_class = AccountAddressForm form_class = AccountAddressForm
permission_denied_message = 'Not authorized.'
raise_exception = True
def test_func(self):
return self.request.user.pk == self.get_object().customer.pk
def get_context_data(self, **kwargs): def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs) context = super().get_context_data(**kwargs)
@ -355,16 +404,18 @@ class CustomerAddressUpdateView(LoginRequiredMixin, UpdateView):
return reverse('storefront:customer-detail', kwargs={'pk': self.kwargs['pk']}) return reverse('storefront:customer-detail', kwargs={'pk': self.kwargs['pk']})
class AboutView(TemplateView): class AboutView(TemplateView):
template_name = 'storefront/about.html' template_name = 'storefront/about.html'
class FairTradeView(TemplateView): class FairTradeView(TemplateView):
template_name = 'storefront/fairtrade.html' template_name = 'storefront/fairtrade.html'
class ReviewListView(TemplateView): class ReviewListView(TemplateView):
template_name = 'storefront/reviews.html' template_name = 'storefront/reviews.html'
class ContactFormView(FormView, SuccessMessageMixin): class ContactFormView(FormView, SuccessMessageMixin):
template_name = 'storefront/contact_form.html' template_name = 'storefront/contact_form.html'
form_class = ContactForm form_class = ContactForm