active_merchant_payumoney_com 0.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/.gitignore +2 -0
- data/Gemfile +2 -0
- data/License +20 -0
- data/Rakefile +37 -0
- data/active_merchant_payu_in.gemspec +36 -0
- data/lib/active_merchant/payu_in/helper.rb +70 -0
- data/lib/active_merchant/payu_in/notification.rb +154 -0
- data/lib/active_merchant/payu_in/return.rb +56 -0
- data/lib/active_merchant/payu_in/version.rb +48 -0
- data/lib/active_merchant/payu_in/web_service.rb +89 -0
- data/lib/active_merchant_payu_in.rb +108 -0
- data/lib/php_serialize.rb +313 -0
- data/pkg/active_merchant_payu_in-0.0.1.gem +0 -0
- data/spec/active_merchant_payu_in_spec.rb +5 -0
- metadata +92 -0
data/.gitignore
ADDED
data/Gemfile
ADDED
data/License
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
Copyright (c) 2011 Ram Singla
|
2
|
+
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
4
|
+
a copy of this software and associated documentation files (the
|
5
|
+
'Software'), to deal in the Software without restriction, including
|
6
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
7
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
8
|
+
permit persons to whom the Software is furnished to do so, subject to
|
9
|
+
the following conditions:
|
10
|
+
|
11
|
+
The above copyright notice and this permission notice shall be
|
12
|
+
included in all copies or substantial portions of the Software.
|
13
|
+
|
14
|
+
THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
|
15
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
16
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
17
|
+
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
18
|
+
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
19
|
+
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
20
|
+
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/Rakefile
ADDED
@@ -0,0 +1,37 @@
|
|
1
|
+
$LOAD_PATH.unshift File.expand_path('../lib', __FILE__)
|
2
|
+
|
3
|
+
begin
|
4
|
+
require 'bundler'
|
5
|
+
Bundler::GemHelper.install_tasks
|
6
|
+
rescue LoadError => e
|
7
|
+
$stderr.puts e
|
8
|
+
end
|
9
|
+
|
10
|
+
desc "run specs"
|
11
|
+
task(:spec) { ruby '-S rspec spec' }
|
12
|
+
|
13
|
+
desc "generate gemspec"
|
14
|
+
task 'active_merchant_payu_in.gemspec' do
|
15
|
+
require 'active_merchant_payu_in/version'
|
16
|
+
content = File.read 'active_merchant_payu_in.gemspec'
|
17
|
+
|
18
|
+
fields = {
|
19
|
+
:authors => `git shortlog -sn`.scan(/[^\d\s].*/),
|
20
|
+
:email => `git shortlog -sne`.scan(/[^<]+@[^>]+/),
|
21
|
+
:files => `git ls-files`.split("\n").reject { |f| f =~ /^(\.|Gemfile)/ }
|
22
|
+
}
|
23
|
+
|
24
|
+
fields.each do |field, values|
|
25
|
+
updated = " s.#{field} = ["
|
26
|
+
updated << values.map { |v| "\n %p" % v }.join(',')
|
27
|
+
updated << "\n ]"
|
28
|
+
content.sub!(/ s\.#{field} = \[\n( .*\n)* \]/, updated)
|
29
|
+
end
|
30
|
+
|
31
|
+
content.sub! /(s\.version.*=\s+).*/, "\\1\"#{ActiveMerchantPayuIn::VERSION}\""
|
32
|
+
File.open('active_merchant_payu_in.gemspec', 'w') { |f| f << content }
|
33
|
+
end
|
34
|
+
|
35
|
+
task :gemspec => 'active_merchant_payu_in.gemspec'
|
36
|
+
task :default => :spec
|
37
|
+
task :test => :spec
|
@@ -0,0 +1,36 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
$:.push File.expand_path("../lib", __FILE__)
|
3
|
+
require "active_merchant/payu_in/version"
|
4
|
+
|
5
|
+
Gem::Specification.new do |s|
|
6
|
+
s.name = "active_merchant_payumoney_com"
|
7
|
+
s.version = ActiveMerchant::Billing::Integrations::PayuIn::VERSION
|
8
|
+
s.platform = Gem::Platform::RUBY
|
9
|
+
s.authors = ["Ram Singla"]
|
10
|
+
s.email = ["ram.singla@gmail.com"]
|
11
|
+
s.homepage = "http://www.payumoney.com"
|
12
|
+
s.summary = %q{PayUMoney.com Payment Gateweay Integration Kit}
|
13
|
+
s.description = %q{PayUMoney.com Payment Gateway integration for ActiveMerchant}
|
14
|
+
|
15
|
+
s.rubyforge_project = "active_merchant_payumoney_com"
|
16
|
+
|
17
|
+
s.files = `git ls-files`.split("\n")
|
18
|
+
s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
|
19
|
+
s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
|
20
|
+
s.require_paths = ["lib"]
|
21
|
+
|
22
|
+
if s.respond_to? :specification_version then
|
23
|
+
current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
|
24
|
+
s.specification_version = 3
|
25
|
+
if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then
|
26
|
+
s.add_development_dependency(%q<rspec>, ["~> 2.7.0"])
|
27
|
+
s.add_runtime_dependency(%q<activemerchant>, ["~> 1.8"])
|
28
|
+
else
|
29
|
+
s.add_dependency(%q<rspec>, ["~> 2.7.0"])
|
30
|
+
s.add_dependency(%q<activemerchant>, ["~> 1.8"])
|
31
|
+
end
|
32
|
+
else
|
33
|
+
s.add_dependency(%q<rspec>, ["~> 2.7.0"])
|
34
|
+
s.add_dependency(%q<activemerchant>, ["~> 1.8"])
|
35
|
+
end
|
36
|
+
end
|
@@ -0,0 +1,70 @@
|
|
1
|
+
module ActiveMerchant #:nodoc:
|
2
|
+
module Billing #:nodoc:
|
3
|
+
module Integrations #:nodoc:
|
4
|
+
module PayuIn
|
5
|
+
class Helper < ActiveMerchant::Billing::Integrations::Helper
|
6
|
+
|
7
|
+
mapping :amount, 'amount'
|
8
|
+
mapping :account, 'key'
|
9
|
+
mapping :order, 'txnid'
|
10
|
+
mapping :credential2, 'productinfo'
|
11
|
+
|
12
|
+
mapping :customer, :first_name => 'firstname',
|
13
|
+
:last_name => 'lastname',
|
14
|
+
:email => 'email',
|
15
|
+
:phone => 'phone'
|
16
|
+
|
17
|
+
mapping :billing_address, :city => 'city',
|
18
|
+
:address1 => 'address1',
|
19
|
+
:address2 => 'address2',
|
20
|
+
:state => 'state',
|
21
|
+
:zip => 'zip',
|
22
|
+
:country => 'country'
|
23
|
+
|
24
|
+
# Which tab you want to be open default on PayU
|
25
|
+
# CC (CreditCard) or NB (NetBanking)
|
26
|
+
mapping :mode, 'pg'
|
27
|
+
|
28
|
+
mapping :notify_url, 'notify_url'
|
29
|
+
mapping :return_url, :success => 'surl',
|
30
|
+
:failure => 'furl'
|
31
|
+
mapping :cancel_return_url, 'curl'
|
32
|
+
mapping :checksum, 'hash'
|
33
|
+
|
34
|
+
mapping :user_defined, { :var1 => 'udf1',
|
35
|
+
:var2 => 'udf2',
|
36
|
+
:var3 => 'udf3',
|
37
|
+
:var4 => 'udf4',
|
38
|
+
:var5 => 'udf5',
|
39
|
+
:var6 => 'udf6',
|
40
|
+
:var7 => 'udf7',
|
41
|
+
:var8 => 'udf8',
|
42
|
+
:var9 => 'udf9',
|
43
|
+
:var10 => 'udf10'
|
44
|
+
}
|
45
|
+
|
46
|
+
# Computes the checksum for the form data and add it to the field
|
47
|
+
def add_checksum( options = {} )
|
48
|
+
checksum_fields = [ :order, :amount, :credential2, { :customer => [ :first_name, :email ] },
|
49
|
+
{ :user_defined => [ :var1, :var2, :var3, :var4, :var5, :var6, :var7, :var8, :var9, :var10 ] } ]
|
50
|
+
checksum_payload_items = checksum_fields.inject( [] ) do | items, field |
|
51
|
+
if Hash === field then
|
52
|
+
key = field.keys.first
|
53
|
+
field[key].inject( items ){ |s,x| items.push( form_fields[ mappings[key][x] ] ) }
|
54
|
+
# items.push( form_fields[ field.values.each{ |x| mappings[ key ][ x ] } ] )
|
55
|
+
else
|
56
|
+
items.push( form_fields[ mappings[field] ] )
|
57
|
+
end
|
58
|
+
end
|
59
|
+
checksum_payload_items.push( options )
|
60
|
+
checksum = PayuIn.checksum( *checksum_payload_items )
|
61
|
+
add_field( mappings[:checksum], checksum )
|
62
|
+
return checksum_payload_items
|
63
|
+
end
|
64
|
+
|
65
|
+
end
|
66
|
+
|
67
|
+
end
|
68
|
+
end
|
69
|
+
end
|
70
|
+
end
|
@@ -0,0 +1,154 @@
|
|
1
|
+
module ActiveMerchant #:nodoc:
|
2
|
+
module Billing #:nodoc:
|
3
|
+
module Integrations #:nodoc:
|
4
|
+
module PayuIn
|
5
|
+
class Notification < ActiveMerchant::Billing::Integrations::Notification
|
6
|
+
|
7
|
+
# Was the transaction complete?
|
8
|
+
def complete?
|
9
|
+
status == "success"
|
10
|
+
end
|
11
|
+
|
12
|
+
# Status of the transaction. List of possible values:
|
13
|
+
# <tt>invalid</tt>:: transaction id is not present
|
14
|
+
# <tt>tampered</tt>:: transaction data has been tampered
|
15
|
+
# <tt>success</tt>:: transaction successful
|
16
|
+
# <tt>pending</tt>:: transaction is pending for some approval
|
17
|
+
# <tt>failure</tt>:: transaction failure
|
18
|
+
def status
|
19
|
+
@status ||= if checksum_ok?
|
20
|
+
if transaction_id.blank?
|
21
|
+
'invalid'
|
22
|
+
else
|
23
|
+
transaction_status.downcase
|
24
|
+
end
|
25
|
+
else
|
26
|
+
'tampered'
|
27
|
+
end.freeze
|
28
|
+
end
|
29
|
+
|
30
|
+
def invoice_ok?( order_id )
|
31
|
+
order_id.to_s == invoice.to_s
|
32
|
+
end
|
33
|
+
|
34
|
+
# Order amount should be equal to gross - discount
|
35
|
+
def amount_ok?( order_amount, order_discount = BigDecimal.new( '0.0' ) )
|
36
|
+
BigDecimal.new( gross ) == order_amount && BigDecimal.new( discount ) == order_discount
|
37
|
+
end
|
38
|
+
|
39
|
+
# Status of transaction return from the PayU. List of possible values:
|
40
|
+
# <tt>SUCCESS</tt>::
|
41
|
+
# <tt>PENDING</tt>::
|
42
|
+
# <tt>FAILURE</tt>::
|
43
|
+
def transaction_status
|
44
|
+
params['status']
|
45
|
+
end
|
46
|
+
|
47
|
+
# ID of this transaction (PayU.in number)
|
48
|
+
def transaction_id
|
49
|
+
params['mihpayid']
|
50
|
+
end
|
51
|
+
|
52
|
+
# Mode of Payment
|
53
|
+
#
|
54
|
+
# 'CC' for credit-card
|
55
|
+
# 'NB' for net-banking
|
56
|
+
# 'CD' for cheque or DD
|
57
|
+
# 'CO' for Cash Pickup
|
58
|
+
def type
|
59
|
+
params['mode']
|
60
|
+
end
|
61
|
+
|
62
|
+
# What currency have we been dealing with
|
63
|
+
def currency
|
64
|
+
'INR'
|
65
|
+
end
|
66
|
+
|
67
|
+
# This is the invoice which you passed to PayU.in
|
68
|
+
def invoice
|
69
|
+
params['txnid']
|
70
|
+
end
|
71
|
+
|
72
|
+
# Merchant Id provided by the PayU.in
|
73
|
+
def account
|
74
|
+
params['key']
|
75
|
+
end
|
76
|
+
|
77
|
+
# original amount send by merchant
|
78
|
+
def gross
|
79
|
+
params['amount']
|
80
|
+
end
|
81
|
+
|
82
|
+
# This is discount given to user - based on promotion set by merchants.
|
83
|
+
def discount
|
84
|
+
params['discount']
|
85
|
+
end
|
86
|
+
|
87
|
+
# Description offer for what PayU given the offer to user - based on promotion set by merchants.
|
88
|
+
def offer_description
|
89
|
+
params['offer']
|
90
|
+
end
|
91
|
+
|
92
|
+
# Information about the product as send by merchant
|
93
|
+
def product_info
|
94
|
+
params['productinfo']
|
95
|
+
end
|
96
|
+
|
97
|
+
# Email of the customer
|
98
|
+
def customer_email
|
99
|
+
params['email']
|
100
|
+
end
|
101
|
+
|
102
|
+
# Phone of the customer
|
103
|
+
def customer_phone
|
104
|
+
params['phone']
|
105
|
+
end
|
106
|
+
|
107
|
+
# Firstname of the customer
|
108
|
+
def customer_first_name
|
109
|
+
params['firstname']
|
110
|
+
end
|
111
|
+
|
112
|
+
# Lastname of the customer
|
113
|
+
def customer_last_name
|
114
|
+
params['lastname']
|
115
|
+
end
|
116
|
+
|
117
|
+
# Full address of the customer
|
118
|
+
def customer_address
|
119
|
+
{ :address1 => params['address1'], :address2 => params['address2'],
|
120
|
+
:city => params['city'], :state => params['state'],
|
121
|
+
:country => params['country'], :zipcode => params['zipcode'] }
|
122
|
+
end
|
123
|
+
|
124
|
+
def user_defined
|
125
|
+
return @user_defined if @user_defined
|
126
|
+
@user_defined = []
|
127
|
+
10.times{ |i| @user_defined.push( params[ "udf#{i+1}" ] ) }
|
128
|
+
@user_defined
|
129
|
+
end
|
130
|
+
|
131
|
+
def checksum
|
132
|
+
params['hash']
|
133
|
+
end
|
134
|
+
|
135
|
+
def message
|
136
|
+
@message || params['error']
|
137
|
+
end
|
138
|
+
|
139
|
+
def checksum_ok?
|
140
|
+
fields = user_defined.dup.push( customer_email, customer_first_name, product_info, gross, invoice, :reverse => true )
|
141
|
+
fields.unshift( transaction_status )
|
142
|
+
unless PayuIn.checksum( *fields ) == checksum
|
143
|
+
@message = 'Return checksum not matching the data provided'
|
144
|
+
return false
|
145
|
+
end
|
146
|
+
return true
|
147
|
+
end
|
148
|
+
|
149
|
+
end
|
150
|
+
end
|
151
|
+
end
|
152
|
+
end
|
153
|
+
end
|
154
|
+
|
@@ -0,0 +1,56 @@
|
|
1
|
+
module ActiveMerchant #:nodoc:
|
2
|
+
module Billing #:nodoc:
|
3
|
+
module Integrations #:nodoc:
|
4
|
+
module PayuIn
|
5
|
+
class Return < ActiveMerchant::Billing::Integrations::Return
|
6
|
+
|
7
|
+
def initialize(query_string, options = {})
|
8
|
+
@notification = Notification.new(query_string, options)
|
9
|
+
end
|
10
|
+
|
11
|
+
# PayU Transaction Id
|
12
|
+
#
|
13
|
+
def transaction_id
|
14
|
+
@notification.transaction_id
|
15
|
+
end
|
16
|
+
|
17
|
+
# Returns the status of the transaction as a string
|
18
|
+
# The status can be one of the following
|
19
|
+
#
|
20
|
+
# invalid - transaction id not present
|
21
|
+
# tampered - checksum does not mismatch
|
22
|
+
# mismatch - order id mismatch
|
23
|
+
# success - transaction success
|
24
|
+
# pending - transaction pending
|
25
|
+
# failure - transaction failure
|
26
|
+
#
|
27
|
+
# payu does not put the discount field in the checksum
|
28
|
+
# it can be easily forged by the attacker without detection
|
29
|
+
#
|
30
|
+
def status( order_id, order_amount )
|
31
|
+
if @notification.invoice_ok?( order_id ) && @notification.amount_ok?( order_amount )
|
32
|
+
@notification.status
|
33
|
+
else
|
34
|
+
'mismatch'.freeze
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
# check success of the transaction
|
39
|
+
# check order_id and
|
40
|
+
def success?( order_id, order_amount )
|
41
|
+
status( order_id, order_amount ) == 'success'
|
42
|
+
end
|
43
|
+
|
44
|
+
def cancelled?
|
45
|
+
false
|
46
|
+
end
|
47
|
+
|
48
|
+
def message
|
49
|
+
@notification.message
|
50
|
+
end
|
51
|
+
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
@@ -0,0 +1,48 @@
|
|
1
|
+
module ActiveMerchant
|
2
|
+
module Billing
|
3
|
+
module Integrations
|
4
|
+
module PayuIn
|
5
|
+
def self.version
|
6
|
+
VERSION
|
7
|
+
end
|
8
|
+
|
9
|
+
module VERSION
|
10
|
+
extend Comparable
|
11
|
+
|
12
|
+
MAJOR = 0
|
13
|
+
MINOR = 0
|
14
|
+
TINY = 1
|
15
|
+
SIGNATURE = [MAJOR, MINOR, TINY]
|
16
|
+
STRING = SIGNATURE.join '.'
|
17
|
+
|
18
|
+
def self.major; MAJOR end
|
19
|
+
def self.minor; MINOR end
|
20
|
+
def self.tiny; TINY end
|
21
|
+
def self.to_s; STRING end
|
22
|
+
|
23
|
+
def self.hash
|
24
|
+
STRING.hash
|
25
|
+
end
|
26
|
+
|
27
|
+
def self.<=>(other)
|
28
|
+
other = other.split('.').map { |i| i.to_i } if other.respond_to? :split
|
29
|
+
SIGNATURE <=> Array(other)
|
30
|
+
end
|
31
|
+
|
32
|
+
def self.inspect
|
33
|
+
STRING.inspect
|
34
|
+
end
|
35
|
+
|
36
|
+
def self.respond_to?(meth, *)
|
37
|
+
meth.to_s !~ /^__|^to_str$/ and STRING.respond_to? meth unless super
|
38
|
+
end
|
39
|
+
|
40
|
+
def self.method_missing(meth, *args, &block)
|
41
|
+
return super unless STRING.respond_to?(meth)
|
42
|
+
STRING.send(meth, *args, &block)
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
@@ -0,0 +1,89 @@
|
|
1
|
+
require 'net/http'
|
2
|
+
require 'php_serialize'
|
3
|
+
|
4
|
+
module ActiveMerchant #:nodoc:
|
5
|
+
module Billing #:nodoc:
|
6
|
+
module Integrations #:nodoc:
|
7
|
+
module PayuIn
|
8
|
+
|
9
|
+
# PayU.in provides web services to help you with reconciliation of your transactions in real time.
|
10
|
+
class WebService < Hash
|
11
|
+
|
12
|
+
# Add helper method to make api calls using ssl_post, ssl_get
|
13
|
+
include PostsData
|
14
|
+
|
15
|
+
# Whether the invoice is success or not
|
16
|
+
# Invoice id is required when multiple invoices are queried at once
|
17
|
+
def complete?( invoice_id = nil )
|
18
|
+
status( invoice_id ).to_s.downcase == 'success'
|
19
|
+
end
|
20
|
+
|
21
|
+
# Whether the invoice is pending confirmation
|
22
|
+
# Invoice id is required when multiple invoices are queried at once
|
23
|
+
def pending?( invoice_id = nil )
|
24
|
+
status( invoice_id ).to_s.downcase == 'pending'
|
25
|
+
end
|
26
|
+
|
27
|
+
# Returns the payment status of the invoice
|
28
|
+
# invoice_id is required if multiple invoices are queried at once
|
29
|
+
def status( invoice_id = nil )
|
30
|
+
( invoice_id ? self[ invoice_id.to_s ] : self )[ 'status']
|
31
|
+
end
|
32
|
+
|
33
|
+
# Returns whether the order amount and order discount matches
|
34
|
+
# generally in third party shopping carts order discount is handle by the application
|
35
|
+
# and should generally by 0.0
|
36
|
+
def amount_ok?( order_amount, order_discount = BigDecimal.new( '0.0' ), invoice_id = nil )
|
37
|
+
hash = ( invoice_id ? self[ invoice_id.to_s ] : self )
|
38
|
+
( BigDecimal.new( hash[ 'amt' ] ) == order_amount ) && ( BigDecimal.new( hash[ 'disc' ] ) == order_discount )
|
39
|
+
end
|
40
|
+
|
41
|
+
# Returns whether the nett amount after reducing the discounts
|
42
|
+
def nett_amount( invoice_id = nil )
|
43
|
+
hash = ( invoice_id ? self[ invoice_id.to_s ] : self )
|
44
|
+
BigDecimal.new( hash[ 'amt' ] ) - BigDecimal.new( hash[ 'disc' ] )
|
45
|
+
end
|
46
|
+
|
47
|
+
# Returns the PayU.in transaction if for the invocie
|
48
|
+
# invoice_id is required if multiple invoices are queried at once
|
49
|
+
def transaction_id( invoice_id = nil )
|
50
|
+
( invoice_id ? self[ invoice_id.to_s ] : self )[ 'mihpayid']
|
51
|
+
end
|
52
|
+
|
53
|
+
# Makes verify payment API call to PayU.in web service
|
54
|
+
# Params - any number of invoice ids ( provided by the merchant )
|
55
|
+
def self.verify_payment( *invoice_ids )
|
56
|
+
invoice_string = invoice_ids.join( '|' )
|
57
|
+
checksum = PayuIn.checksum( 'verify_payment', invoice_string )
|
58
|
+
new.web_service_call( :command => 'verify_payment', :var1 => invoice_string, :hash => checksum, :key => PayuIn.merchant_id )
|
59
|
+
end
|
60
|
+
|
61
|
+
# Makes check payment API call to PayU.in web service
|
62
|
+
# Params - PayU.in transaction id
|
63
|
+
def self.check_payment( payu_id )
|
64
|
+
checksum = PayuIn.checksum( 'check_payment', payu_id )
|
65
|
+
new.web_service_call( :command => 'check_payment', :var1 => payu_id, :hash => checksum, :key => PayuIn.merchant_id )
|
66
|
+
end
|
67
|
+
|
68
|
+
# Utility method which makes the web service call and
|
69
|
+
# parse the response into WebService object
|
70
|
+
def web_service_call( params = {} )
|
71
|
+
payload_hash = ActiveMerchant::PostData.new
|
72
|
+
payload_hash.merge!( params )
|
73
|
+
payload = payload_hash.to_post_data
|
74
|
+
response = PHP.unserialize(
|
75
|
+
ssl_post(
|
76
|
+
PayuIn.web_service_url, payload,
|
77
|
+
'Content-Length' => "#{payload.size}",
|
78
|
+
'User-Agent' => "Active Merchant -- http://activemerchant.org",
|
79
|
+
'service_provider' => "payu_paisa"
|
80
|
+
)
|
81
|
+
)
|
82
|
+
merge!( response["transaction_details"] && response["transaction_details"].size == 1 ? response["transaction_details"].values.first : ( response["transaction_details"] || { :status => response['msg'] } ) )
|
83
|
+
end
|
84
|
+
|
85
|
+
end
|
86
|
+
end
|
87
|
+
end
|
88
|
+
end
|
89
|
+
end
|
@@ -0,0 +1,108 @@
|
|
1
|
+
require 'active_merchant'
|
2
|
+
require 'active_merchant/billing/integrations'
|
3
|
+
require 'digest/sha2'
|
4
|
+
require 'bigdecimal'
|
5
|
+
|
6
|
+
module ActiveMerchant #:nodoc:
|
7
|
+
module Billing #:nodoc:
|
8
|
+
module Integrations #:nodoc:
|
9
|
+
module PayuIn
|
10
|
+
autoload :Return, 'active_merchant/payu_in/return.rb'
|
11
|
+
autoload :Helper, 'active_merchant/payu_in/helper.rb'
|
12
|
+
autoload :Notification, 'active_merchant/payu_in/notification.rb'
|
13
|
+
autoload :WebService, 'active_merchant/payu_in/web_service.rb'
|
14
|
+
|
15
|
+
mattr_accessor :merchant_id
|
16
|
+
mattr_accessor :secret_key
|
17
|
+
|
18
|
+
# Overwrite this if you want to change the PayU.in test url
|
19
|
+
mattr_accessor :test_url
|
20
|
+
self.test_url = 'https://test.payu.in/_payment.php'
|
21
|
+
|
22
|
+
# Overwrite this if you want to change the PayU.in test web
|
23
|
+
# service url
|
24
|
+
mattr_accessor :test_web_service_url
|
25
|
+
self.test_web_service_url = 'https://test.payu.in/merchant/postservice.php'
|
26
|
+
|
27
|
+
# Overwrite this if you want to change the PayU.in production url
|
28
|
+
mattr_accessor :production_url
|
29
|
+
self.production_url = 'https://secure.payu.in/_payment.php'
|
30
|
+
|
31
|
+
# Overwrite this if you want to change the PayU.in production web
|
32
|
+
# service url
|
33
|
+
mattr_accessor :production_web_service_url
|
34
|
+
self.production_web_service_url = 'https://info.payu.in/merchant/postservice.php'
|
35
|
+
|
36
|
+
def self.new( options = {} )
|
37
|
+
self.merchant_id = options[:merchant_id]
|
38
|
+
self.secret_key = options[:secret_key]
|
39
|
+
self
|
40
|
+
end
|
41
|
+
|
42
|
+
def self.service_url
|
43
|
+
mode = ActiveMerchant::Billing::Base.integration_mode
|
44
|
+
case mode
|
45
|
+
when :production
|
46
|
+
self.production_url
|
47
|
+
when :test
|
48
|
+
self.test_url
|
49
|
+
else
|
50
|
+
raise StandardError, "Integration mode set to an invalid value: #{mode}"
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
def self.web_service_url
|
55
|
+
mode = ActiveMerchant::Billing::Base.integration_mode
|
56
|
+
case mode
|
57
|
+
when :production
|
58
|
+
self.production_web_service_url
|
59
|
+
when :test
|
60
|
+
self.test_web_service_url
|
61
|
+
else
|
62
|
+
raise StandardError, "Integration mode set to an invalid value: #{mode}"
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
# Query the PayU server using there web services
|
67
|
+
def self.query( command, *args )
|
68
|
+
WebService.send( command, *args )
|
69
|
+
end
|
70
|
+
|
71
|
+
def self.return(query_string, options = {})
|
72
|
+
Return.new(query_string, options)
|
73
|
+
end
|
74
|
+
|
75
|
+
def self.checksum( *payload_items )
|
76
|
+
options = payload_items.pop if Hash === payload_items.last
|
77
|
+
options ||= {}
|
78
|
+
payload = if options[:reverse] then
|
79
|
+
payload_items.dup.push( self.merchant_id || "" ).unshift( self.secret_key || "" ).collect{ |x| trim(x) }.join("|")
|
80
|
+
else
|
81
|
+
payload_items.dup.unshift( self.merchant_id || "" ).push( self.secret_key || "" ).collect{ |x| trim(x) }.join("|")
|
82
|
+
end
|
83
|
+
if options[:debug]
|
84
|
+
puts "-"*80
|
85
|
+
puts payload
|
86
|
+
puts "-"*80
|
87
|
+
end
|
88
|
+
Digest::SHA512.hexdigest( payload )
|
89
|
+
end
|
90
|
+
|
91
|
+
# PayU uses php trim when building the string to compute the checksum
|
92
|
+
# trim removes whitespaces from start and end of the string
|
93
|
+
# and floats cannot have trailing zeros
|
94
|
+
def self.trim(obj)
|
95
|
+
# if (BigDecimal === obj)
|
96
|
+
# obj.to_s('F')
|
97
|
+
# else
|
98
|
+
# obj.to_s
|
99
|
+
# end.strip.gsub(/(\\d+)\\.0$/){ $1 }.gsub(/(\\d+)(\\.[1-9]+)0+$/){ $1+$2 }
|
100
|
+
obj.to_s
|
101
|
+
end
|
102
|
+
|
103
|
+
end
|
104
|
+
end
|
105
|
+
end
|
106
|
+
end
|
107
|
+
|
108
|
+
require 'active_merchant/payu_in/version'
|
@@ -0,0 +1,313 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
# Copyright (c) 2003-2009 Thomas Hurst <tom@hur.st>
|
3
|
+
#
|
4
|
+
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
5
|
+
# of this software and associated documentation files (the "Software"), to deal
|
6
|
+
# in the Software without restriction, including without limitation the rights
|
7
|
+
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
8
|
+
# copies of the Software, and to permit persons to whom the Software is
|
9
|
+
# furnished to do so, subject to the following conditions:
|
10
|
+
#
|
11
|
+
# The above copyright notice and this permission notice shall be included in
|
12
|
+
# all copies or substantial portions of the Software.
|
13
|
+
#
|
14
|
+
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
15
|
+
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
16
|
+
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
17
|
+
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
18
|
+
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
19
|
+
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
20
|
+
# SOFTWARE.
|
21
|
+
|
22
|
+
# PHP serialize() and unserialize() workalikes
|
23
|
+
#
|
24
|
+
# Release History:
|
25
|
+
# 1.0.0 - 2003-06-02 - First release.
|
26
|
+
# 1.0.1 - 2003-06-16 - Minor bugfixes.
|
27
|
+
# 1.0.2 - 2004-09-17 - Switch all {}'s to explicit Hash.new's.
|
28
|
+
# 1.1.0 - 2009-04-01 - Pass assoc to recursive calls (thanks to Edward Speyer).
|
29
|
+
# - Serialize Symbol like String.
|
30
|
+
# - Add testsuite.
|
31
|
+
# - Instantiate auto-generated Structs properly (thanks
|
32
|
+
# to Philip Hallstrom).
|
33
|
+
# - Unserialize arrays properly in assoc mode.
|
34
|
+
# - Add PHP session support (thanks to TJ Vanderpoel).
|
35
|
+
# - Release as tarball and gem.
|
36
|
+
#
|
37
|
+
# See http://www.php.net/serialize and http://www.php.net/unserialize for
|
38
|
+
# details on the PHP side of all this.
|
39
|
+
module PHP
|
40
|
+
# string = PHP.serialize(mixed var[, bool assoc])
|
41
|
+
#
|
42
|
+
# Returns a string representing the argument in a form PHP.unserialize
|
43
|
+
# and PHP's unserialize() should both be able to load.
|
44
|
+
#
|
45
|
+
# Array, Hash, Fixnum, Float, True/FalseClass, NilClass, String and Struct
|
46
|
+
# are supported; as are objects which support the to_assoc method, which
|
47
|
+
# returns an array of the form [['attr_name', 'value']..]. Anything else
|
48
|
+
# will raise a TypeError.
|
49
|
+
#
|
50
|
+
# If 'assoc' is specified, Array's who's first element is a two value
|
51
|
+
# array will be assumed to be an associative array, and will be serialized
|
52
|
+
# as a PHP associative array rather than a multidimensional array.
|
53
|
+
def PHP.serialize(var, assoc = false) # {{{
|
54
|
+
s = ''
|
55
|
+
case var
|
56
|
+
when Array
|
57
|
+
s << "a:#{var.size}:{"
|
58
|
+
if assoc and var.first.is_a?(Array) and var.first.size == 2
|
59
|
+
var.each { |k,v|
|
60
|
+
s << PHP.serialize(k, assoc) << PHP.serialize(v, assoc)
|
61
|
+
}
|
62
|
+
else
|
63
|
+
var.each_with_index { |v,i|
|
64
|
+
s << "i:#{i};#{PHP.serialize(v, assoc)}"
|
65
|
+
}
|
66
|
+
end
|
67
|
+
|
68
|
+
s << '}'
|
69
|
+
|
70
|
+
when Hash
|
71
|
+
s << "a:#{var.size}:{"
|
72
|
+
var.each do |k,v|
|
73
|
+
s << "#{PHP.serialize(k, assoc)}#{PHP.serialize(v, assoc)}"
|
74
|
+
end
|
75
|
+
s << '}'
|
76
|
+
|
77
|
+
when Struct
|
78
|
+
# encode as Object with same name
|
79
|
+
s << "O:#{var.class.to_s.length}:\"#{var.class.to_s.downcase}\":#{var.members.length}:{"
|
80
|
+
var.members.each do |member|
|
81
|
+
s << "#{PHP.serialize(member, assoc)}#{PHP.serialize(var[member], assoc)}"
|
82
|
+
end
|
83
|
+
s << '}'
|
84
|
+
|
85
|
+
when String, Symbol
|
86
|
+
s << "s:#{var.to_s.bytesize}:\"#{var.to_s}\";"
|
87
|
+
|
88
|
+
when Fixnum # PHP doesn't have bignums
|
89
|
+
s << "i:#{var};"
|
90
|
+
|
91
|
+
when Float
|
92
|
+
s << "d:#{var};"
|
93
|
+
|
94
|
+
when NilClass
|
95
|
+
s << 'N;'
|
96
|
+
|
97
|
+
when FalseClass, TrueClass
|
98
|
+
s << "b:#{var ? 1 :0};"
|
99
|
+
|
100
|
+
else
|
101
|
+
if var.respond_to?(:to_assoc)
|
102
|
+
v = var.to_assoc
|
103
|
+
# encode as Object with same name
|
104
|
+
s << "O:#{var.class.to_s.length}:\"#{var.class.to_s.downcase}\":#{v.length}:{"
|
105
|
+
v.each do |k,v|
|
106
|
+
s << "#{PHP.serialize(k.to_s, assoc)}#{PHP.serialize(v, assoc)}"
|
107
|
+
end
|
108
|
+
s << '}'
|
109
|
+
else
|
110
|
+
raise TypeError, "Unable to serialize type #{var.class}"
|
111
|
+
end
|
112
|
+
end
|
113
|
+
|
114
|
+
s
|
115
|
+
end # }}}
|
116
|
+
|
117
|
+
# string = PHP.serialize_session(mixed var[, bool assoc])
|
118
|
+
#
|
119
|
+
# Like PHP.serialize, but only accepts a Hash or associative Array as the root
|
120
|
+
# type. The results are returned in PHP session format.
|
121
|
+
def PHP.serialize_session(var, assoc = false) # {{{
|
122
|
+
s = ''
|
123
|
+
case var
|
124
|
+
when Hash
|
125
|
+
var.each do |key,value|
|
126
|
+
if key.to_s =~ /\|/
|
127
|
+
raise IndexError, "Top level names may not contain pipes"
|
128
|
+
end
|
129
|
+
s << "#{key}|#{PHP.serialize(value, assoc)}"
|
130
|
+
end
|
131
|
+
when Array
|
132
|
+
var.each do |x|
|
133
|
+
case x
|
134
|
+
when Array
|
135
|
+
if x.size == 2
|
136
|
+
s << "#{x[0]}|#{PHP.serialize(x[1])}"
|
137
|
+
else
|
138
|
+
raise TypeError, "Array is not associative"
|
139
|
+
end
|
140
|
+
end
|
141
|
+
end
|
142
|
+
else
|
143
|
+
raise TypeError, "Unable to serialize sessions with top level types other than Hash and associative Array"
|
144
|
+
end
|
145
|
+
s
|
146
|
+
end # }}}
|
147
|
+
|
148
|
+
# mixed = PHP.unserialize(string serialized, [hash classmap, [bool assoc]])
|
149
|
+
#
|
150
|
+
# Returns an object containing the reconstituted data from serialized.
|
151
|
+
#
|
152
|
+
# If a PHP array (associative; like an ordered hash) is encountered, it
|
153
|
+
# scans the keys; if they're all incrementing integers counting from 0,
|
154
|
+
# it's unserialized as an Array, otherwise it's unserialized as a Hash.
|
155
|
+
# Note: this will lose ordering. To avoid this, specify assoc=true,
|
156
|
+
# and it will be unserialized as an associative array: [[key,value],...]
|
157
|
+
#
|
158
|
+
# If a serialized object is encountered, the hash 'classmap' is searched for
|
159
|
+
# the class name (as a symbol). Since PHP classnames are not case-preserving,
|
160
|
+
# this *must* be a .capitalize()d representation. The value is expected
|
161
|
+
# to be the class itself; i.e. something you could call .new on.
|
162
|
+
#
|
163
|
+
# If it's not found in 'classmap', the current constant namespace is searched,
|
164
|
+
# and failing that, a new Struct(classname) is generated, with the arguments
|
165
|
+
# for .new specified in the same order PHP provided; since PHP uses hashes
|
166
|
+
# to represent attributes, this should be the same order they're specified
|
167
|
+
# in PHP, but this is untested.
|
168
|
+
#
|
169
|
+
# each serialized attribute is sent to the new object using the respective
|
170
|
+
# {attribute}=() method; you'll get a NameError if the method doesn't exist.
|
171
|
+
#
|
172
|
+
# Array, Hash, Fixnum, Float, True/FalseClass, NilClass and String should
|
173
|
+
# be returned identically (i.e. foo == PHP.unserialize(PHP.serialize(foo))
|
174
|
+
# for these types); Struct should be too, provided it's in the namespace
|
175
|
+
# Module.const_get within unserialize() can see, or you gave it the same
|
176
|
+
# name in the Struct.new(<structname>), otherwise you should provide it in
|
177
|
+
# classmap.
|
178
|
+
#
|
179
|
+
# Note: StringIO is required for unserialize(); it's loaded as needed
|
180
|
+
def PHP.unserialize(string, classmap = nil, assoc = false) # {{{
|
181
|
+
if classmap == true or classmap == false
|
182
|
+
assoc = classmap
|
183
|
+
classmap = {}
|
184
|
+
end
|
185
|
+
classmap ||= {}
|
186
|
+
|
187
|
+
require 'stringio'
|
188
|
+
string = StringIO.new(string)
|
189
|
+
def string.read_until(char)
|
190
|
+
val = ''
|
191
|
+
while (c = self.read(1)) != char
|
192
|
+
val << c
|
193
|
+
end
|
194
|
+
val
|
195
|
+
end
|
196
|
+
|
197
|
+
if string.string =~ /^(\w+)\|/ # session_name|serialized_data
|
198
|
+
ret = Hash.new
|
199
|
+
loop do
|
200
|
+
if string.string[string.pos, 32] =~ /^(\w+)\|/
|
201
|
+
string.pos += $&.size
|
202
|
+
ret[$1] = PHP.do_unserialize(string, classmap, assoc)
|
203
|
+
else
|
204
|
+
break
|
205
|
+
end
|
206
|
+
end
|
207
|
+
ret
|
208
|
+
else
|
209
|
+
PHP.do_unserialize(string, classmap, assoc)
|
210
|
+
end
|
211
|
+
end
|
212
|
+
|
213
|
+
private
|
214
|
+
def PHP.do_unserialize(string, classmap, assoc)
|
215
|
+
val = nil
|
216
|
+
# determine a type
|
217
|
+
type = string.read(2)[0,1]
|
218
|
+
case type
|
219
|
+
when 'a' # associative array, a:length:{[index][value]...}
|
220
|
+
count = string.read_until('{').to_i
|
221
|
+
val = vals = Array.new
|
222
|
+
count.times do |i|
|
223
|
+
vals << [do_unserialize(string, classmap, assoc), do_unserialize(string, classmap, assoc)]
|
224
|
+
end
|
225
|
+
string.read(1) # skip the ending }
|
226
|
+
|
227
|
+
# now, we have an associative array, let's clean it up a bit...
|
228
|
+
# arrays have all numeric indexes, in order; otherwise we assume a hash
|
229
|
+
array = true
|
230
|
+
i = 0
|
231
|
+
vals.each do |key,value|
|
232
|
+
if key != i # wrong index -> assume hash
|
233
|
+
array = false
|
234
|
+
break
|
235
|
+
end
|
236
|
+
i += 1
|
237
|
+
end
|
238
|
+
|
239
|
+
if array
|
240
|
+
vals.collect! do |key,value|
|
241
|
+
value
|
242
|
+
end
|
243
|
+
else
|
244
|
+
if assoc
|
245
|
+
val = vals.map {|v| v }
|
246
|
+
else
|
247
|
+
val = Hash.new
|
248
|
+
vals.each do |key,value|
|
249
|
+
val[key] = value
|
250
|
+
end
|
251
|
+
end
|
252
|
+
end
|
253
|
+
|
254
|
+
when 'O' # object, O:length:"class":length:{[attribute][value]...}
|
255
|
+
# class name (lowercase in PHP, grr)
|
256
|
+
len = string.read_until(':').to_i + 3 # quotes, seperator
|
257
|
+
klass = string.read(len)[1...-2].capitalize.intern # read it, kill useless quotes
|
258
|
+
|
259
|
+
# read the attributes
|
260
|
+
attrs = []
|
261
|
+
len = string.read_until('{').to_i
|
262
|
+
|
263
|
+
len.times do
|
264
|
+
attr = (do_unserialize(string, classmap, assoc))
|
265
|
+
attrs << [attr.intern, (attr << '=').intern, do_unserialize(string, classmap, assoc)]
|
266
|
+
end
|
267
|
+
string.read(1)
|
268
|
+
|
269
|
+
val = nil
|
270
|
+
# See if we need to map to a particular object
|
271
|
+
if classmap.has_key?(klass)
|
272
|
+
val = classmap[klass].new
|
273
|
+
elsif Struct.const_defined?(klass) # Nope; see if there's a Struct
|
274
|
+
classmap[klass] = val = Struct.const_get(klass)
|
275
|
+
val = val.new
|
276
|
+
else # Nope; see if there's a Constant
|
277
|
+
begin
|
278
|
+
classmap[klass] = val = Module.const_get(klass)
|
279
|
+
|
280
|
+
val = val.new
|
281
|
+
rescue NameError # Nope; make a new Struct
|
282
|
+
classmap[klass] = Struct.new(klass.to_s, *attrs.collect { |v| v[0].to_s })
|
283
|
+
val = val.new
|
284
|
+
end
|
285
|
+
end
|
286
|
+
|
287
|
+
attrs.each do |attr,attrassign,v|
|
288
|
+
val.__send__(attrassign, v)
|
289
|
+
end
|
290
|
+
|
291
|
+
when 's' # string, s:length:"data";
|
292
|
+
len = string.read_until(':').to_i + 3 # quotes, separator
|
293
|
+
val = string.read(len)[1...-2] # read it, kill useless quotes
|
294
|
+
|
295
|
+
when 'i' # integer, i:123
|
296
|
+
val = string.read_until(';').to_i
|
297
|
+
|
298
|
+
when 'd' # double (float), d:1.23
|
299
|
+
val = string.read_until(';').to_f
|
300
|
+
|
301
|
+
when 'N' # NULL, N;
|
302
|
+
val = nil
|
303
|
+
|
304
|
+
when 'b' # bool, b:0 or 1
|
305
|
+
val = (string.read(2)[0] == ?1 ? true : false)
|
306
|
+
|
307
|
+
else
|
308
|
+
raise TypeError, "Unable to unserialize type '#{type}'"
|
309
|
+
end
|
310
|
+
|
311
|
+
val
|
312
|
+
end # }}}
|
313
|
+
end
|
Binary file
|
metadata
ADDED
@@ -0,0 +1,92 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: active_merchant_payumoney_com
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.1
|
5
|
+
prerelease:
|
6
|
+
platform: ruby
|
7
|
+
authors:
|
8
|
+
- Ram Singla
|
9
|
+
autorequire:
|
10
|
+
bindir: bin
|
11
|
+
cert_chain: []
|
12
|
+
date: 2014-01-31 00:00:00.000000000 Z
|
13
|
+
dependencies:
|
14
|
+
- !ruby/object:Gem::Dependency
|
15
|
+
name: rspec
|
16
|
+
requirement: !ruby/object:Gem::Requirement
|
17
|
+
none: false
|
18
|
+
requirements:
|
19
|
+
- - ~>
|
20
|
+
- !ruby/object:Gem::Version
|
21
|
+
version: 2.7.0
|
22
|
+
type: :development
|
23
|
+
prerelease: false
|
24
|
+
version_requirements: !ruby/object:Gem::Requirement
|
25
|
+
none: false
|
26
|
+
requirements:
|
27
|
+
- - ~>
|
28
|
+
- !ruby/object:Gem::Version
|
29
|
+
version: 2.7.0
|
30
|
+
- !ruby/object:Gem::Dependency
|
31
|
+
name: activemerchant
|
32
|
+
requirement: !ruby/object:Gem::Requirement
|
33
|
+
none: false
|
34
|
+
requirements:
|
35
|
+
- - ~>
|
36
|
+
- !ruby/object:Gem::Version
|
37
|
+
version: '1.8'
|
38
|
+
type: :runtime
|
39
|
+
prerelease: false
|
40
|
+
version_requirements: !ruby/object:Gem::Requirement
|
41
|
+
none: false
|
42
|
+
requirements:
|
43
|
+
- - ~>
|
44
|
+
- !ruby/object:Gem::Version
|
45
|
+
version: '1.8'
|
46
|
+
description: PayUMoney.com Payment Gateway integration for ActiveMerchant
|
47
|
+
email:
|
48
|
+
- ram.singla@gmail.com
|
49
|
+
executables: []
|
50
|
+
extensions: []
|
51
|
+
extra_rdoc_files: []
|
52
|
+
files:
|
53
|
+
- .gitignore
|
54
|
+
- Gemfile
|
55
|
+
- License
|
56
|
+
- Rakefile
|
57
|
+
- active_merchant_payu_in.gemspec
|
58
|
+
- lib/active_merchant/payu_in/helper.rb
|
59
|
+
- lib/active_merchant/payu_in/notification.rb
|
60
|
+
- lib/active_merchant/payu_in/return.rb
|
61
|
+
- lib/active_merchant/payu_in/version.rb
|
62
|
+
- lib/active_merchant/payu_in/web_service.rb
|
63
|
+
- lib/active_merchant_payu_in.rb
|
64
|
+
- lib/php_serialize.rb
|
65
|
+
- pkg/active_merchant_payu_in-0.0.1.gem
|
66
|
+
- spec/active_merchant_payu_in_spec.rb
|
67
|
+
homepage: http://www.payumoney.com
|
68
|
+
licenses: []
|
69
|
+
post_install_message:
|
70
|
+
rdoc_options: []
|
71
|
+
require_paths:
|
72
|
+
- lib
|
73
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
74
|
+
none: false
|
75
|
+
requirements:
|
76
|
+
- - ! '>='
|
77
|
+
- !ruby/object:Gem::Version
|
78
|
+
version: '0'
|
79
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
80
|
+
none: false
|
81
|
+
requirements:
|
82
|
+
- - ! '>='
|
83
|
+
- !ruby/object:Gem::Version
|
84
|
+
version: '0'
|
85
|
+
requirements: []
|
86
|
+
rubyforge_project: active_merchant_payumoney_com
|
87
|
+
rubygems_version: 1.8.23
|
88
|
+
signing_key:
|
89
|
+
specification_version: 3
|
90
|
+
summary: PayUMoney.com Payment Gateweay Integration Kit
|
91
|
+
test_files: []
|
92
|
+
has_rdoc:
|