Skip to content

Commit

Permalink
save currency code in session (rather than Currency object)
Browse files Browse the repository at this point in the history
  • Loading branch information
bashu committed Sep 26, 2015
1 parent adfff8d commit 39b785a
Show file tree
Hide file tree
Showing 7 changed files with 119 additions and 79 deletions.
6 changes: 6 additions & 0 deletions currencies/conf.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
# -*- coding: utf-8 -*-

from django.conf import settings

SESSION_PREFIX = getattr(settings, 'CURRENCY_SESSION_PREFIX', 'session')
SESSION_KEY = '%s:currency_code' % SESSION_PREFIX
21 changes: 10 additions & 11 deletions currencies/context_processors.py
Original file line number Diff line number Diff line change
@@ -1,17 +1,16 @@
from currencies.models import Currency
# -*- coding: utf-8 -*-

from .models import Currency
from .utils import get_currency_code
from .conf import SESSION_KEY

def currencies(request):
currencies = Currency.objects.active()

if not request.session.get('currency'):
try:
currency = Currency.objects.get(is_default__exact=True)
except Currency.DoesNotExist:
currency = None
request.session['currency'] = currency
def currencies(request):
# make sure that currency was initialized
if not SESSION_KEY in request.session or request.session.get(SESSION_KEY) is None:
request.session[SESSION_KEY] = get_currency_code(False)

return {
'CURRENCIES': currencies,
'CURRENCY': request.session['currency']
'CURRENCIES': Currency.active.all(), # get all active currencies
'CURRENCY_CODE': request.session[SESSION_KEY],
}
8 changes: 0 additions & 8 deletions currencies/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -46,11 +46,3 @@ def save(self, **kwargs):
self.is_active = True

super(Currency, self).save(**kwargs)

def to_base(self, price):
from . import utils
return utils.price_to_base(price, self)

@classmethod
def price_to_base(cls, price, code):
return cls.objects.get(code__exact=code).to_base(price)
71 changes: 47 additions & 24 deletions currencies/templatetags/currency.py
Original file line number Diff line number Diff line change
@@ -1,36 +1,59 @@
# -*- coding: utf-8 -*-

from decimal import Decimal

from django import template
from django.template.defaultfilters import stringfilter
from currencies.models import Currency
from currencies.utils import calculate_price

register = template.Library()
from classytags.core import Tag, Options
from classytags.arguments import Argument

from ..models import Currency
from ..utils import get_currency_code, calculate

@register.filter(name='currency')
@stringfilter
def set_currency(value, arg):
return calculate_price(value, arg)

register = template.Library()

class ChangeCurrencyNode(template.Node):

def __init__(self, price, currency):
self.price = template.Variable(price)
self.currency = template.Variable(currency)
class CurrentCurrencyTag(Tag):
name = 'get_current_currency'
options = Options(
'as',
Argument('varname', resolve=False, required=False),
)

def render(self, context):
def render_tag(self, context, varname):
code = get_currency_code(context['request'])
try:
return calculate_price(self.price.resolve(context),
self.currency.resolve(context))
except template.VariableDoesNotExist:
currency = Currency.active.get(code=code)
except Currency.DoesNotExist:
try:
currency = Currency.active.default()
except Currency.DoesNotExist:
currency = None # shit happens...

if varname:
context[varname] = currency
return ''
else:
return currency

register.tag(CurrentCurrencyTag)

@register.tag(name='change_currency')
def change_currency(parser, token):
try:
tag_name, current_price, new_currency = token.split_contents()
except ValueError:
tag_name = token.contents.split()[0]
raise template.TemplateSyntaxError('%r tag requires exactly two arguments' % (tag_name))
return ChangeCurrencyNode(current_price, new_currency)

class ChangeCurrencyTag(Tag):
name = 'change_currency'
options = Options(
Argument('price', resolve=True, required=True),
Argument('code', resolve=True, required=True),
)

