activemerchant 1.21.0 → 1.22.0
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.tar.gz.sig +0 -0
- data/CHANGELOG +63 -0
- data/CONTRIBUTORS +29 -0
- data/README.md +195 -0
- data/lib/active_merchant/billing/gateways/authorize_net_cim.rb +2 -0
- data/lib/active_merchant/billing/gateways/barclays_epdq.rb +2 -2
- data/lib/active_merchant/billing/gateways/blue_pay.rb +492 -11
- data/lib/active_merchant/billing/gateways/braintree_blue.rb +46 -19
- data/lib/active_merchant/billing/gateways/certo_direct.rb +1 -1
- data/lib/active_merchant/billing/gateways/cyber_source.rb +342 -106
- data/lib/active_merchant/billing/gateways/elavon.rb +2 -0
- data/lib/active_merchant/billing/gateways/epay.rb +3 -1
- data/lib/active_merchant/billing/gateways/itransact.rb +450 -0
- data/lib/active_merchant/billing/gateways/migs.rb +259 -0
- data/lib/active_merchant/billing/gateways/migs/migs_codes.rb +100 -0
- data/lib/active_merchant/billing/gateways/moneris_us.rb +211 -0
- data/lib/active_merchant/billing/gateways/ogone.rb +104 -12
- data/lib/active_merchant/billing/gateways/orbital.rb +15 -6
- data/lib/active_merchant/billing/gateways/paybox_direct.rb +1 -4
- data/lib/active_merchant/billing/gateways/payflow.rb +8 -3
- data/lib/active_merchant/billing/gateways/payflow/payflow_common_api.rb +4 -1
- data/lib/active_merchant/billing/gateways/payflow_express.rb +4 -2
- data/lib/active_merchant/billing/gateways/payment_express.rb +1 -1
- data/lib/active_merchant/billing/gateways/paypal.rb +3 -18
- data/lib/active_merchant/billing/gateways/paypal/paypal_common_api.rb +287 -1
- data/lib/active_merchant/billing/gateways/paypal/paypal_recurring_api.rb +245 -0
- data/lib/active_merchant/billing/gateways/paypal_express.rb +14 -66
- data/lib/active_merchant/billing/gateways/realex.rb +5 -7
- data/lib/active_merchant/billing/gateways/stripe.rb +1 -9
- data/lib/active_merchant/billing/gateways/usa_epay_advanced.rb +2 -2
- data/lib/active_merchant/billing/gateways/usa_epay_transaction.rb +1 -5
- data/lib/active_merchant/billing/gateways/viaklix.rb +7 -2
- data/lib/active_merchant/billing/gateways/vindicia.rb +359 -0
- data/lib/active_merchant/billing/integrations/dotpay.rb +22 -0
- data/lib/active_merchant/billing/integrations/dotpay/helper.rb +77 -0
- data/lib/active_merchant/billing/integrations/dotpay/notification.rb +86 -0
- data/lib/active_merchant/billing/integrations/dotpay/return.rb +11 -0
- data/lib/active_merchant/billing/integrations/epay.rb +21 -0
- data/lib/active_merchant/billing/integrations/epay/helper.rb +55 -0
- data/lib/active_merchant/billing/integrations/epay/notification.rb +110 -0
- data/lib/active_merchant/billing/integrations/paypal/notification.rb +2 -1
- data/lib/active_merchant/billing/integrations/quickpay/helper.rb +2 -3
- data/lib/active_merchant/billing/integrations/robokassa.rb +49 -0
- data/lib/active_merchant/billing/integrations/robokassa/common.rb +19 -0
- data/lib/active_merchant/billing/integrations/robokassa/helper.rb +50 -0
- data/lib/active_merchant/billing/integrations/robokassa/notification.rb +55 -0
- data/lib/active_merchant/billing/integrations/robokassa/return.rb +17 -0
- data/lib/active_merchant/billing/integrations/two_checkout.rb +25 -3
- data/lib/active_merchant/billing/integrations/two_checkout/helper.rb +15 -0
- data/lib/active_merchant/billing/integrations/verkkomaksut.rb +20 -0
- data/lib/active_merchant/billing/integrations/verkkomaksut/helper.rb +87 -0
- data/lib/active_merchant/billing/integrations/verkkomaksut/notification.rb +59 -0
- data/lib/active_merchant/version.rb +1 -1
- metadata +59 -26
- metadata.gz.sig +0 -0
@@ -74,7 +74,7 @@ module ActiveMerchant #:nodoc:
|
|
74
74
|
|
75
75
|
def store(creditcard, options = {})
|
76
76
|
commit do
|
77
|
-
|
77
|
+
parameters = {
|
78
78
|
:first_name => creditcard.first_name,
|
79
79
|
:last_name => creditcard.last_name,
|
80
80
|
:email => options[:email],
|
@@ -84,7 +84,8 @@ module ActiveMerchant #:nodoc:
|
|
84
84
|
:expiration_month => creditcard.month.to_s.rjust(2, "0"),
|
85
85
|
:expiration_year => creditcard.year.to_s
|
86
86
|
}
|
87
|
-
|
87
|
+
}
|
88
|
+
result = Braintree::Customer.create(merge_credit_card_options(parameters, options))
|
88
89
|
Response.new(result.success?, message_from_result(result),
|
89
90
|
{
|
90
91
|
:braintree_customer => (customer_hash(result.customer) if result.success?),
|
@@ -99,24 +100,25 @@ module ActiveMerchant #:nodoc:
|
|
99
100
|
customer_update_result = commit do
|
100
101
|
braintree_credit_card = Braintree::Customer.find(vault_id).credit_cards.detect { |cc| cc.default? }
|
101
102
|
return Response.new(false, 'Braintree::NotFoundError') if braintree_credit_card.nil?
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
:
|
106
|
-
)
|
107
|
-
Response.new(result.success?, message_from_result(result),
|
108
|
-
:braintree_customer => (customer_hash(Braintree::Customer.find(vault_id)) if result.success?)
|
109
|
-
)
|
110
|
-
end
|
111
|
-
return customer_update_result unless customer_update_result.success?
|
112
|
-
credit_card_update_result = commit do
|
113
|
-
result = Braintree::CreditCard.update(braintree_credit_card.token,
|
103
|
+
|
104
|
+
options.merge!(:update_existing_token => braintree_credit_card.token)
|
105
|
+
credit_card_params = merge_credit_card_options({
|
106
|
+
:credit_card => {
|
114
107
|
:number => creditcard.number,
|
115
108
|
:expiration_month => creditcard.month.to_s.rjust(2, "0"),
|
116
109
|
:expiration_year => creditcard.year.to_s
|
110
|
+
}
|
111
|
+
}, options)[:credit_card]
|
112
|
+
|
113
|
+
result = Braintree::Customer.update(vault_id,
|
114
|
+
:first_name => creditcard.first_name,
|
115
|
+
:last_name => creditcard.last_name,
|
116
|
+
:email => options[:email],
|
117
|
+
:credit_card => credit_card_params
|
117
118
|
)
|
118
119
|
Response.new(result.success?, message_from_result(result),
|
119
|
-
:braintree_customer => (customer_hash(Braintree::Customer.find(vault_id)) if result.success?)
|
120
|
+
:braintree_customer => (customer_hash(Braintree::Customer.find(vault_id)) if result.success?),
|
121
|
+
:customer_vault_id => (result.customer.id if result.success?)
|
120
122
|
)
|
121
123
|
end
|
122
124
|
end
|
@@ -131,17 +133,38 @@ module ActiveMerchant #:nodoc:
|
|
131
133
|
|
132
134
|
private
|
133
135
|
|
136
|
+
def merge_credit_card_options(parameters, options)
|
137
|
+
valid_options = {}
|
138
|
+
options.each do |key, value|
|
139
|
+
valid_options[key] = value if [:update_existing_token, :verify_card, :verification_merchant_account_id].include?(key)
|
140
|
+
end
|
141
|
+
|
142
|
+
parameters[:credit_card] ||= {}
|
143
|
+
parameters[:credit_card].merge!(:options => valid_options)
|
144
|
+
parameters[:credit_card][:billing_address] = map_address(options[:billing_address]) if options[:billing_address]
|
145
|
+
parameters
|
146
|
+
end
|
147
|
+
|
134
148
|
def map_address(address)
|
135
149
|
return {} if address.nil?
|
136
|
-
{
|
150
|
+
mapped = {
|
137
151
|
:street_address => address[:address1],
|
138
152
|
:extended_address => address[:address2],
|
139
153
|
:company => address[:company],
|
140
154
|
:locality => address[:city],
|
141
155
|
:region => address[:state],
|
142
156
|
:postal_code => address[:zip],
|
143
|
-
:country_name => address[:country]
|
144
157
|
}
|
158
|
+
if(address[:country] || address[:country_code_alpha2])
|
159
|
+
mapped[:country_code_alpha2] = (address[:country] || address[:country_code_alpha2])
|
160
|
+
elsif address[:country_name]
|
161
|
+
mapped[:country_name] = address[:country_name]
|
162
|
+
elsif address[:country_code_alpha3]
|
163
|
+
mapped[:country_code_alpha3] = address[:country_code_alpha3]
|
164
|
+
elsif address[:country_code_numeric]
|
165
|
+
mapped[:country_code_numeric] = address[:country_code_numeric]
|
166
|
+
end
|
167
|
+
mapped
|
145
168
|
end
|
146
169
|
|
147
170
|
def commit(&block)
|
@@ -153,6 +176,8 @@ module ActiveMerchant #:nodoc:
|
|
153
176
|
def message_from_result(result)
|
154
177
|
if result.success?
|
155
178
|
"OK"
|
179
|
+
elsif result.errors.size == 0 && result.credit_card_verification
|
180
|
+
"Processor declined: #{result.credit_card_verification.processor_response_text} (#{result.credit_card_verification.processor_response_code})"
|
156
181
|
else
|
157
182
|
result.errors.map { |e| "#{e.message} (#{e.code})" }.join(" ")
|
158
183
|
end
|
@@ -207,7 +232,8 @@ module ActiveMerchant #:nodoc:
|
|
207
232
|
credit_cards = customer.credit_cards.map do |cc|
|
208
233
|
{
|
209
234
|
"bin" => cc.bin,
|
210
|
-
"expiration_date" => cc.expiration_date
|
235
|
+
"expiration_date" => cc.expiration_date,
|
236
|
+
"token" => cc.token
|
211
237
|
}
|
212
238
|
end
|
213
239
|
|
@@ -215,7 +241,8 @@ module ActiveMerchant #:nodoc:
|
|
215
241
|
"email" => customer.email,
|
216
242
|
"first_name" => customer.first_name,
|
217
243
|
"last_name" => customer.last_name,
|
218
|
-
"credit_cards" => credit_cards
|
244
|
+
"credit_cards" => credit_cards,
|
245
|
+
"id" => customer.id
|
219
246
|
}
|
220
247
|
end
|
221
248
|
|
@@ -7,7 +7,7 @@ module ActiveMerchant #:nodoc:
|
|
7
7
|
self.supported_countries = [
|
8
8
|
"BE", "BG", "CZ", "DK", "DE", "EE", "IE", "EL", "ES", "FR",
|
9
9
|
"IT", "CY", "LV", "LT", "LU", "HU", "MT", "NL", "AT", "PL",
|
10
|
-
"PT", "RO", "SI", "SK", "FI", "SE", "
|
10
|
+
"PT", "RO", "SI", "SK", "FI", "SE", "GB"
|
11
11
|
]
|
12
12
|
|
13
13
|
self.supported_cardtypes = [:visa, :master, :american_express, :discover]
|
@@ -3,35 +3,37 @@ module ActiveMerchant #:nodoc:
|
|
3
3
|
# See the remote and mocked unit test files for example usage. Pay special attention to the contents of the options hash.
|
4
4
|
#
|
5
5
|
# Initial setup instructions can be found in http://cybersource.com/support_center/implementation/downloads/soap_api/SOAP_toolkits.pdf
|
6
|
-
#
|
7
|
-
# Debugging
|
6
|
+
#
|
7
|
+
# Debugging
|
8
8
|
# If you experience an issue with this gateway be sure to examine the transaction information from a general transaction search inside the CyberSource Business
|
9
|
-
# Center for the full error messages including field names.
|
9
|
+
# Center for the full error messages including field names.
|
10
10
|
#
|
11
11
|
# Important Notes
|
12
|
-
# * AVS and CVV only work against the production server. You will always get back X for AVS and no response for CVV against the test server.
|
13
|
-
# * Nexus is the list of states or provinces where you have a physical presence. Nexus is used to calculate tax. Leave blank to tax everyone.
|
14
|
-
# * If you want to calculate VAT for overseas customers you must supply a registration number in the options hash as vat_reg_number.
|
12
|
+
# * AVS and CVV only work against the production server. You will always get back X for AVS and no response for CVV against the test server.
|
13
|
+
# * Nexus is the list of states or provinces where you have a physical presence. Nexus is used to calculate tax. Leave blank to tax everyone.
|
14
|
+
# * If you want to calculate VAT for overseas customers you must supply a registration number in the options hash as vat_reg_number.
|
15
15
|
# * productCode is a value in the line_items hash that is used to tell CyberSource what kind of item you are selling. It is used when calculating tax/VAT.
|
16
16
|
# * All transactions use dollar values.
|
17
17
|
class CyberSourceGateway < Gateway
|
18
18
|
TEST_URL = 'https://ics2wstest.ic3.com/commerce/1.x/transactionProcessor'
|
19
19
|
LIVE_URL = 'https://ics2ws.ic3.com/commerce/1.x/transactionProcessor'
|
20
|
-
|
20
|
+
|
21
|
+
XSD_VERSION = "1.69"
|
22
|
+
|
21
23
|
# visa, master, american_express, discover
|
22
24
|
self.supported_cardtypes = [:visa, :master, :american_express, :discover]
|
23
25
|
self.supported_countries = ['US']
|
24
26
|
self.default_currency = 'USD'
|
25
27
|
self.homepage_url = 'http://www.cybersource.com'
|
26
28
|
self.display_name = 'CyberSource'
|
27
|
-
|
29
|
+
|
28
30
|
# map credit card to the CyberSource expected representation
|
29
31
|
@@credit_card_codes = {
|
30
32
|
:visa => '001',
|
31
33
|
:master => '002',
|
32
34
|
:american_express => '003',
|
33
35
|
:discover => '004'
|
34
|
-
}
|
36
|
+
}
|
35
37
|
|
36
38
|
# map response codes to something humans can read
|
37
39
|
@@response_codes = {
|
@@ -43,17 +45,17 @@ module ActiveMerchant #:nodoc:
|
|
43
45
|
:r152 => "The request was received, but a service timed out",
|
44
46
|
:r200 => "The authorization request was approved by the issuing bank but declined by CyberSource because it did not pass the AVS check",
|
45
47
|
:r201 => "The issuing bank has questions about the request",
|
46
|
-
:r202 => "Expired card",
|
47
|
-
:r203 => "General decline of the card",
|
48
|
-
:r204 => "Insufficient funds in the account",
|
49
|
-
:r205 => "Stolen or lost card",
|
50
|
-
:r207 => "Issuing bank unavailable",
|
51
|
-
:r208 => "Inactive card or card not authorized for card-not-present transactions",
|
52
|
-
:r209 => "American Express Card Identifiction Digits (CID) did not match",
|
53
|
-
:r210 => "The card has reached the credit limit",
|
54
|
-
:r211 => "Invalid card verification number",
|
55
|
-
:r221 => "The customer matched an entry on the processor's negative file",
|
56
|
-
:r230 => "The authorization request was approved by the issuing bank but declined by CyberSource because it did not pass the card verification check",
|
48
|
+
:r202 => "Expired card",
|
49
|
+
:r203 => "General decline of the card",
|
50
|
+
:r204 => "Insufficient funds in the account",
|
51
|
+
:r205 => "Stolen or lost card",
|
52
|
+
:r207 => "Issuing bank unavailable",
|
53
|
+
:r208 => "Inactive card or card not authorized for card-not-present transactions",
|
54
|
+
:r209 => "American Express Card Identifiction Digits (CID) did not match",
|
55
|
+
:r210 => "The card has reached the credit limit",
|
56
|
+
:r211 => "Invalid card verification number",
|
57
|
+
:r221 => "The customer matched an entry on the processor's negative file",
|
58
|
+
:r230 => "The authorization request was approved by the issuing bank but declined by CyberSource because it did not pass the card verification check",
|
57
59
|
:r231 => "Invalid account number",
|
58
60
|
:r232 => "The card type is not accepted by the payment processor",
|
59
61
|
:r233 => "General decline by the processor",
|
@@ -72,44 +74,44 @@ module ActiveMerchant #:nodoc:
|
|
72
74
|
:r247 => "You requested a credit for a capture that was previously voided",
|
73
75
|
:r250 => "The request was received, but a time-out occurred with the payment processor",
|
74
76
|
:r254 => "Your CyberSource account is prohibited from processing stand-alone refunds",
|
75
|
-
:r255 => "Your CyberSource account is not configured to process the service in the country you specified"
|
77
|
+
:r255 => "Your CyberSource account is not configured to process the service in the country you specified"
|
76
78
|
}
|
77
79
|
|
78
80
|
# These are the options that can be used when creating a new CyberSource Gateway object.
|
79
|
-
#
|
80
|
-
# :login => your username
|
81
81
|
#
|
82
|
-
# :
|
82
|
+
# :login => your username
|
83
|
+
#
|
84
|
+
# :password => the transaction key you generated in the Business Center
|
83
85
|
#
|
84
86
|
# :test => true sets the gateway to test mode
|
85
87
|
#
|
86
|
-
# :vat_reg_number => your VAT registration number
|
88
|
+
# :vat_reg_number => your VAT registration number
|
87
89
|
#
|
88
90
|
# :nexus => "WI CA QC" sets the states/provinces where you have a physical presense for tax purposes
|
89
91
|
#
|
90
|
-
# :ignore_avs => true don't want to use AVS so continue processing even if AVS would have failed
|
92
|
+
# :ignore_avs => true don't want to use AVS so continue processing even if AVS would have failed
|
91
93
|
#
|
92
|
-
# :ignore_cvv => true don't want to use CVV so continue processing even if CVV would have failed
|
94
|
+
# :ignore_cvv => true don't want to use CVV so continue processing even if CVV would have failed
|
93
95
|
def initialize(options = {})
|
94
96
|
requires!(options, :login, :password)
|
95
97
|
@options = options
|
96
98
|
super
|
97
|
-
end
|
99
|
+
end
|
98
100
|
|
99
101
|
# Should run against the test servers or not?
|
100
102
|
def test?
|
101
103
|
@options[:test] || Base.gateway_mode == :test
|
102
104
|
end
|
103
|
-
|
104
|
-
# Request an authorization for an amount from CyberSource
|
105
|
+
|
106
|
+
# Request an authorization for an amount from CyberSource
|
105
107
|
#
|
106
|
-
# You must supply an :order_id in the options hash
|
108
|
+
# You must supply an :order_id in the options hash
|
107
109
|
def authorize(money, creditcard, options = {})
|
108
110
|
requires!(options, :order_id, :email)
|
109
111
|
setup_address_hash(options)
|
110
112
|
commit(build_auth_request(money, creditcard, options), options )
|
111
113
|
end
|
112
|
-
|
114
|
+
|
113
115
|
def auth_reversal(money, identification, options = {})
|
114
116
|
commit(build_auth_reversal_request(money, identification, options), options)
|
115
117
|
end
|
@@ -121,13 +123,18 @@ module ActiveMerchant #:nodoc:
|
|
121
123
|
end
|
122
124
|
|
123
125
|
# Purchase is an auth followed by a capture
|
124
|
-
# You must supply an order_id in the options hash
|
125
|
-
def purchase(money,
|
126
|
+
# You must supply an order_id in the options hash
|
127
|
+
def purchase(money, payment_source, options = {})
|
126
128
|
requires!(options, :order_id, :email)
|
127
129
|
setup_address_hash(options)
|
128
|
-
|
130
|
+
if payment_source.is_a?(String)
|
131
|
+
requires!(options, [:type, :credit_card, :check])
|
132
|
+
commit(build_subscription_purchase_request(money, payment_source, options), options)
|
133
|
+
else
|
134
|
+
commit(build_purchase_request(money, payment_source, options), options)
|
135
|
+
end
|
129
136
|
end
|
130
|
-
|
137
|
+
|
131
138
|
def void(identification, options = {})
|
132
139
|
commit(build_void_request(identification, options), options)
|
133
140
|
end
|
@@ -135,17 +142,80 @@ module ActiveMerchant #:nodoc:
|
|
135
142
|
def refund(money, identification, options = {})
|
136
143
|
commit(build_credit_request(money, identification, options), options)
|
137
144
|
end
|
138
|
-
|
145
|
+
|
139
146
|
def credit(money, identification, options = {})
|
140
147
|
deprecated CREDIT_DEPRECATION_MESSAGE
|
141
148
|
refund(money, identification, options)
|
142
149
|
end
|
143
150
|
|
151
|
+
# Creates or updates a cybersource customer profile, aka a subscription with type "on-demand"
|
152
|
+
# to charge the card while creating a profile, pass options[:setup_fee] => money
|
153
|
+
def store(credit_card_or_reference, options = {})
|
154
|
+
|
155
|
+
requires!(options, :order_id)
|
156
|
+
setup_address_hash(options)
|
157
|
+
|
158
|
+
if credit_card_or_reference.respond_to?(:number)
|
159
|
+
# create subscription
|
160
|
+
requires!(options, :billing_address, :email)
|
161
|
+
requires!(options[:billing_address], :first_name, :last_name)
|
162
|
+
|
163
|
+
# set subscription options for storing the credit card
|
164
|
+
options[:subscription] ||={}
|
165
|
+
options[:subscription].merge!(:frequency => "on-demand", :amount => 0, :auto_renew => false)
|
166
|
+
|
167
|
+
setup_address_hash(options)
|
168
|
+
request = build_create_subscription_request(credit_card_or_reference, options)
|
169
|
+
else
|
170
|
+
# update subscription
|
171
|
+
request = build_update_subscription_request(credit_card_or_reference, options)
|
172
|
+
end
|
173
|
+
|
174
|
+
commit(request, options)
|
175
|
+
end
|
176
|
+
|
177
|
+
# retrieves a customer subscription/profile
|
178
|
+
def retrieve(reference, options = {})
|
179
|
+
requires!(options, :order_id)
|
180
|
+
commit(build_retrieve_subscription_request(reference, options), options)
|
181
|
+
end
|
182
|
+
|
183
|
+
# removes a customer subscription/profile
|
184
|
+
def unstore(reference, options = {})
|
185
|
+
requires!(options, :order_id)
|
186
|
+
commit(build_delete_subscription_request(reference, options), options)
|
187
|
+
end
|
188
|
+
|
189
|
+
# Creates or updates a Cybersource recurring payment profile/subscription
|
190
|
+
def recurring(money, credit_card_or_reference, options = {})
|
191
|
+
requires!(options, :order_id, :subscription)
|
192
|
+
requires!(options[:subscription], [:frequency, "on-demand", "weekly", "bi-weekly", "semi-monthly", "quarterly", "quad-weekly", "semi-annually", "annually"])
|
193
|
+
|
194
|
+
options[:subscription].merge!(:amount => money)
|
195
|
+
|
196
|
+
setup_address_hash(options)
|
197
|
+
|
198
|
+
if credit_card_or_reference.respond_to?(:number)
|
199
|
+
# create subscription
|
200
|
+
requires!(options, :billing_address, :email)
|
201
|
+
requires!(options[:billing_address], :first_name, :last_name)
|
202
|
+
|
203
|
+
setup_address_hash(options)
|
204
|
+
request = build_create_subscription_request(credit_card_or_reference, options)
|
205
|
+
else
|
206
|
+
# update subscription
|
207
|
+
request = build_update_subscription_request(credit_card_or_reference, options)
|
208
|
+
end
|
209
|
+
|
210
|
+
commit(request, options)
|
211
|
+
end
|
212
|
+
|
213
|
+
|
144
214
|
# CyberSource requires that you provide line item information for tax calculations
|
145
215
|
# If you do not have prices for each item or want to simplify the situation then pass in one fake line item that costs the subtotal of the order
|
146
216
|
#
|
147
|
-
# The line_item hash goes in the options hash and should look like
|
148
|
-
#
|
217
|
+
# The line_item hash goes in the options hash and should look like
|
218
|
+
#
|
149
219
|
# :line_items => [
|
150
220
|
# {
|
151
221
|
# :declared_value => '1',
|
@@ -165,22 +235,23 @@ module ActiveMerchant #:nodoc:
|
|
165
235
|
#
|
166
236
|
# This functionality is only supported by this particular gateway may
|
167
237
|
# be changed at any time
|
168
|
-
def calculate_tax(
|
238
|
+
def calculate_tax(options)
|
169
239
|
requires!(options, :line_items)
|
240
|
+
|
170
241
|
setup_address_hash(options)
|
171
|
-
commit(build_tax_calculation_request(
|
242
|
+
commit(build_tax_calculation_request(options), options)
|
172
243
|
end
|
173
|
-
|
174
|
-
private
|
175
|
-
# Create all address hash key value pairs so that we still function if we were only provided with one or two of them
|
244
|
+
|
245
|
+
private
|
246
|
+
# Create all address hash key value pairs so that we still function if we were only provided with one or two of them
|
176
247
|
def setup_address_hash(options)
|
177
248
|
options[:billing_address] = options[:billing_address] || options[:address] || {}
|
178
249
|
options[:shipping_address] = options[:shipping_address] || {}
|
179
250
|
end
|
180
|
-
|
251
|
+
|
181
252
|
def build_auth_request(money, creditcard, options)
|
182
253
|
xml = Builder::XmlMarkup.new :indent => 2
|
183
|
-
add_address(xml,
|
254
|
+
add_address(xml, options[:billing_address], options)
|
184
255
|
add_purchase_data(xml, money, true, options)
|
185
256
|
add_creditcard(xml, creditcard)
|
186
257
|
add_auth_service(xml)
|
@@ -188,17 +259,17 @@ module ActiveMerchant #:nodoc:
|
|
188
259
|
xml.target!
|
189
260
|
end
|
190
261
|
|
191
|
-
def build_tax_calculation_request(
|
262
|
+
def build_tax_calculation_request(options)
|
192
263
|
xml = Builder::XmlMarkup.new :indent => 2
|
193
|
-
add_address(xml,
|
194
|
-
add_address(xml,
|
264
|
+
add_address(xml, options[:billing_address], options, false)
|
265
|
+
add_address(xml, options[:shipping_address], options, true) unless options[:shipping_address].empty?
|
195
266
|
add_line_item_data(xml, options)
|
196
267
|
add_purchase_data(xml, 0, false, options)
|
197
|
-
add_tax_service(xml)
|
268
|
+
add_tax_service(xml, options)
|
198
269
|
add_business_rules_data(xml)
|
199
270
|
xml.target!
|
200
271
|
end
|
201
|
-
|
272
|
+
|
202
273
|
def build_capture_request(money, authorization, options)
|
203
274
|
order_id, request_id, request_token = authorization.split(";")
|
204
275
|
options[:order_id] = order_id
|
@@ -208,22 +279,22 @@ module ActiveMerchant #:nodoc:
|
|
208
279
|
add_capture_service(xml, request_id, request_token)
|
209
280
|
add_business_rules_data(xml)
|
210
281
|
xml.target!
|
211
|
-
end
|
282
|
+
end
|
212
283
|
|
213
|
-
def build_purchase_request(money,
|
284
|
+
def build_purchase_request(money, payment_source, options)
|
214
285
|
xml = Builder::XmlMarkup.new :indent => 2
|
215
|
-
add_address(xml,
|
286
|
+
add_address(xml, options[:billing_address], options)
|
216
287
|
add_purchase_data(xml, money, true, options)
|
217
|
-
|
218
|
-
add_purchase_service(xml, options)
|
288
|
+
add_payment_source(xml, payment_source)
|
289
|
+
add_purchase_service(xml, payment_source, options)
|
219
290
|
add_business_rules_data(xml)
|
220
291
|
xml.target!
|
221
292
|
end
|
222
|
-
|
293
|
+
|
223
294
|
def build_void_request(identification, options)
|
224
295
|
order_id, request_id, request_token = identification.split(";")
|
225
296
|
options[:order_id] = order_id
|
226
|
-
|
297
|
+
|
227
298
|
xml = Builder::XmlMarkup.new :indent => 2
|
228
299
|
add_void_service(xml, request_id, request_token)
|
229
300
|
xml.target!
|
@@ -241,11 +312,84 @@ module ActiveMerchant #:nodoc:
|
|
241
312
|
def build_credit_request(money, identification, options)
|
242
313
|
order_id, request_id, request_token = identification.split(";")
|
243
314
|
options[:order_id] = order_id
|
244
|
-
|
315
|
+
|
245
316
|
xml = Builder::XmlMarkup.new :indent => 2
|
246
317
|
add_purchase_data(xml, money, true, options)
|
247
318
|
add_credit_service(xml, request_id, request_token)
|
248
|
-
|
319
|
+
|
320
|
+
xml.target!
|
321
|
+
end
|
322
|
+
|
323
|
+
def build_create_subscription_request(payment_source, options)
|
324
|
+
xml = Builder::XmlMarkup.new :indent => 2
|
325
|
+
add_address(xml, options[:billing_address], options)
|
326
|
+
add_purchase_data(xml, options[:setup_fee], true, options)
|
327
|
+
|
328
|
+
|
329
|
+
case determine_funding_source(payment_source)
|
330
|
+
when :credit_card then add_creditcard(xml, payment_source)
|
331
|
+
when :check then add_check(xml, payment_source)
|
332
|
+
else raise ArgumentError, "Unsupported funding source provided"
|
333
|
+
end
|
334
|
+
|
335
|
+
add_subscription(xml, options, payment_source)
|
336
|
+
add_subscription_create_service(xml, options)
|
337
|
+
add_business_rules_data(xml)
|
338
|
+
xml.target!
|
339
|
+
end
|
340
|
+
|
341
|
+
def build_update_subscription_request(identification, options)
|
342
|
+
reference_code, subscription_id, request_token = identification.split(";")
|
343
|
+
options[:subscription] ||= {}
|
344
|
+
options[:subscription][:subscription_id] = subscription_id
|
345
|
+
|
346
|
+
xml = Builder::XmlMarkup.new :indent => 2
|
347
|
+
add_address(xml, options[:billing_address], options) unless options[:billing_address].blank?
|
348
|
+
add_purchase_data(xml, options[:setup_fee], true, options) unless options[:setup_fee].blank?
|
349
|
+
add_creditcard(xml, options[:credit_card]) if options[:credit_card]
|
350
|
+
add_subscription(xml, options)
|
351
|
+
add_subscription_update_service(xml, options)
|
352
|
+
add_business_rules_data(xml)
|
353
|
+
xml.target!
|
354
|
+
end
|
355
|
+
|
356
|
+
def build_retrieve_subscription_request(identification, options)
|
357
|
+
reference_code, subscription_id, request_token = identification.split(";")
|
358
|
+
options[:subscription] ||= {}
|
359
|
+
options[:subscription][:subscription_id] = subscription_id
|
360
|
+
|
361
|
+
xml = Builder::XmlMarkup.new :indent => 2
|
362
|
+
add_subscription(xml, options)
|
363
|
+
add_subscription_retrieve_service(xml, options)
|
364
|
+
xml.target!
|
365
|
+
end
|
366
|
+
|
367
|
+
def build_delete_subscription_request(identification, options)
|
368
|
+
reference_code, subscription_id, request_token = identification.split(";")
|
369
|
+
options[:subscription] ||= {}
|
370
|
+
options[:subscription][:subscription_id] = subscription_id
|
371
|
+
|
372
|
+
xml = Builder::XmlMarkup.new :indent => 2
|
373
|
+
add_subscription(xml, options)
|
374
|
+
add_subscription_delete_service(xml, options)
|
375
|
+
xml.target!
|
376
|
+
end
|
377
|
+
|
378
|
+
def build_subscription_purchase_request(money, identification, options)
|
379
|
+
reference_code, subscription_id, request_token = identification.split(";")
|
380
|
+
options[:subscription] ||= {}
|
381
|
+
options[:subscription][:subscription_id] = subscription_id
|
382
|
+
|
383
|
+
xml = Builder::XmlMarkup.new :indent => 2
|
384
|
+
add_purchase_data(xml, money, true, options)
|
385
|
+
add_subscription(xml, options)
|
386
|
+
|
387
|
+
case options[:type]
|
388
|
+
when :credit_card then add_cc_purchase_service(xml, options)
|
389
|
+
when :check then add_check_service(xml)
|
390
|
+
end
|
391
|
+
|
392
|
+
add_business_rules_data(xml)
|
249
393
|
xml.target!
|
250
394
|
end
|
251
395
|
|
@@ -253,13 +397,13 @@ module ActiveMerchant #:nodoc:
|
|
253
397
|
xml.tag! 'businessRules' do
|
254
398
|
xml.tag!('ignoreAVSResult', 'true') if @options[:ignore_avs]
|
255
399
|
xml.tag!('ignoreCVResult', 'true') if @options[:ignore_cvv]
|
256
|
-
end
|
400
|
+
end
|
257
401
|
end
|
258
|
-
|
402
|
+
|
259
403
|
def add_line_item_data(xml, options)
|
260
404
|
options[:line_items].each_with_index do |value, index|
|
261
405
|
xml.tag! 'item', {'id' => index} do
|
262
|
-
xml.tag! 'unitPrice', amount(value[:declared_value])
|
406
|
+
xml.tag! 'unitPrice', amount(value[:declared_value])
|
263
407
|
xml.tag! 'quantity', value[:quantity]
|
264
408
|
xml.tag! 'productCode', value[:code] || 'shipping_only'
|
265
409
|
xml.tag! 'productName', value[:description]
|
@@ -267,37 +411,51 @@ module ActiveMerchant #:nodoc:
|
|
267
411
|
end
|
268
412
|
end
|
269
413
|
end
|
270
|
-
|
414
|
+
|
271
415
|
def add_merchant_data(xml, options)
|
272
416
|
xml.tag! 'merchantID', @options[:login]
|
273
417
|
xml.tag! 'merchantReferenceCode', options[:order_id]
|
274
418
|
xml.tag! 'clientLibrary' ,'Ruby Active Merchant'
|
275
|
-
xml.tag! 'clientLibraryVersion',
|
276
|
-
xml.tag! 'clientEnvironment' ,
|
419
|
+
xml.tag! 'clientLibraryVersion', VERSION
|
420
|
+
xml.tag! 'clientEnvironment' , RUBY_PLATFORM
|
421
|
+
end
|
422
|
+
|
423
|
+
def add_payment_source(xml, source, options={})
|
424
|
+
case determine_funding_source(source)
|
425
|
+
#when :subscription then add_customer_vault_id(params, source)
|
426
|
+
when :credit_card then add_creditcard(xml, source)
|
427
|
+
when :check then add_check(xml, source)
|
428
|
+
end
|
277
429
|
end
|
278
430
|
|
279
|
-
def add_purchase_data(xml, money
|
431
|
+
def add_purchase_data(xml, money, include_grand_total = false, options={})
|
432
|
+
money ||=0
|
280
433
|
xml.tag! 'purchaseTotals' do
|
281
434
|
xml.tag! 'currency', options[:currency] || currency(money)
|
282
|
-
xml.tag!('grandTotalAmount', amount(money)) if include_grand_total
|
435
|
+
xml.tag!('grandTotalAmount', amount(money)) if include_grand_total
|
283
436
|
end
|
284
437
|
end
|
285
438
|
|
286
|
-
def add_address(xml,
|
439
|
+
def add_address(xml, address, options, shipTo = false)
|
287
440
|
xml.tag! shipTo ? 'shipTo' : 'billTo' do
|
288
|
-
xml.tag! 'firstName',
|
289
|
-
xml.tag! 'lastName',
|
290
|
-
xml.tag! 'street1',
|
291
|
-
xml.tag! 'street2',
|
292
|
-
xml.tag! 'city',
|
293
|
-
xml.tag! 'state',
|
294
|
-
xml.tag! 'postalCode',
|
295
|
-
xml.tag! 'country',
|
296
|
-
xml.tag! '
|
297
|
-
|
298
|
-
|
299
|
-
|
300
|
-
|
441
|
+
xml.tag! 'firstName', address[:first_name]
|
442
|
+
xml.tag! 'lastName', address[:last_name]
|
443
|
+
xml.tag! 'street1', address[:address1]
|
444
|
+
xml.tag! 'street2', address[:address2]
|
445
|
+
xml.tag! 'city', address[:city]
|
446
|
+
xml.tag! 'state', address[:state]
|
447
|
+
xml.tag! 'postalCode', address[:zip]
|
448
|
+
xml.tag! 'country', address[:country]
|
449
|
+
xml.tag! 'company', address[:company] unless address[:company].blank?
|
450
|
+
xml.tag! 'companyTaxID', address[:companyTaxID] unless address[:company_tax_id].blank?
|
451
|
+
xml.tag! 'phoneNumber', address[:phone_number] unless address[:phone_number].blank?
|
452
|
+
xml.tag! 'email', options[:email] unless options[:email].blank?
|
453
|
+
xml.tag! 'driversLicenseNumber', options[:drivers_license_number] unless options[:drivers_license_number].blank?
|
454
|
+
xml.tag! 'driversLicenseState', options[:drivers_license_state] unless options[:drivers_license_state].blank?
|
455
|
+
end
|
456
|
+
end
|
457
|
+
|
458
|
+
def add_creditcard(xml, creditcard)
|
301
459
|
xml.tag! 'card' do
|
302
460
|
xml.tag! 'accountNumber', creditcard.number
|
303
461
|
xml.tag! 'expirationMonth', format(creditcard.month, :two_digits)
|
@@ -307,15 +465,35 @@ module ActiveMerchant #:nodoc:
|
|
307
465
|
end
|
308
466
|
end
|
309
467
|
|
310
|
-
def
|
468
|
+
def add_check(xml, check)
|
469
|
+
#convert check object account type into cybs account type code
|
470
|
+
if check.account_type == "checking"
|
471
|
+
accountType = check.account_holder_type == "business" ? 'X' : 'C'
|
472
|
+
else
|
473
|
+
accountType = 'S'
|
474
|
+
end
|
475
|
+
|
476
|
+
xml.tag! 'check' do
|
477
|
+
xml.tag! 'accountNumber', check.account_number
|
478
|
+
xml.tag! 'accountType', accountType
|
479
|
+
xml.tag! 'bankTransitNumber', check.routing_number
|
480
|
+
xml.tag! 'checkNumber', check.number if check.number
|
481
|
+
end
|
482
|
+
end
|
483
|
+
|
484
|
+
def add_check_service(xml)
|
485
|
+
xml.tag! 'ecDebitService', {'run' => 'true'}
|
486
|
+
end
|
487
|
+
|
488
|
+
def add_tax_service(xml, options)
|
311
489
|
xml.tag! 'taxService', {'run' => 'true'} do
|
312
|
-
xml.tag!('nexus',
|
313
|
-
xml.tag!('sellerRegistration', @
|
490
|
+
xml.tag!('nexus', options[:nexus]) unless options[:nexus].blank?
|
491
|
+
xml.tag!('sellerRegistration', @ptions[:vat_reg_number]) unless options[:vat_reg_number].blank?
|
314
492
|
end
|
315
493
|
end
|
316
494
|
|
317
495
|
def add_auth_service(xml)
|
318
|
-
xml.tag! 'ccAuthService', {'run' => 'true'}
|
496
|
+
xml.tag! 'ccAuthService', {'run' => 'true'}
|
319
497
|
end
|
320
498
|
|
321
499
|
def add_capture_service(xml, request_id, request_token)
|
@@ -325,11 +503,18 @@ module ActiveMerchant #:nodoc:
|
|
325
503
|
end
|
326
504
|
end
|
327
505
|
|
328
|
-
def add_purchase_service(xml, options)
|
506
|
+
def add_purchase_service(xml, source, options)
|
507
|
+
case determine_funding_source(source)
|
508
|
+
when :credit_card then add_cc_purchase_service(xml, options)
|
509
|
+
when :check then add_check_service(xml)
|
510
|
+
end
|
511
|
+
end
|
512
|
+
|
513
|
+
def add_cc_purchase_service(xml, options)
|
329
514
|
xml.tag! 'ccAuthService', {'run' => 'true'}
|
330
515
|
xml.tag! 'ccCaptureService', {'run' => 'true'}
|
331
516
|
end
|
332
|
-
|
517
|
+
|
333
518
|
def add_void_service(xml, request_id, request_token)
|
334
519
|
xml.tag! 'voidService', {'run' => 'true'} do
|
335
520
|
xml.tag! 'voidRequestID', request_id
|
@@ -351,7 +536,47 @@ module ActiveMerchant #:nodoc:
|
|
351
536
|
end
|
352
537
|
end
|
353
538
|
|
354
|
-
|
539
|
+
|
540
|
+
def add_subscription_create_service(xml, options)
|
541
|
+
add_cc_purchase_service(xml, options) if options[:setup_fee]
|
542
|
+
xml.tag! 'paySubscriptionCreateService', {'run' => 'true'}
|
543
|
+
end
|
544
|
+
|
545
|
+
def add_subscription_update_service(xml, options)
|
546
|
+
add_cc_purchase_service(xml, options) if options[:setup_fee]
|
547
|
+
xml.tag! 'paySubscriptionUpdateService', {'run' => 'true'}
|
548
|
+
end
|
549
|
+
|
550
|
+
def add_subscription_retrieve_service(xml, options)
|
551
|
+
xml.tag! 'paySubscriptionRetrieveService', {'run' => 'true'}
|
552
|
+
end
|
553
|
+
|
554
|
+
def add_subscription_delete_service(xml, options)
|
555
|
+
xml.tag! 'paySubscriptionDeleteService', {'run' => 'true'}
|
556
|
+
end
|
557
|
+
|
558
|
+
def add_subscription(xml, options, payment_source=nil)
|
559
|
+
if payment_source
|
560
|
+
xml.tag! 'subscription' do
|
561
|
+
xml.tag! 'paymentMethod', determine_funding_source(payment_source).to_s.gsub(/_/, " ")
|
562
|
+
end
|
563
|
+
end
|
564
|
+
|
565
|
+
xml.tag! 'recurringSubscriptionInfo' do
|
566
|
+
xml.tag! 'subscriptionID', options[:subscription][:subscription_id]
|
567
|
+
xml.tag! 'status', options[:subscription][:status] if options[:subscription][:status]
|
568
|
+
xml.tag! 'amount', options[:subscription][:amount] if options[:subscription][:amount]
|
569
|
+
xml.tag! 'numberOfPayments', options[:subscription][:occurrences] if options[:subscription][:occurrences]
|
570
|
+
xml.tag! 'automaticRenew', options[:subscription][:auto_renew] if options[:subscription][:auto_renew]
|
571
|
+
xml.tag! 'frequency', options[:subscription][:frequency] if options[:subscription][:frequency]
|
572
|
+
xml.tag! 'startDate', options[:subscription][:start_date].strftime("%Y%m%d") if options[:subscription][:start_date]
|
573
|
+
xml.tag! 'endDate', options[:subscription][:end_date].strftime("%Y%m%d") if options[:subscription][:end_date]
|
574
|
+
xml.tag! 'approvalRequired', options[:subscription][:approval_required] || false
|
575
|
+
xml.tag! 'event', options[:subscription][:event] if options[:subscription][:event]
|
576
|
+
xml.tag! 'billPayment', options[:subscription][:bill_payment] if options[:subscription][:bill_payment]
|
577
|
+
end
|
578
|
+
end
|
579
|
+
|
355
580
|
# Where we actually build the full SOAP request using builder
|
356
581
|
def build_request(body, options)
|
357
582
|
xml = Builder::XmlMarkup.new :indent => 2
|
@@ -366,31 +591,32 @@ module ActiveMerchant #:nodoc:
|
|
366
591
|
end
|
367
592
|
end
|
368
593
|
xml.tag! 's:Body', {'xmlns:xsi' => 'http://www.w3.org/2001/XMLSchema-instance', 'xmlns:xsd' => 'http://www.w3.org/2001/XMLSchema'} do
|
369
|
-
xml.tag! 'requestMessage', {'xmlns' =>
|
594
|
+
xml.tag! 'requestMessage', {'xmlns' => "urn:schemas-cybersource-com:transaction-data-#{XSD_VERSION}"} do
|
370
595
|
add_merchant_data(xml, options)
|
371
596
|
xml << body
|
372
597
|
end
|
373
598
|
end
|
374
599
|
end
|
375
|
-
xml.target!
|
600
|
+
xml.target!
|
376
601
|
end
|
377
|
-
|
602
|
+
|
378
603
|
# Contact CyberSource, make the SOAP request, and parse the reply into a Response object
|
379
604
|
def commit(request, options)
|
380
|
-
|
381
|
-
|
605
|
+
request = build_request(request, options)
|
606
|
+
post_response = ssl_post(test? ? TEST_URL : LIVE_URL, request)
|
607
|
+
response = parse(post_response)
|
382
608
|
success = response[:decision] == "ACCEPT"
|
383
|
-
message = @@response_codes[('r' + response[:reasonCode]).to_sym] rescue response[:message]
|
609
|
+
message = @@response_codes[('r' + response[:reasonCode]).to_sym] rescue response[:message]
|
384
610
|
authorization = success ? [ options[:order_id], response[:requestID], response[:requestToken] ].compact.join(";") : nil
|
385
|
-
|
386
|
-
Response.new(success, message, response,
|
387
|
-
:test => test?,
|
611
|
+
|
612
|
+
Response.new(success, message, response,
|
613
|
+
:test => test?,
|
388
614
|
:authorization => authorization,
|
389
615
|
:avs_result => { :code => response[:avsCode] },
|
390
616
|
:cvv_result => response[:cvCode]
|
391
617
|
)
|
392
618
|
end
|
393
|
-
|
619
|
+
|
394
620
|
# Parse the SOAP response
|
395
621
|
# Technique inspired by the Paypal Gateway
|
396
622
|
def parse(xml)
|
@@ -398,19 +624,19 @@ module ActiveMerchant #:nodoc:
|
|
398
624
|
xml = REXML::Document.new(xml)
|
399
625
|
if root = REXML::XPath.first(xml, "//c:replyMessage")
|
400
626
|
root.elements.to_a.each do |node|
|
401
|
-
case node.name
|
627
|
+
case node.name
|
402
628
|
when 'c:reasonCode'
|
403
629
|
reply[:message] = reply(node.text)
|
404
630
|
else
|
405
631
|
parse_element(reply, node)
|
406
632
|
end
|
407
633
|
end
|
408
|
-
elsif root = REXML::XPath.first(xml, "//soap:Fault")
|
634
|
+
elsif root = REXML::XPath.first(xml, "//soap:Fault")
|
409
635
|
parse_element(reply, root)
|
410
636
|
reply[:message] = "#{reply[:faultcode]}: #{reply[:faultstring]}"
|
411
637
|
end
|
412
638
|
return reply
|
413
|
-
end
|
639
|
+
end
|
414
640
|
|
415
641
|
def parse_element(reply, node)
|
416
642
|
if node.has_elements?
|
@@ -419,12 +645,22 @@ module ActiveMerchant #:nodoc:
|
|
419
645
|
if node.parent.name =~ /item/
|
420
646
|
parent = node.parent.name + (node.parent.attributes["id"] ? "_" + node.parent.attributes["id"] : '')
|
421
647
|
reply[(parent + '_' + node.name).to_sym] = node.text
|
422
|
-
else
|
648
|
+
else
|
423
649
|
reply[node.name.to_sym] = node.text
|
424
650
|
end
|
425
651
|
end
|
426
652
|
return reply
|
427
653
|
end
|
428
|
-
|
429
|
-
|
430
|
-
|
654
|
+
|
655
|
+
def determine_funding_source(source)
|
656
|
+
case
|
657
|
+
when source.is_a?(String) then :subscription
|
658
|
+
when CreditCard.card_companies.keys.include?(card_brand(source)) then :credit_card
|
659
|
+
when card_brand(source) == 'check' then :check
|
660
|
+
else raise ArgumentError, "Unsupported funding source provided"
|
661
|
+
end
|
662
|
+
end
|
663
|
+
|
664
|
+
end
|
665
|
+
end
|
666
|
+
end
|