Source code for shoop.front.checkout.single_page
# -*- coding: utf-8 -*-
# This file is part of Shoop.
#
# Copyright (c) 2012-2016, Shoop Ltd. All rights reserved.
#
# This source code is licensed under the AGPLv3 license found in the
# LICENSE file in the root directory of this source tree.
from __future__ import unicode_literals
from django import forms
from django.core.exceptions import ValidationError
from django.shortcuts import redirect
from django.utils.translation import ugettext_lazy as _
from django.views.generic import FormView
from shoop.core.models import (
CompanyContact, OrderStatus, PaymentMethod, ShippingMethod
)
from shoop.front.basket import get_basket_order_creator
from shoop.front.basket.objects import BaseBasket
from shoop.front.checkout import CheckoutPhaseViewMixin
from shoop.utils.fields import RelaxedModelChoiceField
from shoop.utils.form_group import FormGroup
from ._mixins import TaxNumberCleanMixin
from .addresses import AddressForm
def _to_choices(objects):
return [(x.id, x) for x in objects]
[docs]class OrderForm(TaxNumberCleanMixin, forms.Form):
company_name = forms.CharField(max_length=128, required=False, label=_(u"Company name"))
tax_number = forms.CharField(max_length=32, required=False, label=_("Tax number"))
shipping_method = RelaxedModelChoiceField(queryset=ShippingMethod.objects.none(), label=_(u"Shipping method"))
payment_method = RelaxedModelChoiceField(queryset=PaymentMethod.objects.none(), label=_(u"Payment method"))
accept_terms = forms.BooleanField(required=True, label=_(u"I accept the terms and conditions"))
marketing = forms.BooleanField(required=False, label=_(u"Please send me marketing correspondence"))
comment = forms.CharField(widget=forms.Textarea(), required=False, label=_("Comment"))
def __init__(self, *args, **kwargs):
self.basket = kwargs.pop("basket")
self.shop = kwargs.pop("shop")
super(OrderForm, self).__init__(*args, **kwargs)
self.limit_method_fields()
[docs] def limit_method_fields(self):
basket = self.basket # type: shoop.front.basket.objects.BaseBasket
shipping_methods = basket.get_available_shipping_methods()
payment_methods = basket.get_available_payment_methods()
self["shipping_method"].field.choices = _to_choices(shipping_methods)
self["payment_method"].field.choices = _to_choices(payment_methods)
[docs]class SingleCheckoutPhase(CheckoutPhaseViewMixin, FormView):
identifier = "checkout"
final = True
template_name = "shoop/front/checkout/single_phase.jinja"
billing_address_form_class = AddressForm
shipping_address_form_class = AddressForm
order_form_class = OrderForm
def get_form(self, form_class):
kwargs = self.get_form_kwargs()
fg = FormGroup(data=kwargs.get("data"), files=kwargs.get("files"))
fg.add_form_def("billing", self.billing_address_form_class)
fg.add_form_def("shipping", self.shipping_address_form_class)
fg.add_form_def("order", self.order_form_class, kwargs={
"basket": self.request.basket,
"shop": self.request.shop
})
return fg
[docs] def get_context_data(self, **kwargs):
ctx = FormView.get_context_data(self, **kwargs)
basket = self.request.basket # type: shoop.front.basket.objects.BaseBasket
ctx["basket"] = basket
basket.calculate_taxes()
errors = list(basket.get_validation_errors())
ctx["errors"] = errors
ctx["orderable"] = (not errors)
return ctx
[docs] def form_valid(self, form):
basket = self.request.basket
assert isinstance(basket, BaseBasket)
order_data = form["order"].cleaned_data.copy()
if not order_data.pop("accept_terms", None): # pragma: no cover
raise ValidationError("Terms must be accepted")
basket.shop = self.request.shop
basket.orderer = self.request.person
basket.customer = self.request.customer
basket.shipping_address = form["shipping"].save(commit=False)
basket.billing_address = form["billing"].save(commit=False)
basket.shipping_method = order_data.pop("shipping_method")
basket.payment_method = order_data.pop("payment_method")
basket.status = OrderStatus.objects.get_default_initial()
company_name = order_data.pop("company_name")
tax_number = order_data.pop("tax_number")
if company_name and tax_number:
# Not using `get_or_create` here because duplicates are better than accidental information leakage
basket.customer = CompanyContact.objects.create(name=company_name, tax_number=tax_number)
for address in (basket.shipping_address, basket.billing_address):
address.company_name = basket.customer.name
address.tax_number = basket.customer.tax_number
basket.marketing_permission = order_data.pop("marketing")
basket.customer_comment = order_data.pop("comment")
if order_data: # pragma: no cover
raise ValueError("`order_data` should be empty by now")
order_creator = get_basket_order_creator()
order = order_creator.create_order(basket)
basket.finalize()
self.checkout_process.complete()
if order.require_verification:
return redirect("shoop:order_requires_verification", pk=order.pk, key=order.key)
else:
return redirect("shoop:order_process_payment", pk=order.pk, key=order.key)