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: chrisglass/django-shop
...
head fork: chrisglass/django-shop
Checking mergeability… Don't worry, you can still create the pull request.
  • 7 commits
  • 7 files changed
  • 0 commit comments
  • 3 contributors
View
2  AUTHORS.rst
@@ -9,6 +9,7 @@ CONTRIBUTORS
* Adrien Lemaire
* airtonix
+* Aleš Kocjančič
* Audrey Roy
* Ben Lopatin
* Benjamin Wohlwend
@@ -26,6 +27,7 @@ CONTRIBUTORS
* Per Rosengren
* Raúl Cumplido
* Rolo Mawlabaux
+* Stephen Muss
* Thomas Woolford
TRANSLATORS
View
4 CHANGELOG.rst
@@ -1,6 +1,10 @@
Version NEXT
==============
+* Made Backends internationalizable, as well as the BillingShippingForm
+ thanks to the introduciton of a new optional backend_verbose_name attribute
+ to backends.
+* Added a order_required decorator to fix bug #84
* Added get_product_reference method to Product (for extensibility)
* Cart object is not saved to database if it is empty (#147)
* Changed spelling mistakes in methods from `payed` to `paid` on the Order
View
11 shop/forms.py
@@ -2,6 +2,7 @@
"""Forms for the django-shop app."""
from django import forms
from django.forms.models import modelformset_factory
+from django.utils.translation import ugettext_lazy as _
from shop.backends_pool import backends_pool
from shop.models.cartmodel import CartItem
@@ -9,13 +10,12 @@
def get_shipping_backends_choices():
shipping_backends = backends_pool.get_shipping_backends_list()
- return tuple(
- [(x.url_namespace, x.backend_name) for x in shipping_backends])
+ return tuple([(x.url_namespace, getattr(x, 'backend_verbose_name', x.backend_name)) for x in shipping_backends])
def get_billing_backends_choices():
billing_backends = backends_pool.get_payment_backends_list()
- return tuple([(x.url_namespace, x.backend_name) for x in billing_backends])
+ return tuple([(x.url_namespace, getattr(x, 'backend_verbose_name', x.backend_name)) for x in billing_backends])
class BillingShippingForm(forms.Form):
@@ -24,9 +24,8 @@ class BillingShippingForm(forms.Form):
defined in settings.SHOP_SHIPPING_BACKENDS and
settings.SHOP_PAYMENT_BACKENDS)
"""
- shipping_method = forms.ChoiceField(
- choices=get_shipping_backends_choices())
- payment_method = forms.ChoiceField(choices=get_billing_backends_choices())
+ shipping_method = forms.ChoiceField(choices=get_shipping_backends_choices(), label=_('Shipping method'))
+ payment_method = forms.ChoiceField(choices=get_billing_backends_choices(), label=_('Payment method'))
class CartItemModelForm(forms.ModelForm):
View
2  shop/payment/backends/pay_on_delivery.py
@@ -1,12 +1,14 @@
# -*- coding: utf-8 -*-
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
class PayOnDeliveryBackend(object):
backend_name = "Pay On Delivery"
+ verbose_backend_name = _("Pay On Delivery")
url_namespace = "pay-on-delivery"
def __init__(self, shop):
View
5 shop/shipping/backends/flat_rate.py
@@ -5,8 +5,9 @@
from django.conf.urls.defaults import patterns, url
from django.shortcuts import render_to_response
from django.template import RequestContext
+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 FlatRateShipping(object):
@@ -16,6 +17,7 @@ class FlatRateShipping(object):
"""
url_namespace = 'flat'
backend_name = 'Flat rate'
+ verbose_backend_name = _('Flat rate')
def __init__(self, shop):
self.shop = shop # This is the shop reference, it allows this backend
@@ -23,6 +25,7 @@ def __init__(self, shop):
self.rate = getattr(settings, 'SHOP_SHIPPING_FLAT_RATE', '10')
@on_method(shop_login_required)
+ @on_method(order_required)
def view_process_order(self, request):
"""
A simple (not class-based) view to process an order.
View
23 shop/tests/shipping.py
@@ -9,6 +9,7 @@
from shop.backends_pool import backends_pool
from shop.models.ordermodel import Order
+from shop.shipping.backends.flat_rate import FlatRateShipping
from shop.shipping.api import ShippingAPI
from shop.tests.util import Mock
from shop.tests.utils.context_managers import SettingsOverride
@@ -156,6 +157,11 @@ def test_adding_shipping_costs_twice_works(self):
class FlatRateShippingTestCase(TestCase):
"""Tests for ``shop.shipping.backends.flat_rate.FlatRateShipping``."""
+ def setUp(self):
+ self.backend = FlatRateShipping(shop=ShippingAPI())
+ self.user = User.objects.create(username="test", email="test@example.com")
+ self.request = Mock()
+ setattr(self.request, 'user', self.user)
def test_must_be_logged_in_if_setting_is_true(self):
with SettingsOverride(SHOP_FORCE_LOGIN=True):
@@ -165,3 +171,20 @@ def test_must_be_logged_in_if_setting_is_true(self):
resp = self.client.get(reverse('flat_process'))
self.assertEqual(resp.status_code, 302)
self.assertTrue('accounts/login/' in resp._headers['location'][1])
+
+ def test_order_required_before_shipping_processed(self):
+ """ See issue #84 """
+ # Session only (no order)
+ response = self.client.get(reverse('flat_process'))
+ self.assertEqual(response.status_code, 302)
+
+ # User logged in (no order)
+ view = self.backend.view_process_order(self.request)
+ self.assertEqual(view.get('location'), '/')
+
+ # User logged in with order
+ order = Order()
+ setattr(order, 'user', self.user)
+ order.save()
+ view = self.backend.view_process_order(self.request)
+ self.assertEqual(view.get('location'), reverse('checkout_payment'))
View
34 shop/util/decorators.py
@@ -1,8 +1,12 @@
"""Decorators for the django-shop application."""
+from functools import wraps
+
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.login_mixin import get_test_func
+from shop.util.order import get_order_from_request
def on_method(function_decorator):
@@ -37,3 +41,33 @@ def shop_login_required(function=None, redirect_field_name=REDIRECT_FIELD_NAME,
if function:
return actual_decorator(function)
return actual_decorator
+
+
+def order_required(redirect_url='/'):
+ """
+ Ensures that an order exists before carrying out any additional functions
+ that rely on one.
+
+ If an order does not exist the browser will be redirected to another page
+ supplied in the optional keyword argument `redirect_url`.
+
+ Usage:
+ @order_required
+ def some_view(...
+
+ OR:
+ @order_required(redirect_url='/some/path/')
+ def some_view(...
+ """
+ if callable(redirect_url):
+ func = redirect_url
+ decorator = order_required()
+ return decorator(func)
+
+ def decorator(func):
+ def inner(request, *args, **kwargs):
+ if get_order_from_request(request) is None:
+ return HttpResponseRedirect(redirect_url)
+ return func(request, *args, **kwargs)
+ return wraps(func)(inner)
+ return decorator

No commit comments for this range

Something went wrong with that request. Please try again.