Skip to content

pyrat/solon

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

11 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Solon – Sagepay VSP Server

Introduction

Solon is another library for interacting with the sagepay VSP server. It is largely the codebase from the seemingly defunct Peeves library with some modifications.

This library is not the cleanest out there and you may want to look at the other sagepay offerings before using this library.

Installation (Rails 3)

Add the following to your Gemfile

gem 'solon'
  bundle

In each of your environments you can define the sagepay mode of operation accordingly.

In config/environments/(development|test|production|[staging]).rb

	Solon::Config.vendor 		= [vendor_name]
	Solon::Config.gateway_mode = :simulator | :test | :live

Integration Guide

Best plan is to generate yourself an controller for dealing with the integration.

rails g controller sages

in routes.rb

resources :sages

Assumes an order has an identifier in order.identifier

require 'digest/sha1'

before_create :set_identifier

def set_identifier
  self.identifier = Digest::SHA1.hexdigest(rand(1000).to_s + Time.now.to_s.split(//).sort_by {rand}.join)
end

It is a good plan to create an order_transaction model to store order transactions locally for debugging.

The first step is registering the payment.

def create
  @order.update_attribute(:transaction_reference, Solon::UniqueId.generate(@order.id.to_s))

  p = SolonGateway.new
  @response = p.payment Solon::Money.new(@order.amount.to_f, "GBP"),
  {
    :transaction_reference => @order.transaction_reference,
    :description => "Description of payment",
    :notification_url => callback_sage_url(@order.identifier),
    :customer_data => @order.sage_customer_data
  }
  if @response.next_url
    @order.transactions.create(:params => @response, :success => true, :message => "Purchase Transaction", 
    :amount => @order.amount.to_f, :reference => @order.transaction_reference)
    @order.update_attributes(:security_key => @response.security_key, :user_location => 'away')
    @order.send_pending_email
    redirect_to @response.next_url
  else
    @order.transactions.create(:params => @response, :success => false, :message => "Purchase Transaction")
    flash[:warning] = "Unable to make payment, please contact support."
    redirect_to root_url
  end
end

The next step is handling to callbacks from sage page.

def callback
  # Parse the callback
  callback = SolonGateway.parse_callback(request.raw_post)
  
  
  # Get the order from identifier
  begin
    @order = Order.find_by_identifier!(params[:id])
    @order.sage_callback = callback
  rescue ActiveRecord::RecordNotFound =>  msg
    # Error if cannot find.
    render :text => SolonGateway.response('INVALID', no_order_sage_url, 'Transaction complete'), :layout => false
    return
  end
  
  
  # If the order has already been paid, render an OK response.
  if @order.paid?
    render_response(@order)
    return
  end

  if @order.valid_callback?
    # all is well
  else
    # error
  end

  render_response(@order)
end

Various responses tell the app different things about the order and you need to render a response in the right manner.

  private
  def render_response(order)
    if order.valid_callback?
      render :text => SolonGateway.response('OK', sage_url(order), 'Transaction complete'), :layout => false
    elsif order.invalid_callback?
      render :text => SolonGateway.response('INVALID', invalid_order_sage_url(order), 'Transaction complete'), :layout => false
    elsif order.sage_callback.st(:NOTAUTHED)
      render :text => SolonGateway.response('OK', notauthed_sage_url(order), 'Transaction complete'), :layout => false
    elsif order.sage_callback.st(:ABORT)
      render :text => SolonGateway.response('OK', abort_sage_url(order), 'Transaction complete'), :layout => false
    elsif order.sage_callback.st(:REJECTED)
      render :text => SolonGateway.response('OK', rejected_sage_url(order), 'Transaction complete'), :layout => false
    elsif order.sage_callback.error?
      render :text => SolonGateway.response('INVALID', invalid_sage_url(order), 'Transaction complete'), :layout => false
    else
      render :text => SolonGateway.response('ERROR', error_sage_url(order), 'Transaction complete'), :layout => false
    end
  end

Valid and invalid callbacks not only check that the callback is approved (callback.approved?) but also check that the value of the order locally has not changed since the transaction began. This is a danger with offsite payment gateways.

The checking of whether a callback is valid is left to the app developer.

Testing

1. Set vendor name in spec helper.
2. run bundle
3. bundle exec rspec

About

Sagepay VSP Server Integration

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published

Languages