Checkout

Flow

The checkout process comprises the following steps:

  1. Gateway - Anonymous users are offered the choice of logging in, registering, or checking out anonymously. Signed in users will be automatically redirected to the next step.
  2. Shipping address - Enter or choose a shipping address.
  3. Shipping method - Choose a shipping method. If only one shipping method is available then it is automatically chosen and the user is redirected onto the next step.
  4. Payment method - Choose the method of payment plus any allocations if payment is to be split across multiple sources. If only one method is available, then the user is redirected onto the next step.
  5. Preview - The prospective order can be previewed.
  6. Payment details - If any sensitive payment details are required (e.g., bankcard number), then a form is presented within this step. This has to be the last step before submission so that sensitive details don’t have to be stored in the session.
  7. Submission - The order is placed.
  8. Thank you - A summary of the order with any relevant tracking information.

Abstract models

None.

Views and mixins

class oscar.apps.checkout.views.IndexView(**kwargs)[source]

First page of the checkout. We prompt user to either sign in, or to proceed as a guest (where we still collect their email address).

class oscar.apps.checkout.views.PaymentDetailsView(**kwargs)[source]

For taking the details of payment and creating the order.

This view class is used by two separate URLs: ‘payment-details’ and ‘preview’. The preview class attribute is used to distinguish which is being used. Chronologically, payment-details (preview=False) comes before preview (preview=True).

If sensitive details are required (eg a bankcard), then the payment details view should submit to the preview URL and a custom implementation of validate_payment_submission should be provided.

  • If the form data is valid, then the preview template can be rendered with the payment-details forms re-rendered within a hidden div so they can be re-submitted when the ‘place order’ button is clicked. This avoids having to write sensitive data to disk anywhere during the process. This can be done by calling render_preview, passing in the extra template context vars.
  • If the form data is invalid, then the payment details templates needs to be re-rendered with the relevant error messages. This can be done by calling render_payment_details, passing in the form instances to pass to the templates.

The class is deliberately split into fine-grained methods, responsible for only one thing. This is to make it easier to subclass and override just one component of functionality.

All projects will need to subclass and customise this class as no payment is taken by default.

get_default_billing_address()[source]

Return default billing address for user

This is useful when the payment details view includes a billing address form - you can use this helper method to prepopulate the form.

Note, this isn’t used in core oscar as there is no billing address form by default.

handle_payment_details_submission(request)[source]

Handle a request to submit payment details.

This method will need to be overridden by projects that require forms to be submitted on the payment details view. The new version of this method should validate the submitted form data and:

  • If the form data is valid, show the preview view with the forms re-rendered in the page
  • If the form data is invalid, show the payment details view with the form errors showing.
handle_place_order_submission(request)[source]

Handle a request to place an order.

This method is normally called after the customer has clicked “place order” on the preview page. It’s responsible for (re-)validating any form information then building the submission dict to pass to the submit method.

If forms are submitted on your payment details view, you should override this method to ensure they are valid before extracting their data into the submission dict and passing it onto submit.

render_payment_details(request, **kwargs)[source]

Show the payment details page

This method is useful if the submission from the payment details view is invalid and needs to be re-rendered with form errors showing.

render_preview(request, **kwargs)[source]

Show a preview of the order.

If sensitive data was submitted on the payment details page, you will need to pass it back to the view here so it can be stored in hidden form inputs. This avoids ever writing the sensitive data to disk.

submit(user, basket, shipping_address, shipping_method, shipping_charge, billing_address, order_total, payment_kwargs=None, order_kwargs=None)[source]

Submit a basket for order placement.

The process runs as follows:

  • Generate an order number
  • Freeze the basket so it cannot be modified any more (important when redirecting the user to another site for payment as it prevents the basket being manipulated during the payment process).
  • Attempt to take payment for the order - If payment is successful, place the order - If a redirect is required (eg PayPal, 3DSecure), redirect - If payment is unsuccessful, show an appropriate error message
