=======================
Oscar 2.1 release notes
=======================

:release: 2020-07-10

Welcome to Oscar 2.1! This is a significant release which includes a number of
new features and performance improvements.

.. contents::
    :local:
    :depth: 1

.. _compatibility_of_2.1:

Compatibility
~~~~~~~~~~~~~

Oscar 2.1 is compatible with Django versions 2.2 and 3.0, and Python versions 3.5, 3.6, 3.7 and 3.8.

Support for Django versions 1.11 and 2.0 has been dropped.

.. _new_in_2.1:

What's new in Oscar 2.1?
~~~~~~~~~~~~~~~~~~~~~~~~~~

- The ability to add arbitrary surcharges to orders (e.g., a processing fee for
  a particular payment method) was introduced.
  See :ref:`how_to_surcharges` for details on how to configure this.
  This change requires a database migration.

- The database performance of ``offer.Range.all_products()`` was substantially
  improved. The internals of that method have changed and specifically
  ``Range.invalidate_cached_ids()`` has been removed and replaced with
  ``Range.invalidate_cached_queryset()``.

- The ``upload_to`` argument of image fields in Oscar's ``ProductImage`` and
  ``ProductAttributeValue`` models was changed to use a callable, so that
  Django doesn't generate migrations if a project modifies the ``OSCAR_IMAGE_FOLDER``
  to specify a custom directory structure for uploaded images.
  This change requires a database migration.

- ``catalogue.Category`` now has an ``is_public`` boolean field that serves a
  similar purpose to ``catalogue.Product.is_public`` - i.e., to hide categories
  public views. The ``Category`` model also now has a custom manager
  that provides a ``browsable()`` queryset method that excludes non-public
  categories. This change requires a database migration.

  Category hierarchy implies that the children of any non-public category are
  also non-public. This is enforced through an ``ancestors_are_public`` field
  on the ``Category`` model.

- A ``date_updated`` field was added to the ``basket.Line`` model, which is updated
  every time a line is saved. This change requires a database migration.

Communications app
------------------

A new ``communication`` app was introduced to provide a single point of entry
for all communications sent by Oscar. This is a significant change with implications
as follows:

- Projects will need to add
  ``oscar.apps.communication.apps.CommunicationConfig`` to ``INSTALLED_APPS``.

  The ``CommunicationEventType``, ``Email`` and ``Notification`` models have
  moved from the ``customer`` app to the ``communication`` app. In order to
  preserve existing data, the table names for these models are unchanged.

  This change requires a database migration.

- The ``Dispatcher`` class moved from ``customer.utils`` to
  ``communication.utils``. ``Dispatcher`` is now responsible for sending
  all notifications, and not just emails.

- A ``CustomerDispatcher`` utility class that wraps the core ``Dispatcher``
  has been introduced to the ``customer`` app for sending communications to
  customers.

- An ``AlertsDispatcher`` utility class that wraps the core ``Dispatcher``
  has been introduced to the ``customer.alerts`` module for sending product
  alerts.

- An ``OrderDispatcher``  utility class that wraps the core ``Dispatcher``
  has been introduced to the ``order`` app for sending order related
  communications.

- A new setting, ``OSCAR_SAVE_SENT_EMAILS_TO_DB`` controls whether emails
  sent through the ``Dispatcher`` are saved to the database. This defaults
  to ``True``.

- The ability to send multipart emails with attachments was added to the new
  dispatcher.

- All communication email templates (``commtype_*``) have moved from
  moved from ``customer/emails`` to ``communication/emails``.

- Templates in ``customer/email/`` and ``customer/notification/`` have moved
  to ``communication/email/`` and ``communication/notification/``.

- An ``absolute_url`` template tag was introduced to facilitate generating
  absolute URLs in templates for a given domain and path. The schema for
  generated URLs is configured via the ``OSCAR_URL_SCHEMA`` setting, which defaults
  to ``http``.

Backwards incompatible changes in Oscar 2.1
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

- The ``category`` field has been removed from the
  ``communication.Notification`` model. This change requires database migration.

- The ``checkout.mixins.OrderPlacementMixin.send_confirmation_message``
  method has been replaced with a new ``send_order_placed_email`` method.

- ``customer.notifications.context_processors.notifications`` has moved to
  ``communication.notifications.context_processors.notifications``.

Bug fixes
~~~~~~~~~

- Fixed a bug in the handling of requests to save an item in the basket for
  later(:issue:`3215`).

- Fixed an error when deleting an offer whose related conditions/benefits have
  been deleted.

- Fixed handling of count conditions in ``MultibuyDiscountBenefit``.
  Previously, when a count condition was used with this benefit it would result
  in a discount being applied for all items in the basket rather than the
  cheapest one.

