unified_payment 1.0.0
Sign up to get free protection for your applications and to get access to all the features.
- data/Rakefile +34 -0
- data/app/controllers/unified_payment/transactions_controller.rb +4 -0
- data/app/models/unified_payment/transaction.rb +24 -0
- data/app/views/unified_payment/transactions/index.html.erb +20 -0
- data/config/boot.rb +5 -0
- data/config/environment.rb +5 -0
- data/config/locales/en.yml +23 -0
- data/config/routes.rb +4 -0
- data/lib/generators/unified_payment/USAGE +8 -0
- data/lib/generators/unified_payment/install_generator.rb +26 -0
- data/lib/generators/unified_payment/templates/migrations/20131101092408_add_unified_payment_transactions.rb +23 -0
- data/lib/tasks/unified_payment_tasks.rake +4 -0
- data/lib/unified_payment.rb +27 -0
- data/lib/unified_payment/client.rb +148 -0
- data/lib/unified_payment/engine.rb +7 -0
- data/lib/unified_payment/utility.rb +13 -0
- data/lib/unified_payment/version.rb +3 -0
- data/spec/Libraries/client_spec.rb +152 -0
- data/spec/models/unified_payment/transaction_spec.rb +121 -0
- data/spec/spec_helper.rb +45 -0
- metadata +102 -0
data/Rakefile
ADDED
@@ -0,0 +1,34 @@
|
|
1
|
+
begin
|
2
|
+
require 'bundler/setup'
|
3
|
+
rescue LoadError
|
4
|
+
puts 'You must `gem install bundler` and `bundle install` to run rake tasks'
|
5
|
+
end
|
6
|
+
|
7
|
+
require 'rdoc/task'
|
8
|
+
|
9
|
+
RDoc::Task.new(:rdoc) do |rdoc|
|
10
|
+
rdoc.rdoc_dir = 'rdoc'
|
11
|
+
rdoc.title = 'UnifiedPayment'
|
12
|
+
rdoc.options << '--line-numbers'
|
13
|
+
rdoc.rdoc_files.include('README.rdoc')
|
14
|
+
rdoc.rdoc_files.include('lib/**/*.rb')
|
15
|
+
end
|
16
|
+
|
17
|
+
# APP_RAKEFILE = File.expand_path("../test/dummy/Rakefile", __FILE__)
|
18
|
+
# load 'rails/tasks/engine.rake'
|
19
|
+
|
20
|
+
|
21
|
+
|
22
|
+
Bundler::GemHelper.install_tasks
|
23
|
+
|
24
|
+
require 'rake/testtask'
|
25
|
+
|
26
|
+
Rake::TestTask.new(:test) do |t|
|
27
|
+
t.libs << 'lib'
|
28
|
+
t.libs << 'test'
|
29
|
+
t.pattern = 'test/**/*_test.rb'
|
30
|
+
t.verbose = false
|
31
|
+
end
|
32
|
+
|
33
|
+
|
34
|
+
task default: :test
|
@@ -0,0 +1,24 @@
|
|
1
|
+
module UnifiedPayment
|
2
|
+
class Transaction < ActiveRecord::Base
|
3
|
+
include Utility
|
4
|
+
self.table_name = "unified_payment_transactions"
|
5
|
+
attr_accessible :amount, :gateway_session_id, :gateway_order_id, :url, :merchant_id, :approval_code, :xml_response, :pan, :response_description, :response_status, :order_description, :currency, :gateway_order_status
|
6
|
+
|
7
|
+
def self.create_order_at_unified(amount, options)
|
8
|
+
3.times do |attempt|
|
9
|
+
begin
|
10
|
+
@response = Client.create_order((amount.to_f)*100, options)
|
11
|
+
create(:url => @response['url'], :gateway_order_id => @response['orderId'], :gateway_session_id => @response['sessionId'], :xml_response => @response['xml_response'].to_s)
|
12
|
+
break
|
13
|
+
rescue
|
14
|
+
@response = false
|
15
|
+
end
|
16
|
+
end
|
17
|
+
@response
|
18
|
+
end
|
19
|
+
|
20
|
+
def self.extract_url_for_unified_payment(response)
|
21
|
+
response['url'] + '?' + 'ORDERID=' + response['orderId'] + '&' + 'SESSIONID=' + response['sessionId']
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
<table>
|
2
|
+
<thead>
|
3
|
+
<tr>
|
4
|
+
<th>Gateway Session Id</th>
|
5
|
+
<th>Gateway Order Id</th>
|
6
|
+
<th>Url</th>
|
7
|
+
<th>Merchant Id</th>
|
8
|
+
<th>Approval Code</th>
|
9
|
+
</tr>
|
10
|
+
</thead>
|
11
|
+
<% UnifiedPayment::Transaction.all.each do |transaction| %>
|
12
|
+
<tr>
|
13
|
+
<td><%= transaction.gateway_session_id %></td>
|
14
|
+
<td><%= transaction.gateway_order_id %></td>
|
15
|
+
<td><%= transaction.url %></td>
|
16
|
+
<td><%= transaction.merchant_id %></td>
|
17
|
+
<td><%= transaction.approval_code %></td>
|
18
|
+
</tr>
|
19
|
+
<% end %>
|
20
|
+
</table>
|
data/config/boot.rb
ADDED
@@ -0,0 +1,23 @@
|
|
1
|
+
# Files in the config/locales directory are used for internationalization
|
2
|
+
# and are automatically loaded by Rails. If you want to use locales other
|
3
|
+
# than English, add the necessary files in this directory.
|
4
|
+
#
|
5
|
+
# To use the locales, use `I18n.t`:
|
6
|
+
#
|
7
|
+
# I18n.t 'hello'
|
8
|
+
#
|
9
|
+
# In views, this is aliased to just `t`:
|
10
|
+
#
|
11
|
+
# <%= t('hello') %>
|
12
|
+
#
|
13
|
+
# To use a different locale, set it with `I18n.locale`:
|
14
|
+
#
|
15
|
+
# I18n.locale = :es
|
16
|
+
#
|
17
|
+
# This would use the information in config/locales/es.yml.
|
18
|
+
#
|
19
|
+
# To learn more, please read the Rails Internationalization guide
|
20
|
+
# available at http://guides.rubyonrails.org/i18n.html.
|
21
|
+
|
22
|
+
en:
|
23
|
+
hello: "Hello world"
|
data/config/routes.rb
ADDED
@@ -0,0 +1,26 @@
|
|
1
|
+
require 'rails/generators'
|
2
|
+
module UnifiedPayment
|
3
|
+
class InstallGenerator < Rails::Generators::Base
|
4
|
+
desc "Some description of my generator here"
|
5
|
+
|
6
|
+
# Commandline options can be defined here using Thor-like options:
|
7
|
+
class_option :my_opt, :type => :boolean, :default => false, :desc => "My Option"
|
8
|
+
|
9
|
+
# I can later access that option using:
|
10
|
+
# options[:my_opt]
|
11
|
+
|
12
|
+
|
13
|
+
def self.source_root
|
14
|
+
@source_root ||= File.join(File.dirname(__FILE__), 'templates')
|
15
|
+
end
|
16
|
+
|
17
|
+
# Generator Code. Remember this is just suped-up Thor so methods are executed in order
|
18
|
+
def create_migrations
|
19
|
+
Dir["#{self.class.source_root}/migrations/*.rb"].sort.each do |filepath|
|
20
|
+
name = File.basename(filepath)
|
21
|
+
template "migrations/#{name}", "db/migrate/#{name}"
|
22
|
+
sleep 1
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
class AddUnifiedPaymentTransactions < ActiveRecord::Migration
|
2
|
+
def change
|
3
|
+
create_table :unified_payment_transactions do |t|
|
4
|
+
t.integer :gateway_order_id
|
5
|
+
t.string :gateway_order_status
|
6
|
+
t.string :amount
|
7
|
+
t.string :gateway_session_id
|
8
|
+
t.string :url
|
9
|
+
t.string :merchant_id
|
10
|
+
t.string :currency
|
11
|
+
t.string :order_description
|
12
|
+
t.string :response_status
|
13
|
+
t.string :response_description
|
14
|
+
t.string :pan
|
15
|
+
t.string :approval_code
|
16
|
+
t.text :xml_response
|
17
|
+
t.timestamps
|
18
|
+
end
|
19
|
+
|
20
|
+
add_index :unified_payment_transactions, [:gateway_order_id, :gateway_session_id], name: :order_session_index
|
21
|
+
add_index :unified_payment_transactions, :response_status
|
22
|
+
end
|
23
|
+
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
module UnifiedPayment
|
2
|
+
@config = {
|
3
|
+
:merchant_name => "verbose",
|
4
|
+
:base_uri => 'http://127.0.0.1:5555'
|
5
|
+
}
|
6
|
+
|
7
|
+
@valid_config_keys = @config.keys
|
8
|
+
|
9
|
+
# Configure through hash
|
10
|
+
def self.configure(opts = {})
|
11
|
+
opts.each {|k,v| @config[k.to_sym] = v if @valid_config_keys.include? k.to_sym}
|
12
|
+
end
|
13
|
+
|
14
|
+
# Configure through yaml file
|
15
|
+
def self.configure_with(path_to_yaml_file)
|
16
|
+
config = YAML::load(IO.read(path_to_yaml_file))
|
17
|
+
global_config = config.select { |key, value| value.class != Hash } || {}
|
18
|
+
env_config = config[Rails.env] || {}
|
19
|
+
config = global_config.merge(env_config)
|
20
|
+
configure(config)
|
21
|
+
end
|
22
|
+
|
23
|
+
def self.config
|
24
|
+
@config
|
25
|
+
end
|
26
|
+
end
|
27
|
+
require "unified_payment/engine"
|
@@ -0,0 +1,148 @@
|
|
1
|
+
require 'httparty'
|
2
|
+
require 'builder'
|
3
|
+
module UnifiedPayment
|
4
|
+
# This is the usual error raised on any UnifiedPayment related Errors
|
5
|
+
class Error < RuntimeError
|
6
|
+
|
7
|
+
attr_accessor :http_response, :error, :user_error
|
8
|
+
|
9
|
+
def initialize(error, xml_response=nil, user_error=nil)
|
10
|
+
@error = error
|
11
|
+
@xml_response = xml_response
|
12
|
+
@user_error = user_error
|
13
|
+
end
|
14
|
+
|
15
|
+
def to_s
|
16
|
+
return "#{ user_error } (#{ error })" if user_error
|
17
|
+
"#{ error }"
|
18
|
+
end
|
19
|
+
|
20
|
+
end
|
21
|
+
|
22
|
+
class Client
|
23
|
+
|
24
|
+
MERCHANT_NAME = UnifiedPayment.config[:merchant_name]
|
25
|
+
|
26
|
+
include HTTParty
|
27
|
+
format :xml
|
28
|
+
base_uri UnifiedPayment.config[:base_uri]
|
29
|
+
|
30
|
+
# debug_output
|
31
|
+
follow_redirects(50)
|
32
|
+
|
33
|
+
def success?
|
34
|
+
self["orderId"]
|
35
|
+
end
|
36
|
+
|
37
|
+
def self.build_xml_for_create(amount, options)
|
38
|
+
xml_builder = ::Builder::XmlMarkup.new
|
39
|
+
xml_builder.instruct!
|
40
|
+
xml_builder.TKKPG { |tkkpg|
|
41
|
+
tkkpg.Request { |request|
|
42
|
+
request.Operation("CreateOrder")
|
43
|
+
request.Language(options[:language] || "EN")
|
44
|
+
request.Order { |order|
|
45
|
+
order.Merchant(MERCHANT_NAME)
|
46
|
+
order.Amount(amount)
|
47
|
+
order.Currency(options[:currency] || "566")
|
48
|
+
order.Description(options[:description] || "Test Order")
|
49
|
+
order.ApproveURL(options[:approve_url])
|
50
|
+
order.CancelURL(options[:cancel_url])
|
51
|
+
order.DeclineURL(options[:decline_url])
|
52
|
+
if params_to_add = options[:add_params]
|
53
|
+
order.AddParams do |add_param|
|
54
|
+
add_param.email(params_to_add[:email]) if params_to_add[:email]
|
55
|
+
add_param.phone(params_to_add[:phone]) if params_to_add[:phone]
|
56
|
+
end
|
57
|
+
end
|
58
|
+
}
|
59
|
+
}
|
60
|
+
}
|
61
|
+
xml_builder
|
62
|
+
end
|
63
|
+
|
64
|
+
def self.ping_gateway_for(operation, xml_request)
|
65
|
+
begin
|
66
|
+
response = post('/Exec', :body => xml_request.target! )
|
67
|
+
rescue => exception
|
68
|
+
raise Error.new("################### Unable to send " + operation + " request to Unified Payments Ltd " + exception.message)
|
69
|
+
end
|
70
|
+
response
|
71
|
+
end
|
72
|
+
|
73
|
+
def self.send_request_for_create(amount, options)
|
74
|
+
xml_builder = build_xml_for_create(amount, options)
|
75
|
+
ping_gateway_for('CreateOrder', xml_builder)
|
76
|
+
end
|
77
|
+
|
78
|
+
def self.create_order(amount, options={})
|
79
|
+
xml_response = send_request_for_create(amount, options)
|
80
|
+
response = xml_response["TKKPG"]["Response"]
|
81
|
+
if response["Status"] == "00"
|
82
|
+
response_order_details = response["Order"]
|
83
|
+
|
84
|
+
return { "url" => response_order_details["URL"],
|
85
|
+
"sessionId" => response_order_details["SessionID"],
|
86
|
+
"orderId" => response_order_details["OrderID"],
|
87
|
+
"Order" => response_order_details,
|
88
|
+
"Status" => response["Status"],
|
89
|
+
"xml_response" => xml_response
|
90
|
+
}
|
91
|
+
else
|
92
|
+
raise Error.new("CreateOrder Failed", response)
|
93
|
+
end
|
94
|
+
end
|
95
|
+
|
96
|
+
def self.build_xml_for(operation, order_id, session_id)
|
97
|
+
xml_builder = Builder::XmlMarkup.new
|
98
|
+
xml_builder.instruct!
|
99
|
+
xml_builder.TKKPG { |tkkpg|
|
100
|
+
tkkpg.Request { |request|
|
101
|
+
request.Operation(operation)
|
102
|
+
request.Language("EN")
|
103
|
+
request.Order { |order|
|
104
|
+
order.Merchant(MERCHANT_NAME)
|
105
|
+
order.OrderID(order_id) }
|
106
|
+
request.SessionID(session_id)
|
107
|
+
}
|
108
|
+
}
|
109
|
+
xml_builder
|
110
|
+
end
|
111
|
+
|
112
|
+
def self.send_request_for(operation, order_id, session_id)
|
113
|
+
xml_request = build_xml_for(operation, order_id, session_id)
|
114
|
+
ping_gateway_for(operation, xml_request)
|
115
|
+
end
|
116
|
+
|
117
|
+
def self.get_order_status(order_id, session_id)
|
118
|
+
xml_response = send_request_for("GetOrderStatus", order_id, session_id)
|
119
|
+
response = xml_response["TKKPG"]["Response"]
|
120
|
+
|
121
|
+
if response["Status"] == "00"
|
122
|
+
response_order_details = response["Order"]
|
123
|
+
|
124
|
+
return { "orderStatus" => response_order_details["OrderStatus"],
|
125
|
+
"orderId" => response_order_details["OrderID"],
|
126
|
+
"xml_response" => xml_response }
|
127
|
+
else
|
128
|
+
raise Error.new("GetOrderStatus Failed", xml_response)
|
129
|
+
end
|
130
|
+
|
131
|
+
end
|
132
|
+
|
133
|
+
def self.reverse(order_id, session_id)
|
134
|
+
xml_response = send_request_for("Reverse", order_id, session_id)
|
135
|
+
response = xml_response["TKKPG"]["Response"]
|
136
|
+
if response["Status"] == "00"
|
137
|
+
response_order_id, response_reversal_details = response["Order"]["OrderID"], response["Reversal"]
|
138
|
+
|
139
|
+
return { "orderId" => response_order_id,
|
140
|
+
"respCode" => response_reversal_details["RespCode"],
|
141
|
+
"respMessage" => response_reversal_details["RespMessage"],
|
142
|
+
"xml_response" => xml_response }
|
143
|
+
else
|
144
|
+
raise Error.new("Reverse Request Failed", xml_response)
|
145
|
+
end
|
146
|
+
end
|
147
|
+
end
|
148
|
+
end
|
@@ -0,0 +1,13 @@
|
|
1
|
+
module UnifiedPayment
|
2
|
+
module Utility
|
3
|
+
def approved_at_gateway?
|
4
|
+
get_unified_order_status == 'APPROVED'
|
5
|
+
end
|
6
|
+
|
7
|
+
private
|
8
|
+
def get_unified_order_status
|
9
|
+
response = Client.get_order_status(gateway_order_id, gateway_session_id)
|
10
|
+
response['orderStatus']
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
@@ -0,0 +1,152 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe UnifiedPayment::Client do
|
4
|
+
describe '#create_order' do
|
5
|
+
before do
|
6
|
+
@xml_builder = Builder::XmlMarkup.new
|
7
|
+
Builder::XmlMarkup.stub(:new).and_return(@xml_builder)
|
8
|
+
end
|
9
|
+
|
10
|
+
context 'not able to reach gateway' do
|
11
|
+
it { expect { UnifiedPayment::Client.create_order(200)}.to raise_error(UnifiedPayment::Error, "################### Unable to send CreateOrder request to Unified Payments Ltd Connection refused - connect(2)") }
|
12
|
+
end
|
13
|
+
|
14
|
+
context 'response status is not 00' do
|
15
|
+
before do
|
16
|
+
my_response = { "TKKPG" => { "Response" => { "Operation"=>"CreateOrder", "Status"=>"01", "Order"=>{"OrderID"=>"1086880", "SessionID"=>"740A7AB7EB527908EB9507154CFAD389", "URL"=> "https://mpi.valucardnigeria.com:443/index.jsp"}}}}
|
17
|
+
UnifiedPayment::Client.stub(:post).with('/Exec', :body => @xml_builder.target!).and_return(my_response)
|
18
|
+
end
|
19
|
+
|
20
|
+
it { expect { UnifiedPayment::Client.create_order(200)}.to raise_error(UnifiedPayment::Error, "CreateOrder Failed") }
|
21
|
+
end
|
22
|
+
|
23
|
+
context 'response status is 00' do
|
24
|
+
before do
|
25
|
+
my_response = { "TKKPG" => { "Response" => { "Operation"=>"CreateOrder", "Status"=>"00", "Order"=>{"OrderID"=>"1086880", "SessionID"=>"740A7AB7EB527908EB9507154CFAD389", "URL"=> "https://mpi.valucardnigeria.com:443/index.jsp"}}}}
|
26
|
+
UnifiedPayment::Client.stub(:post).with('/Exec', :body => @xml_builder.target!).and_return(my_response)
|
27
|
+
end
|
28
|
+
|
29
|
+
it { expect { UnifiedPayment::Client.create_order(200)}.not_to raise_error() }
|
30
|
+
it { UnifiedPayment::Client.create_order(200).should eq({"url"=>"https://mpi.valucardnigeria.com:443/index.jsp", "sessionId"=>"740A7AB7EB527908EB9507154CFAD389", "orderId"=>"1086880", "Order"=>{"OrderID"=>"1086880", "SessionID"=>"740A7AB7EB527908EB9507154CFAD389", "URL"=> "https://mpi.valucardnigeria.com:443/index.jsp"}, "Status"=>"00", "xml_response"=>{"TKKPG"=>{"Response"=>{"Operation"=>"CreateOrder", "Status"=>"00", "Order"=>{"OrderID"=>"1086880", "SessionID"=>"740A7AB7EB527908EB9507154CFAD389", "URL"=>"https://mpi.valucardnigeria.com:443/index.jsp"}}}}}) }
|
31
|
+
end
|
32
|
+
|
33
|
+
describe 'method calls' do
|
34
|
+
before do
|
35
|
+
my_response = { "TKKPG" => { "Response" => { "Operation"=>"CreateOrder", "Status"=>"00", "Order"=>{"OrderID"=>"1086880", "SessionID"=>"740A7AB7EB527908EB9507154CFAD389", "URL"=> "https://mpi.valucardnigeria.com:443/index.jsp"}}}}
|
36
|
+
UnifiedPayment::Client.stub(:post).with('/Exec', :body => @xml_builder.target!).and_return(my_response)
|
37
|
+
end
|
38
|
+
|
39
|
+
it { Builder::XmlMarkup.should_receive(:new).and_return(@xml_builder) }
|
40
|
+
it { @xml_builder.should_receive(:instruct!).and_return(true) }
|
41
|
+
|
42
|
+
after { UnifiedPayment::Client.create_order(200) }
|
43
|
+
end
|
44
|
+
|
45
|
+
describe 'sends request along options' do
|
46
|
+
before do
|
47
|
+
my_response = { "TKKPG" => { "Response" => { "Operation"=>"CreateOrder", "Status"=>"00", "Order"=>{"OrderID"=>"1086880", "SessionID"=>"740A7AB7EB527908EB9507154CFAD389", "URL"=> "https://mpi.valucardnigeria.com:443/index.jsp"}}}}
|
48
|
+
UnifiedPayment::Client.stub(:post).with('/Exec', :body => @xml_builder.target!).and_return(my_response)
|
49
|
+
end
|
50
|
+
|
51
|
+
context 'default options' do
|
52
|
+
before do
|
53
|
+
UnifiedPayment::Client.create_order(200, :approve_url => 'approve-url', :decline_url => 'decline-url', :cancel_url => 'cancel-url')
|
54
|
+
end
|
55
|
+
|
56
|
+
it { @xml_builder.inspect.should eq("<?xml version=\"1.0\" encoding=\"UTF-8\"?><TKKPG><Request><Operation>CreateOrder</Operation><Language>EN</Language><Order><Merchant>verbose</Merchant><Amount>200</Amount><Currency>566</Currency><Description>Test Order</Description><ApproveURL>approve-url</ApproveURL><CancelURL>cancel-url</CancelURL><DeclineURL>decline-url</DeclineURL></Order></Request></TKKPG><inspect/>")}
|
57
|
+
end
|
58
|
+
|
59
|
+
context 'Currency, Description and Language' do
|
60
|
+
before do
|
61
|
+
UnifiedPayment::Client.create_order(200,:currency => '444', :description => 'unified-payment-order', :language => 'HIN', :approve_url => 'approve-url', :decline_url => 'decline-url', :cancel_url => 'cancel-url')
|
62
|
+
end
|
63
|
+
|
64
|
+
it { @xml_builder.inspect.should eq("<?xml version=\"1.0\" encoding=\"UTF-8\"?><TKKPG><Request><Operation>CreateOrder</Operation><Language>HIN</Language><Order><Merchant>verbose</Merchant><Amount>200</Amount><Currency>444</Currency><Description>unified-payment-order</Description><ApproveURL>approve-url</ApproveURL><CancelURL>cancel-url</CancelURL><DeclineURL>decline-url</DeclineURL></Order></Request></TKKPG><inspect/>")}
|
65
|
+
end
|
66
|
+
|
67
|
+
context 'with email and phone' do
|
68
|
+
before do
|
69
|
+
UnifiedPayment::Client.create_order(200, :add_params => { :email => 'test-email@test.com', :phone => '07123456789' }, :currency => '444', :description => 'unified-payment-order', :language => 'HIN', :approve_url => 'approve-url', :decline_url => 'decline-url', :cancel_url => 'cancel-url')
|
70
|
+
end
|
71
|
+
|
72
|
+
it { @xml_builder.inspect.should eq("<?xml version=\"1.0\" encoding=\"UTF-8\"?><TKKPG><Request><Operation>CreateOrder</Operation><Language>HIN</Language><Order><Merchant>verbose</Merchant><Amount>200</Amount><Currency>444</Currency><Description>unified-payment-order</Description><ApproveURL>approve-url</ApproveURL><CancelURL>cancel-url</CancelURL><DeclineURL>decline-url</DeclineURL><AddParams><email>test-email@test.com</email><phone>07123456789</phone></AddParams></Order></Request></TKKPG><inspect/>")}
|
73
|
+
end
|
74
|
+
end
|
75
|
+
end
|
76
|
+
|
77
|
+
describe '.get_order_status' do
|
78
|
+
before do
|
79
|
+
@xml_builder = Builder::XmlMarkup.new
|
80
|
+
Builder::XmlMarkup.stub(:new).and_return(@xml_builder)
|
81
|
+
end
|
82
|
+
|
83
|
+
it { expect { UnifiedPayment::Client.get_order_status(1086880, '740A7AB7EB527908EB9507154CFAD389') }.to raise_error(UnifiedPayment::Error, '################### Unable to send GetOrderStatus request to Unified Payments Ltd Connection refused - connect(2)')}
|
84
|
+
|
85
|
+
context 'response status is not 00' do
|
86
|
+
before do
|
87
|
+
my_response = {"TKKPG"=>{"Response"=>{"Operation"=>"GetOrderStatus", "Status"=>"01", "Order"=>{"OrderID"=>"1086880", "OrderStatus"=>"CREATED"}}}}
|
88
|
+
UnifiedPayment::Client.stub(:post).with('/Exec', :body => @xml_builder.target!).and_return(my_response)
|
89
|
+
end
|
90
|
+
|
91
|
+
it { expect { UnifiedPayment::Client.get_order_status(1086880, '740A7AB7EB527908EB9507154CFAD389') }.to raise_error(UnifiedPayment::Error, 'GetOrderStatus Failed') }
|
92
|
+
end
|
93
|
+
|
94
|
+
context 'response status is 00' do
|
95
|
+
before do
|
96
|
+
my_response = {"TKKPG"=>{"Response"=>{"Operation"=>"GetOrderStatus", "Status"=>"00", "Order"=>{"OrderID"=>"1086880", "OrderStatus"=>"CREATED"}}}}
|
97
|
+
UnifiedPayment::Client.stub(:post).with('/Exec', :body => @xml_builder.target!).and_return(my_response)
|
98
|
+
end
|
99
|
+
|
100
|
+
it { expect { UnifiedPayment::Client.get_order_status(1086880, '740A7AB7EB527908EB9507154CFAD389') }.not_to raise_error() }
|
101
|
+
it { UnifiedPayment::Client.get_order_status(1086880, '740A7AB7EB527908EB9507154CFAD389').should eq({"orderStatus"=>"CREATED", "orderId"=>"1086880", "xml_response"=>{"TKKPG"=>{"Response"=>{"Operation"=>"GetOrderStatus", "Status"=>"00", "Order"=>{"OrderID"=>"1086880", "OrderStatus"=>"CREATED"}}}}}) }
|
102
|
+
end
|
103
|
+
|
104
|
+
describe 'sends request along options' do
|
105
|
+
before do
|
106
|
+
my_response = {"TKKPG"=>{"Response"=>{"Operation"=>"GetOrderStatus", "Status"=>"00", "Order"=>{"OrderID"=>"1086880", "OrderStatus"=>"CREATED"}}}}
|
107
|
+
UnifiedPayment::Client.stub(:post).with('/Exec', :body => @xml_builder.target!).and_return(my_response)
|
108
|
+
UnifiedPayment::Client.get_order_status(1086880, '740A7AB7EB527908EB9507154CFAD389')
|
109
|
+
end
|
110
|
+
|
111
|
+
it { @xml_builder.inspect.should eq("<?xml version=\"1.0\" encoding=\"UTF-8\"?><TKKPG><Request><Operation>GetOrderStatus</Operation><Language>EN</Language><Order><Merchant>verbose</Merchant><OrderID>1086880</OrderID></Order><SessionID>740A7AB7EB527908EB9507154CFAD389</SessionID></Request></TKKPG><inspect/>") }
|
112
|
+
end
|
113
|
+
end
|
114
|
+
|
115
|
+
describe '.reverse' do
|
116
|
+
before do
|
117
|
+
@xml_builder = Builder::XmlMarkup.new
|
118
|
+
Builder::XmlMarkup.stub(:new).and_return(@xml_builder)
|
119
|
+
end
|
120
|
+
|
121
|
+
it { expect { UnifiedPayment::Client.reverse(1086880, '740A7AB7EB527908EB9507154CFAD389') }.to raise_error(UnifiedPayment::Error, '################### Unable to send Reverse request to Unified Payments Ltd Connection refused - connect(2)')}
|
122
|
+
|
123
|
+
context 'response status is not 00' do
|
124
|
+
before do
|
125
|
+
my_response = {"TKKPG"=>{"Response"=>{"Operation"=>"GetOrderStatus", "Status"=>"01", "Order"=>{"OrderID"=>"1086880", "OrderStatus"=>"CREATED"}, "Reversal" => {'RespCode' => '876', 'RespMessage' => 'resp-message' }}}}
|
126
|
+
UnifiedPayment::Client.stub(:post).with('/Exec', :body => @xml_builder.target!).and_return(my_response)
|
127
|
+
end
|
128
|
+
|
129
|
+
it { expect { UnifiedPayment::Client.reverse(1086880, '740A7AB7EB527908EB9507154CFAD389') }.to raise_error(UnifiedPayment::Error, 'Reverse Request Failed') }
|
130
|
+
end
|
131
|
+
|
132
|
+
context 'response status is 00' do
|
133
|
+
before do
|
134
|
+
my_response = {"TKKPG"=>{"Response"=>{"Operation"=>"GetOrderStatus", "Status"=>"00", "Order"=>{"OrderID"=>"1086880", "OrderStatus"=>"CREATED"}, "Reversal" => {'RespCode' => '876', 'RespMessage' => 'resp-message' }}}}
|
135
|
+
UnifiedPayment::Client.stub(:post).with('/Exec', :body => @xml_builder.target!).and_return(my_response)
|
136
|
+
end
|
137
|
+
|
138
|
+
it { expect { UnifiedPayment::Client.reverse(1086880, '740A7AB7EB527908EB9507154CFAD389') }.not_to raise_error() }
|
139
|
+
it { UnifiedPayment::Client.reverse(1086880, '740A7AB7EB527908EB9507154CFAD389').should eq({"orderId"=>"1086880", "respCode"=>"876", "respMessage"=>"resp-message", "xml_response"=>{"TKKPG"=>{"Response"=>{"Operation"=>"GetOrderStatus", "Status"=>"00", "Order"=>{"OrderID"=>"1086880", "OrderStatus"=>"CREATED"}, "Reversal"=>{"RespCode"=>"876", "RespMessage"=>"resp-message"}}}}}) }
|
140
|
+
end
|
141
|
+
|
142
|
+
describe 'sends request along options' do
|
143
|
+
before do
|
144
|
+
my_response = {"TKKPG"=>{"Response"=>{"Operation"=>"GetOrderStatus", "Status"=>"00", "Order"=>{"OrderID"=>"1086880", "OrderStatus"=>"CREATED"}, "Reversal" => {'RespCode' => '876', 'RespMessage' => 'resp-message' }}}}
|
145
|
+
UnifiedPayment::Client.stub(:post).with('/Exec', :body => @xml_builder.target!).and_return(my_response)
|
146
|
+
UnifiedPayment::Client.reverse(1086880, '740A7AB7EB527908EB9507154CFAD389')
|
147
|
+
end
|
148
|
+
|
149
|
+
it { @xml_builder.inspect.should eq("<?xml version=\"1.0\" encoding=\"UTF-8\"?><TKKPG><Request><Operation>Reverse</Operation><Language>EN</Language><Order><Merchant>verbose</Merchant><OrderID>1086880</OrderID></Order><SessionID>740A7AB7EB527908EB9507154CFAD389</SessionID></Request></TKKPG><inspect/>") }
|
150
|
+
end
|
151
|
+
end
|
152
|
+
end
|
@@ -0,0 +1,121 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe UnifiedPayment::Transaction do
|
4
|
+
it { UnifiedPayment::Transaction.table_name.should eq('unified_payment_transactions') }
|
5
|
+
[:gateway_session_id, :gateway_order_id, :url, :merchant_id, :approval_code].each do |attribute|
|
6
|
+
it { should allow_mass_assignment_of attribute }
|
7
|
+
end
|
8
|
+
|
9
|
+
let(:unified_payment) { UnifiedPayment::Transaction.new }
|
10
|
+
context 'utility methods' do
|
11
|
+
describe '#create_order_at_unified' do
|
12
|
+
context 'attempt fails' do
|
13
|
+
context 'never' do
|
14
|
+
before do
|
15
|
+
UnifiedPayment::Client.stub(:create_order).and_return({ 'url' => 'https://mpi.valucardnigeria.com:443/index.jsp', 'orderId' => '12345', 'sessionId' => '040C78AA2FACF4B1164EDAA27BB281A7'})
|
16
|
+
end
|
17
|
+
|
18
|
+
it 'calls to client only once with no error raised' do
|
19
|
+
UnifiedPayment::Client.should_receive(:create_order).and_return({ 'url' => 'https://mpi.valucardnigeria.com:443/index.jsp', 'orderId' => '12345', 'sessionId' => '040C78AA2FACF4B1164EDAA27BB281A7'})
|
20
|
+
UnifiedPayment::Transaction.create_order_at_unified(200, {})
|
21
|
+
end
|
22
|
+
|
23
|
+
it 'creates a unified transaction entry' do
|
24
|
+
UnifiedPayment::Transaction.should_receive(:create).with({ :url => 'https://mpi.valucardnigeria.com:443/index.jsp', :gateway_order_id => '12345', :gateway_session_id => '040C78AA2FACF4B1164EDAA27BB281A7', :xml_response => ""})
|
25
|
+
UnifiedPayment::Transaction.create_order_at_unified(200, {})
|
26
|
+
end
|
27
|
+
|
28
|
+
it 'sets response' do
|
29
|
+
UnifiedPayment::Transaction.create_order_at_unified(200, {}).should eq({ 'url' => 'https://mpi.valucardnigeria.com:443/index.jsp', 'orderId' => '12345', 'sessionId' => '040C78AA2FACF4B1164EDAA27BB281A7'})
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
context 'once' do
|
34
|
+
before do
|
35
|
+
UnifiedPayment::Client.stub(:create_order).once.and_raise(UnifiedPayment::Error.new("Unable to send create order request to Unified Payments Ltd. ERROR: Connection refused - connect(2)") )
|
36
|
+
UnifiedPayment::Client.stub(:create_order).once.and_return({ 'url' => 'https://mpi.valucardnigeria.com:443/index.jsp', 'orderId' => '12345', 'sessionId' => '040C78AA2FACF4B1164EDAA27BB281A7'})
|
37
|
+
end
|
38
|
+
|
39
|
+
it 'calls to client twice with error raise once' do
|
40
|
+
UnifiedPayment::Client.should_receive(:create_order).once.and_raise(UnifiedPayment::Error.new("Unable to send create order request to Unified Payments Ltd. ERROR: Connection refused - connect(2)") )
|
41
|
+
UnifiedPayment::Client.should_receive(:create_order).once.and_return({ 'url' => 'https://mpi.valucardnigeria.com:443/index.jsp', 'orderId' => '12345', 'sessionId' => '040C78AA2FACF4B1164EDAA27BB281A7'})
|
42
|
+
UnifiedPayment::Transaction.create_order_at_unified(200, {})
|
43
|
+
end
|
44
|
+
|
45
|
+
it 'sets response' do
|
46
|
+
UnifiedPayment::Transaction.create_order_at_unified(200, {}).should eq({ 'url' => 'https://mpi.valucardnigeria.com:443/index.jsp', 'orderId' => '12345', 'sessionId' => '040C78AA2FACF4B1164EDAA27BB281A7'})
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
context 'twice' do
|
51
|
+
before do
|
52
|
+
UnifiedPayment::Client.stub(:create_order).twice.and_raise(UnifiedPayment::Error.new("Unable to send create order request to Unified Payments Ltd. ERROR: Connection refused - connect(2)") )
|
53
|
+
UnifiedPayment::Client.stub(:create_order).once.and_return({ 'url' => 'https://mpi.valucardnigeria.com:443/index.jsp', 'orderId' => '12345', 'sessionId' => '040C78AA2FACF4B1164EDAA27BB281A7'})
|
54
|
+
end
|
55
|
+
|
56
|
+
it 'calls to client thrice with error raise twice' do
|
57
|
+
UnifiedPayment::Client.should_receive(:create_order).twice.and_raise(UnifiedPayment::Error.new("Unable to send create order request to Unified Payments Ltd. ERROR: Connection refused - connect(2)") )
|
58
|
+
UnifiedPayment::Client.should_receive(:create_order).once.and_return({ 'url' => 'https://mpi.valucardnigeria.com:443/index.jsp', 'orderId' => '12345', 'sessionId' => '040C78AA2FACF4B1164EDAA27BB281A7'})
|
59
|
+
UnifiedPayment::Transaction.create_order_at_unified(200, {})
|
60
|
+
end
|
61
|
+
|
62
|
+
it 'sets response' do
|
63
|
+
UnifiedPayment::Transaction.create_order_at_unified(200, {}).should eq({ 'url' => 'https://mpi.valucardnigeria.com:443/index.jsp', 'orderId' => '12345', 'sessionId' => '040C78AA2FACF4B1164EDAA27BB281A7'})
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
context 'thrice' do
|
68
|
+
before do
|
69
|
+
UnifiedPayment::Client.stub(:create_order).and_raise(UnifiedPayment::Error.new("Unable to send create order request to Unified Payments Ltd. ERROR: Connection refused - connect(2)"))
|
70
|
+
end
|
71
|
+
|
72
|
+
it 'calls to client thrice with error raised thrice' do
|
73
|
+
UnifiedPayment::Client.should_receive(:create_order).exactly(3).times.and_raise(UnifiedPayment::Error.new("Unable to send create order request to Unified Payments Ltd. ERROR: Connection refused - connect(2)"))
|
74
|
+
UnifiedPayment::Transaction.create_order_at_unified(200, {})
|
75
|
+
end
|
76
|
+
|
77
|
+
it 'sets response false' do
|
78
|
+
UnifiedPayment::Transaction.create_order_at_unified(200, {}).should be_false
|
79
|
+
end
|
80
|
+
end
|
81
|
+
end
|
82
|
+
end
|
83
|
+
|
84
|
+
describe '#extract_url_for_unified_payment' do
|
85
|
+
before do
|
86
|
+
@response = { 'url' => 'https://mpi.valucardnigeria.com:443/index.jsp', 'orderId' => '12345', 'sessionId' => '040C78AA2FACF4B1164EDAA27BB281A7'}
|
87
|
+
end
|
88
|
+
|
89
|
+
it { UnifiedPayment::Transaction.extract_url_for_unified_payment(@response).should eq('https://mpi.valucardnigeria.com:443/index.jsp?ORDERID=12345&SESSIONID=040C78AA2FACF4B1164EDAA27BB281A7') }
|
90
|
+
end
|
91
|
+
|
92
|
+
describe '#approved_at_gateway?' do
|
93
|
+
context 'when approved' do
|
94
|
+
before { unified_payment.stub(:get_unified_order_status).and_return('APPROVED') }
|
95
|
+
|
96
|
+
it { unified_payment.should be_approved_at_gateway }
|
97
|
+
end
|
98
|
+
|
99
|
+
context 'when not approved' do
|
100
|
+
before { unified_payment.stub(:get_unified_order_status).and_return('NOT-APPROVED') }
|
101
|
+
|
102
|
+
it { unified_payment.should_not be_approved_at_gateway }
|
103
|
+
end
|
104
|
+
end
|
105
|
+
|
106
|
+
describe '#get_unified_order_status' do
|
107
|
+
before do
|
108
|
+
unified_payment.stub(:gateway_order_id).and_return('12345')
|
109
|
+
unified_payment.stub(:gateway_session_id).and_return('040C78AA2FACF4B1164EDAA27BB281A7')
|
110
|
+
UnifiedPayment::Client.stub(:get_order_status).with(unified_payment.gateway_order_id, unified_payment.gateway_session_id).and_return('orderStatus' => 'APPROVED')
|
111
|
+
end
|
112
|
+
|
113
|
+
it 'calls client' do
|
114
|
+
UnifiedPayment::Client.should_receive(:get_order_status).with(unified_payment.gateway_order_id, unified_payment.gateway_session_id).and_return('orderStatus' => 'APPROVED')
|
115
|
+
unified_payment.send(:get_unified_order_status)
|
116
|
+
end
|
117
|
+
|
118
|
+
it { unified_payment.send(:get_unified_order_status).should eq('APPROVED')}
|
119
|
+
end
|
120
|
+
end
|
121
|
+
end
|
data/spec/spec_helper.rb
ADDED
@@ -0,0 +1,45 @@
|
|
1
|
+
# This file is copied to spec/ when you run 'rails generate rspec:install'
|
2
|
+
ENV["RAILS_ENV"] ||= 'test'
|
3
|
+
require File.expand_path("../../config/environment", __FILE__)
|
4
|
+
# require 'rspec/rails'
|
5
|
+
# require 'rspec/autorun'
|
6
|
+
|
7
|
+
require 'rubygems'
|
8
|
+
require 'bundler/setup'
|
9
|
+
require 'unified_payment'
|
10
|
+
# Requires supporting ruby files with custom matchers and macros, etc,
|
11
|
+
# in spec/support/ and its subdirectories.
|
12
|
+
# Dir[Rails.root.join("spec/support/**/*.rb")].each { |f| require f }
|
13
|
+
|
14
|
+
# Checks for pending migrations before tests are run.
|
15
|
+
# If you are not using ActiveRecord, you can remove this line.
|
16
|
+
# ActiveRecord::Migration.check_pending! if defined?(ActiveRecord::Migration)
|
17
|
+
|
18
|
+
RSpec.configure do |config|
|
19
|
+
# ## Mock Framework
|
20
|
+
#
|
21
|
+
# If you prefer to use mocha, flexmock or RR, uncomment the appropriate line:
|
22
|
+
#
|
23
|
+
# config.mock_with :mocha
|
24
|
+
# config.mock_with :flexmock
|
25
|
+
# config.mock_with :rr
|
26
|
+
|
27
|
+
# Remove this line if you're not using ActiveRecord or ActiveRecord fixtures
|
28
|
+
# config.fixture_path = "#{::Rails.root}/spec/fixtures"
|
29
|
+
|
30
|
+
# If you're not using ActiveRecord, or you'd prefer not to run each of your
|
31
|
+
# examples within a transaction, remove the following line or assign false
|
32
|
+
# instead of true.
|
33
|
+
# config.use_transactional_fixtures = true
|
34
|
+
|
35
|
+
# If true, the base class of anonymous controllers will be inferred
|
36
|
+
# automatically. This will be the default behavior in future versions of
|
37
|
+
# rspec-rails.
|
38
|
+
# config.infer_base_class_for_anonymous_controllers = false
|
39
|
+
|
40
|
+
# Run specs in random order to surface order dependencies. If you find an
|
41
|
+
# order dependency and want to debug it, you can fix the order by providing
|
42
|
+
# the seed, which is printed after each run.
|
43
|
+
# --seed 1234
|
44
|
+
config.order = "random"
|
45
|
+
end
|
metadata
ADDED
@@ -0,0 +1,102 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: unified_payment
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
hash: 23
|
5
|
+
prerelease:
|
6
|
+
segments:
|
7
|
+
- 1
|
8
|
+
- 0
|
9
|
+
- 0
|
10
|
+
version: 1.0.0
|
11
|
+
platform: ruby
|
12
|
+
authors:
|
13
|
+
- Manish Kangia
|
14
|
+
- Sushant Mittal
|
15
|
+
autorequire:
|
16
|
+
bindir: bin
|
17
|
+
cert_chain: []
|
18
|
+
|
19
|
+
date: 2014-02-27 00:00:00 Z
|
20
|
+
dependencies:
|
21
|
+
- !ruby/object:Gem::Dependency
|
22
|
+
name: rails
|
23
|
+
prerelease: false
|
24
|
+
requirement: &id001 !ruby/object:Gem::Requirement
|
25
|
+
none: false
|
26
|
+
requirements:
|
27
|
+
- - ">"
|
28
|
+
- !ruby/object:Gem::Version
|
29
|
+
hash: 7
|
30
|
+
segments:
|
31
|
+
- 3
|
32
|
+
- 0
|
33
|
+
version: "3.0"
|
34
|
+
type: :runtime
|
35
|
+
version_requirements: *id001
|
36
|
+
description: Interface to handle payments via UnifiedPayment for rails app.
|
37
|
+
email:
|
38
|
+
- info@vinsol.com
|
39
|
+
executables: []
|
40
|
+
|
41
|
+
extensions: []
|
42
|
+
|
43
|
+
extra_rdoc_files: []
|
44
|
+
|
45
|
+
files:
|
46
|
+
- app/controllers/unified_payment/transactions_controller.rb
|
47
|
+
- app/models/unified_payment/transaction.rb
|
48
|
+
- app/views/unified_payment/transactions/index.html.erb
|
49
|
+
- config/boot.rb
|
50
|
+
- config/environment.rb
|
51
|
+
- config/locales/en.yml
|
52
|
+
- config/routes.rb
|
53
|
+
- lib/generators/unified_payment/install_generator.rb
|
54
|
+
- lib/generators/unified_payment/templates/migrations/20131101092408_add_unified_payment_transactions.rb
|
55
|
+
- lib/generators/unified_payment/USAGE
|
56
|
+
- lib/tasks/unified_payment_tasks.rake
|
57
|
+
- lib/unified_payment/client.rb
|
58
|
+
- lib/unified_payment/engine.rb
|
59
|
+
- lib/unified_payment/utility.rb
|
60
|
+
- lib/unified_payment/version.rb
|
61
|
+
- lib/unified_payment.rb
|
62
|
+
- Rakefile
|
63
|
+
- spec/Libraries/client_spec.rb
|
64
|
+
- spec/models/unified_payment/transaction_spec.rb
|
65
|
+
- spec/spec_helper.rb
|
66
|
+
homepage: http://vinsol.com
|
67
|
+
licenses:
|
68
|
+
- MIT
|
69
|
+
post_install_message:
|
70
|
+
rdoc_options: []
|
71
|
+
|
72
|
+
require_paths:
|
73
|
+
- lib
|
74
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
75
|
+
none: false
|
76
|
+
requirements:
|
77
|
+
- - ">="
|
78
|
+
- !ruby/object:Gem::Version
|
79
|
+
hash: 3
|
80
|
+
segments:
|
81
|
+
- 0
|
82
|
+
version: "0"
|
83
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
84
|
+
none: false
|
85
|
+
requirements:
|
86
|
+
- - ">="
|
87
|
+
- !ruby/object:Gem::Version
|
88
|
+
hash: 3
|
89
|
+
segments:
|
90
|
+
- 0
|
91
|
+
version: "0"
|
92
|
+
requirements: []
|
93
|
+
|
94
|
+
rubyforge_project:
|
95
|
+
rubygems_version: 1.8.24
|
96
|
+
signing_key:
|
97
|
+
specification_version: 3
|
98
|
+
summary: Interface to handle payments via UnifiedPayment for rails app.
|
99
|
+
test_files:
|
100
|
+
- spec/Libraries/client_spec.rb
|
101
|
+
- spec/models/unified_payment/transaction_spec.rb
|
102
|
+
- spec/spec_helper.rb
|