rubyonrailsin

A Ruby and Rails talk

Monday, March 15, 2010


[spree-user] Re: Third party Payment Gateway on edge

by rubyonrailsin 0 comments

Tag


Share this post:
Design Float
StumbleUpon
Reddit

Hi,

I am half way through the implementation. There are many rough edges
that I am still working out.

Before I outline the solution here are the problems with hosted
gateways
(Hopefully it will help when someone else wants to take a shot at it)

It relies on heavily browser redirects - this may not seem to be a
problem at first, but it is a PITA.
Once the amount + other details are passed on to the Payment Gateway
via a form post, the possible outcomes are as follows:
a) Happy flow - the customer selects the payment instrument and makes
the payment, Once done he is redirected back to the registered
callback URL.
Process the payment as success and life goes on. no problems.
b) Unsuccessful flow - Customer makes a bad payment, eg. expired card
and such, he is redirected back with failure as the status - Do not
record the payment on the order - keep the checkout alive, report the
error and ask the customer to retry
c) Broken flow - (a) or (b) happens and the last redirect does not
happen because of a system failure - say network issue/etc. Now, we do
not know if the payment was successful or not. This is a stuck order
and needs to be cleared on a regular basis.
The problem gets worse if the payment succeeds and the customer makes
another payment (as the cart/checkout is still alive) thinking it
failed. Now we have 2 payments for the same order.
One more ugly case is: the customer changes the cart. Here we lose
track of what he actually ordered even if we manage to salvage the
payment.

Here is a brief of the approach that has worked for me - it handles
only cases (a) and (b). I am still working out a solution for (c)
It may not be the most suitable implementation per spree's way of
thought but it works for me -

Assumptions:
There will be only one hosted payment gateway - atleast thats my
requirement so I didn't make it generic. Once I get to a stable
working version, I may refactor it.

Steps:
a) Create a new extension for the payment gateway with 2 models.
RequestLog and ResponseLog.
Request log will record all attempts to the payment gateway(with order
details) and ResponseLog will log all responses good or bad from the
gateway.
This can also be useful for debugging.
To handle the broken flow outlined above, we need to be able to
recreate the order from the request log if the need arises.
c) create a controller with a return method (with its route) and
create a method that you can configure as your return url
d) Create a model for your pamentgateway that extends Gateway.
Override
def method_type
"hosted_gateway"
end
This will give you access to a new partial which will be called from
_payment.html.erb

Under app/views/checkouts/payment, create a _hosted_gateway.html.erb
that will be called for your hosted gateway

Note: I conditionally removed everything from _payment.html if
@payment_methods.length == 1 and @payment_methods.method_type
=="hosted_gateway" and included only partial in that case (this is
because of my assumption) - you can also add another step in the
checkout instead of riding over payments, but I ran into issues with
that and hence this approach

My _hosted_gateway.html.erb looks like this:

<form action="<%=payment_method.request_url %>" method="post">

<% payment_method.request_form_fields(@order).each do |tag| %>
<%= tag %>
<% end %>

<%= submit_tag %>
</form>

request_url and request_form_fields are implemented by the payment
gateway. to help build the form that will post to the gateway.
The gateway in my case was configured (via the request params) to
callback the url configured in (c)

my return method looks like this:

def process_return
ccavenue = PaymentMethod.find_by_type('Gateway::CCAvenue')
order, is_payment_success = ccavenue.process_response(params)

if is_payment_success
checkout = order.checkout
checkout.payments.clear
payment = order.checkout.payments.create
payment.amount = params[:Amount]
payment.payment_method = ccavenue
checkout.save
checkout.next!

if checkout.completed_at
session[:order_id] = nil
flash[:commerce_tracking] =
I18n.t("notice_messages.track_me_in_GA")
end

redirect_to order_url(order, {:checkout_complete => true})
else
#todo: failure needs to be handled properly
redirect_to order_checkout_path(order)
end


This has been long! hopefully it helps you. If anyone else has a
better shot at this problem I would be glad to test/extend it :)

-Ajay

On Mar 15, 12:06 am, Cameron <czcar...@gmail.com> wrote:
> Hi Ajay,
>
> If you manage to accomplish this would appreciate a write-up of some
> description - after talking to a couple of providers in NZ, they all
> strongly "suggest" I use a redirect to a hosted page, curious as to
> how you work it out,
>
> Regards,
>
> Cameron
>
> On Mar 10, 11:34 am, BryanMTL <bryan...@gmail.com> wrote:
>
> > Hi Ajay,
>
> > I recently completed something for this. I'm just reviewing it with
> > the client and I believe he has plans on open-sourcing it.
>
> > On Mar 9, 3:01 pm, Ajay CB <ajay...@gmail.com> wrote:
>
> > > I am looking at implementing a new Payment Gateway on spree edge.
>
> > > Requirement is to do a client side redirect to the payment gateway
> > > (where the payment is made) and on successful completion - i.e
> > > redirect to the success url, the order gets confirmed (checkout
> > > complete) on failure, make the customer retry the payment (basically
> > > another url endpoint for failure).
>
> > > On the admin side, pretty much everything is manual - it sucks but I
> > > am stuck with this gateway. The workflow to settle a payment is
> > > closest to cheques. i.e just finalizing the payment will suffice.
>
> > > Is there any existing payment gateway that works on this model, that I
> > > can look at for an example?
> > > If not what is the best way of going about this on the edge, given the
> > > payment gateway refactoring.
>
> > > Any suggestions/pointers will be of great help.
>
> > > Thanks!
> > > -Ajay

--
You received this message because you are subscribed to the Google Groups "Spree" group.
To post to this group, send email to spree-user@googlegroups.com.
To unsubscribe from this group, send email to spree-user+unsubscribe@googlegroups.com.
For more options, visit this group at http://groups.google.com/group/spree-user?hl=en.

No comments:

Post a Comment

Subscribe feeds via e-mail

Blog Archive