| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283 | 
							- from decimal import Decimal
 - import logging
 - 
 - from django.conf import settings
 - from django.http import HttpResponse, Http404, HttpResponseRedirect, HttpResponseBadRequest
 - from django.template import RequestContext
 - from django.shortcuts import render, get_object_or_404
 - from django.core.urlresolvers import reverse
 - from django.forms import ModelForm
 - from django.contrib import messages
 - from django.core.urlresolvers import resolve
 - from django.core.exceptions import ObjectDoesNotExist
 - from django.utils.translation import ugettext as _
 - 
 - from oscar.view.generic import ModelView
 - from oscar.core.loading import import_module
 - 
 - basket_factory = import_module('basket.factory', ['BasketFactory'])
 - checkout_forms = import_module('checkout.forms', ['ShippingAddressForm'])
 - checkout_calculators = import_module('checkout.calculators', ['OrderTotalCalculator'])
 - checkout_utils = import_module('checkout.utils', ['ProgressChecker', 'CheckoutSessionData'])
 - checkout_signals = import_module('checkout.signals', ['pre_payment', 'post_payment'])
 - checkout_views = import_module('checkout.core_views', ['CheckoutView', 'mark_step_as_complete'])
 - order_models = import_module('order.models', ['Order', 'ShippingAddress'])
 - order_utils = import_module('order.utils', ['OrderNumberGenerator', 'OrderCreator'])
 - address_models = import_module('address.models', ['UserAddress'])
 - shipping_repository = import_module('shipping.repository', ['Repository'])
 - 
 - 
 - logger = logging.getLogger('oscar.checkout')
 - 
 - 
 - class IndexView(object):
 -     template_file = 'checkout/gateway.html'
 -     
 -     def __call__(self, request):
 -         if request.user.is_authenticated():
 -             return HttpResponseRedirect(reverse('oscar-checkout-shipping-address'))
 -         return render(request, self.template_file, locals())    
 - 
 - 
 - class ShippingAddressView(checkout_views.CheckoutView):
 -     template_file = 'checkout/shipping_address.html'
 -     
 -     def handle_POST(self):
 -         if self.request.user.is_authenticated and 'address_id' in self.request.POST:
 -             address = address_models.UserAddress._default_manager.get(pk=self.request.POST['address_id'])
 -             if 'action' in self.request.POST and self.request.POST['action'] == 'ship_to':
 -                 # User has selected a previous address to ship to
 -                 self.co_data.ship_to_user_address(address)
 -                 return self.get_success_response()
 -             elif 'action' in self.request.POST and self.request.POST['action'] == 'delete':
 -                 address.delete()
 -                 messages.info(self.request, "Address deleted from your address book")
 -                 return HttpResponseRedirect(reverse('oscar-checkout-shipping-method'))
 -             else:
 -                 return HttpResponseBadRequest()
 -         else:
 -             form = checkout_forms.ShippingAddressForm(self.request.POST)
 -             if form.is_valid():
 -                 # Address data is valid - store in session and redirect to next step.
 -                 self.co_data.ship_to_new_address(form.clean())
 -                 return self.get_success_response()
 -             return self.handle_GET(form)
 -         
 -     def handle_GET(self, form=None):
 -         if not form:
 -             addr_fields = self.co_data.new_address_fields()
 -             if addr_fields:
 -                 form = checkout_forms.ShippingAddressForm(addr_fields)
 -             else:
 -                 form = checkout_forms.ShippingAddressForm()
 -         self.context['form'] = form
 -     
 -         # Look up address book data
 -         if self.request.user.is_authenticated():
 -             self.context['addresses'] = address_models.UserAddress._default_manager.filter(user=self.request.user)
 -         
 -         return render(self.request, self.template_file, self.context)
 -     
 -     
 - class ShippingMethodView(checkout_views.CheckoutView):
 -     u"""
 -     Shipping methods are domain-specific and so need implementing in a 
 -     subclass of this class.
 -     """
 -     template_file = 'checkout/shipping_methods.html';
 -     
 -     def handle_GET(self):
 -         methods = self.get_available_shipping_methods()
 -         if len(methods) == 1:
 -             # Only one method - set this and redirect onto the next step
 -             self.co_data.use_shipping_method(methods[0].code)
 -             return self.get_success_response()
 -         
 -         self.context['methods'] = methods
 -         return render(self.request, self.template_file, self.context)
 -     
 -     def get_shipping_methods_for_basket(self, basket):
 -         u"""Return available shipping methods for a basket"""
 -         return shipping_models.Method.objects.all()
 - 
 -     def get_available_shipping_methods(self):
 -         u"""
 -         Returns all applicable shipping method objects
 -         for a given basket.
 -         """ 
 -         repo = shipping_repository.Repository()
 -         return repo.get_shipping_methods(self.request.user, self.basket, self.get_shipping_address())
 -     
 -     def handle_POST(self):
 -         method_code = self.request.POST['method_code']
 -         self.co_data.use_shipping_method(method_code)
 -         return self.get_success_response()
 -         
 - 
 - class PaymentMethodView(checkout_views.CheckoutView):
 -     u"""
 -     View for a user to choose which payment method(s) they want to use.
 -     
 -     This would include setting allocations if payment is to be split
 -     between multiple sources.
 -     """
 -     pass
 - 
 - 
 - class OrderPreviewView(checkout_views.CheckoutView):
 -     u"""View a preview of the order before submitting."""
 -     
 -     template_file = 'checkout/preview.html'
 -     
 -     def handle_GET(self):
 -         checkout_views.mark_step_as_complete(self.request)
 -         return render(self.request, self.template_file, self.context)
 - 
 - 
 - class PaymentDetailsView(checkout_views.CheckoutView):
 -     u"""
 -     For taking the details of payment and creating the order
 -     
 -     The class is deliberately split into fine-grained method, responsible for only one
 -     thing.  This is to make it easier to subclass and override just one component of
 -     functionality.
 -     """
 - 
 -     # Any payment sources should be added to this list as part of the
 -     # _handle_payment method.  If the order is placed successfully, then
 -     # they will be persisted.
 -     payment_sources = []
 - 
 -     def handle_GET(self):
 -         return self.handle_POST()
 -     
 -     def handle_POST(self):
 -         """
 -         This method is designed to be overridden by subclasses which will
 -         validate the forms from the payment details page.  If the forms are valid
 -         then the method can call _submit()."""
 -         return self._submit()
 -     
 -     def _submit(self):
 -         # We generate the order number first as this will be used
 -         # in payment requests (ie before the order model has been 
 -         # created).
 -         order_number = self._generate_order_number(self.basket)
 -         logger.info(_("Submitting order #%s" % order_number))
 -         
 -         checkout_signals.pre_payment.send_robust(sender=self, view=self)
 -         self._handle_payment(self.basket, order_number)
 -         checkout_signals.post_payment.send_robust(sender=self, view=self)
 -         order = self._place_order(self.basket, order_number)
 -         self._save_payment_sources(order)
 -         self._reset_checkout()
 -         
 -         logger.info(_("Order #%s submitted successfully" % order_number))
 -         
 -         # Save order id in session so thank-you page can load it
 -         self.request.session['checkout_order_id'] = order.id
 -         return HttpResponseRedirect(reverse('oscar-checkout-thank-you'))
 -     
 -     def _generate_order_number(self, basket):
 -         generator = order_utils.OrderNumberGenerator()
 -         return generator.order_number(basket)
 - 
 -     def _handle_payment(self, basket, order_number):
 -         u"""Handle any payment processing"""
 -         pass
 - 
 -     def _save_payment_sources(self, order):
 -         u"""
 -         Saves any payment sources used in this order.
 -         """
 -         for source in self.payment_sources:
 -             source.order = order
 -             source.save()
 -     
 -     def _reset_checkout(self):
 -         u"""Reset any checkout session state"""
 -         self.co_data.flush()
 -         checkout_utils.ProgressChecker().all_steps_complete(self.request)
 -     
 -     def _place_order(self, basket, order_number):
 -         u"""Writes the order out to the DB"""
 -         calc = checkout_calculators.OrderTotalCalculator(self.request)
 -         shipping_address = self._get_shipping_address()
 -         shipping_method = self._get_shipping_method(basket)
 -         order_creator = order_utils.OrderCreator(calc)
 -         return order_creator.place_order(self.request.user, basket, 
 -                                          shipping_address, shipping_method, order_number)
 - 
 -     def _get_chargable_total(self, basket):
 -         u"""
 -         Returns the total amount to take payment for.
 -         """
 -         calc = checkout_calculators.OrderTotalCalculator(self.request)
 -         shipping_method = self._get_shipping_method(basket)
 -         return calc.order_total_incl_tax(basket, shipping_method)
 -     
 -     def _get_shipping_method(self, basket):
 -         u"""Returns the shipping method object"""
 -         method = self.co_data.shipping_method()
 -         method.set_basket(basket)
 -         return method
 -     
 -     def _get_shipping_address(self):
 -         u"""Returns the shipping address"""
 -         addr_data = self.co_data.new_address_fields()
 -         addr_id = self.co_data.user_address_id()
 -         if addr_data:
 -             addr = self._create_shipping_address_from_form_fields(addr_data)
 -             self._create_user_address(addr_data)
 -         elif addr_id:
 -             addr = self._create_shipping_address_from_user_address(addr_id)
 -         else:
 -             raise AttributeError("No shipping address data found")
 -         return addr
 -     
 -     def _create_shipping_address_from_form_fields(self, addr_data):
 -         u"""Creates a shipping address model from the saved form fields"""
 -         shipping_addr = order_models.ShippingAddress(**addr_data)
 -         shipping_addr.save() 
 -         return shipping_addr
 -     
 -     def _create_user_address(self, addr_data):
 -         u"""
 -         For signed-in users, we create a user address model which will go 
 -         into their address book.
 -         """
 -         if self.request.user.is_authenticated():
 -             addr_data['user_id'] = self.request.user.id
 -             user_addr = address_models.UserAddress(**addr_data)
 -             # Check that this address isn't already in the db as we don't want
 -             # to fill up the customer address book with duplicate addresses
 -             try:
 -                 duplicate_addr = address_models.UserAddress._default_manager.get(hash=user_addr.generate_hash())
 -             except ObjectDoesNotExist:
 -                 user_addr.save()
 -     
 -     def _create_shipping_address_from_user_address(self, addr_id):
 -         u"""Creates a shipping address from a user address"""
 -         address = address_models.UserAddress._default_manager.get(pk=addr_id)
 -         # Increment the number of orders to help determine popularity of orders 
 -         address.num_orders += 1
 -         address.save()
 -         
 -         shipping_addr = order_models.ShippingAddress()
 -         address.populate_alternative_model(shipping_addr)
 -         shipping_addr.save()
 -         return shipping_addr
 - 
 - 
 - class ThankYouView(object):
 -     
 -     def __call__(self, request):
 -         try:
 -             order = order_models.Order._default_manager.get(pk=request.session['checkout_order_id'])
 -             
 -             # Remove order number from session to ensure that the thank-you page is only 
 -             # viewable once.
 -             del request.session['checkout_order_id']
 -         except KeyError, ObjectDoesNotExist:
 -             return HttpResponseRedirect(reverse('oscar-checkout-index'))
 -         return render(request, 'checkout/thank_you.html', locals())
 
 
  |