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 6.8KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150
  1. from django.contrib.sites.models import Site
  2. from oscar.core.loading import import_module
  3. import_module('order.models', ['ShippingAddress', 'Order', 'Line',
  4. 'LinePrice', 'LineAttribute', 'OrderDiscount'], locals())
  5. import_module('order.signals', ['order_placed'], locals())
  6. class OrderNumberGenerator(object):
  7. u"""
  8. Simple object for generating order numbers.
  9. We need this as the order number is often required for payment
  10. which takes place before the order model has been created.
  11. """
  12. def order_number(self, basket):
  13. u"""
  14. Return an order number for a given basket
  15. """
  16. return 100000 + basket.id
  17. class OrderCreator(object):
  18. u"""
  19. Places the order by writing out the various models
  20. """
  21. def place_order(self, user, basket, shipping_address, shipping_method,
  22. billing_address, total_incl_tax, total_excl_tax, order_number=None, status=None):
  23. u"""
  24. Placing an order involves creating all the relevant models based on the
  25. basket and session data.
  26. """
  27. if not order_number:
  28. generator = OrderNumberGenerator()
  29. order_number = generator.order_number(basket)
  30. order = self._create_order_model(user, basket, shipping_address,
  31. shipping_method, billing_address, total_incl_tax,
  32. total_excl_tax, order_number, status)
  33. for line in basket.all_lines():
  34. self._create_line_models(order, line)
  35. self._update_stock_records(line)
  36. for discount in basket.discounts:
  37. self._create_discount_model(order, discount)
  38. for voucher in basket.vouchers.all():
  39. self._record_voucher_usage(order, voucher, user)
  40. basket.set_as_submitted()
  41. # Send signal for analytics to pick up
  42. order_placed.send(sender=self, order=order, user=user)
  43. return order
  44. def _create_order_model(self, user, basket, shipping_address, shipping_method,
  45. billing_address, total_incl_tax, total_excl_tax, order_number, status):
  46. u"""Creates an order model."""
  47. order_data = {'basket': basket,
  48. 'number': order_number,
  49. 'site': Site._default_manager.get_current(),
  50. 'total_incl_tax': total_incl_tax,
  51. 'total_excl_tax': total_excl_tax,
  52. 'shipping_address': shipping_address,
  53. 'shipping_incl_tax': shipping_method.basket_charge_incl_tax(),
  54. 'shipping_excl_tax': shipping_method.basket_charge_excl_tax(),
  55. 'shipping_method': shipping_method.name}
  56. if billing_address:
  57. order_data['billing_address'] = billing_address
  58. if user.is_authenticated():
  59. order_data['user_id'] = user.id
  60. if status:
  61. order_data['status'] = status
  62. order = Order(**order_data)
  63. order.save()
  64. return order
  65. def _get_partner_for_product(self, product):
  66. u"""Returns the partner for a product"""
  67. if product.has_stockrecord:
  68. return product.stockrecord.partner
  69. raise AttributeError("No partner found for product '%s'" % product)
  70. def _create_line_models(self, order, basket_line):
  71. u"""Creates the batch line model."""
  72. partner = self._get_partner_for_product(basket_line.product)
  73. stockrecord = basket_line.product.stockrecord
  74. order_line = Line(order=order,
  75. # Partner details
  76. partner=partner,
  77. partner_name=partner.name,
  78. partner_sku=stockrecord.partner_sku,
  79. # Product details
  80. product=basket_line.product,
  81. title=basket_line.product.get_title(),
  82. quantity=basket_line.quantity,
  83. # Price details
  84. line_price_excl_tax=basket_line.line_price_excl_tax_and_discounts,
  85. line_price_incl_tax=basket_line.line_price_incl_tax_and_discounts,
  86. line_price_before_discounts_excl_tax=basket_line.line_price_excl_tax,
  87. line_price_before_discounts_incl_tax=basket_line.line_price_incl_tax,
  88. # Reporting details
  89. unit_cost_price = stockrecord.cost_price,
  90. unit_site_price = stockrecord.price_incl_tax,
  91. unit_retail_price = stockrecord.price_retail,
  92. # Shipping details
  93. est_dispatch_date = basket_line.product.stockrecord.dispatch_date
  94. )
  95. order_line.save()
  96. self._create_line_price_models(order, order_line, basket_line)
  97. self._create_line_attributes(order, order_line, basket_line)
  98. def _update_stock_records(self, line):
  99. line.product.stockrecord.allocate(line.quantity)
  100. def _create_line_price_models(self, order, order_line, basket_line):
  101. u"""Creates the batch line price models"""
  102. breakdown = basket_line.get_price_breakdown()
  103. for price_incl_tax, price_excl_tax, quantity in breakdown:
  104. LinePrice._default_manager.create(order=order,
  105. line=order_line,
  106. quantity=quantity,
  107. price_incl_tax=price_incl_tax,
  108. price_excl_tax=price_excl_tax)
  109. def _create_line_attributes(self, order, order_line, basket_line):
  110. u"""Creates the batch line attributes."""
  111. for attr in basket_line.attributes.all():
  112. LineAttribute._default_manager.create(line=order_line,
  113. option=attr.option,
  114. type=attr.option.code,
  115. value=attr.value)
  116. def _create_discount_model(self, order, discount):
  117. u"""
  118. Creates an order discount model for each discount attached to the basket.
  119. """
  120. order_discount = OrderDiscount(order=order, offer=discount['offer'], amount=discount['discount'])
  121. if discount['voucher']:
  122. order_discount.voucher = discount['voucher']
  123. order_discount.voucher_code = discount['voucher'].code
  124. order_discount.save()
  125. def _record_voucher_usage(self, order, voucher, user):
  126. u"""
  127. Updates the models that care about this voucher.
  128. """
  129. voucher.record_usage(order, user)
  130. voucher.num_orders += 1
  131. voucher.save()