payment_gateway_solutions 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/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: []
|