Basket:The basket to submit.
Payment_kwargs:Additional kwargs to pass to the handle_payment method. It normally makes sense to pass form instances (rather than model instances) so that the forms can be re-rendered correctly if payment fails.
Order_kwargs:Additional kwargs to pass to the place_order method
class oscar.apps.checkout.views.PaymentMethodView(**kwargs)[source]

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. It’s not the place for entering sensitive details like bankcard numbers though - that belongs on the payment details view.

class oscar.apps.checkout.views.ShippingAddressView(**kwargs)[source]

Determine the shipping address for the order.

The default behaviour is to display a list of addresses from the users’s address book, from which the user can choose one to be their shipping address. They can add/edit/delete these USER addresses. This address will be automatically converted into a SHIPPING address when the user checks out.

Alternatively, the user can enter a SHIPPING address directly which will be saved in the session and later saved as ShippingAddress model when the order is successfully submitted.

class oscar.apps.checkout.views.ShippingMethodView(**kwargs)[source]

View for allowing a user to choose a shipping method.

Shipping methods are largely domain-specific and so this view will commonly need to be subclassed and customised.

The default behaviour is to load all the available shipping methods using the shipping Repository. If there is only 1, then it is automatically selected. Otherwise, a page is rendered where the user can choose the appropriate one.

get_available_shipping_methods()[source]

Returns all applicable shipping method objects for a given basket.

class oscar.apps.checkout.views.ThankYouView(**kwargs)[source]

Displays the ‘thank you’ page which summarises the order just submitted.

class oscar.apps.checkout.views.UserAddressDeleteView(**kwargs)[source]

Delete an address from a user’s addressbook.

class oscar.apps.checkout.views.UserAddressUpdateView(**kwargs)[source]

Update a user address

class oscar.apps.checkout.mixins.OrderPlacementMixin[source]

Mixin which provides functionality for placing orders.

Any view class which needs to place an order should use this mixin.

add_payment_event(event_type_name, amount, reference='')[source]

Record a payment event for creation once the order is placed

add_payment_source(source)[source]

Record a payment source for this order

create_billing_address(billing_address=None, shipping_address=None, **kwargs)[source]

Saves any relevant billing data (eg a billing address).

create_shipping_address(user, shipping_address)[source]

Create and return the shipping address for the current order.

Compared to self.get_shipping_address(), ShippingAddress is saved and makes sure that appropriate UserAddress exists.

freeze_basket(basket)[source]

Freeze the basket so it can no longer be modified

generate_order_number(basket)[source]

Return a new order number

handle_order_placement(order_number, user, basket, shipping_address, shipping_method, shipping_charge, billing_address, order_total, **kwargs)[source]

Write out the order models and return the appropriate HTTP response

We deliberately pass the basket in here as the one tied to the request isn’t necessarily the correct one to use in placing the order. This can happen when a basket gets frozen.

handle_payment(order_number, total, **kwargs)[source]

Handle any payment processing and record payment sources and events.

This method is designed to be overridden within your project. The default is to do nothing as payment is domain-specific.

This method is responsible for handling payment and recording the payment sources (using the add_payment_source method) and payment events (using add_payment_event) so they can be linked to the order when it is saved later on.

handle_successful_order(order)[source]

Handle the various steps required after an order has been successfully placed.

Override this view if you want to perform custom actions when an order is submitted.

place_order(order_number, user, basket, shipping_address, shipping_method, shipping_charge, order_total, billing_address=None, **kwargs)[source]

Writes the order out to the DB including the payment models

restore_frozen_basket()[source]

Restores a frozen basket as the sole OPEN basket. Note that this also merges in any new products that have been added to a basket that has been created while payment.

save_payment_details(order)[source]

Saves all payment-related details. This could include a billing address, payment sources and any order payment events.

save_payment_events(order)[source]

Saves any relevant payment events for this order

