Payment Options in Checkout workflow

2,018 views
Skip to first unread message

Srinivasan Venkataraman

unread,
Aug 12, 2013, 12:42:41 AM8/12/13
to django...@googlegroups.com
First I would like to thank the oscar team for coming up with fine piece software.

Second, please humour my programming/tech naivete.

I am looking at the sandbox checkout flow and I would like to incorporate my own business logic in the checkout flow. The sandbox checkout flow is:
1. Shipping address -> 2. Shipping Method -> 3. Payment -> 4. Confirmation

I would like to modify the payment page (#3). In this page, I would like to display payment options as radio select. Like so:

Select your preferred payment method:

- COD (Cash on Delivery)
- Bank Transfer
- Credit/Debit Card

Once an option is selected, I would like to proceed to the confirmation page. In the confirmation page, after the buyer presses the "Place Order" button, I would like to proceed as follows:

a) If COD or Bank was selected, I want an entry to be made in the database so that the site owner can view this in the dashboard. The buyer will be shown a thank you page with order summary.
b) If CC/DC was selected, then the buyer would have to be redirected to a payment gateway (PG). Again an entry needs to be made in the database and this should be available in the dashboard. Once the buyer is done with the PG, the buyer is shown a thank you page with order summary.

I looked at Tomas' implementation of django-oscar-payments and tried to implement something based on that but I was unable to get it working. I looked at the documentation for checkout at the URL below:


Step 4 in the above URL mentions Payment Method. But I am unable to find any additional information regarding how to wire up the payment methods.

What am I missing? Maybe this is something simple that is eluding me. Please help.

Thanks.
Srini

David Winterbottom

unread,
Aug 12, 2013, 4:47:24 AM8/12/13
to django-oscar
Hi Srini,

I've written a checkout just like that one previously (for www.landmarkonthenet.com).

You should create a form to show on your payment details page (where the customer selects their chosen option) and find a way to persist the form values so they are available when the customer submits on the preview page.  
  • One way to do this is to simply re-render the form in a hidden div on the preview page.
  • You could alternatively store the option in the session.
Now I recommend that you place the order no matter what payment method is chosen - you should use order statuses to indicate that the order is awaiting payment.  

Rather than trying to shoe-horn your checkout flow into Oscar's PaymentDetails view (which is tricky as you're placing orders before payment).  I would recommend you write your own methods, something like this:

def post(self, request, *args, **kwargs):
    if self.preview:
        if request.POST.get('action', '') == 'place_order':
            # Get results of payment option
            option = ...
            if option == options.COD:
                return self.submit_cod_order(request.basket)
            elif option == options.BANK:
                return self.submit_bank_order(request.basket)
            else:
                return self.submit_bankcard_order(request.basket)
        return self.render_preview(request)

You have all the methods you need available to you (for placing the order, saving payment sources etc).  It's a bit more work but it will be more explicit and easier to maintain.

Hope that makes sense.




--
https://github.com/tangentlabs/django-oscar
http://django-oscar.readthedocs.org/en/latest/
https://twitter.com/django_oscar
---
You received this message because you are subscribed to the Google Groups "django-oscar" group.
To unsubscribe from this group and stop receiving emails from it, send an email to django-oscar...@googlegroups.com.
Visit this group at http://groups.google.com/group/django-oscar.
To view this discussion on the web visit https://groups.google.com/d/msgid/django-oscar/2e5b8e85-3915-4276-b9ad-0aea66d0632a%40googlegroups.com?hl=en-US.
For more options, visit https://groups.google.com/groups/opt_out.



--
David Winterbottom
Head of Programming

Tangent Labs
84-86 Great Portland Street
London W1W 7NR
England, UK

Srinivasan Venkataraman

unread,
Aug 23, 2013, 10:41:31 AM8/23/13
to django...@googlegroups.com
Hi David.

Thanks for the pointers. I was able to implement the required workflow using form hidden in a div method.

Srini 

Dairon Medina Caro

unread,
Feb 14, 2014, 4:30:09 PM2/14/14
to django...@googlegroups.com
Hi how do you persist the form on preview??

David Winterbottom

unread,
Feb 16, 2014, 5:03:23 PM2/16/14
to django-oscar
As noted, you can simply re-render the form but in a hidden div (but within the main <form> tags).  This ensures the form data from the previous page is re-submitted on the next page.


--
https://github.com/tangentlabs/django-oscar
http://django-oscar.readthedocs.org/en/latest/
https://twitter.com/django_oscar
---
You received this message because you are subscribed to the Google Groups "django-oscar" group.
To unsubscribe from this group and stop receiving emails from it, send an email to django-oscar...@googlegroups.com.
Visit this group at http://groups.google.com/group/django-oscar.

For more options, visit https://groups.google.com/groups/opt_out.



--
David Winterbottom
Technical Director
Message has been deleted

Claudio Pomo

