payment_gateway_solutions 0.0.1
Sign up to get free protection for your applications and to get access to all the features.
- data/lib/gateway_card.rb +50 -0
- data/lib/gateway_customer.rb +86 -0
- data/lib/gateway_customer_profile.rb +10 -0
- data/lib/gateway_errors.rb +97 -0
- data/lib/payment_gateway.rb +8 -0
- data/lib/transaction_gateway/authorize_net_gateway.rb +125 -0
- data/lib/transaction_gateway/braintree_gateway.rb +146 -0
- data/lib/transaction_gateway/fortis_gateway.rb +141 -0
- data/lib/transaction_gateway/result.rb +79 -0
- metadata +101 -0
data/lib/gateway_card.rb
ADDED
@@ -0,0 +1,50 @@
|
|
1
|
+
class GatewayCard
|
2
|
+
include GatewayErrors
|
3
|
+
|
4
|
+
attr_accessor :card_number, :cvv, :expiration_month, :expiration_year
|
5
|
+
|
6
|
+
def initialize(card_number, cvv, expiration_month, expiration_year)
|
7
|
+
self.card_number = card_number.to_s.gsub(/\s/, "")
|
8
|
+
self.cvv = cvv.to_s
|
9
|
+
self.expiration_month = expiration_month.to_s
|
10
|
+
self.expiration_year = format('%04d', expiration_year)
|
11
|
+
|
12
|
+
self.validate
|
13
|
+
end
|
14
|
+
|
15
|
+
def validate
|
16
|
+
######## Card Number Validation ##########
|
17
|
+
######## start ##########
|
18
|
+
raise CardNumberInvalid unless self.card_number =~ /^\d+$/ # Ensure card contains only digits
|
19
|
+
|
20
|
+
######## LUHN ALGORITHM TO CHECK CARD NUMBER #######
|
21
|
+
######## start ########
|
22
|
+
arr = card.split('').reverse.each_with_index.map {|d, index| (index.odd? ? 2*(d.to_i) : d.to_i)}
|
23
|
+
raise CardNumberInvalid unless (arr.join.split('').inject(0) {|tot, d| tot + d.to_i}) % 10 == 0
|
24
|
+
######## end ##########
|
25
|
+
######## end ##########
|
26
|
+
|
27
|
+
######## CVV Validation #########
|
28
|
+
raise CardCVVInvalid if (self.cvv != "") and (!(self.cvv =~ /^\d+$/ ) or self.cvv.length > 4 or self.cvv.to_i == 0)
|
29
|
+
|
30
|
+
######## Expiration Month Validation #########
|
31
|
+
raise CardExpirationMonthInvalid unless [1..12].index(self.expiration_month.to_i)
|
32
|
+
|
33
|
+
######## Expiration Year Validation #########
|
34
|
+
######## start #########
|
35
|
+
raise CardExpirationYearInvalid if (!(self.expiration_year =~ /^\d+$/ ) or self.expiration_year.length > 4 or self.expiration_year.to_i == 0)
|
36
|
+
|
37
|
+
begin
|
38
|
+
self.expiration_year = Date.parse(self.expiration_year.to_s + "0101").strftime("%y")
|
39
|
+
rescue
|
40
|
+
raise CardExpirationYearInvalid
|
41
|
+
end
|
42
|
+
######## end ##########
|
43
|
+
|
44
|
+
raise CardExpireError if (self.expiration_month + self.expiration_year).to_i < Time.now.strftime("%m%y")
|
45
|
+
end
|
46
|
+
|
47
|
+
def authorize_net_credit_card
|
48
|
+
return AuthorizeNet::CreditCard.new(self.card_number, self.expiration_month.to_s + self.expiration_year.to_s, {:card_code => self.cvv})
|
49
|
+
end
|
50
|
+
end
|
@@ -0,0 +1,86 @@
|
|
1
|
+
class GatewayCustomer
|
2
|
+
include GatewayErrors
|
3
|
+
|
4
|
+
attr_accessor :first_name, :last_name, :email_id, :address, :city, :state, :zip, :cell_phone, :home_phone, :office_phone, :office_ext, :fax, :country
|
5
|
+
|
6
|
+
def initialize(first_name, last_name, email_id)
|
7
|
+
self.first_name = first_name.to_s.gsub(/\s/, "")
|
8
|
+
self.last_name = last_name.to_s.gsub(/\s/, "")
|
9
|
+
self.email_id = email_id.to_s.gsub(/\s/, "")
|
10
|
+
end
|
11
|
+
|
12
|
+
def convert_to_fortis_input
|
13
|
+
return {
|
14
|
+
:first_name => self.first_name,
|
15
|
+
:last_name => self.last_name,
|
16
|
+
:email => self.email_id,
|
17
|
+
:address => self.address,
|
18
|
+
:city => self.city,
|
19
|
+
:state => self.state,
|
20
|
+
:zip => self.zip,
|
21
|
+
:cell_phone => self.cell_phone,
|
22
|
+
:office_phone => self.office_phone,
|
23
|
+
:office_ext_phone => self.office_ext,
|
24
|
+
:home_phone => self.home_phone
|
25
|
+
}
|
26
|
+
end
|
27
|
+
|
28
|
+
def convert_to_authorize_net_input(card = nil)
|
29
|
+
customer = {
|
30
|
+
:description => "Diaspark Payment Gateway",
|
31
|
+
:email => self.email_id,
|
32
|
+
|
33
|
+
:payment_profiles =>
|
34
|
+
[{
|
35
|
+
:cust_type => AuthorizeNet::CIM::PaymentProfile::CustomerType::INDIVIDUAL,
|
36
|
+
|
37
|
+
:first_name => self.first_name,
|
38
|
+
:last_name => self.last_name,
|
39
|
+
|
40
|
+
:address => self.address,
|
41
|
+
:city => self.city,
|
42
|
+
:state => self.state,
|
43
|
+
:zip => self.zip,
|
44
|
+
:phone => self.cell_phone,
|
45
|
+
:fax => self.fax,
|
46
|
+
:country => self.country
|
47
|
+
}]
|
48
|
+
}
|
49
|
+
|
50
|
+
if card
|
51
|
+
raise TransactionGatewayInvalidCardType unless card.class == GatewayCard
|
52
|
+
|
53
|
+
customer[:payment_profiles][0].merge!({
|
54
|
+
:card_num => card.card_number,
|
55
|
+
:exp_date => "#{card.expiration_month}#{card.expiration_year}"
|
56
|
+
})
|
57
|
+
end
|
58
|
+
|
59
|
+
return customer
|
60
|
+
end
|
61
|
+
|
62
|
+
def convert_to_braintree_input(card = nil)
|
63
|
+
customer = {
|
64
|
+
:first_name => self.first_name,
|
65
|
+
:last_name => self.last_name,
|
66
|
+
:email => self.email_id
|
67
|
+
}
|
68
|
+
|
69
|
+
if card
|
70
|
+
raise TransactionGatewayInvalidCardType unless card.class == GatewayCard
|
71
|
+
|
72
|
+
customer.merge!(
|
73
|
+
{:credit_card =>
|
74
|
+
{
|
75
|
+
:number => card.card_number,
|
76
|
+
:cvv => card.cvv,
|
77
|
+
:expiration_month => card.expiration_month,
|
78
|
+
:expiration_year => card.expiration_year,
|
79
|
+
:options => {:verify_card => "1"}
|
80
|
+
}
|
81
|
+
})
|
82
|
+
end
|
83
|
+
|
84
|
+
return customer
|
85
|
+
end
|
86
|
+
end
|
@@ -0,0 +1,10 @@
|
|
1
|
+
class GatewayCustomerProfile < GatewayCustomer
|
2
|
+
include GatewayErrors
|
3
|
+
|
4
|
+
attr_accessor :profile_id, :payment_profile_id
|
5
|
+
|
6
|
+
def initialize(profile_id, payment_profile_id)
|
7
|
+
self.profile_id = profile_id.to_s
|
8
|
+
self.payment_profile_id = payment_profile_id.to_s
|
9
|
+
end
|
10
|
+
end
|
@@ -0,0 +1,97 @@
|
|
1
|
+
module GatewayErrors
|
2
|
+
class TransactionGatewayError < StandardError
|
3
|
+
def initialize(msg = "Transaction gateway error.")
|
4
|
+
super(msg)
|
5
|
+
end
|
6
|
+
end
|
7
|
+
|
8
|
+
class TransactionGatewayInvalidCardType < TransactionGatewayError
|
9
|
+
def initialize(msg = "Card type is invalid.")
|
10
|
+
super(msg)
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
class TransactionGatewayInvalidAmount < TransactionGatewayError
|
15
|
+
def initialize(msg = "Amount should be greater than zero.")
|
16
|
+
super(msg)
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
class TransactionInvalid < TransactionGatewayError
|
21
|
+
def initialize(msg = "Validations preveneted transaction from being created.")
|
22
|
+
super(msg)
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
class TransactionDeclined < TransactionGatewayError
|
27
|
+
def initialize(msg = "Transaction is declined.")
|
28
|
+
super(msg)
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
class TransactionIDInvalid < TransactionGatewayError
|
33
|
+
def initialize(msg = "Transaction id shouldn't be blank.")
|
34
|
+
super(msg)
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
class TransactionSettlementError < TransactionGatewayError
|
39
|
+
def initialize(msg = "Transaction can't settle.")
|
40
|
+
super(msg)
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
class TransactionGatewayNotSupported < TransactionGatewayError
|
45
|
+
def initialize(msg = "Transaction gateway not supported.")
|
46
|
+
super(msg)
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
class ConnectionNotMade < StandardError
|
51
|
+
def initialize(msg = "Connection is not established to perform transaction, check connection.")
|
52
|
+
super(msg)
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
class CardError < StandardError
|
57
|
+
def initialize(msg = "Card error.")
|
58
|
+
super(msg)
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
class CardNumberInvalid < CardError
|
63
|
+
def initialize(msg = "Card number is invalid")
|
64
|
+
super(msg)
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
68
|
+
class CardExpirationYearInvalid < CardError
|
69
|
+
def initialize(msg = "Card expiration year is invalid")
|
70
|
+
super(msg)
|
71
|
+
end
|
72
|
+
end
|
73
|
+
|
74
|
+
class CardExpirationMonthInvalid < CardError
|
75
|
+
def initialize(msg = "Card expiration month is invalid")
|
76
|
+
super(msg)
|
77
|
+
end
|
78
|
+
end
|
79
|
+
|
80
|
+
class CardExpireError < CardError
|
81
|
+
def initialize(msg = "Card is expired.")
|
82
|
+
super(msg)
|
83
|
+
end
|
84
|
+
end
|
85
|
+
|
86
|
+
class InvalidCustomerType < TransactionGatewayError
|
87
|
+
def initialize(msg = "Customer type is invalid.")
|
88
|
+
super(msg)
|
89
|
+
end
|
90
|
+
end
|
91
|
+
|
92
|
+
class InvalidPaymentProfileType < TransactionGatewayError
|
93
|
+
def initialize(msg = "Payment profile type is invalid.")
|
94
|
+
super(msg)
|
95
|
+
end
|
96
|
+
end
|
97
|
+
end
|
@@ -0,0 +1,8 @@
|
|
1
|
+
require 'gateway_errors'
|
2
|
+
require 'gateway_card'
|
3
|
+
require 'gateway_customer'
|
4
|
+
require 'gateway_customer_profile'
|
5
|
+
require 'transaction_gateway/result'
|
6
|
+
require 'transaction_gateway/braintree_gateway'
|
7
|
+
require 'transaction_gateway/authorize_net_gateway'
|
8
|
+
require 'transaction_gateway/fortis_gateway'
|
@@ -0,0 +1,125 @@
|
|
1
|
+
require "authorize-net"
|
2
|
+
|
3
|
+
#This is patch for constant incorrect name in gem in CIM capture_only.
|
4
|
+
module AuthorizeNet
|
5
|
+
module CIM
|
6
|
+
module Fields
|
7
|
+
TRASNACTION_CAPTURE_FIELDS = TRANSACTION_CAPTURE_FIELDS
|
8
|
+
end
|
9
|
+
end
|
10
|
+
end
|
11
|
+
|
12
|
+
module TransactionGateway
|
13
|
+
class AuthorizeNetGateway < Result
|
14
|
+
include GatewayErrors
|
15
|
+
|
16
|
+
attr_accessor :login_id, :transaction_key, :gateway
|
17
|
+
|
18
|
+
private
|
19
|
+
def get_aim_transaction_object
|
20
|
+
return AuthorizeNet::AIM::Transaction.new(self.login_id, self.transaction_key, :gateway => self.gateway)
|
21
|
+
end
|
22
|
+
|
23
|
+
def get_cim_transaction_object
|
24
|
+
return AuthorizeNet::CIM::Transaction.new(self.login_id, self.transaction_key, :gateway => self.gateway)
|
25
|
+
end
|
26
|
+
|
27
|
+
public
|
28
|
+
def initialize(login_id, transaction_key, environment = :sandbox)
|
29
|
+
self.login_id = login_id
|
30
|
+
self.transaction_key = transaction_key
|
31
|
+
|
32
|
+
environment = environment.to_s.gsub(/\s/, '').downcase
|
33
|
+
self.gateway = (environment == "") ? :sandbox : environment.to_sym
|
34
|
+
end
|
35
|
+
|
36
|
+
def self.gateway_url(environment = :sandbox)
|
37
|
+
environment = environment.to_s.gsub(/\s/, "").downcase
|
38
|
+
environment = "sandbox" if environment == ""
|
39
|
+
return AuthorizeNet::XmlTransaction.new("","", :gateway => environment.to_sym).instance_variable_get(:@gateway)
|
40
|
+
end
|
41
|
+
|
42
|
+
def create_transaction(card_or_profile, amount, settle = false)
|
43
|
+
raise TransactionGatewayInvalidAmount if amount.to_f <= 0
|
44
|
+
|
45
|
+
case card_or_profile
|
46
|
+
when GatewayCard
|
47
|
+
transaction = get_aim_transaction_object
|
48
|
+
if settle == true
|
49
|
+
result = transaction.purchase(amount, card_or_profile.authorize_net_credit_card)
|
50
|
+
else
|
51
|
+
result = transaction.authorize(amount, card_or_profile.authorize_net_credit_card)
|
52
|
+
end
|
53
|
+
|
54
|
+
when GatewayCustomerProfile
|
55
|
+
transaction = get_cim_transaction_object
|
56
|
+
type = :auth_only
|
57
|
+
type = :prior_auth_capture if settle == true
|
58
|
+
|
59
|
+
result = transaction.create_transaction(type, amount, card_or_profile.profile_id.to_s, card_or_profile.payment_profile_id.to_s, nil)
|
60
|
+
|
61
|
+
else
|
62
|
+
raise TransactionGatewayInvalidCardType
|
63
|
+
end
|
64
|
+
|
65
|
+
return handle_result(result, AUTHORIZEDOTNET)
|
66
|
+
end
|
67
|
+
|
68
|
+
def settle_transaction(transaction_id, amount = nil)
|
69
|
+
raise TransactionIDInvalid if transaction_id.to_s.gsub(/\s/, "") == ""
|
70
|
+
|
71
|
+
capture_transaction = get_aim_transaction_object
|
72
|
+
|
73
|
+
result = capture_transaction.prior_auth_capture(transaction_id, amount)
|
74
|
+
|
75
|
+
return handle_result(result, AUTHORIZEDOTNET)
|
76
|
+
end
|
77
|
+
|
78
|
+
def refund(profile, amount)
|
79
|
+
raise InvalidPaymentProfileType unless profile.class == GatewayCustomerProfile
|
80
|
+
raise TransactionGatewayInvalidAmount if amount.to_f == 0
|
81
|
+
|
82
|
+
transaction = get_cim_transaction_object
|
83
|
+
result = transaction.create_transaction(:refund, amount.abs, profile.profile_id.to_s, profile.payment_profile_id.to_s, nil)
|
84
|
+
|
85
|
+
return handle_result(result, AUTHORIZEDOTNET)
|
86
|
+
end
|
87
|
+
|
88
|
+
def void_transaction(transaction_id)
|
89
|
+
transaction = get_aim_transaction_object
|
90
|
+
result = transaction.void(transaction_id)
|
91
|
+
return handle_result(result, AUTHORIZEDOTNET)
|
92
|
+
end
|
93
|
+
|
94
|
+
def create_customer_profile(customer, card = nil)
|
95
|
+
raise InvalidCustomerType unless customer.class == GatewayCustomer
|
96
|
+
|
97
|
+
transaction = get_cim_transaction_object
|
98
|
+
result = transaction.create_profile(customer.convert_to_authorize_net_input(card), {:validation_mode => :liveMode})
|
99
|
+
|
100
|
+
return handle_result(result, AUTHORIZEDOTNET)
|
101
|
+
end
|
102
|
+
|
103
|
+
def create_card_account(card, customer_profile_id)
|
104
|
+
raise TransactionGatewayInvalidCardType unless card.class == GatewayCard
|
105
|
+
|
106
|
+
transaction = get_cim_transaction_object
|
107
|
+
payment_profile = AuthorizeNet::CIM::PaymentProfile.new(:payment_method => card.authorize_net_credit_card)
|
108
|
+
result = transaction.create_payment_profile(payment_profile, customer_profile_id)
|
109
|
+
|
110
|
+
return handle_result(result, AUTHORIZEDOTNET)
|
111
|
+
end
|
112
|
+
|
113
|
+
def force_settle(profile, authorize_code, amount)
|
114
|
+
raise InvalidPaymentProfileType unless profile.class == GatewayCustomerProfile
|
115
|
+
raise TransactionGatewayInvalidAmount if amount.to_f <= 0
|
116
|
+
|
117
|
+
transaction = get_cim_transaction_object
|
118
|
+
transaction.set_fields( {:auth_code => authorize_code})
|
119
|
+
|
120
|
+
result = transaction.create_transaction(:capture_only, amount, profile.profile_id.to_s, profile.payment_profile_id.to_s, nil)
|
121
|
+
|
122
|
+
return handle_result(result, AUTHORIZEDOTNET)
|
123
|
+
end
|
124
|
+
end
|
125
|
+
end
|
@@ -0,0 +1,146 @@
|
|
1
|
+
module TransactionGateway
|
2
|
+
class BraintreeGateway < Result
|
3
|
+
require "braintree"
|
4
|
+
|
5
|
+
include GatewayErrors
|
6
|
+
|
7
|
+
attr_accessor :merchant_id, :public_key, :private_key, :environment
|
8
|
+
|
9
|
+
def initialize(merchant_id, public_key, private_key, environment = :sandbox)
|
10
|
+
self.merchant_id = merchant_id
|
11
|
+
self.public_key = public_key
|
12
|
+
self.private_key = private_key
|
13
|
+
|
14
|
+
self.environment = environment.to_s.gsub(/\s/, '').downcase
|
15
|
+
self.environment = (self.environment == "") ? :sandbox : self.environment.to_sym
|
16
|
+
end
|
17
|
+
|
18
|
+
def configure_braintree
|
19
|
+
Braintree::Configuration.environment = self.environment
|
20
|
+
Braintree::Configuration.merchant_id = self.merchant_id
|
21
|
+
Braintree::Configuration.public_key = self.public_key
|
22
|
+
Braintree::Configuration.private_key = self.private_key
|
23
|
+
end
|
24
|
+
|
25
|
+
def create_transaction(card_or_profile, amount, settle = false, customer = nil)
|
26
|
+
raise TransactionGatewayInvalidAmount if amount.to_f <= 0
|
27
|
+
|
28
|
+
case card_or_profile
|
29
|
+
when GatewayCard
|
30
|
+
credit_card = {
|
31
|
+
:credit_card =>
|
32
|
+
{
|
33
|
+
:number => card_or_profile.card_number,
|
34
|
+
:expiration_month => card_or_profile.expiration_month,
|
35
|
+
:expiration_year => card_or_profile.expiration_year,
|
36
|
+
:cvv => card_or_profile.cvv
|
37
|
+
}
|
38
|
+
}
|
39
|
+
|
40
|
+
when GatewayCustomerProfile
|
41
|
+
credit_card ={:payment_method_token => card_or_profile.payment_profile_id}
|
42
|
+
|
43
|
+
else
|
44
|
+
raise TransactionGatewayInvalidCardType unless card_or_profile.class == GatewayCard
|
45
|
+
end
|
46
|
+
|
47
|
+
sale_info = { :amount => amount }
|
48
|
+
|
49
|
+
sale_info[:options] = {
|
50
|
+
:submit_for_settlement => true
|
51
|
+
} if settle == true
|
52
|
+
|
53
|
+
sale_info[:customer] = {
|
54
|
+
:first_name => customer.first_name,
|
55
|
+
:last_name => customer.last_name,
|
56
|
+
:email => customer.email_id
|
57
|
+
} if customer and customer.class == GatewayCustomer
|
58
|
+
|
59
|
+
sale_info.merge!(credit_card)
|
60
|
+
|
61
|
+
configure_braintree
|
62
|
+
|
63
|
+
result = Braintree::Transaction.sale(sale_info)
|
64
|
+
|
65
|
+
return handle_result(result, BRAINTREE)
|
66
|
+
end
|
67
|
+
|
68
|
+
def settle_transaction(transaction_id, amount = nil)
|
69
|
+
raise TransactionIDInvalid if transaction_id.to_s.gsub(/\s/, "") == ""
|
70
|
+
|
71
|
+
configure_braintree
|
72
|
+
|
73
|
+
result = Braintree::Transaction.submit_for_settlement(transaction_id, amount)
|
74
|
+
|
75
|
+
return handle_result(result, BRAINTREE)
|
76
|
+
end
|
77
|
+
|
78
|
+
def void_transaction(transaction_id)
|
79
|
+
configure_braintree
|
80
|
+
|
81
|
+
result = Braintree::Transaction.void(transaction_id)
|
82
|
+
return handle_result(result, BRAINTREE)
|
83
|
+
end
|
84
|
+
|
85
|
+
def refund(profile, amount)
|
86
|
+
raise InvalidPaymentProfileType unless profile.class == GatewayCustomerProfile
|
87
|
+
raise TransactionGatewayInvalidAmount if amount.to_f == 0
|
88
|
+
|
89
|
+
configure_braintree
|
90
|
+
|
91
|
+
result = Braintree::Transaction.credit(
|
92
|
+
:amount => amount.abs,
|
93
|
+
:payment_method_token => profile.payment_profile_id
|
94
|
+
)
|
95
|
+
return handle_result(result, BRAINTREE)
|
96
|
+
end
|
97
|
+
|
98
|
+
def create_customer_profile(customer, card = nil)
|
99
|
+
raise InvalidCustomerType unless customer.class == GatewayCustomer
|
100
|
+
|
101
|
+
configure_braintree
|
102
|
+
|
103
|
+
result = Braintree::Customer.create(customer.convert_to_braintree_input(card))
|
104
|
+
return handle_result(result, BRAINTREE)
|
105
|
+
end
|
106
|
+
|
107
|
+
def create_card_account(card, customer_profile_id)
|
108
|
+
raise TransactionGatewayInvalidCardType unless card.class == GatewayCard
|
109
|
+
|
110
|
+
configure_braintree
|
111
|
+
|
112
|
+
result = Braintree::Customer.update(customer_profile_id,
|
113
|
+
:credit_card => {
|
114
|
+
:number => card.card_number,
|
115
|
+
:cvv => card.cvv,
|
116
|
+
:expiration_month => card.expiration_month,
|
117
|
+
:expiration_year => card.expiration_year
|
118
|
+
})
|
119
|
+
|
120
|
+
return handle_result(result, BRAINTREE)
|
121
|
+
end
|
122
|
+
|
123
|
+
#Patched for voice authorization settlement. Not provided any method from Braintree in Ruby but referred from Braintree control panel new transaction HTML page.
|
124
|
+
def force_settle(profile, authorize_code, amount)
|
125
|
+
raise InvalidPaymentProfileType unless profile.class == GatewayCustomerProfile
|
126
|
+
raise TransactionGatewayInvalidAmount if amount.to_f <= 0
|
127
|
+
|
128
|
+
configure_braintree
|
129
|
+
|
130
|
+
sale_info = {
|
131
|
+
:type => :sale,
|
132
|
+
:amount => amount,
|
133
|
+
:voice_authorization => "1",
|
134
|
+
:processor_authorization_code => authorize_code,
|
135
|
+
:payment_method_token => profile.payment_profile_id,
|
136
|
+
}
|
137
|
+
|
138
|
+
gateway = Braintree::Gateway.new(Braintree::Configuration.instantiate)
|
139
|
+
transaction = Braintree::TransactionGateway.new(gateway)
|
140
|
+
Braintree::Util.verify_keys(Braintree::TransactionGateway._create_signature.concat([:voice_authorization, :processor_authorization_code]) , sale_info)
|
141
|
+
result = transaction._do_create("/transactions", :transaction => sale_info)
|
142
|
+
|
143
|
+
return handle_result(result, BRAINTREE)
|
144
|
+
end
|
145
|
+
end
|
146
|
+
end
|
@@ -0,0 +1,141 @@
|
|
1
|
+
module TransactionGateway
|
2
|
+
class FortisGateway < Result
|
3
|
+
require 'cgi'
|
4
|
+
|
5
|
+
include GatewayErrors
|
6
|
+
|
7
|
+
attr_accessor :user_id, :user_api_key, :location_api_key, :api
|
8
|
+
|
9
|
+
module API
|
10
|
+
VERSION = "v1"
|
11
|
+
AUTHONLYPATH = "/cardTransactions/authOnly"
|
12
|
+
SETTLEPATH = "/cardTransactions/?/authComplete" #replace ? with card_transaction_id
|
13
|
+
REFUND = "/cardTransactions/refund"
|
14
|
+
VOID = "/cardTransactions/?/void" #replace ? with card_transaction_id
|
15
|
+
CAPTURE_FORCE = "/cardTransactions/force"
|
16
|
+
CONTACT = "/contacts"
|
17
|
+
CARD_ACCOUNT = "/cardAccounts"
|
18
|
+
end
|
19
|
+
|
20
|
+
private
|
21
|
+
def convert_hash_to_query(params)
|
22
|
+
URI.encode(params.map{|key, value| "#{CGI::escape(key)}=#{CGI::escape(value)}" if value}.select{|value| value if value}.join("&"))
|
23
|
+
end
|
24
|
+
|
25
|
+
def call_request(path, body = {}, request_type = "PUT")
|
26
|
+
credentials = Hash.new
|
27
|
+
credentials[:user_id] = self.user_id
|
28
|
+
credentials[:user_api_key] = self.user_api_key
|
29
|
+
credentials[:location_api_key] = self.location_api_key
|
30
|
+
|
31
|
+
uri = URI.parse(File.join(self.api, API::VERSION, path))
|
32
|
+
http = Net::HTTP.new(uri.host, uri.port)
|
33
|
+
http.verify_mode = OpenSSL::SSL::VERIFY_NONE
|
34
|
+
http.use_ssl = true
|
35
|
+
|
36
|
+
response = http.start do |http1|
|
37
|
+
if request_type.to_s.upcase == "POST"
|
38
|
+
request = Net::HTTP::Post.new("#{uri.path}?#{convert_hash_to_query(credentials)}", {'Content-Type' => 'application/x-www-form-urlencoded'})
|
39
|
+
else
|
40
|
+
request = Net::HTTP::Put.new("#{uri.path}?#{convert_hash_to_query(credentials)}", {'Content-Type' => 'application/x-www-form-urlencoded'})
|
41
|
+
end
|
42
|
+
request.body = convert_hash_to_query(body)
|
43
|
+
http1.request(request)
|
44
|
+
end
|
45
|
+
|
46
|
+
return response.body
|
47
|
+
end
|
48
|
+
|
49
|
+
public
|
50
|
+
def initialize(user_id, user_api_key, location_api_key, environment = :sandbox)
|
51
|
+
self.user_id = user_id
|
52
|
+
self.user_api_key = user_api_key
|
53
|
+
self.location_api_key = location_api_key
|
54
|
+
|
55
|
+
case environment.to_s.gsub(/\s/, '').downcase.to_sym
|
56
|
+
when :production
|
57
|
+
self.api = "https://api.zeamster.com"
|
58
|
+
else
|
59
|
+
self.api = "https://api.sandbox.zeamster.com"
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
def self.gateway_url(environment = :sandbox)
|
64
|
+
environment = environment.to_s.gsub(/\s/, "").downcase
|
65
|
+
environment = "sandbox" if environment == ""
|
66
|
+
return self.new("", "", "", environment.to_sym).api
|
67
|
+
end
|
68
|
+
|
69
|
+
def create_transaction(card, amount)
|
70
|
+
raise TransactionGatewayInvalidCardType unless card.class == GatewayCard
|
71
|
+
raise TransactionGatewayInvalidAmount if amount.to_f <= 0
|
72
|
+
|
73
|
+
sale_info ={
|
74
|
+
:cv => card.cvv,
|
75
|
+
:card_number => card.card_number,
|
76
|
+
:exp_date => "#{card.expiration_month}#{card.expiration_year}",
|
77
|
+
:transaction_amount => amount
|
78
|
+
}
|
79
|
+
|
80
|
+
return handle_result(call_request(API::AUTHONLYPATH, sale_info, "POST"), FORTIS)
|
81
|
+
end
|
82
|
+
|
83
|
+
def settle_transaction(card_transaction_id, amount = nil)
|
84
|
+
sale_info = {}
|
85
|
+
sale_info = {:transaction_amount => amount} if amount
|
86
|
+
return handle_result(call_request(API::SETTLEPATH.gsub('?', card_transaction_id), sale_info), FORTIS)
|
87
|
+
end
|
88
|
+
|
89
|
+
def refund(profile, amount)
|
90
|
+
raise InvalidPaymentProfileType unless profile.class == GatewayCustomerProfile
|
91
|
+
raise TransactionGatewayInvalidAmount, "Amount to refund shouldn't equal to zero." if amount.to_f == 0
|
92
|
+
|
93
|
+
sale_info ={
|
94
|
+
:card_account_id => profile.profile_id,
|
95
|
+
:transaction_amount => amount.abs
|
96
|
+
}
|
97
|
+
|
98
|
+
return handle_result(call_request(API::REFUND, sale_info, "POST"), FORTIS)
|
99
|
+
end
|
100
|
+
|
101
|
+
def void_transaction(transaction_id)
|
102
|
+
return handle_result(call_request(API::VOID.gsub('?', transaction_id)), FORTIS)
|
103
|
+
end
|
104
|
+
|
105
|
+
def create_customer_profile(customer, card = nil)
|
106
|
+
raise InvalidCustomerType unless customer.class == GatewayCustomer
|
107
|
+
|
108
|
+
|
109
|
+
result = handle_result(call_request(API::CONTACT, customer.convert_to_fortis_input, "POST"), FORTIS)
|
110
|
+
|
111
|
+
result = create_card_account(card, result["contact"]["contact_id"]) if card
|
112
|
+
|
113
|
+
return result
|
114
|
+
end
|
115
|
+
|
116
|
+
def create_card_account(card, customer_profile_id)
|
117
|
+
raise TransactionGatewayInvalidCardType unless card.class == GatewayCard
|
118
|
+
|
119
|
+
sale_info ={
|
120
|
+
:contact_id => customer_profile_id,
|
121
|
+
:card_number => card.card_number,
|
122
|
+
:exp_date => "#{card.expiration_month}#{card.expiration_year}"
|
123
|
+
}
|
124
|
+
|
125
|
+
return handle_result(call_request(API::CARD_ACCOUNT, sale_info, "POST"), FORTIS)
|
126
|
+
end
|
127
|
+
|
128
|
+
def force_settle(profile, authorize_code, amount)
|
129
|
+
raise InvalidPaymentProfileType unless profile.class == GatewayCustomerProfile
|
130
|
+
raise TransactionGatewayInvalidAmount if amount.to_f <= 0
|
131
|
+
|
132
|
+
sale_info ={
|
133
|
+
:card_account_id => profile.payment_profile_id,
|
134
|
+
:transaction_amount => amount,
|
135
|
+
:auth => authorize_code
|
136
|
+
}
|
137
|
+
|
138
|
+
return handle_result(call_request(API::CAPTURE_FORCE, sale_info, "POST"), FORTIS)
|
139
|
+
end
|
140
|
+
end
|
141
|
+
end
|
@@ -0,0 +1,79 @@
|
|
1
|
+
require 'json'
|
2
|
+
|
3
|
+
module TransactionGateway
|
4
|
+
class Result
|
5
|
+
BRAINTREE = 'BT'
|
6
|
+
AUTHORIZEDOTNET = 'ADN'
|
7
|
+
FORTIS = 'FORTIS'
|
8
|
+
|
9
|
+
include GatewayErrors
|
10
|
+
|
11
|
+
########## HANDLE GETWAY RESPONSE #############
|
12
|
+
def handle_result(result, gateway)
|
13
|
+
case gateway
|
14
|
+
|
15
|
+
when BRAINTREE
|
16
|
+
return handle_braintree_result(result)
|
17
|
+
|
18
|
+
when AUTHORIZEDOTNET
|
19
|
+
return handle_authorize_net_result(result)
|
20
|
+
|
21
|
+
when FORTIS
|
22
|
+
return handle_fortis_result(result)
|
23
|
+
|
24
|
+
else
|
25
|
+
raise TransactionGatewayNotSupported
|
26
|
+
end
|
27
|
+
|
28
|
+
raise ConnectionNotMade
|
29
|
+
end
|
30
|
+
|
31
|
+
private
|
32
|
+
|
33
|
+
############# HANDLE BRAINTREE RESPONSE ###############
|
34
|
+
def handle_braintree_result(result)
|
35
|
+
if result.success?
|
36
|
+
if transaction = result.send(result.instance_variable_get("@attrs")[0])
|
37
|
+
return transaction
|
38
|
+
else
|
39
|
+
raise TransactionGatewayError, result.errors.inspect.to_s
|
40
|
+
end
|
41
|
+
else
|
42
|
+
raise TransactionDeclined, result.message
|
43
|
+
end if result
|
44
|
+
end
|
45
|
+
|
46
|
+
############# HANDLE AUTHORIZE.NET RESPONSE ###############
|
47
|
+
def handle_authorize_net_result(result)
|
48
|
+
if result
|
49
|
+
if result.direct_response
|
50
|
+
result = result.direct_response
|
51
|
+
else
|
52
|
+
return result if result.result_code.to_s.upcase == "OK"
|
53
|
+
raise TransactionDeclined, result.message_text
|
54
|
+
end if(result.class == AuthorizeNet::CIM::Response)
|
55
|
+
|
56
|
+
if result.transaction
|
57
|
+
raise TransactionDeclined, result.response_reason_text unless result.response_code == "1"
|
58
|
+
|
59
|
+
return result
|
60
|
+
else
|
61
|
+
raise TransactionGatewayError, result.response_reason_text
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
############# HANDLE FORTIS RESPONSE ###############
|
67
|
+
def handle_fortis_result(result)
|
68
|
+
begin
|
69
|
+
result = JSON.parse(result)
|
70
|
+
rescue Exception => ex
|
71
|
+
raise TransactionGatewayError, [result, ex.message]
|
72
|
+
end if(result.class != Hash)
|
73
|
+
|
74
|
+
raise TransactionDeclined, [result["errors"]] if(result["valid"].to_s.upcase != "TRUE" or (result["errors"].to_s.gsub(/s/, "") != ""))
|
75
|
+
|
76
|
+
return result
|
77
|
+
end
|
78
|
+
end
|
79
|
+
end
|
metadata
ADDED
@@ -0,0 +1,101 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: payment_gateway_solutions
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.1
|
5
|
+
prerelease:
|
6
|
+
platform: ruby
|
7
|
+
authors:
|
8
|
+
- Kunal Lalge
|
9
|
+
autorequire:
|
10
|
+
bindir: bin
|
11
|
+
cert_chain: []
|
12
|
+
date: 2015-06-25 00:00:00.000000000 Z
|
13
|
+
dependencies:
|
14
|
+
- !ruby/object:Gem::Dependency
|
15
|
+
name: authorize-net
|
16
|
+
requirement: !ruby/object:Gem::Requirement
|
17
|
+
none: false
|
18
|
+
requirements:
|
19
|
+
- - ~>
|
20
|
+
- !ruby/object:Gem::Version
|
21
|
+
version: 1.5.2
|
22
|
+
type: :runtime
|
23
|
+
prerelease: false
|
24
|
+
version_requirements: !ruby/object:Gem::Requirement
|
25
|
+
none: false
|
26
|
+
requirements:
|
27
|
+
- - ~>
|
28
|
+
- !ruby/object:Gem::Version
|
29
|
+
version: 1.5.2
|
30
|
+
- !ruby/object:Gem::Dependency
|
31
|
+
name: braintree
|
32
|
+
requirement: !ruby/object:Gem::Requirement
|
33
|
+
none: false
|
34
|
+
requirements:
|
35
|
+
- - ~>
|
36
|
+
- !ruby/object:Gem::Version
|
37
|
+
version: 2.25.0
|
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: 2.25.0
|
46
|
+
- !ruby/object:Gem::Dependency
|
47
|
+
name: json
|
48
|
+
requirement: !ruby/object:Gem::Requirement
|
49
|
+
none: false
|
50
|
+
requirements:
|
51
|
+
- - ~>
|
52
|
+
- !ruby/object:Gem::Version
|
53
|
+
version: 1.8.1
|
54
|
+
type: :runtime
|
55
|
+
prerelease: false
|
56
|
+
version_requirements: !ruby/object:Gem::Requirement
|
57
|
+
none: false
|
58
|
+
requirements:
|
59
|
+
- - ~>
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: 1.8.1
|
62
|
+
description: Multiple Payment Gateway support. Authorize.net, Braintree, Fortis
|
63
|
+
email: kunallalge@gmail.com
|
64
|
+
executables: []
|
65
|
+
extensions: []
|
66
|
+
extra_rdoc_files: []
|
67
|
+
files:
|
68
|
+
- lib/payment_gateway.rb
|
69
|
+
- lib/gateway_card.rb
|
70
|
+
- lib/gateway_customer.rb
|
71
|
+
- lib/gateway_customer_profile.rb
|
72
|
+
- lib/gateway_errors.rb
|
73
|
+
- lib/transaction_gateway/braintree_gateway.rb
|
74
|
+
- lib/transaction_gateway/authorize_net_gateway.rb
|
75
|
+
- lib/transaction_gateway/fortis_gateway.rb
|
76
|
+
- lib/transaction_gateway/result.rb
|
77
|
+
homepage:
|
78
|
+
licenses: []
|
79
|
+
post_install_message:
|
80
|
+
rdoc_options: []
|
81
|
+
require_paths:
|
82
|
+
- lib
|
83
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
84
|
+
none: false
|
85
|
+
requirements:
|
86
|
+
- - ! '>='
|
87
|
+
- !ruby/object:Gem::Version
|
88
|
+
version: 1.8.6
|
89
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
90
|
+
none: false
|
91
|
+
requirements:
|
92
|
+
- - ! '>='
|
93
|
+
- !ruby/object:Gem::Version
|
94
|
+
version: '0'
|
95
|
+
requirements: []
|
96
|
+
rubyforge_project:
|
97
|
+
rubygems_version: 1.8.24
|
98
|
+
signing_key:
|
99
|
+
specification_version: 3
|
100
|
+
summary: Payment Gateway Solutions
|
101
|
+
test_files: []
|