how to override a class method in Django Oscar

73 Views Asked by At

Currently I can already overwrite the class, but I can't overwrite the method get() what am i missing?

I need to do this because if there is only 1 shipping method it does not load the 'Shipping-Method' page and it redirects to the payment page, but I want the customer to see the shipping value before going to the payment page.

apps.py

import oscar.apps.checkout.apps as apps
from oscar.core.loading import get_class
from django.urls import path

class CheckoutConfig(apps.CheckoutConfig):
    name = 'apps.checkout'
    
    def ready(self):
        self.shipping_method_view = get_class('checkout.views', 'ShippingMethodViewOverwritten')
        super().ready()

    def get_urls(self):
        urls = super(CheckoutConfig, self).get_urls()
        urls += [
            path('shipping-method/',
                self.shipping_method_view.as_view(), name='shipping-method'),
        ]
        return urls
views.py

from oscar.apps.checkout import views
from oscar.core.loading import get_class
ShippingAddressForm, ShippingMethodForm, GatewayForm \
    = get_classes('checkout.forms', ['ShippingAddressForm', 'ShippingMethodForm', 'GatewayForm'])
from django.contrib import messages
Repository = get_class('shipping.repository', 'Repository')

class ShippingMethodViewOverwritten(views.ShippingMethodView):
    template_name = 'oscar/checkout/shipping_methods.html'
    form_class = ShippingMethodForm
    pre_conditions = ['check_basket_is_not_empty',
                      'check_basket_is_valid',
                      'check_user_email_is_captured']
    success_url = reverse_lazy('checkout:payment-method')

    def get(self, request, *args, **kwargs):

        if not request.basket.is_shipping_required():
            self.checkout_session.use_shipping_method(
                NoShippingRequired().code)
            return self.get_success_response()

        if not self.checkout_session.is_shipping_address_set():
            messages.error(request, _("Please choose a shipping address"))
            return redirect('checkout:shipping-address')

        self._methods = self.get_available_shipping_methods()
        if len(self._methods) == 0:
            # No shipping methods available for given address
            messages.warning(request, _(
                "Shipping is unavailable for your chosen address - please "
                "choose another"))
            return redirect('checkout:shipping-address')
        elif len(self._methods) == 1:
            # Only one shipping method - set this and redirect onto the next
            # step
            self.checkout_session.use_shipping_method(self._methods[0].code)
            return self.get_success_response()

        return super().get(request, *args, **kwargs)

    def get_available_shipping_methods(self):
        return Repository().get_shipping_methods(basket=self.request.basket, 
        user=self.request.user,shipping_addr=self.get_shipping_address(self.request.basket), 
        request=self.request)

1

There are 1 best solutions below

0
Muhammad Arsalan On

There's an explicit logic in ShippingMethodView that handles this case of a single shipping method available and skips the 'Shipping Method' selection screen. In order to overwrite this behaviour, firstly you need to customize the Checkout app. Follow the guidelines here on how to fork an Oscar app.

Here's how it is implemented in Oscar

File: oscar/apps/checkout/views.py

def get(self, request, *args, **kwargs):
            .....
            self._methods = self.get_available_shipping_methods()
        if len(self._methods) == 0:
            # No shipping methods available for given address
            messages.warning(
                request,
                _(
                    "Shipping is unavailable for your chosen address - please "
                    "choose another"
                ),
            )
            return redirect("checkout:shipping-address")
        elif len(self._methods) == 1:
            # Only one shipping method - set this and redirect onto the next
            # step
            self.checkout_session.use_shipping_method(self._methods[0].code)
            return self.get_success_response()
            .....

Simply remove elif block to bypass workflow where shipping method is being set if only found.