You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

utils.py 7.7KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244
  1. from django.utils.encoding import force_text
  2. class CheckoutSessionData(object):
  3. """
  4. Responsible for marshalling all the checkout session data
  5. Multi-stage checkouts often require several forms to be submitted and their
  6. data persisted until the final order is placed. This class helps store and
  7. organise checkout form data until it is required to write out the final
  8. order.
  9. """
  10. SESSION_KEY = 'checkout_data'
  11. def __init__(self, request):
  12. self.request = request
  13. if self.SESSION_KEY not in self.request.session:
  14. self.request.session[self.SESSION_KEY] = {}
  15. def _check_namespace(self, namespace):
  16. """
  17. Ensure a namespace within the session dict is initialised
  18. """
  19. if namespace not in self.request.session[self.SESSION_KEY]:
  20. self.request.session[self.SESSION_KEY][namespace] = {}
  21. def _get(self, namespace, key, default=None):
  22. """
  23. Return a value from within a namespace
  24. """
  25. self._check_namespace(namespace)
  26. if key in self.request.session[self.SESSION_KEY][namespace]:
  27. return self.request.session[self.SESSION_KEY][namespace][key]
  28. return default
  29. def _set(self, namespace, key, value):
  30. """
  31. Set a namespaced value
  32. """
  33. self._check_namespace(namespace)
  34. self.request.session[self.SESSION_KEY][namespace][key] = value
  35. self.request.session.modified = True
  36. def _unset(self, namespace, key):
  37. """
  38. Remove a namespaced value
  39. """
  40. self._check_namespace(namespace)
  41. if key in self.request.session[self.SESSION_KEY][namespace]:
  42. del self.request.session[self.SESSION_KEY][namespace][key]
  43. self.request.session.modified = True
  44. def _flush_namespace(self, namespace):
  45. """
  46. Flush a namespace
  47. """
  48. self.request.session[self.SESSION_KEY][namespace] = {}
  49. self.request.session.modified = True
  50. def flush(self):
  51. """
  52. Flush all session data
  53. """
  54. self.request.session[self.SESSION_KEY] = {}
  55. # Guest checkout
  56. # ==============
  57. def set_guest_email(self, email):
  58. self._set('guest', 'email', email)
  59. def get_guest_email(self):
  60. return self._get('guest', 'email')
  61. # Shipping address
  62. # ================
  63. # Options:
  64. # 1. No shipping required (eg digital products)
  65. # 2. Ship to new address (entered in a form)
  66. # 3. Ship to an addressbook address (address chosen from list)
  67. def reset_shipping_data(self):
  68. self._flush_namespace('shipping')
  69. def ship_to_user_address(self, address):
  70. """
  71. Use an user address (from an address book) as the shipping address.
  72. """
  73. self.reset_shipping_data()
  74. self._set('shipping', 'user_address_id', address.id)
  75. def ship_to_new_address(self, address_fields):
  76. """
  77. Use a manually entered address as the shipping address
  78. """
  79. self._unset('shipping', 'new_address_fields')
  80. phone_number = address_fields.get('phone_number')
  81. if phone_number:
  82. address_fields = address_fields.copy()
  83. address_fields['phone_number'] = force_text(
  84. address_fields['phone_number'])
  85. self._set('shipping', 'new_address_fields', address_fields)
  86. def new_shipping_address_fields(self):
  87. """
  88. Return shipping address fields
  89. """
  90. return self._get('shipping', 'new_address_fields')
  91. def shipping_user_address_id(self):
  92. """
  93. Return user address id
  94. """
  95. return self._get('shipping', 'user_address_id')
  96. # Legacy accessor
  97. user_address_id = shipping_user_address_id
  98. def is_shipping_address_set(self):
  99. """
  100. Test whether a shipping address has been stored in the session.
  101. This can be from a new address or re-using an existing address.
  102. """
  103. new_fields = self.new_shipping_address_fields()
  104. has_new_address = new_fields is not None
  105. user_address_id = self.shipping_user_address_id()
  106. has_old_address = user_address_id is not None and user_address_id > 0
  107. return has_new_address or has_old_address
  108. # Shipping method
  109. # ===============
  110. def use_free_shipping(self):
  111. """
  112. Set "free shipping" code to session
  113. """
  114. self._set('shipping', 'method_code', '__free__')
  115. def use_shipping_method(self, code):
  116. """
  117. Set shipping method code to session
  118. """
  119. self._set('shipping', 'method_code', code)
  120. def shipping_method_code(self, basket):
  121. """
  122. Return the shipping method code
  123. """
  124. return self._get('shipping', 'method_code')
  125. def is_shipping_method_set(self, basket):
  126. """
  127. Test if a valid shipping method is stored in the session
  128. """
  129. return self.shipping_method_code(basket) is not None
  130. # Billing address fields
  131. # ======================
  132. #
  133. # There are 3 common options:
  134. # 1. Billing address is entered manually through a form
  135. # 2. Billing address is selected from address book
  136. # 3. Billing address is the same as the shipping address
  137. def bill_to_new_address(self, address_fields):
  138. """
  139. Store address fields for a billing address.
  140. """
  141. self._flush_namespace('billing')
  142. self._set('billing', 'new_address_fields', address_fields)
  143. def bill_to_user_address(self, address):
  144. """
  145. Set an address from a user's address book as the billing address
  146. :address: The address object
  147. """
  148. self._flush_namespace('billing')
  149. self._set('billing', 'user_address_id', address.id)
  150. def bill_to_shipping_address(self):
  151. """
  152. Record fact that the billing address is to be the same as
  153. the shipping address.
  154. """
  155. self._flush_namespace('billing')
  156. self._set('billing', 'billing_address_same_as_shipping', True)
  157. # Legacy method name
  158. billing_address_same_as_shipping = bill_to_shipping_address
  159. def is_billing_address_same_as_shipping(self):
  160. return self._get('billing', 'billing_address_same_as_shipping', False)
  161. def billing_user_address_id(self):
  162. """
  163. Return the ID of the user address being used for billing
  164. """
  165. return self._get('billing', 'user_address_id')
  166. def new_billing_address_fields(self):
  167. """
  168. Return fields for a billing address
  169. """
  170. return self._get('billing', 'new_address_fields')
  171. def is_billing_address_set(self):
  172. """
  173. Test whether a billing address has been stored in the session.
  174. This can be from a new address or re-using an existing address.
  175. """
  176. if self.is_billing_address_same_as_shipping():
  177. return True
  178. new_fields = self.new_billing_address_fields()
  179. has_new_address = new_fields is not None
  180. user_address_id = self.billing_user_address_id()
  181. has_old_address = user_address_id is not None and user_address_id > 0
  182. return has_new_address or has_old_address
  183. # Payment methods
  184. # ===============
  185. def pay_by(self, method):
  186. self._set('payment', 'method', method)
  187. def payment_method(self):
  188. return self._get('payment', 'method')
  189. # Submission methods
  190. # ==================
  191. def set_order_number(self, order_number):
  192. self._set('submission', 'order_number', order_number)
  193. def get_order_number(self):
  194. return self._get('submission', 'order_number')
  195. def set_submitted_basket(self, basket):
  196. self._set('submission', 'basket_id', basket.id)
  197. def get_submitted_basket_id(self):
  198. return self._get('submission', 'basket_id')