Permalink
Browse files

chapter 6

  • Loading branch information...
ButuzGOL committed Apr 19, 2010
1 parent 9662dac commit 719d8b8b519adfad9868c465c28f7036e7db1ffd
View
@@ -0,0 +1,33 @@
+from django.conf import settings
+from django.http import HttpResponseRedirect, \
+ HttpResponsePermanentRedirect, get_host
+
+SSL = 'SSL'
+
+class SSLRedirect:
+
+ def process_view(self, request, view_func, view_args, view_kwargs):
+ if SSL in view_kwargs:
+ secure = view_kwargs[SSL]
+ del view_kwargs[SSL]
+ else:
+ secure = False
+ if not secure == self._is_secure(request):
+ return self._redirect(request, secure)
+
+ def _is_secure(self, request):
+ if request.is_secure():
+ return True
+ if 'HTTP_X_FORWARDED_SSL' in request.META:
+ return request.META['HTTP_X_FORWARDED_SSL'] == 'on'
+ return False
+
+ def _redirect(self, request, secure):
+ protocol = secure and "https" or "http"
+ newurl = "%s://%s%s" % (protocol,get_host(request),request.get_full_path())
+ if settings.DEBUG and request.method == 'POST':
+ raise RuntimeError, \
+ """Django can't perform a SSL redirect while maintaining POST data.
+ Please structure your views so that redirects only occur during
+ GETs."""
+ return HttpResponsePermanentRedirect(newurl)
View
@@ -89,3 +89,10 @@ def cart_subtotal(request):
cart_total += cart_item.product.price * cart_item.quantity
return cart_total
+def is_empty(request):
+ return cart_distinct_item_count(request) == 0
+
+def empty_cart(request):
+ user_cart = get_cart_items(request)
+ user_cart.delete()
+
View
@@ -1,17 +1,24 @@
from django.shortcuts import render_to_response
from django.template import RequestContext
from ecomstore.cart import cart
+from django.http import HttpResponseRedirect
+from ecomstore.checkout import checkout
+from ecomstore import settings
-def show_cart(request, template_name="cart/cart.html"):
+def show_cart(request, template_name):
if request.method == 'POST':
postdata = request.POST.copy()
if postdata['submit'] == 'Remove':
cart.remove_from_cart(request)
if postdata['submit'] == 'Update':
cart.update_cart(request)
+ if postdata['submit'] == 'Checkout':
+ checkout_url = checkout.get_checkout_url(request)
+ return HttpResponseRedirect(checkout_url)
cart_items = cart.get_cart_items(request)
- page_title = 'Shopping Cart'
+ page_title = 'Shopping Cart'
cart_subtotal = cart.cart_subtotal(request)
+ # for Google Checkout button
+ merchant_id = settings.GOOGLE_CHECKOUT_MERCHANT_ID
return render_to_response(template_name, locals(),
context_instance=RequestContext(request))
-
View
No changes.
View
@@ -0,0 +1,24 @@
+from django.contrib import admin
+from ecomstore.checkout.models import Order, OrderItem
+
+class OrderItemInline(admin.StackedInline):
+ model = OrderItem
+ extra = 0
+
+class OrderAdmin(admin.ModelAdmin):
+ list_display = ('__unicode__', 'date', 'status', 'transaction_id', 'user')
+ list_filter = ('status', 'date')
+ search_fields = ('email', 'shipping_name', 'billing_name', 'id',
+ 'transaction_id')
+ inlines = [OrderItemInline,]
+ fieldsets = (
+ ('Basics', {'fields': ('status','email','phone')}),
+ ('Shipping', {'fields':('shipping_name','shipping_address_1',
+ 'shipping_address_2','shipping_city','shipping_state',
+ 'shipping_zip','shipping_country')}),
+ ('Billing', {'fields':('billing_name','billing_address_1',
+ 'billing_address_2','billing_city','billing_state',
+ 'billing_zip','billing_country')})
+ )
+
+admin.site.register(Order, OrderAdmin)
View
@@ -0,0 +1,27 @@
+from ecomstore import settings
+import httplib
+import urllib
+
+def do_auth_capture(amount='0.00', card_num=None, exp_date=None, card_cvv=None):
+ delimiter = '|'
+ raw_params = {
+ 'x_login':settings.AUTHNET_LOGIN,
+ 'x_tran_key':settings.AUTHNET_KEY,
+ 'x_type':'AUTH_CAPTURE',
+ 'x_amount':amount,
+ 'x_version':'3.1',
+ 'x_card_num':card_num,
+ 'x_exp_date':exp_date,
+ 'x_delim_char':delimiter,
+ 'x_relay_response':'FALSE',
+ 'x_delim_data':'TRUE',
+ 'x_card_code':card_cvv
+ }
+ params = urllib.urlencode(raw_params)
+ headers = { 'content-type':'application/x-www-form-urlencoded',
+ 'content-length':len(params) }
+ post_url = settings.AUTHNET_POST_URL
+ post_path = settings.AUTHNET_POST_PATH
+ cn = httplib.HTTPSConnection(post_url, httplib.HTTPS_PORT)
+ cn.request('POST', post_path, params, headers)
+ return cn.getresponse().read().split(delimiter)
View
@@ -0,0 +1,66 @@
+from ecomstore.checkout import google_checkout
+from ecomstore.cart import cart
+from ecomstore.checkout.models import Order, OrderItem
+from ecomstore.checkout.forms import CheckoutForm
+from ecomstore.checkout import authnet
+from ecomstore import settings
+from django.core import urlresolvers
+import urllib
+
+# returns the URL from the checkout module for cart
+def get_checkout_url(request):
+ return urlresolvers.reverse('checkout')
+
+def process(request):
+ # Transaction results
+ APPROVED = '1'
+ DECLINED = '2'
+ ERROR = '3'
+ HELD_FOR_REVIEW = '4'
+ postdata = request.POST.copy()
+ card_num = postdata.get('credit_card_number', '')
+ exp_month = postdata.get('credit_card_expire_month', '')
+ exp_year = postdata.get('credit_card_expire_year', '')
+ exp_date = exp_month + exp_year
+ cvv = postdata.get('credit_card_cvv', '')
+ amount = cart.cart_subtotal(request)
+ results = {}
+ response = authnet.do_auth_capture(amount=amount,
+ card_num=card_num,
+ exp_date=exp_date,
+ card_cvv=cvv)
+ if response[0] == APPROVED:
+ transaction_id = response[6]
+ order = create_order(request, transaction_id)
+ results = {'order_number':order.id, 'message':''}
+ if response[0] == DECLINED:
+ results = {'order_number':0,
+ 'message':'There is a problem with your credit card.'}
+ if response[0] == ERROR or response[0] == HELD_FOR_REVIEW:
+ results = {'order_number':0, 'message':'Error processing your order.'}
+ return results
+
+def create_order(request, transaction_id):
+ order = Order()
+ checkout_form = CheckoutForm(request.POST, instance=order)
+ order = checkout_form.save(commit=False)
+ order.transaction_id = transaction_id
+ order.ip_address = request.META.get('REMOTE_ADDR')
+ order.user = None
+ order.status = Order.SUBMITTED
+ order.save()
+ # if the order save succeeded
+ if order.pk:
+ cart_items = cart.get_cart_items(request)
+ for ci in cart_items:
+ # create order item for each cart item
+ oi = OrderItem()
+ oi.order = order
+ oi.quantity = ci.quantity
+ oi.price = ci.price # now using @property
+ oi.product = ci.product
+ oi.save()
+ # all set, empty cart
+ cart.empty_cart(request)
+ # return the new order object
+ return order
View
@@ -0,0 +1,90 @@
+from django import forms
+from ecomstore.checkout.models import Order
+import datetime
+import re
+
+def cc_expire_years():
+ current_year = datetime.datetime.now().year
+ years = range(current_year, current_year+12)
+ return [(str(x),str(x)) for x in years]
+
+def cc_expire_months():
+ months = []
+ for month in range(1, 13):
+ if len(str(month)) == 1:
+ numeric = '0' + str(month)
+ else:
+ numeric = str(month)
+ months.append((numeric, datetime.date(2009, month, 1).strftime('%B')))
+ return months
+
+CARD_TYPES = (('Mastercard','Mastercard'),
+ ('VISA','VISA'),
+ ('AMEX','AMEX'),
+ ('Discover','Discover'),)
+
+def strip_non_numbers(data):
+ """ gets rid of all non-number characters """
+ non_numbers = re.compile('\D')
+ return non_numbers.sub('', data)
+
+# Gateway test credit cards won't pass this validation
+def cardLuhnChecksumIsValid(card_number):
+ """ checks to make sure that the card passes a luhn mod-10 checksum """
+ sum = 0
+ num_digits = len(card_number)
+ oddeven = num_digits & 1
+ for count in range(0, num_digits):
+ digit = int(card_number[count])
+ if not (( count & 1 ) ^ oddeven ):
+ digit = digit * 2
+ if digit > 9:
+ digit = digit - 9
+ sum = sum + digit
+ return ( (sum % 10) == 0 )
+
+class CheckoutForm(forms.ModelForm):
+ def __init__(self, *args, **kwargs):
+ super(CheckoutForm, self).__init__(*args, **kwargs)
+ # override default attributes
+ for field in self.fields:
+ self.fields[field].widget.attrs['size'] = '30'
+ self.fields['shipping_state'].widget.attrs['size'] = '3'
+ self.fields['shipping_state'].widget.attrs['size'] = '3'
+ self.fields['shipping_zip'].widget.attrs['size'] = '6'
+ self.fields['billing_state'].widget.attrs['size'] = '3'
+ self.fields['billing_state'].widget.attrs['size'] = '3'
+ self.fields['billing_zip'].widget.attrs['size'] = '6'
+ self.fields['credit_card_type'].widget.attrs['size'] = '1'
+ self.fields['credit_card_expire_year'].widget.attrs['size'] = '1'
+ self.fields['credit_card_expire_month'].widget.attrs['size'] = '1'
+ self.fields['credit_card_cvv'].widget.attrs['size'] = '5'
+
+ class Meta:
+ model = Order
+ exclude = ('status', 'ip_address', 'user', 'transaction_id',)
+
+ credit_card_number = forms.CharField()
+ credit_card_type = forms.CharField(widget=forms.Select(choices=CARD_TYPES))
+ credit_card_expire_month = \
+ forms.CharField(widget=forms.Select(choices=cc_expire_months()))
+ credit_card_expire_year = \
+ forms.CharField(widget=forms.Select(choices=cc_expire_years()))
+ credit_card_cvv = forms.CharField()
+
+ def clean_credit_card_number(self):
+ cc_number = self.cleaned_data['credit_card_number']
+ stripped_cc_number = strip_non_numbers(cc_number)
+ if not cardLuhnChecksumIsValid(stripped_cc_number):
+ raise forms.ValidationError('The credit card you entered is \
+ invalid.')
+
+ def clean_phone(self):
+ phone = self.cleaned_data['phone']
+ stripped_phone = strip_non_numbers(phone)
+ if len(stripped_phone) < 10:
+ raise forms.ValidationError('Enter a valid phone number with area \
+ code.(e.g.555-555-5555)')
+ return self.cleaned_data['phone']
+
+
@@ -0,0 +1,93 @@
+from xml.dom.minidom import Document
+from xml.dom import minidom
+from django.http import HttpRequest, HttpResponseRedirect
+from urllib2 import Request, urlopen, HTTPError, URLError
+import base64
+from ecomstore.cart.models import CartItem
+from ecomstore.cart import cart
+from ecomstore import settings
+
+def get_checkout_url(request):
+ redirect_url = ''
+ req =_create_google_checkout_request(request)
+ try:
+ response_xml = urlopen(req).read()
+ except HTTPError, err:
+ raise err
+ except URLError, err:
+ raise err
+ else:
+ redirect_url = _parse_google_checkout_response(response_xml)
+ return redirect_url
+
+def _create_google_checkout_request(request):
+ url = settings.GOOGLE_CHECKOUT_URL
+ cart = _build_xml_shopping_cart(request)
+ req = Request(url=url, data=cart)
+ merchant_id = settings.GOOGLE_CHECKOUT_MERCHANT_ID
+ merchant_key = settings.GOOGLE_CHECKOUT_MERCHANT_KEY
+ key_id = merchant_id + ':' + merchant_key
+ authorization_value = base64.encodestring(key_id)[:-1]
+ req.add_header('Authorization', 'Basic %s' % authorization_value)
+ req.add_header('Content-Type','application/xml; charset=UTF-8')
+ req.add_header('Accept','application/xml; charset=UTF-8')
+ return req
+
+def _parse_google_checkout_response(response_xml):
+ redirect_url = ''
+ xml_doc = minidom.parseString(response_xml)
+ root = xml_doc.documentElement
+ node = root.childNodes[1]
+ if node.tagName == 'redirect-url':
+ redirect_url = node.firstChild.data
+ if node.tagName == 'error-message':
+ raise RuntimeError(node.firstChild.data)
+ return redirect_url
+
+def _build_xml_shopping_cart(request):
+ doc = Document()
+ root = doc.createElement('checkout-shopping-cart')
+ root.setAttribute('xmlns', 'http://checkout.google.com/schema/2')
+ doc.appendChild(root)
+ shopping_cart = doc.createElement('shopping-cart')
+ root.appendChild(shopping_cart)
+ items = doc.createElement('items')
+ shopping_cart.appendChild(items)
+ cart_items = cart.get_cart_items(request)
+
+ for cart_item in cart_items:
+ item = doc.createElement('item')
+ items.appendChild(item)
+ item_name = doc.createElement('item-name')
+ item_name_text = doc.createTextNode(str(cart_item.name))
+ item_name.appendChild(item_name_text)
+ item.appendChild(item_name)
+ item_description = doc.createElement('item-description')
+ item_description_text = doc.createTextNode(str(cart_item.name))
+ item_description.appendChild(item_description_text)
+ item.appendChild(item_description)
+ unit_price = doc.createElement('unit-price')
+ unit_price.setAttribute('currency', 'USD')
+ unit_price_text = doc.createTextNode(str(cart_item.price))
+ unit_price.appendChild(unit_price_text)
+ item.appendChild(unit_price)
+ quantity = doc.createElement('quantity')
+ quantity_text = doc.createTextNode(str(cart_item.quantity))
+ quantity.appendChild(quantity_text)
+ item.appendChild(quantity)
+
+ checkout_flow = doc.createElement('checkout-flow-support')
+ root.appendChild(checkout_flow)
+ merchant_flow = doc.createElement('merchant-checkout-flow-support')
+ checkout_flow.appendChild(merchant_flow)
+ shipping_methods = doc.createElement('shipping-methods')
+ merchant_flow.appendChild(shipping_methods)
+ flat_rate_shipping = doc.createElement('flat-rate-shipping')
+ flat_rate_shipping.setAttribute('name', 'FedEx Ground')
+ shipping_methods.appendChild(flat_rate_shipping)
+ shipping_price = doc.createElement('price')
+ shipping_price.setAttribute('currency', 'USD')
+ flat_rate_shipping.appendChild(shipping_price)
+ shipping_price_text = doc.createTextNode('9.99')
+ shipping_price.appendChild(shipping_price_text)
+ return doc.toxml(encoding='utf-8')
Oops, something went wrong.

0 comments on commit 719d8b8

Please sign in to comment.