def render_tag(self, context, price, code):
return calculate(price, code)

register.tag(ChangeCurrencyTag)


@stringfilter
@register.filter(name='currency')
def do_currency(price, code):
return calculate(price, code)
10 changes: 5 additions & 5 deletions currencies/urls.py
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
from django.conf.urls import url, patterns
from currencies.views import set_currency
# -*- coding: utf-8 -*-

from django.conf.urls import url, patterns

urlpatterns = patterns('',
url(r'^setcurrency/$', set_currency,
name='currencies_set_currency'),
urlpatterns = patterns('currencies.views',
url(r'^setcurrency/$', 'set_currency', name='currencies_set_currency'),
)

48 changes: 32 additions & 16 deletions currencies/utils.py
Original file line number Diff line number Diff line change
@@ -1,25 +1,41 @@
from decimal import Decimal, ROUND_UP
from currencies.models import Currency
# -*- coding: utf-8 -*-

from decimal import Decimal as D, ROUND_UP

def calculate_price(price, currency):
price = Decimal(price)
currency = Currency.objects.get(code__exact=currency)
default = Currency.objects.get(is_default=True)
from .models import Currency as C
from .conf import SESSION_KEY

# First, convert from the default currency to the base currency
price = price / default.factor

# Now, convert from the base to the given currency
price = price * currency.factor
def calculate(price, code):
to, default = C.active.get(code=code), C.active.default()

return price.quantize(Decimal("0.01"), rounding=ROUND_UP)
# First, convert from the default currency to the base currency,
# then convert from the base to the given currency
price = (D(price) / default.factor) * to.factor

return price.quantize(D("0.01"), rounding=ROUND_UP)

def price_to_base(price, currency):
price = Decimal(price)

# Convert from the given currency to the base currency
price = price / currency.factor
def convert(amount, from_code, to_code):
if from_code == to_code:
return amount

return price.quantize(Decimal("0.01"), rounding=ROUND_UP)
from_, to = C.active.get(code=from_code), C.active.get(code=to_code)

amount = D(amount) * (to.factor / from_.factor)
return amount.quantize(D("0.01"), rounding=ROUND_UP)


def get_currency_code(request):
for attr in ('session', 'COOKIES'):
if hasattr(request, attr):
try:
return getattr(request, attr)[SESSION_KEY]
except KeyError:
continue

# fallback to default...
try:
return C.active.default().code
except C.DoesNotExist:
return None # shit happens...
34 changes: 19 additions & 15 deletions currencies/views.py
Original file line number Diff line number Diff line change
@@ -1,23 +1,27 @@
# -*- coding: utf-8 -*-

from django.utils.http import is_safe_url
from django.http import HttpResponseRedirect
from currencies.models import Currency
from django.views.decorators.cache import never_cache

from .models import Currency
from .conf import SESSION_KEY


@never_cache
def set_currency(request):
if request.method == 'POST':
currency_code = request.POST.get('currency', None)
next = request.POST.get('next', None)
else:
currency_code = request.GET.get('currency', None)
next = request.GET.get('next', None)
if not next:
next = request.META.get('HTTP_REFERER', None)
if not next:
next = '/'
next, currency_code = (
request.REQUEST.get('next'), request.REQUEST.get('currency_code', None))

if not is_safe_url(url=next, host=request.get_host()):
next = request.META.get('HTTP_REFERER')
if not is_safe_url(url=next, host=request.get_host()):
next = '/'

response = HttpResponseRedirect(next)
if currency_code:
if currency_code and Currency.active.filter(code=currency_code).exists():
if hasattr(request, 'session'):
request.session['currency'] = \
Currency.objects.get(code__exact=currency_code)
request.session[SESSION_KEY] = currency_code
else:
response.set_cookie('currency', currency_code)
response.set_cookie(SESSION_KEY, currency_code)
return response

0 comments on commit 39b785a

Please sign in to comment.