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.

how_to_configure_shipping.rst 5.9KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153
  1. =========================
  2. How to configure shipping
  3. =========================
  4. Configuring shipping is not trivial. It generally requires creating a
  5. 'shipping' app within your project where you can define your own shipping
  6. methods as well as a 'repository' class which determines when methods are
  7. available.
  8. This recipe explains in more detail how Oscar models shipping as well as the
  9. steps involved in configuring shipping for your project.
  10. How Oscar handles shipping charges
  11. ----------------------------------
  12. Oscar uses a "repository" class to manage shipping charges. The class is used
  13. in two ways:
  14. * **It provides a list of shipping methods available to the user.** This is used to
  15. generate the content for the shipping methods page of checkout, where the user
  16. can choose a shipping method. The methods available generally depend on the
  17. user, the basket and the shipping address.
  18. * **It allows a shipping method to be retrieved based on a identifying code.** When
  19. a user selects a shipping method during checkout, it is persisted in the
  20. session using a code. This code is used to retrieve the chosen shipping
  21. method when it is required.
  22. The default shipping repository `can be seen here`_. It defaults to only
  23. providing one shipping method, which has no charge.
  24. .. note::
  25. Oscar's checkout process includes a page for choosing your shipping method.
  26. If there is only one method available for your basket then it will be chosen
  27. automatically and the user immediately redirected to the next step.
  28. Custom shipping charges
  29. -----------------------
  30. In order to control shipping logic for your project, you need to define your own
  31. repository class (see :doc:`/topics/customisation`). It normally makes
  32. sense to subclass the core ``Repository`` class and override the
  33. ``get_shipping_methods`` and ``find_by_code`` methods.
  34. Here's a very simple example where all shipping costs are a fixed price,
  35. irrespective of basket and shipping address::
  36. # myproject/shipping/repository.py
  37. from decimal import Decimal as D
  38. from oscar.apps.shipping import repository, methods as core_methods
  39. class Repository(repository.Repository):
  40. methods = [core_methods.FixedPrice(D('9.99'))]
  41. def get_shipping_methods(self, user, basket, shipping_addr=None, **kwargs):
  42. return self.prime_methods(basket, self.methods)
  43. def find_by_code(self, code, basket):
  44. for method in self.methods:
  45. if code == method.code:
  46. return self.prime_method(basket, method)
  47. Note that both these methods must return 'primed' method instances, which means
  48. the basket instance has been injected into the method. This allows the method
  49. instance to return the shipping charge directly without requiring the basket to
  50. be passed again (which is useful in templates).
  51. As you can see the ``get_shipping_methods`` can depend on several things:
  52. * the user in question (e.g., staff get cheaper shipping rates)
  53. * the basket (e.g., shipping is charged based on the weight of the basket)
  54. * the shipping address (e.g., overseas shipping is more expensive)
  55. Here's a more involved example repository that has two fixed price charges::
  56. # myproject/shipping/repository.py
  57. from decimal import Decimal as D
  58. from oscar.apps.shipping import repository, methods as core_methods
  59. # We create subclasses so we can give them different codes and names
  60. class Standard(core_methods.FixedPrice):
  61. code = 'standard'
  62. name = _("Standard shipping")
  63. class Express(core_methods.FixedPrice):
  64. code = 'express'
  65. name = _("Express shipping")
  66. class Repository(repository.Repository):
  67. methods = [Standard(D('10.00')), Express(D('20.00'))]
  68. def get_shipping_methods(self, user, basket, shipping_addr=None, **kwargs):
  69. return self.prime_methods(basket, self.methods)
  70. def find_by_code(self, code, basket):
  71. for method in self.methods:
  72. if code == method.code:
  73. return self.prime_method(basket, method)
  74. .. _`can be seen here`: https://github.com/tangentlabs/django-oscar/blob/master/oscar/apps/shipping/repository.py
  75. Shipping methods
  76. ----------------
  77. The repository class is responsible for return shipping method instances. Oscar
  78. defines several of these but it is easy to write your own, their interface is
  79. simple.
  80. The base shipping method class ``oscar.apps.shipping.methods.Base`` (that
  81. all shipping methods should subclass has API:
  82. .. autoclass:: oscar.apps.shipping.methods.Base
  83. :members:
  84. :noindex:
  85. Core shipping methods
  86. ~~~~~~~~~~~~~~~~~~~~~
  87. The shipping methods that ship with Oscar are:
  88. * ``oscar.apps.shipping.methods.Free``. No shipping charges.
  89. * ``oscar.apps.shipping.methods.FixedPrice``. This simply charges a fixed price for
  90. shipping, irrespective of the basket contents.
  91. * ``oscar.apps.shipping.methods.OfferDiscount``. This applies a discount
  92. to an existing shipping method's charges.
  93. * ``oscar.apps.shipping.methods.TaxExclusiveOfferDiscount``. Children of ``OfferDiscount``
  94. * ``oscar.apps.shipping.methods.TaxInclusiveOfferDiscount``. Children of ``OfferDiscount``
  95. To apply your domain logic for shipping, you will need to override
  96. the default repository class (see :doc:`/topics/customisation`) and alter
  97. the implementation of the ``get_shipping_methods`` method. This method
  98. should return a list of "shipping method" classes already instantiated
  99. and holding a reference to the basket instance.
  100. Building a custom shipping method
  101. ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  102. At a minimum, a custom shipping method class should define a ``code`` and
  103. ``name`` attribute to distinguish it from other methods. It is also normal to
  104. override the ``basket_charge_incl_tax`` and ``basket_charge_excl_tax`` methods
  105. to implement your custom shipping charge logic.
  106. .. tip::
  107. Most of the shipping logic should live in the repository class, the method
  108. instance is only responsible for returning the charge for a given basket.