django-oscar / django-oscar-api

RESTful JSON API for django-oscar

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Oscar-api Order Placement issue

theArsalanM opened this issue · comments

From Django-oscar's code, an Order is placed by calling handle_order_placement(...) from apps/checkout.

    def handle_order_placement(self, order_number, user, basket,
                               shipping_address, shipping_method,
                               shipping_charge, billing_address, order_total,
                               **kwargs):
        order = self.place_order(
            order_number=order_number, user=user, basket=basket,
            shipping_address=shipping_address, shipping_method=shipping_method,
            shipping_charge=shipping_charge, order_total=order_total,
            billing_address=billing_address, **kwargs)
        basket.submit()
        return self.handle_successful_order(order)

This works perfectly fine for oscar, but in django-oscar-api's implementation of Order placement, I wonder why place_order(...) is called directly instead of sticking to oscar's default approach? Maybe we need to create oscar-api's own OrderPlacementMixin to rewrite Restful structure for handle_successful_order().

Oscar API places order by calling place_order() directly from serializers/checkout.
The problem? It ends up with 2 issues:

  • Order Confirmation email is not being sent when Order placed via API
  • Basket status remains Frozen even after order placement. It should have been changed to Submitted

I wanted to understand is it intentionally left behind for developers to implement on their own, or can we add it to core code?

One of the reasons that we can't use Oscar's handler_order_placement is that the handle_successful_order method is not really generic:

        # Flush all session data
        self.checkout_session.flush()

        # Save order id in session so thank-you page can load it
        self.request.session['checkout_order_id'] = order.id

        response = HttpResponseRedirect(self.get_success_url())

In the API we don't use a session, nor is the HttpResponseRedirect a desired response.

Next to that, the flow of OscarAPI is a bit different. There is a possibility that payment fails for example, or that a user cancels one of the payment methods. Then you would want to resubmit your basket again with another payment method. That's why we don't set the status to submitted at this point and do not send a confirmation email yet.

This is also explained in a note in the documentation: https://django-oscar-api.readthedocs.io/en/latest/topics/communicate_with_the_api.html#place-an-order-checkout

It's up to the developer what to do from here. It can be as easy a registering a receiver for the oscarapi_post_checkout signal and you call the methods you would like to call:

@receiver(oscarapi_post_checkout)
def post_checkout(sender, **kwargs):
    # send email, do some checks, submit basket etc.

See also the oscar-api-checkout plugin which continues where oscarpi stops, including a nice wrapper for sending the confirmation email.