unread,
May 18, 2015, 4:45:19 AM5/18/15
to django...@googlegroups.com, david.win...@tangentlabs.co.uk
Hi David,
I would follow this approach: I would modify PaymentMethodView into checkout/views.py to handle different payment method for single user and into next view, payment-details, insert a summary about payment selected: COD +10€ paypal discount 4%
Is this way correct?

YusufSalahAdDin

unread,
Aug 17, 2016, 4:12:46 AM8/17/16
to django-oscar
Hi man,

I want to know how did you solve this case?

I have three paymen methods: Cash on Delivery, PayPal and PayU but i haven't idea how implement it in check out.

Can anyone explain me please?

Sergio Brero

unread,
Sep 13, 2016, 9:50:17 AM9/13/16
to django-oscar
Hello everybody,
I'm new to oscar and probably i'm trying to handle payments the wrong way, but i'm trying to implement 3 payment methods: PayPal, Wire Tranfer and Pay on delivery.
I followed suggestions below, i added a form in payment_details.html and modified the post method in the PaymentDetailsView as follow:

class PaymentDetailsView(PaymentDetailsViewCore):


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

        # Posting to payment-details isn't the right thing to do.  Form

        # submissions should use the preview URL.

        if not self.preview:

            return http.HttpResponseBadRequest()


        # We use a custom parameter to indicate if this is an attempt to place

        # an order (normally from the preview page).  Without this, we assume a

        # payment form is being submitted from the payment details view. In

        # this case, the form needs validating and the order preview shown.

        if request.POST.get('action', '') == 'place_order':

            if request.POST.get('wire-transfer', '') == 'on':

                return self.handle_place_wire_submission(request)

            elif request.POST.get('contrassegno', '') == 'on':

                return self.handle_place_contrassegno_submission(request)

        return self.handle_payment_details_submission(request)


And my handle_submission methods are:


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

        kwargs['payment_kwargs'] = {'source': 'wire'}

        return self.submit(**self.build_submission(**kwargs))


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

        kwargs['payment_kwargs'] = {'source': 'contrassegno'}

        return self.submit(**self.build_submission(**kwargs))


    def build_submission(self, **kwargs):

        submission = super(PaymentDetailsViewCore, self).build_submission(**kwargs)

        return submission


Then i found that PaymentDetailsView.submit calls oscar.apps.checkout.mixins.OrderPlacementMixin.handle_payment that 

"... is designed to be overridden within your project. The

default is to do nothing as payment is domain-specific.


This method is responsible for handling payment and recording the

payment sources (using the add_payment_source method) and payment

events (using add_payment_event) so they can be

linked to the order when it is saved later on."


So i'm trying to override this method as follow:


    # Any payment sources should be added to this list as part of the

    # handle_payment method.  If the order is placed successfully, then

    # they will be persisted. We need to have the order instance before the

    # payment sources can be saved.

    _payment_sources = None


    # Any payment events should be added to this list as part of the

    # handle_payment method.

    _payment_events = None


    # Payment handling methods

    # ------------------------


    def handle_payment(self, order_number, total, **kwargs):

        """

        Handle any payment processing and record payment sources and events.


        This method is designed to be overridden within your project.  The

        default is to do nothing as payment is domain-specific.


        This method is responsible for handling payment and recording the

        payment sources (using the add_payment_source method) and payment

        events (using add_payment_event) so they can be

        linked to the order when it is saved later on.

        """

        sourceType = None

        source = None


        if kwargs['source'] == 'wire':

            sourceType = SourceType.objects.get(code='bonifico-bancario')


        if kwargs['source'] == 'contrassegno':

            sourceType = SourceType.objects.get(code='spedizione-in-contrassegno')


        if sourceType:

            basket = self.request.basket

            source = Source.objects.create(

                order_id=self.generate_order_number(basket),

                source_type_id=sourceType,

                amount_allocated=D('20.0'),

                amount_debited=D('20'),

            )


        if source:

            self.add_payment_source(source)

            self.add_payment_event(

                sourceType.code,

                D('20'),

                'Some Text'

            )


But i'm getting this error: TransactionManagementError: An error occurred in the current transaction. You can't execute queries until the end of the 'atomic' block.

Probably i'm trying to save something in the wrong time, or getting wrong order number, or i don't know.


Am i doing payments handling in the wrong way?

Has please, anybody any suggestion?


Thanks in advance


Sergio Brero






   

Sergio Brero

unread,
Sep 13, 2016, 10:31:54 AM9/13/16
to django-oscar
I was doing some typo..

Using:

class OrderPlacementMixin(OrderPlacementMixinCore):
            source = Source.objects.create(
                order_id=order_number,
                source_type=sourceType,
                amount_allocated=total.incl_tax,
                amount_debited=total.incl_tax,
            )

        if source:
            self.add_payment_source(source)
            self.add_payment_event(
                sourceType.name,
                total.incl_tax,
                'Some Text'
            )

It works. Now i'm wondering how to manage payments status - something like 'Waiting Wire Tranfer'...
Reply all
Reply to author
Forward
0 new messages