save_payment_sources(order)[source]

Saves any payment sources used in this order.

When the payment sources are created, the order model does not exist and so they need to have it set before saving.

update_address_book(user, shipping_addr)[source]

Update the user’s address book based on the new shipping address

class oscar.apps.checkout.session.CheckoutSessionMixin[source]

Mixin to provide common functionality shared between checkout views.

All checkout views subclass this mixin. It ensures that all relevant checkout information is available in the template context.

build_submission(**kwargs)[source]

Return a dict of data that contains everything required for an order submission. This includes payment details (if any).

This can be the right place to perform tax lookups and apply them to the basket.

check_basket_is_valid(request)[source]

Check that the basket is permitted to be submitted as an order. That is, all the basket lines are available to buy - nothing has gone out of stock since it was added to the basket.

get_billing_address(shipping_address)[source]

Return an unsaved instance of the billing address (if one exists)

This method only returns a billing address if the session has been used to store billing address information. It’s also possible to capture billing address information as part of the payment details forms, which never get stored in the session. In that circumstance, the billing address can be set directly in the build_submission dict (see Oscar’s demo site for an example of this approach).

get_order_totals(basket, shipping_charge, **kwargs)[source]

Returns the total for the order with and without tax

get_pre_conditions(request)[source]

Return the pre-condition method names to run for this view

get_shipping_address(basket)[source]

Return the (unsaved) shipping address for this checkout session.

If the shipping address was entered manually, then we instantiate a ShippingAddress model with the appropriate form data (which is saved in the session).

If the shipping address was selected from the user’s address book, then we convert the UserAddress to a ShippingAddress.

The ShippingAddress instance is not saved as sometimes you need a shipping address instance before the order is placed. For example, if you are submitting fraud information as part of a payment request.

The OrderPlacementMixin.create_shipping_address method is responsible for saving a shipping address when an order is placed.

get_shipping_method(basket, shipping_address=None, **kwargs)[source]

Return the selected shipping method instance from this checkout session

The shipping address is passed as we need to check that the method stored in the session is still valid for the shipping address.

get_skip_conditions(request)[source]

Return the skip-condition method names to run for this view

Forms

Utils

class oscar.apps.checkout.calculators.OrderTotalCalculator(request=None)[source]

Calculator class for calculating the order total.

class oscar.apps.checkout.utils.CheckoutSessionData(request)[source]

Responsible for marshalling all the checkout session data

Multi-stage checkouts often require several forms to be submitted and their data persisted until the final order is placed. This class helps store and organise checkout form data until it is required to write out the final order.

bill_to_new_address(address_fields)[source]

Store address fields for a billing address.

bill_to_shipping_address()[source]

Record fact that the billing address is to be the same as the shipping address.

bill_to_user_address(address)[source]

Set an address from a user’s address book as the billing address

Address:The address object
billing_address_same_as_shipping()

Record fact that the billing address is to be the same as the shipping address.

billing_user_address_id()[source]

Return the ID of the user address being used for billing

flush()[source]

Flush all session data

is_billing_address_set()[source]

Test whether a billing address has been stored in the session.

This can be from a new address or re-using an existing address.

is_shipping_address_set()[source]

Test whether a shipping address has been stored in the session.

This can be from a new address or re-using an existing address.

is_shipping_method_set(basket)[source]

Test if a valid shipping method is stored in the session

new_billing_address_fields()[source]

Return fields for a billing address

new_shipping_address_fields()[source]

Return shipping address fields

ship_to_new_address(address_fields)[source]

Use a manually entered address as the shipping address

ship_to_user_address(address)[source]

Use an user address (from an address book) as the shipping address.

shipping_method_code(basket)[source]

Return the shipping method code

shipping_user_address_id()[source]

Return user address id

use_free_shipping()[source]

Set “free shipping” code to session

use_shipping_method(code)[source]

Set shipping method code to session

user_address_id()

Return user address id