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_handle_us_taxes.rst 2.8KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778
  1. ======================
  2. How to handle US taxes
  3. ======================
  4. When trading in the US, taxes aren't known until the customer's shipping
  5. address has been entered. This scenario requires two changes from core Oscar.
  6. Ensure your site strategy returns prices without taxes applied
  7. --------------------------------------------------------------
  8. First, the site strategy should return all prices without tax when the customer
  9. is based in the US. Oscar provides a :class:`~oscar.apps.partner.strategy.US`
  10. strategy class that uses the :class:`~oscar.apps.partner.strategy.DeferredTax`
  11. mixin to indicate that prices don't include taxes.
  12. See :doc:`the documentation on strategies </topics/prices_and_availability>`
  13. for further guidance on how to replace strategies.
  14. Adjust checkout views to apply taxes once they are known
  15. --------------------------------------------------------
  16. Second, the :class:`~oscar.apps.checkout.session.CheckoutSessionMixin`
  17. should be overridden within your project to apply taxes
  18. to the submission.
  19. .. code-block:: python
  20. from oscar.apps.checkout import session
  21. from . import tax
  22. class CheckoutSessionMixin(session.CheckoutSessionMixin):
  23. def build_submission(self, **kwargs):
  24. submission = super().build_submission(
  25. **kwargs)
  26. if submission['shipping_address'] and submission['shipping_method']:
  27. tax.apply_to(submission)
  28. # Recalculate order total to ensure we have a tax-inclusive total
  29. submission['order_total'] = self.get_order_totals(
  30. submission['basket'],
  31. submission['shipping_charge'])
  32. return submission
  33. An example implementation of the ``tax.py`` module is:
  34. .. code-block:: python
  35. from decimal import Decimal as D
  36. def apply_to(submission):
  37. # Assume 7% sales tax on sales to New Jersey You could instead use an
  38. # external service like Avalara to look up the appropriates taxes.
  39. STATE_TAX_RATES = {
  40. 'NJ': D('0.07')
  41. }
  42. shipping_address = submission['shipping_address']
  43. rate = STATE_TAX_RATES.get(
  44. shipping_address.state, D('0.00'))
  45. for line in submission['basket'].all_lines():
  46. line_tax = calculate_tax(
  47. line.line_price_excl_tax_incl_discounts, rate)
  48. unit_tax = (line_tax / line.quantity).quantize(D('0.01'))
  49. line.purchase_info.price.tax = unit_tax
  50. # Note, we change the submission in place - we don't need to
  51. # return anything from this function
  52. shipping_charge = submission['shipping_charge']
  53. if shipping_charge is not None:
  54. shipping_charge.tax = calculate_tax(
  55. shipping_charge.excl_tax, rate)
  56. def calculate_tax(price, rate):
  57. tax = price * rate
  58. return tax.quantize(D('0.01'))