Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP

Comparing changes

Choose two branches to see what's changed or to start a new pull request. If you need to, you can also compare across forks.

Open a pull request

Create a new pull request by comparing changes across two branches. If you need to, you can also compare across forks.
base fork: divio/django-shop
base: e49974c94e
...
head fork: divio/django-shop
compare: be5b2cc480
Checking mergeability… Don't worry, you can still create the pull request.
  • 8 commits
  • 7 files changed
  • 0 commit comments
  • 2 contributors
View
3  shop/payment/backends/pay_on_delivery.py
@@ -2,7 +2,7 @@
from django.conf.urls.defaults import patterns, url
from django.http import HttpResponseRedirect
from django.utils.translation import ugettext_lazy as _
-from shop.util.decorators import on_method, shop_login_required
+from shop.util.decorators import on_method, shop_login_required, order_required
class PayOnDeliveryBackend(object):
@@ -17,6 +17,7 @@ def __init__(self, shop):
# it in a tidy way (look ma', no imports!)
@on_method(shop_login_required)
+ @on_method(order_required)
def simple_view(self, request):
"""
This simple view does nothing but record the "payment" as being
View
1  shop/shipping/backends/flat_rate.py
@@ -43,6 +43,7 @@ def view_process_order(self, request):
# That's an HttpResponseRedirect
@on_method(shop_login_required)
+ @on_method(order_required)
def view_display_fees(self, request):
"""
A simple, normal view that displays a template showing how much the
View
26 shop/tests/payment.py
@@ -197,3 +197,29 @@ def test02_must_be_logged_in_if_setting_is_true(self):
resp = self.client.get(reverse('pay-on-delivery'))
self.assertEqual(resp.status_code, 302)
self.assertTrue('accounts/login/' in resp._headers['location'][1])
+
+ def test_order_required_before_payment(self):
+ """ See issue #84 """
+ # Session only (no order)
+ response = self.client.get(reverse('pay-on-delivery'))
+ self.assertEqual(302, response.status_code)
+ self.assertEqual('http://testserver/', response._headers['location'][1])
+
+ # User logged in (no order)
+ username = 'user'
+ pw = 'pass'
+ User.objects.create_user(username=username, password=pw, email='test@example.com')
+ logged_in = self.client.login(username=username, password=pw)
+ self.assertTrue(logged_in)
+ response = self.client.get(reverse('pay-on-delivery'))
+ self.assertEqual(302, response.status_code)
+ self.assertEqual('http://testserver/', response._headers['location'][1])
+ self.client.logout()
+
+ # User logged in and has order
+ self.user.set_password('blah')
+ self.user.save()
+ logged_in = self.client.login(username=self.user.username, password='blah')
+ self.assertTrue(logged_in)
+ response = self.client.get(reverse('pay-on-delivery'))
+ self.assertTrue(reverse('thank_you_for_your_order') in response._headers['location'][1])
View
23 shop/tests/views_checkout.py
@@ -1,11 +1,13 @@
#-*- coding: utf-8 -*-
from decimal import Decimal
+from django.conf import settings
from django.contrib.auth.models import User
from django.core.urlresolvers import reverse
from django.test.testcases import TestCase
from shop.addressmodel.models import Country, Address
+from shop.models import Product
from shop.models.cartmodel import Cart
from shop.models.ordermodel import Order
from shop.order_signals import processing
@@ -24,6 +26,9 @@ def setUp(self):
last_name="Toto")
self.country = Country.objects.create(name="Switzerland")
self.address = Address.objects.create(country=self.country)
+ self.cart = Cart.objects.create()
+ self.product = Product.objects.create(name='pizza', active=True, unit_price='1.25')
+ self.cart.add_product(self.product)
self.request = Mock()
setattr(self.request, 'user', self.user)
setattr(self.request, 'session', {})
@@ -135,10 +140,28 @@ def test_get_context_data(self):
#==========================================================================
def test_must_be_logged_in_if_setting_is_true(self):
with SettingsOverride(SHOP_FORCE_LOGIN=True):
+ # force creating of session
+ # https://code.djangoproject.com/ticket/11475
+ self.client.cookies[settings.SESSION_COOKIE_NAME] = '1'
+ self.client.get(reverse('shop_welcome'))
+
+ # save a non-empty cart in the session
+ session = self.client.session
+ session['cart_id'] = self.cart.pk
+ session.save()
+
resp = self.client.get(reverse('checkout_selection'))
self.assertEqual(resp.status_code, 302)
self.assertTrue('accounts/login/' in resp._headers['location'][1])
+ #==========================================================================
+ # Cart Required Decorator
+ #==========================================================================
+ def test_cart_required_redirects_on_checkout(self):
+ resp = self.client.get(reverse('checkout_selection'))
+ self.assertEqual(resp.status_code, 302)
+ self.assertEqual('http://testserver/', resp._headers['location'][1])
+
class ShippingBillingViewOrderStuffTestCase(TestCase):
View
3  shop/urls/checkout.py
@@ -1,4 +1,5 @@
from django.conf.urls.defaults import url, patterns
+from shop.util.decorators import cart_required
from shop.views.checkout import (
# SelectPaymentView,
@@ -10,7 +11,7 @@
)
urlpatterns = patterns('',
- url(r'^$', CheckoutSelectionView.as_view(),
+ url(r'^$', cart_required(CheckoutSelectionView.as_view()),
name='checkout_selection' # First step of the checkout process
),
#url(r'^checkout/ship/$', SelectShippingView.as_view(),
View
33 shop/util/decorators.py
@@ -4,6 +4,7 @@
from django.contrib.auth import REDIRECT_FIELD_NAME
from django.contrib.auth.decorators import user_passes_test
from django.http import HttpResponseRedirect
+from shop.util.cart import get_or_create_cart
from shop.util.login_mixin import get_test_func
from shop.util.order import get_order_from_request
@@ -43,7 +44,6 @@ def shop_login_required(function=None, redirect_field_name=REDIRECT_FIELD_NAME,
return actual_decorator(function)
return actual_decorator
-
def order_required(redirect_url='/'):
"""
Ensures that an non-complete order exists before carrying out any
@@ -68,7 +68,36 @@ def some_view(...
def decorator(func):
def inner(request, *args, **kwargs):
order = get_order_from_request(request)
- if order is None or getattr(order, 'status', Order.COMPLETED) == Order.COMPLETED:
+ if order is None or getattr(order, 'status', Order.COMPLETED) >= Order.COMPLETED:
+ return HttpResponseRedirect(redirect_url)
+ return func(request, *args, **kwargs)
+ return wraps(func)(inner)
+ return decorator
+
+def cart_required(redirect_url='/'):
+ """
+ Ensures that a non-empty cart is present.
+
+ If a cart does not exist the browser will be redirected to another page
+ supplied in the optional keyword argument `redirect_url`.
+
+ Usage:
+ @cart_required
+ def some_view(...
+
+ OR:
+ @cart_required(redirect_url='/some/path/')
+ def some_view(...
+ """
+ if callable(redirect_url):
+ func = redirect_url
+ decorator = cart_required()
+ return decorator(func)
+
+ def decorator(func):
+ def inner(request, *args, **kwargs):
+ cart = get_or_create_cart(request)
+ if cart.total_quantity <= 0:
return HttpResponseRedirect(redirect_url)
return func(request, *args, **kwargs)
return wraps(func)(inner)
View
5 shop/util/order.py
@@ -24,7 +24,10 @@ def get_order_from_request(request):
# There is a session
order_id = session.get('order_id')
if order_id:
- order = Order.objects.get(pk=order_id)
+ try:
+ order = Order.objects.get(pk=order_id)
+ except Order.DoesNotExist:
+ return None
return order

No commit comments for this range

Something went wrong with that request. Please try again.