- Fixed a bug where a line could not be deleted from the basket, if the basket
  had another line with a validation error - i.e. its product was out of stock
  (see :issue:`2791` and :issue:`1654`).

- Fixed a bug where non-public child products were not excluded from parent product
  forms and detail views.

Removal of deprecated features
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

- Support for verifying order hashes using an insecure MD5 algorithm generated
  by Oscar 1.5 and below has been dropped. The ``OSCAR_DEPRECATED_ORDER_VERIFY_KEY``
  setting is no longer used. Order verification hashes generated by Oscar 1.5
  and lower will no longer validate.

- ``offer.Range.contains()`` has been removed. Use ``contains_product()`` instead.

- ``catalogue.managers.ProductManager`` has been removed.  Use
  ``catalogue.managers.ProductQuerySet.as_manager()`` instead.

- ``catalogue.managers.BrowsableProductManager`` has been removed.  Use
  ``Product.objects.browsable()`` instead.

- ``catalogue.Product.browsable`` has been removed. Use
  ``Product.objects.browsable()`` instead.

- Invalid URLs supplied to ``OSCAR_DASHBOARD_NAVIGATION`` are no longer ignored.
  URLs that cannot be resolved will now result in a ``NoReverseMatch`` exception.
  URLs that are not provided by a subclass of ``oscar.core.application.OscarDashboardConfig``
  will result in a ``KeyError``.

- ``customer.forms.PasswordResetForm.get_reset_url`` has been removed.

- The internal and undocumented class ``oscar.core.compat.UnicodeCSVReader``
  has been removed. Use ``csv.reader`` instead.

Minor changes
~~~~~~~~~~~~~

- ``OrderPlacementMixin.place_order`` now ignores inactive vouchers when placing
  an order (instead of raising an exception), for consistency with how
  the basket flows handle inactive vouchers.

- Fixed the logic of ``StockRequired.parent_availability_policy`` to use
  child products to determine availability of children, rather than the parent.

- ``customer.forms.PasswordResetForm`` now uses the parent class' ``get_users()``
  method to determine the list of users to send an email to. ``get_users()``
  filters out users who do not currently have a usable password - which
  did not happen previously.

  This change was made in response to changes in Django to address
  CVE-2019-19844. Oscar's ``PasswordResetForm`` was not vulnerable to the issue
  in Django's form, but it was possible to send a password reset email to
  unintended recipients because of unicode character collision.

- ``catalogue.Product.is_public`` is now an indexed field. This change requires
  a database migration.

- When a voucher that was created through the Oscar dashboard is deleted, the
  auto-generated offer that was created with the voucher is also deleted.

- Fixed the ``brand_title`` block in ``partials/brand.html`` so that it doesn't span unclosed HTML tags.

- ``customer.views.ProfileUpdateView.form_valid`` was modified
  to use a new ``send_email_changed_email`` method.

- ``customer.views.ChangePasswordView.form_valid`` was modified
  to use a new ``send_password_changed_email`` method.

- A ``public`` method was added to the ``ProductQuerySet``, which filters on products with ``is_public=True``.

Dependency changes
~~~~~~~~~~~~~~~~~~

Python package dependencies:

- Upgraded ``pillow`` to version 6.0.0 or higher.
- Upgraded ``django-extra-views`` to version 0.13.
- Upgraded ``django-haystack`` to version 3.0 or higher.
- Upgraded ``django-phonenumber-field`` to version 3.0.
- Upgraded ``django-tables2`` to version 2.2.
- Upgraded ``sorl-thumbnail`` (optional requirement) to version 12.6.
- Upgraded ``easy-thumbnails`` (optional requirement) to version 2.7.


Javascript dependencies:

- Upgraded ``jquery`` to version 3.5.
- Upgraded ``inputmask`` to version 5.0.
- Upgraded ``select2`` to version 4.0.
- Upgraded ``tinymce`` to version 5.3.

.. _deprecated_features_in_2.1:

Deprecated features
~~~~~~~~~~~~~~~~~~~

- ``customer.alerts.utils.send_alerts`` is deprecated.
  Use ``AlertsDispatcher.send_alerts`` instead.

- ``customer.alerts.utils.send_alert_confirmation`` is deprecated.
  Use ``AlertsDispatcher.send_product_alert_confirmation_email_for_user``
  instead.

- ``customer.alerts.utils.send_product_alerts`` is deprecated.
  Use ``AlertsDispatcher.send_product_alert_email_for_user`` instead.

- ``customer.notifications.services.notify_user`` is deprecated.
  Use Dispatcher.notify_user``.

- ``customer.notifications.services.notify_users`` is deprecated.
  Use ``Dispatcher.notify_users`` instead.
