Coverage for /home/chris/workspace/django-shop/shop/views/checkout: 68.61%

# Coverage for /home/chris/workspace/django-shop/shop/views/checkout : 68.61%

## 115 statements 78 run 37 missing 0 excluded 0 partial

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 | # -*- coding: utf-8 -*- """ This models the checkout process using views. """ from django.core.urlresolvers import reverse from django.forms import models as model_forms from django.http import HttpResponseRedirect from shop.forms import BillingShippingForm from shop.models import AddressModel from shop.models.ordermodel import Order from shop.order_signals import completed from shop.util.address import get_shipping_address_from_request, \ get_billing_address_from_request, assign_address_to_request from shop.util.cart import get_or_create_cart from shop.util.order import add_order_to_request, get_order_from_request from shop.views import ShopTemplateView, ShopView class CheckoutSelectionView(ShopTemplateView): template_name = 'shop/checkout/selection.html' def _get_dynamic_form_class_from_factory(self): """ Returns a dynamic ModelForm from the loaded AddressModel """ form_class = model_forms.modelform_factory(AddressModel, exclude=['user_shipping', 'user_billing']) return form_class def get_shipping_form_class(self): """ Provided for extensibility. """ return self._get_dynamic_form_class_from_factory() def get_billing_form_class(self): """ Provided for extensibility. """ return self._get_dynamic_form_class_from_factory() def create_order_object_from_cart(self): """ This will create an Order object form the current cart, and will pass a reference to the Order on either the User object or the session. """ cart = get_or_create_cart(self.request) cart.update() order = Order.objects.create_from_cart(cart) request = self.request add_order_to_request(request, order) return order def get_shipping_address_form(self): """ Initializes and handles the form for the shipping address. AddressModel is a model of the type defined in settings.SHOP_ADDRESS_MODEL. The trick here is that we generate a ModelForm for whatever model was passed to us by the SHOP_ADDRESS_MODEL setting, and us this, prefixed, as the shipping address form. So this can be as complex or as simple as one wants. Subclasses of this view can obviously override this method and return any other form instead. """ # Try to get the cached version first. form = getattr(self, '_shipping_form', None) if not form: # Create a dynamic Form class for the model specified as the address model form_class = self.get_shipping_form_class() # Try to get a shipping address instance from the request (user or session)) shipping_address = get_shipping_address_from_request(self.request) if self.request.method == "POST": form = form_class(self.request.POST, prefix="ship", instance=shipping_address) else: # We should either have an instance, or None if not shipping_address: # The user or guest doesn't already have a favorite address. # Instanciate a blank one, and use this as the default value for # the form. shipping_address = AddressModel() # Instanciate the form form = form_class(instance=shipping_address, prefix="ship") setattr(self, '_shipping_form', form) return form def get_billing_address_form(self): """ Initializes and handles the form for the shipping address. AddressModel is a model of the type defined in settings.SHOP_ADDRESS_MODEL """ # Try to get the cached version first. form = getattr(self, '_billing_form', None) if not form: # Create a dynamic Form class for the model specified as the address model form_class = model_forms.modelform_factory(AddressModel, exclude=['user_shipping', 'user_billing']) # Try to get a shipping address instance from the request (user or session)) billing_address = get_billing_address_from_request(self.request) if self.request.method == "POST": form = form_class(self.request.POST, prefix="bill", instance=billing_address) else: # We should either have an instance, or None if not billing_address: # The user or guest doesn't already have a favorite address. # Instansiate a blank one, and use this as the default value for # the form. billing_address = AddressModel() #Instanciate the form form = form_class(instance=billing_address, prefix="bill") setattr(self, '_billing_form', form) return form def get_billing_and_shipping_selection_form(self): """ Get (and cache) the BillingShippingForm instance """ form = getattr(self, '_billingshipping_form', None) if not form: if self.request.method == 'POST': form = BillingShippingForm(self.request.POST) else: form = BillingShippingForm() self._billingshipping_form = form return form def save_addresses_to_order(self, order, shipping_address, billing_address): """ Provided for extensibility. Adds both addresses (shipping and billing addresses to the Order object. """ order.set_shipping_address(shipping_address) order.set_billing_address(billing_address) order.save() def post(self, *args, **kwargs): """ Called when view is POSTed """ shipping_form = self.get_shipping_address_form() billing_form = self.get_billing_address_form() if shipping_form.is_valid() and billing_form.is_valid(): # Add the address to the order shipping_address = shipping_form.save() billing_address = billing_form.save() order = self.create_order_object_from_cart() self.save_addresses_to_order(order, shipping_address, billing_address) # The following marks addresses as being default addresses for shipping # and billing. For more options (amazon style), we should remove this assign_address_to_request(self.request, shipping_address, shipping=True) assign_address_to_request(self.request, billing_address, shipping=False) billingshipping_form = self.get_billing_and_shipping_selection_form() if billingshipping_form.is_valid(): self.request.session['payment_backend'] = billingshipping_form.cleaned_data['payment_method'] self.request.session['shipping_backend'] = billingshipping_form.cleaned_data['shipping_method'] return HttpResponseRedirect(reverse('checkout_shipping')) return self.get(self, *args, **kwargs) def get_context_data(self, **kwargs): """ This overrides the context from the normal template view """ ctx = super(CheckoutSelectionView, self).get_context_data(**kwargs) shipping_address_form = self.get_shipping_address_form() billing_address_form = self.get_billing_address_form() billingshipping_form = self.get_billing_and_shipping_selection_form() ctx.update({ 'shipping_address':shipping_address_form, 'billing_address':billing_address_form, 'billing_shipping_form':billingshipping_form, }) return ctx class ThankYouView(ShopTemplateView): template_name = 'shop/checkout/thank_you.html' def get_context_data(self, **kwargs): ctx = super(ShopTemplateView, self).get_context_data(**kwargs) # Set the order status: order = get_order_from_request(self.request) if order: order.status = Order.COMPLETED order.save() completed.send(sender=self, order=order) else: order = Order.objects.get_latest_for_user(self.request.user) ctx.update({'order': order,}) # Empty the customers basket, to reflect that the purchase was completed cart_object = get_or_create_cart(self.request) cart_object.empty() return ctx class ShippingBackendRedirectView(ShopView): def get(self, *args, **kwargs): try: backend_namespace = self.request.session.pop('shipping_backend') return HttpResponseRedirect(reverse(backend_namespace)) except KeyError: return HttpResponseRedirect(reverse('cart')) class PaymentBackendRedirectView(ShopView): def get(self, *args, **kwargs): try: backend_namespace = self.request.session.pop('payment_backend') return HttpResponseRedirect(reverse(backend_namespace)) except KeyError: return HttpResponseRedirect(reverse('cart'))