activemerchant 1.75.0 → 1.76.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.
- checksums.yaml +4 -4
- data/CHANGELOG +27 -0
- data/lib/active_merchant/billing/gateways/adyen.rb +12 -6
- data/lib/active_merchant/billing/gateways/barclaycard_smartpay.rb +1 -1
- data/lib/active_merchant/billing/gateways/cardprocess.rb +254 -0
- data/lib/active_merchant/billing/gateways/checkout_v2.rb +17 -24
- data/lib/active_merchant/billing/gateways/credorax.rb +8 -1
- data/lib/active_merchant/billing/gateways/firstdata_e4.rb +14 -3
- data/lib/active_merchant/billing/gateways/global_collect.rb +5 -3
- data/lib/active_merchant/billing/gateways/iats_payments.rb +2 -2
- data/lib/active_merchant/billing/gateways/mercado_pago.rb +10 -6
- data/lib/active_merchant/billing/gateways/migs.rb +17 -5
- data/lib/active_merchant/billing/gateways/paymentez.rb +273 -0
- data/lib/active_merchant/billing/gateways/payu_latam.rb +15 -14
- data/lib/active_merchant/billing/gateways/quickbooks.rb +10 -0
- data/lib/active_merchant/billing/gateways/safe_charge.rb +24 -8
- data/lib/active_merchant/billing/gateways/sage_pay.rb +11 -4
- data/lib/active_merchant/connection.rb +6 -1
- data/lib/active_merchant/version.rb +1 -1
- metadata +4 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: fe5e2a6f611e503ee6acfb6453f46b914f9b93c4
|
4
|
+
data.tar.gz: ecdf4eaa3a3d3697aa769239ac59ac4121f5d46a
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 506d1d259018973cc2d4c9b6c37442f7fdc8903595a5cd6056ab32fa2608bef32d0e94d1f09179f2b660b99e1197c85c146f0afb0a60cd07a42432ebff0d5fc8
|
7
|
+
data.tar.gz: 8e8ca9a39966245232a7b64a685939e7852eab12f28fc3f1dc540b9e10a39c04517fd912bc609d56101e4e16d0165fe5b7a1f45570b009a35aaf27be09760284
|
data/CHANGELOG
CHANGED
@@ -2,6 +2,33 @@
|
|
2
2
|
|
3
3
|
== HEAD
|
4
4
|
|
5
|
+
== Version 1.76.0 (January 3, 2018)
|
6
|
+
* PayU Latam: Change default text for description [nfarve] #2669
|
7
|
+
* Checkout V2: Allows AVS and CVV result details to come through on authorizations [deedeelavinder] #2650
|
8
|
+
* Global Collect: Adds boolean option for pre_authorization [deeedeelavinder] #2651
|
9
|
+
* Credorax: Pass Transaction Type field [curiousepic] #2653
|
10
|
+
* Add CardProcess Gateway [bpollack] #2659
|
11
|
+
* Safe Charge: Provision 3DS option for approved merchants [deedeelavinder] #2661
|
12
|
+
* PayU Latam: Require payment_country on initialize [curiousepic] #2663
|
13
|
+
* Adyen: Remove CVV as Required Field and Determines shopperInteraction [nfarve] #2665
|
14
|
+
* SafeCharge: add support for VendorID, WebsiteID, and IP logging [bpollack] #2667
|
15
|
+
* Safe Charge: Adds 3DS flag [deedeelavinder] #2668
|
16
|
+
* CardProcess: Fix success? to always return true or false [bpollack] #2674
|
17
|
+
* SagePay: Correct CVV, AVS codes for Sagepay [singhai0] #2670
|
18
|
+
* PayU Latam: Count pending Voids as successful [curiousepic] #2677
|
19
|
+
* Mercado Pago: Ensure acess tokens are URL escaped [bpollack] #2675
|
20
|
+
* MiGS: Update hash format to SHA256 and restore remote tests [bpollack] #2676
|
21
|
+
* MiGS: Support verify calls [bpollack] #2664
|
22
|
+
* iATS: Fix Messages with Failure on iATS Server [nfarve] #2680
|
23
|
+
* Barclaycard Smartpay: Correct repsonse for fraud rejects #2683
|
24
|
+
* Adyen: Allow incomplete addresses in some situations [bpollack] #2684
|
25
|
+
* Paymentez: Add new gateway [bpollack] #2685
|
26
|
+
* PayU Latam: Provide a mechanism to override the amount in verify [dtykocki] #2688
|
27
|
+
* Mercado Pago: Support X-Device-Session-ID Header [bpollack] #2689
|
28
|
+
* Mercado Pago: Support arbitrary additional_info JSON [bpollack] #2691
|
29
|
+
* FirstData E4: Override ECI value for Apple Pay transactions with Discover [jasonwebster] #2671
|
30
|
+
* Quickbooks: Add payment context to Quickbooks charges and refunds [bdewater] #2694
|
31
|
+
|
5
32
|
== Version 1.75.0 (November 9, 2017)
|
6
33
|
* Barclaycard Smartpay: Clean up test options hashes [bpollack] #2632
|
7
34
|
* Barclaycard Smartpay: Extra data fields for credits [bpollack] #2631
|
@@ -45,6 +45,7 @@ module ActiveMerchant #:nodoc:
|
|
45
45
|
add_invoice(post, money, options)
|
46
46
|
add_payment(post, payment)
|
47
47
|
add_extra_data(post, options)
|
48
|
+
add_shopper_interaction(post,payment,options)
|
48
49
|
add_address(post, options)
|
49
50
|
commit('authorise', post)
|
50
51
|
end
|
@@ -97,17 +98,21 @@ module ActiveMerchant #:nodoc:
|
|
97
98
|
post[:selectedBrand] = options[:selected_brand] if options[:selected_brand]
|
98
99
|
post[:deliveryDate] = options[:delivery_date] if options[:delivery_date]
|
99
100
|
post[:merchantOrderReference] = options[:merchant_order_reference] if options[:merchant_order_reference]
|
100
|
-
|
101
|
+
end
|
102
|
+
|
103
|
+
def add_shopper_interaction(post, payment, options={})
|
104
|
+
shopper_interaction = payment.verification_value ? "Ecommerce" : "ContAuth"
|
105
|
+
post[:shopperInteraction] = options[:shopper_interaction] || shopper_interaction
|
101
106
|
end
|
102
107
|
|
103
108
|
def add_address(post, options)
|
104
109
|
return unless post[:card] && post[:card].kind_of?(Hash)
|
105
|
-
if address = options[:billing_address] || options[:address]
|
110
|
+
if (address = options[:billing_address] || options[:address]) && address[:country]
|
106
111
|
post[:card][:billingAddress] = {}
|
107
|
-
post[:card][:billingAddress][:street] = address[:address1]
|
108
|
-
post[:card][:billingAddress][:houseNumberOrName] = address[:address2]
|
112
|
+
post[:card][:billingAddress][:street] = address[:address1] || 'N/A'
|
113
|
+
post[:card][:billingAddress][:houseNumberOrName] = address[:address2] || 'N/A'
|
109
114
|
post[:card][:billingAddress][:postalCode] = address[:zip] if address[:zip]
|
110
|
-
post[:card][:billingAddress][:city] = address[:city]
|
115
|
+
post[:card][:billingAddress][:city] = address[:city] || 'N/A'
|
111
116
|
post[:card][:billingAddress][:stateOrProvince] = address[:state] if address[:state]
|
112
117
|
post[:card][:billingAddress][:country] = address[:country] if address[:country]
|
113
118
|
end
|
@@ -138,8 +143,9 @@ module ActiveMerchant #:nodoc:
|
|
138
143
|
number: payment.number,
|
139
144
|
cvc: payment.verification_value
|
140
145
|
}
|
146
|
+
|
141
147
|
card.delete_if{|k,v| v.blank? }
|
142
|
-
requires!(card, :expiryMonth, :expiryYear, :holderName, :number
|
148
|
+
requires!(card, :expiryMonth, :expiryYear, :holderName, :number)
|
143
149
|
post[:card] = card
|
144
150
|
end
|
145
151
|
|
@@ -211,8 +211,8 @@ module ActiveMerchant #:nodoc:
|
|
211
211
|
end
|
212
212
|
|
213
213
|
def success_from(response)
|
214
|
-
return true if response.has_key?('authCode')
|
215
214
|
return true if response['result'] == 'Success'
|
215
|
+
return true if response['resultCode'] == 'Authorised'
|
216
216
|
return true if response['resultCode'] == 'Received'
|
217
217
|
successful_responses = %w([capture-received] [cancel-received] [refund-received])
|
218
218
|
successful_responses.include?(response['response'])
|
@@ -0,0 +1,254 @@
|
|
1
|
+
module ActiveMerchant #:nodoc:
|
2
|
+
module Billing #:nodoc:
|
3
|
+
class CardprocessGateway < Gateway
|
4
|
+
self.test_url = 'https://test.vr-pay-ecommerce.de/v1/payments'
|
5
|
+
self.live_url = 'https://vr-pay-ecommerce.de/v1/payments'
|
6
|
+
|
7
|
+
self.supported_countries = %w[ BE BG CZ DK DE EE IE ES FR HR IT CY LV LT LU
|
8
|
+
MT HU NL AT PL PT RO SI SK FI SE GB IS LI NO
|
9
|
+
CH ME MK AL RS TR BA ]
|
10
|
+
self.default_currency = 'EUR'
|
11
|
+
self.supported_cardtypes = [:visa, :master, :american_express, :diners_club, :jcb]
|
12
|
+
|
13
|
+
self.homepage_url = 'https://vr-pay-ecommerce.docs.oppwa.com/'
|
14
|
+
self.display_name = 'CardProcess VR-Pay'
|
15
|
+
self.money_format = :dollars
|
16
|
+
|
17
|
+
STANDARD_ERROR_CODE_MAPPING = {}
|
18
|
+
|
19
|
+
# Creates a new CardProcess Gateway
|
20
|
+
#
|
21
|
+
# The gateway requires a valid login, password, and entity ID
|
22
|
+
# to be passed in the +options+ hash.
|
23
|
+
#
|
24
|
+
# === Options
|
25
|
+
#
|
26
|
+
# * <tt>:user_id</tt> -- The CardProcess user ID
|
27
|
+
# * <tt>:password</tt> -- The CardProcess password
|
28
|
+
# * <tt>:entity_id</tt> -- The CardProcess channel or entity ID for any transactions
|
29
|
+
def initialize(options={})
|
30
|
+
requires!(options, :user_id, :password, :entity_id)
|
31
|
+
super
|
32
|
+
# This variable exists purely to allow remote tests to force error codes;
|
33
|
+
# the lack of a setter despite its usage is intentional.
|
34
|
+
@test_options = {}
|
35
|
+
end
|
36
|
+
|
37
|
+
def purchase(money, payment, options = {})
|
38
|
+
post = {}
|
39
|
+
add_invoice(post, money, options)
|
40
|
+
add_payment(post, payment)
|
41
|
+
add_address(post, payment, options)
|
42
|
+
add_customer_data(post, options)
|
43
|
+
|
44
|
+
commit('DB', post)
|
45
|
+
end
|
46
|
+
|
47
|
+
def authorize(money, payment, options = {})
|
48
|
+
post = {}
|
49
|
+
add_invoice(post, money, options)
|
50
|
+
add_payment(post, payment)
|
51
|
+
add_address(post, payment, options)
|
52
|
+
add_customer_data(post, options)
|
53
|
+
|
54
|
+
commit('PA', post)
|
55
|
+
end
|
56
|
+
|
57
|
+
def capture(money, authorization, options = {})
|
58
|
+
post = {
|
59
|
+
id: authorization
|
60
|
+
}
|
61
|
+
add_invoice(post, money, options)
|
62
|
+
commit('CP', post)
|
63
|
+
end
|
64
|
+
|
65
|
+
def refund(money, authorization, options = {})
|
66
|
+
post = {
|
67
|
+
id: authorization
|
68
|
+
}
|
69
|
+
add_invoice(post, money, options)
|
70
|
+
commit('RF', post)
|
71
|
+
end
|
72
|
+
|
73
|
+
def credit(money, payment, options = {})
|
74
|
+
post = {}
|
75
|
+
add_invoice(post, money, options)
|
76
|
+
add_payment(post, payment)
|
77
|
+
add_address(post, payment, options)
|
78
|
+
add_customer_data(post, options)
|
79
|
+
|
80
|
+
commit('CD', post)
|
81
|
+
end
|
82
|
+
|
83
|
+
def void(authorization, _options = {})
|
84
|
+
post = {
|
85
|
+
id: authorization
|
86
|
+
}
|
87
|
+
commit('RV', post)
|
88
|
+
end
|
89
|
+
|
90
|
+
def verify(credit_card, options = {})
|
91
|
+
MultiResponse.run do |r|
|
92
|
+
r.process { authorize(100, credit_card, options) }
|
93
|
+
r.process { void(r.authorization, options) }
|
94
|
+
end
|
95
|
+
end
|
96
|
+
|
97
|
+
def supports_scrubbing?
|
98
|
+
true
|
99
|
+
end
|
100
|
+
|
101
|
+
def scrub(transcript)
|
102
|
+
transcript
|
103
|
+
.gsub(%r{(authentication\.[^=]+=)[^&]+}, '\1[FILTERED]')
|
104
|
+
.gsub(%r{(card\.number=)\d+}, '\1[FILTERED]')
|
105
|
+
.gsub(%r{(cvv=)\d{3,4}}, '\1[FILTERED]\2')
|
106
|
+
end
|
107
|
+
|
108
|
+
private
|
109
|
+
|
110
|
+
def add_customer_data(post, options)
|
111
|
+
post['customer.ip'] = options[:ip] if options[:ip]
|
112
|
+
end
|
113
|
+
|
114
|
+
def add_address(post, _card, options)
|
115
|
+
if (address = options[:billing_address] || options[:address])
|
116
|
+
post[:billing] = hashify_address(address)
|
117
|
+
end
|
118
|
+
|
119
|
+
if (shipping = options[:shipping_address])
|
120
|
+
post[:shipping] = hashify_address(shipping)
|
121
|
+
end
|
122
|
+
end
|
123
|
+
|
124
|
+
def add_invoice(post, money, options)
|
125
|
+
return if money.nil?
|
126
|
+
post[:amount] = amount(money)
|
127
|
+
post[:currency] = (options[:currency] || currency(money))
|
128
|
+
post[:merchantInvoiceId] = options[:merchant_invoice_id] if options[:merchant_invoice_id]
|
129
|
+
post[:merchantTransactionId] = options[:merchant_transaction_id] if options[:merchant_transaction_id]
|
130
|
+
post[:transactionCategory] = options[:transaction_category] if options[:transaction_category]
|
131
|
+
end
|
132
|
+
|
133
|
+
def add_payment(post, payment)
|
134
|
+
return if payment.is_a?(String)
|
135
|
+
post[:paymentBrand] = payment.brand.upcase if payment.brand
|
136
|
+
post[:card] ||= {}
|
137
|
+
post[:card][:number] = payment.number
|
138
|
+
post[:card][:holder] = payment.name
|
139
|
+
post[:card][:expiryMonth] = sprintf('%02d', payment.month)
|
140
|
+
post[:card][:expiryYear] = sprintf('%02d', payment.year)
|
141
|
+
post[:card][:cvv] = payment.verification_value
|
142
|
+
end
|
143
|
+
|
144
|
+
def parse(body)
|
145
|
+
JSON.parse(body)
|
146
|
+
end
|
147
|
+
|
148
|
+
def commit(action, parameters)
|
149
|
+
url = (test? ? test_url : live_url)
|
150
|
+
if (id = parameters.delete(:id))
|
151
|
+
url += "/#{id}"
|
152
|
+
end
|
153
|
+
|
154
|
+
begin
|
155
|
+
raw_response = ssl_post(url, post_data(action, parameters.merge(@test_options)))
|
156
|
+
rescue ResponseError => e
|
157
|
+
raw_response = e.response.body
|
158
|
+
end
|
159
|
+
response = parse(raw_response)
|
160
|
+
|
161
|
+
Response.new(
|
162
|
+
success_from(response),
|
163
|
+
message_from(response),
|
164
|
+
response,
|
165
|
+
authorization: authorization_from(response),
|
166
|
+
avs_result: AVSResult.new(code: response['result']['avsResponse']),
|
167
|
+
cvv_result: CVVResult.new(response['result']['cvvResponse']),
|
168
|
+
test: test?,
|
169
|
+
error_code: error_code_from(response)
|
170
|
+
)
|
171
|
+
end
|
172
|
+
|
173
|
+
def success_from(response)
|
174
|
+
!(response['result']['code'] =~ /^(000\.000\.|000\.100\.1|000\.[36])/).nil?
|
175
|
+
end
|
176
|
+
|
177
|
+
def message_from(response)
|
178
|
+
response['result']['description']
|
179
|
+
end
|
180
|
+
|
181
|
+
def authorization_from(response)
|
182
|
+
response['id']
|
183
|
+
end
|
184
|
+
|
185
|
+
def post_data(action, parameters = {})
|
186
|
+
post = parameters.clone
|
187
|
+
post[:authentication] ||= {}
|
188
|
+
post[:authentication][:userId] = @options[:user_id]
|
189
|
+
post[:authentication][:password] = @options[:password]
|
190
|
+
post[:authentication][:entityId] = @options[:entity_id]
|
191
|
+
post[:paymentType] = action
|
192
|
+
dot_flatten_hash(post).map {|key, value| "#{key}=#{CGI.escape(value.to_s)}"}.join("&")
|
193
|
+
end
|
194
|
+
|
195
|
+
def error_code_from(response)
|
196
|
+
unless success_from(response)
|
197
|
+
case response['result']['code']
|
198
|
+
when '100.100.101'
|
199
|
+
STANDARD_ERROR_CODE[:incorrect_number]
|
200
|
+
when '100.100.303'
|
201
|
+
STANDARD_ERROR_CODE[:expired_card]
|
202
|
+
when /100\.100\.(201|301|305)/
|
203
|
+
STANDARD_ERROR_CODE[:invalid_expiry_date]
|
204
|
+
when /100.100.60[01]/
|
205
|
+
STANDARD_ERROR_CODE[:invalid_cvc]
|
206
|
+
when '800.100.151'
|
207
|
+
STANDARD_ERROR_CODE[:invalid_number]
|
208
|
+
when '800.100.153'
|
209
|
+
STANDARD_ERROR_CODE[:incorrect_cvc]
|
210
|
+
when /800.800.(102|302)/
|
211
|
+
STANDARD_ERROR_CODE[:incorrect_address]
|
212
|
+
when '800.800.202'
|
213
|
+
STANDARD_ERROR_CODE[:invalid_zip]
|
214
|
+
when '800.100.166'
|
215
|
+
STANDARD_ERROR_CODE[:incorrect_pin]
|
216
|
+
when '800.100.171'
|
217
|
+
STANDARD_ERROR_CODE[:pickup_card]
|
218
|
+
when /^(200|700)\./
|
219
|
+
STANDARD_ERROR_CODE[:config_error]
|
220
|
+
when /^(800\.[17]00|800\.800\.[123])/
|
221
|
+
STANDARD_ERROR_CODE[:card_declined]
|
222
|
+
when /^(900\.[1234]00)/
|
223
|
+
STANDARD_ERROR_CODE[:processing_error]
|
224
|
+
else
|
225
|
+
STANDARD_ERROR_CODE[:processing_error]
|
226
|
+
end
|
227
|
+
end
|
228
|
+
end
|
229
|
+
|
230
|
+
def hashify_address(address)
|
231
|
+
hash = {}
|
232
|
+
hash[:street1] = address[:address1] if address[:address1]
|
233
|
+
hash[:street2] = address[:address2] if address[:address2]
|
234
|
+
hash[:city] = address[:city] if address[:city]
|
235
|
+
hash[:state] = address[:state] if address[:state]
|
236
|
+
hash[:postcode] = address[:zip] if address[:zip]
|
237
|
+
hash[:country] = address[:country] if address[:country]
|
238
|
+
hash
|
239
|
+
end
|
240
|
+
|
241
|
+
def dot_flatten_hash(hash, prefix = '')
|
242
|
+
h = {}
|
243
|
+
hash.each_pair do |k, v|
|
244
|
+
if v.is_a?(Hash)
|
245
|
+
h.merge!(dot_flatten_hash(v, prefix + k.to_s + '.'))
|
246
|
+
else
|
247
|
+
h[prefix + k.to_s] = v
|
248
|
+
end
|
249
|
+
end
|
250
|
+
h
|
251
|
+
end
|
252
|
+
end
|
253
|
+
end
|
254
|
+
end
|
@@ -25,16 +25,7 @@ module ActiveMerchant #:nodoc:
|
|
25
25
|
merged_params = multi.responses.map { |r| r.params }.reduce({}, :merge)
|
26
26
|
succeeded = success_from(merged_params)
|
27
27
|
|
28
|
-
|
29
|
-
succeeded,
|
30
|
-
message_from(succeeded, merged_params),
|
31
|
-
merged_params,
|
32
|
-
authorization: authorization_from(merged_params),
|
33
|
-
avs_result: avs_result(:purchase, succeeded, merged_params),
|
34
|
-
cvv_result: cvv_result(:purchase, succeeded, merged_params),
|
35
|
-
error_code: error_code_from(succeeded, merged_params),
|
36
|
-
test: test?
|
37
|
-
)
|
28
|
+
response(:purchase, succeeded, merged_params)
|
38
29
|
end
|
39
30
|
|
40
31
|
def authorize(amount, payment_method, options={})
|
@@ -132,6 +123,15 @@ module ActiveMerchant #:nodoc:
|
|
132
123
|
end
|
133
124
|
|
134
125
|
succeeded = success_from(response)
|
126
|
+
|
127
|
+
response(action, succeeded, response)
|
128
|
+
end
|
129
|
+
|
130
|
+
def response(action, succeeded, response)
|
131
|
+
successful_response = succeeded && action == :purchase || action == :authorize
|
132
|
+
avs_result = successful_response ? avs_result(response) : nil
|
133
|
+
cvv_result = successful_response ? cvv_result(response) : nil
|
134
|
+
|
135
135
|
Response.new(
|
136
136
|
succeeded,
|
137
137
|
message_from(succeeded, response),
|
@@ -139,8 +139,9 @@ module ActiveMerchant #:nodoc:
|
|
139
139
|
authorization: authorization_from(response),
|
140
140
|
error_code: error_code_from(succeeded, response),
|
141
141
|
test: test?,
|
142
|
-
avs_result: avs_result
|
143
|
-
cvv_result: cvv_result
|
142
|
+
avs_result: avs_result,
|
143
|
+
cvv_result: cvv_result
|
144
|
+
)
|
144
145
|
end
|
145
146
|
|
146
147
|
def headers
|
@@ -162,20 +163,12 @@ module ActiveMerchant #:nodoc:
|
|
162
163
|
test? ? test_url : live_url
|
163
164
|
end
|
164
165
|
|
165
|
-
def avs_result(
|
166
|
-
|
167
|
-
action == :purchase ? AVSResult.new(code: response["card"]["avsCheck"]) : nil
|
168
|
-
else
|
169
|
-
nil
|
170
|
-
end
|
166
|
+
def avs_result(response)
|
167
|
+
response['card'] && response['card']['avsCheck'] ? AVSResult.new(code: response['card']['avsCheck']) : nil
|
171
168
|
end
|
172
169
|
|
173
|
-
def cvv_result(
|
174
|
-
|
175
|
-
action == :purchase ? CVVResult.new(response["card"]["cvvCheck"]) : nil
|
176
|
-
else
|
177
|
-
nil
|
178
|
-
end
|
170
|
+
def cvv_result(response)
|
171
|
+
response['card'] && response['card']['cvvCheck'] ? CVVResult.new(response['card']['cvvCheck']) : nil
|
179
172
|
end
|
180
173
|
|
181
174
|
def parse(body)
|
@@ -129,6 +129,7 @@ module ActiveMerchant #:nodoc:
|
|
129
129
|
add_email(post, options)
|
130
130
|
add_3d_secure(post, options)
|
131
131
|
add_echo(post, options)
|
132
|
+
add_transaction_type(post, options)
|
132
133
|
|
133
134
|
commit(:purchase, post)
|
134
135
|
end
|
@@ -141,6 +142,7 @@ module ActiveMerchant #:nodoc:
|
|
141
142
|
add_email(post, options)
|
142
143
|
add_3d_secure(post, options)
|
143
144
|
add_echo(post, options)
|
145
|
+
add_transaction_type(post, options)
|
144
146
|
|
145
147
|
commit(:authorize, post)
|
146
148
|
end
|
@@ -182,7 +184,8 @@ module ActiveMerchant #:nodoc:
|
|
182
184
|
add_customer_data(post, options)
|
183
185
|
add_email(post, options)
|
184
186
|
add_echo(post, options)
|
185
|
-
|
187
|
+
add_transaction_type(post, options)
|
188
|
+
|
186
189
|
commit(:credit, post)
|
187
190
|
end
|
188
191
|
|
@@ -264,6 +267,10 @@ module ActiveMerchant #:nodoc:
|
|
264
267
|
post[:d2] = options[:echo] unless options[:echo].blank?
|
265
268
|
end
|
266
269
|
|
270
|
+
def add_transaction_type(post, options)
|
271
|
+
post[:a9] = options[:transaction_type] if options[:transaction_type]
|
272
|
+
end
|
273
|
+
|
267
274
|
ACTIONS = {
|
268
275
|
purchase: '1',
|
269
276
|
authorize: '2',
|
@@ -237,13 +237,24 @@ module ActiveMerchant #:nodoc:
|
|
237
237
|
xml.tag! "CardHoldersName", credit_card.name
|
238
238
|
xml.tag! "CardType", card_type(credit_card.brand)
|
239
239
|
|
240
|
-
|
241
|
-
xml.tag! "Ecommerce_Flag", eci.to_s =~ /^[0-9]+$/ ? eci.to_s.rjust(2, '0') : eci
|
242
|
-
|
240
|
+
add_credit_card_eci(xml, credit_card, options)
|
243
241
|
add_credit_card_verification_strings(xml, credit_card, options)
|
244
242
|
end
|
245
243
|
end
|
246
244
|
|
245
|
+
def add_credit_card_eci(xml, credit_card, options)
|
246
|
+
eci = if credit_card.is_a?(NetworkTokenizationCreditCard) && credit_card.source == :apple_pay && card_brand(credit_card) == "discover"
|
247
|
+
# Discover requires any Apple Pay transaction, regardless of in-app
|
248
|
+
# or web, and regardless of the ECI contained in the PKPaymentToken,
|
249
|
+
# to have an ECI value explicitly of 04.
|
250
|
+
"04"
|
251
|
+
else
|
252
|
+
(credit_card.respond_to?(:eci) ? credit_card.eci : nil) || options[:eci] || DEFAULT_ECI
|
253
|
+
end
|
254
|
+
|
255
|
+
xml.tag! "Ecommerce_Flag", eci.to_s =~ /^[0-9]+$/ ? eci.to_s.rjust(2, '0') : eci
|
256
|
+
end
|
257
|
+
|
247
258
|
def add_credit_card_verification_strings(xml, credit_card, options)
|
248
259
|
address = options[:billing_address] || options[:address]
|
249
260
|
if address
|
@@ -30,7 +30,7 @@ module ActiveMerchant #:nodoc:
|
|
30
30
|
def authorize(money, payment, options={})
|
31
31
|
post = nestable_hash
|
32
32
|
add_order(post, money, options)
|
33
|
-
add_payment(post, payment)
|
33
|
+
add_payment(post, payment, options)
|
34
34
|
add_customer_data(post, options, payment)
|
35
35
|
add_address(post, payment, options)
|
36
36
|
|
@@ -106,15 +106,17 @@ module ActiveMerchant #:nodoc:
|
|
106
106
|
}
|
107
107
|
end
|
108
108
|
|
109
|
-
def add_payment(post, payment)
|
109
|
+
def add_payment(post, payment, options)
|
110
110
|
year = format(payment.year, :two_digits)
|
111
111
|
month = format(payment.month, :two_digits)
|
112
112
|
expirydate = "#{month}#{year}"
|
113
|
+
pre_authorization = options[:pre_authorization] ? 'PRE_AUTHORIZATION' : 'FINAL_AUTHORIZATION'
|
113
114
|
|
114
115
|
post["cardPaymentMethodSpecificInput"] = {
|
115
116
|
"paymentProductId" => BRAND_MAP[payment.brand],
|
116
117
|
"skipAuthentication" => "true", # refers to 3DSecure
|
117
|
-
"skipFraudService" => "true"
|
118
|
+
"skipFraudService" => "true",
|
119
|
+
"authorizationMode" => pre_authorization
|
118
120
|
}
|
119
121
|
post["cardPaymentMethodSpecificInput"]["card"] = {
|
120
122
|
"cvv" => payment.verification_value,
|
@@ -225,7 +225,7 @@ module ActiveMerchant #:nodoc:
|
|
225
225
|
end
|
226
226
|
|
227
227
|
def successful_result_message?(response)
|
228
|
-
response[:authorization_result].start_with?('OK')
|
228
|
+
response[:authorization_result] ? response[:authorization_result].start_with?('OK') : false
|
229
229
|
end
|
230
230
|
|
231
231
|
def success_from(response)
|
@@ -233,7 +233,7 @@ module ActiveMerchant #:nodoc:
|
|
233
233
|
end
|
234
234
|
|
235
235
|
def message_from(response)
|
236
|
-
if
|
236
|
+
if !successful_result_message?(response) && response[:authorization_result]
|
237
237
|
return response[:authorization_result].strip
|
238
238
|
elsif(response[:status] == 'Failure')
|
239
239
|
return response[:errors]
|
@@ -114,9 +114,11 @@ module ActiveMerchant #:nodoc:
|
|
114
114
|
|
115
115
|
def add_additional_data(post, options)
|
116
116
|
post[:sponsor_id] = options[:sponsor_id]
|
117
|
+
post[:device_id] = options[:device_id] if options[:device_id]
|
117
118
|
post[:additional_info] = {
|
118
119
|
ip_address: options[:ip_address]
|
119
|
-
}
|
120
|
+
}.merge(options[:additional_info] || {})
|
121
|
+
|
120
122
|
|
121
123
|
add_address(post, options)
|
122
124
|
add_shipping_address(post, options)
|
@@ -191,7 +193,7 @@ module ActiveMerchant #:nodoc:
|
|
191
193
|
if ["capture", "void"].include?(action)
|
192
194
|
response = parse(ssl_request(:put, url(path), post_data(parameters), headers))
|
193
195
|
else
|
194
|
-
response = parse(ssl_post(url(path), post_data(parameters), headers))
|
196
|
+
response = parse(ssl_post(url(path), post_data(parameters), headers(parameters)))
|
195
197
|
end
|
196
198
|
|
197
199
|
Response.new(
|
@@ -221,7 +223,7 @@ module ActiveMerchant #:nodoc:
|
|
221
223
|
end
|
222
224
|
|
223
225
|
def post_data(parameters = {})
|
224
|
-
parameters.to_json
|
226
|
+
parameters.clone.tap { |p| p.delete(:device_id) }.to_json
|
225
227
|
end
|
226
228
|
|
227
229
|
def error_code_from(action, response)
|
@@ -236,13 +238,15 @@ module ActiveMerchant #:nodoc:
|
|
236
238
|
|
237
239
|
def url(action)
|
238
240
|
full_url = (test? ? test_url : live_url)
|
239
|
-
full_url + "/#{action}?access_token=#{@options[:access_token]}"
|
241
|
+
full_url + "/#{action}?access_token=#{CGI.escape(@options[:access_token])}"
|
240
242
|
end
|
241
243
|
|
242
|
-
def headers
|
243
|
-
{
|
244
|
+
def headers(options = {})
|
245
|
+
headers = {
|
244
246
|
"Content-Type" => "application/json"
|
245
247
|
}
|
248
|
+
headers['X-Device-Session-ID'] = options[:device_id] if options[:device_id]
|
249
|
+
headers
|
246
250
|
end
|
247
251
|
|
248
252
|
def handle_response(response)
|
@@ -1,6 +1,6 @@
|
|
1
1
|
require 'active_merchant/billing/gateways/migs/migs_codes'
|
2
2
|
|
3
|
-
require '
|
3
|
+
require 'openssl' # Used in add_secure_hash
|
4
4
|
|
5
5
|
module ActiveMerchant #:nodoc:
|
6
6
|
module Billing #:nodoc:
|
@@ -121,6 +121,13 @@ module ActiveMerchant #:nodoc:
|
|
121
121
|
refund(money, authorization, options)
|
122
122
|
end
|
123
123
|
|
124
|
+
def verify(credit_card, options={})
|
125
|
+
MultiResponse.run do |r|
|
126
|
+
r.process { authorize(100, credit_card, options) }
|
127
|
+
r.process(:ignore_result) { void(r.authorization, options) }
|
128
|
+
end
|
129
|
+
end
|
130
|
+
|
124
131
|
# Checks the status of a previous transaction
|
125
132
|
# This can be useful when a response is not received due to network issues
|
126
133
|
#
|
@@ -187,7 +194,7 @@ module ActiveMerchant #:nodoc:
|
|
187
194
|
|
188
195
|
response_hash = parse(data)
|
189
196
|
|
190
|
-
expected_secure_hash = calculate_secure_hash(response_hash
|
197
|
+
expected_secure_hash = calculate_secure_hash(response_hash, @options[:secure_hash])
|
191
198
|
unless response_hash[:SecureHash] == expected_secure_hash
|
192
199
|
raise SecurityError, "Secure Hash mismatch, response may be tampered with"
|
193
200
|
end
|
@@ -245,6 +252,7 @@ module ActiveMerchant #:nodoc:
|
|
245
252
|
end
|
246
253
|
|
247
254
|
def commit(post)
|
255
|
+
add_secure_hash(post) if @options[:secure_hash]
|
248
256
|
data = ssl_post self.merchant_hosted_url, post_data(post)
|
249
257
|
response_hash = parse(data)
|
250
258
|
response_object(response_hash)
|
@@ -290,12 +298,16 @@ module ActiveMerchant #:nodoc:
|
|
290
298
|
|
291
299
|
def add_secure_hash(post)
|
292
300
|
post[:SecureHash] = calculate_secure_hash(post, @options[:secure_hash])
|
301
|
+
post[:SecureHashType] = 'SHA256'
|
293
302
|
end
|
294
303
|
|
295
304
|
def calculate_secure_hash(post, secure_hash)
|
296
|
-
|
297
|
-
|
298
|
-
|
305
|
+
input = post
|
306
|
+
.reject { |k| %i[SecureHash SecureHashType].include?(k) }
|
307
|
+
.sort
|
308
|
+
.map { |(k, v)| "vpc_#{k}=#{v}" }
|
309
|
+
.join('&')
|
310
|
+
OpenSSL::HMAC.hexdigest('SHA256', [secure_hash].pack('H*'), input).upcase
|
299
311
|
end
|
300
312
|
end
|
301
313
|
end
|
@@ -0,0 +1,273 @@
|
|
1
|
+
require 'base64'
|
2
|
+
require 'digest'
|
3
|
+
|
4
|
+
module ActiveMerchant #:nodoc:
|
5
|
+
module Billing #:nodoc:
|
6
|
+
class PaymentezGateway < Gateway #:nodoc:
|
7
|
+
self.test_url = 'https://ccapi-stg.paymentez.com/v2/'
|
8
|
+
self.live_url = 'https://ccapi.paymentez.com/v2/'
|
9
|
+
|
10
|
+
self.supported_countries = %w[MX EC VE CO BR CL]
|
11
|
+
self.default_currency = 'USD'
|
12
|
+
self.supported_cardtypes = %i[visa master american_express diners_club]
|
13
|
+
|
14
|
+
self.homepage_url = 'https://secure.paymentez.com/'
|
15
|
+
self.display_name = 'Paymentez'
|
16
|
+
|
17
|
+
STANDARD_ERROR_CODE_MAPPING = {
|
18
|
+
1 => :processing_error,
|
19
|
+
6 => :card_declined,
|
20
|
+
9 => :card_declined,
|
21
|
+
10 => :processing_error,
|
22
|
+
11 => :card_declined,
|
23
|
+
12 => :config_error,
|
24
|
+
13 => :config_error,
|
25
|
+
19 => :invalid_cvc,
|
26
|
+
20 => :config_error,
|
27
|
+
21 => :card_declined,
|
28
|
+
22 => :card_declined,
|
29
|
+
23 => :card_declined,
|
30
|
+
24 => :card_declined,
|
31
|
+
25 => :card_declined,
|
32
|
+
26 => :card_declined,
|
33
|
+
27 => :card_declined,
|
34
|
+
28 => :card_declined
|
35
|
+
}.freeze
|
36
|
+
|
37
|
+
CARD_MAPPING = {
|
38
|
+
'visa' => 'vi',
|
39
|
+
'master' => 'mc',
|
40
|
+
'american_express' => 'ax',
|
41
|
+
'diners_club' => 'di'
|
42
|
+
}.freeze
|
43
|
+
|
44
|
+
def initialize(options = {})
|
45
|
+
requires!(options, :application_code, :app_key)
|
46
|
+
super
|
47
|
+
end
|
48
|
+
|
49
|
+
def purchase(money, payment, options = {})
|
50
|
+
post = {}
|
51
|
+
|
52
|
+
add_invoice(post, money, options)
|
53
|
+
add_payment(post, payment)
|
54
|
+
add_customer_data(post, options)
|
55
|
+
|
56
|
+
commit_transaction('debit_cc', post)
|
57
|
+
end
|
58
|
+
|
59
|
+
def authorize(money, payment, options = {})
|
60
|
+
post = {}
|
61
|
+
|
62
|
+
add_invoice(post, money, options)
|
63
|
+
add_customer_data(post, options)
|
64
|
+
|
65
|
+
MultiResponse.run do |r|
|
66
|
+
r.process { store(payment, options) }
|
67
|
+
post[:card] = { token: r.authorization }
|
68
|
+
r.process { commit_transaction('authorize', post) }
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
72
|
+
def capture(_money, authorization, _options = {})
|
73
|
+
post = { transaction: { id: authorization } }
|
74
|
+
|
75
|
+
commit_transaction('capture', post)
|
76
|
+
end
|
77
|
+
|
78
|
+
def refund(_money, authorization, options = {})
|
79
|
+
void(authorization, options)
|
80
|
+
end
|
81
|
+
|
82
|
+
def void(authorization, _options = {})
|
83
|
+
post = { transaction: { id: authorization } }
|
84
|
+
commit_transaction('refund', post)
|
85
|
+
end
|
86
|
+
|
87
|
+
def verify(credit_card, options = {})
|
88
|
+
MultiResponse.run do |r|
|
89
|
+
r.process { authorize(100, credit_card, options) }
|
90
|
+
r.process { void(r.authorization, options) }
|
91
|
+
end
|
92
|
+
end
|
93
|
+
|
94
|
+
def store(credit_card, options = {})
|
95
|
+
post = {}
|
96
|
+
|
97
|
+
add_customer_data(post, options)
|
98
|
+
add_payment(post, credit_card)
|
99
|
+
|
100
|
+
response = commit_card('add', post)
|
101
|
+
if !response.success? && !(token = extract_previous_card_token(response)).nil?
|
102
|
+
unstore(token, options)
|
103
|
+
response = commit_card('add', post)
|
104
|
+
end
|
105
|
+
response
|
106
|
+
end
|
107
|
+
|
108
|
+
def unstore(identification, options = {})
|
109
|
+
post = { card: { token: identification }, user: { id: options[:user_id] }}
|
110
|
+
commit_card('delete', post)
|
111
|
+
end
|
112
|
+
|
113
|
+
def supports_scrubbing?
|
114
|
+
true
|
115
|
+
end
|
116
|
+
|
117
|
+
def scrub(transcript)
|
118
|
+
transcript
|
119
|
+
.gsub(%r{(\\?"number\\?":)(\\?"[^"]+\\?")}, '\1[FILTERED]')
|
120
|
+
.gsub(%r{(\\?"cvc\\?":)(\\?"[^"]+\\?")}, '\1[FILTERED]')
|
121
|
+
.gsub(%r{(Auth-Token: )([A-Za-z0-9=]+)}, '\1[FILTERED]')
|
122
|
+
end
|
123
|
+
|
124
|
+
private
|
125
|
+
|
126
|
+
def add_customer_data(post, options)
|
127
|
+
requires!(options, :user_id, :email)
|
128
|
+
post[:user] ||= {}
|
129
|
+
post[:user][:id] = options[:user_id]
|
130
|
+
post[:user][:email] = options[:email]
|
131
|
+
post[:user][:ip_address] = options[:ip] if options[:ip]
|
132
|
+
post[:user][:fiscal_number] = options[:fiscal_number] if options[:fiscal_number]
|
133
|
+
end
|
134
|
+
|
135
|
+
def add_invoice(post, money, options)
|
136
|
+
post[:session_id] = options[:session_id] if options[:session_id]
|
137
|
+
|
138
|
+
post[:order] ||= {}
|
139
|
+
post[:order][:amount] = amount(money).to_f
|
140
|
+
post[:order][:vat] = options[:vat] if options[:vat]
|
141
|
+
post[:order][:dev_reference] = options[:dev_reference] if options[:dev_reference]
|
142
|
+
post[:order][:description] = options[:description] if options[:description]
|
143
|
+
post[:order][:discount] = options[:discount] if options[:discount]
|
144
|
+
post[:order][:installments] = options[:installments] if options[:installments]
|
145
|
+
post[:order][:installments_type] = options[:installments_type] if options[:installments_type]
|
146
|
+
post[:order][:taxable_amount] = options[:taxable_amount] if options[:taxable_amount]
|
147
|
+
end
|
148
|
+
|
149
|
+
def add_payment(post, payment)
|
150
|
+
post[:card] ||= {}
|
151
|
+
post[:card][:number] = payment.number
|
152
|
+
post[:card][:holder_name] = payment.name
|
153
|
+
post[:card][:expiry_month] = payment.month
|
154
|
+
post[:card][:expiry_year] = payment.year
|
155
|
+
post[:card][:cvc] = payment.verification_value
|
156
|
+
post[:card][:type] = CARD_MAPPING[payment.brand]
|
157
|
+
end
|
158
|
+
|
159
|
+
def parse(body)
|
160
|
+
JSON.parse(body)
|
161
|
+
end
|
162
|
+
|
163
|
+
def commit_raw(object, action, parameters)
|
164
|
+
url = "#{(test? ? test_url : live_url)}#{object}/#{action}"
|
165
|
+
|
166
|
+
begin
|
167
|
+
raw_response = ssl_post(url, post_data(parameters), headers)
|
168
|
+
rescue ResponseError => e
|
169
|
+
raw_response = e.response.body
|
170
|
+
end
|
171
|
+
parse(raw_response)
|
172
|
+
end
|
173
|
+
|
174
|
+
def commit_transaction(action, parameters)
|
175
|
+
response = commit_raw('transaction', action, parameters)
|
176
|
+
Response.new(
|
177
|
+
success_from(response),
|
178
|
+
message_from(response),
|
179
|
+
response,
|
180
|
+
authorization: authorization_from(response),
|
181
|
+
test: test?,
|
182
|
+
error_code: error_code_from(response)
|
183
|
+
)
|
184
|
+
end
|
185
|
+
|
186
|
+
def commit_card(action, parameters)
|
187
|
+
response = commit_raw('card', action, parameters)
|
188
|
+
Response.new(
|
189
|
+
card_success_from(response),
|
190
|
+
card_message_from(response),
|
191
|
+
response,
|
192
|
+
authorization: card_authorization_from(response),
|
193
|
+
test: test?,
|
194
|
+
error_code: card_error_code_from(response)
|
195
|
+
)
|
196
|
+
end
|
197
|
+
|
198
|
+
def headers
|
199
|
+
{
|
200
|
+
'Auth-Token' => authentication_code,
|
201
|
+
'Content-Type' => 'application/json'
|
202
|
+
}
|
203
|
+
end
|
204
|
+
|
205
|
+
def success_from(response)
|
206
|
+
!response.include?('error') && (response['status'] || response['transaction']['status']) == 'success'
|
207
|
+
end
|
208
|
+
|
209
|
+
def card_success_from(response)
|
210
|
+
return false if response.include?('error')
|
211
|
+
return true if response['message'] == 'card deleted'
|
212
|
+
response['card']['status'] == 'valid'
|
213
|
+
end
|
214
|
+
|
215
|
+
def message_from(response)
|
216
|
+
if success_from(response)
|
217
|
+
response['transaction'] && response['transaction']['message']
|
218
|
+
else
|
219
|
+
response['error'] && response['error']['type']
|
220
|
+
end
|
221
|
+
end
|
222
|
+
|
223
|
+
def card_message_from(response)
|
224
|
+
if !response.include?('error')
|
225
|
+
response['message'] || response['card']['message']
|
226
|
+
else
|
227
|
+
response['error']['type']
|
228
|
+
end
|
229
|
+
end
|
230
|
+
|
231
|
+
def authorization_from(response)
|
232
|
+
response['transaction'] && response['transaction']['id']
|
233
|
+
end
|
234
|
+
|
235
|
+
def card_authorization_from(response)
|
236
|
+
response['card'] && response['card']['token']
|
237
|
+
end
|
238
|
+
|
239
|
+
def extract_previous_card_token(response)
|
240
|
+
match = /Card already added: (\d+)/.match(response.message)
|
241
|
+
match && match[1]
|
242
|
+
end
|
243
|
+
|
244
|
+
def post_data(parameters = {})
|
245
|
+
JSON.dump(parameters)
|
246
|
+
end
|
247
|
+
|
248
|
+
def error_code_from(response)
|
249
|
+
return if success_from(response)
|
250
|
+
if response['transaction']
|
251
|
+
detail = response['transaction']['status_detail']
|
252
|
+
if STANDARD_ERROR_CODE_MAPPING.include?(detail)
|
253
|
+
return STANDARD_ERROR_CODE[STANDARD_ERROR_CODE_MAPPING[detail]]
|
254
|
+
end
|
255
|
+
elsif response['error']
|
256
|
+
return STANDARD_ERROR_CODE[:config_error]
|
257
|
+
end
|
258
|
+
STANDARD_ERROR_CODE[:processing_error]
|
259
|
+
end
|
260
|
+
|
261
|
+
def card_error_code_from(response)
|
262
|
+
STANDARD_ERROR_CODE[:processing_error] unless card_success_from(response)
|
263
|
+
end
|
264
|
+
|
265
|
+
def authentication_code
|
266
|
+
timestamp = Time.new.to_i
|
267
|
+
unique_token = Digest::SHA256.hexdigest("#{@options[:app_key]}#{timestamp}")
|
268
|
+
authentication_string = "#{@options[:application_code]};#{timestamp};#{unique_token}"
|
269
|
+
Base64.encode64(authentication_string).delete("\n")
|
270
|
+
end
|
271
|
+
end
|
272
|
+
end
|
273
|
+
end
|
@@ -29,9 +29,8 @@ module ActiveMerchant #:nodoc:
|
|
29
29
|
}
|
30
30
|
|
31
31
|
def initialize(options={})
|
32
|
-
requires!(options, :merchant_id, :account_id, :api_login, :api_key)
|
32
|
+
requires!(options, :merchant_id, :account_id, :api_login, :api_key, :payment_country)
|
33
33
|
super
|
34
|
-
@options[:payment_country] ||= options[:payment_country] if options[:payment_country]
|
35
34
|
end
|
36
35
|
|
37
36
|
def purchase(amount, payment_method, options={})
|
@@ -78,7 +77,7 @@ module ActiveMerchant #:nodoc:
|
|
78
77
|
|
79
78
|
def verify(credit_card, options={})
|
80
79
|
minimum = MINIMUMS[options[:currency].upcase] if options[:currency]
|
81
|
-
amount = minimum || 100
|
80
|
+
amount = options[:verify_amount] || minimum || 100
|
82
81
|
|
83
82
|
MultiResponse.run(:use_first_response) do |r|
|
84
83
|
r.process { authorize(amount, credit_card, options) }
|
@@ -139,7 +138,7 @@ module ActiveMerchant #:nodoc:
|
|
139
138
|
|
140
139
|
def add_transaction_elements(post, type, options)
|
141
140
|
transaction = {}
|
142
|
-
transaction[:paymentCountry] = @options[:payment_country]
|
141
|
+
transaction[:paymentCountry] = @options[:payment_country]
|
143
142
|
transaction[:type] = type
|
144
143
|
transaction[:ipAddress] = options[:ip] || ''
|
145
144
|
transaction[:userAgent] = options[:user_agent] if options[:user_agent]
|
@@ -153,7 +152,7 @@ module ActiveMerchant #:nodoc:
|
|
153
152
|
order[:accountId] = @options[:account_id]
|
154
153
|
order[:partnerId] = options[:partner_id] if options[:partner_id]
|
155
154
|
order[:referenceCode] = options[:order_id] || generate_unique_id
|
156
|
-
order[:description] = options[:description] || '
|
155
|
+
order[:description] = options[:description] || 'Compra en ' + @options[:merchant_id]
|
157
156
|
order[:language] = 'en'
|
158
157
|
order[:shippingAddress] = shipping_address_fields(options) if options[:shipping_address]
|
159
158
|
post[:transaction][:order] = order
|
@@ -167,7 +166,7 @@ module ActiveMerchant #:nodoc:
|
|
167
166
|
payer[:dniNumber] = options[:dni_number] if options[:dni_number]
|
168
167
|
payer[:dniType] = options[:dni_type] if options[:dni_type]
|
169
168
|
payer[:emailAddress] = options[:email] if options[:email]
|
170
|
-
payer[:birthdate] = options[:birth_date] if options[:birth_date] && options[:payment_country] == 'MX'
|
169
|
+
payer[:birthdate] = options[:birth_date] if options[:birth_date] && @options[:payment_country] == 'MX'
|
171
170
|
payer[:billingAddress] = billing_address_fields(options)
|
172
171
|
post[:transaction][:payer] = payer
|
173
172
|
end
|
@@ -180,7 +179,7 @@ module ActiveMerchant #:nodoc:
|
|
180
179
|
billing_address[:city] = address[:city]
|
181
180
|
billing_address[:state] = address[:state]
|
182
181
|
billing_address[:country] = address[:country]
|
183
|
-
billing_address[:postalCode] = address[:zip] if options[:payment_country] == 'MX'
|
182
|
+
billing_address[:postalCode] = address[:zip] if @options[:payment_country] == 'MX'
|
184
183
|
billing_address[:phone] = address[:phone]
|
185
184
|
billing_address
|
186
185
|
end
|
@@ -191,7 +190,7 @@ module ActiveMerchant #:nodoc:
|
|
191
190
|
buyer[:fullName] = buyer_hash[:name]
|
192
191
|
buyer[:dniNumber] = buyer_hash[:dni_number]
|
193
192
|
buyer[:dniType] = buyer_hash[:dni_type]
|
194
|
-
buyer[:cnpj] = buyer_hash[:cnpj] if options[:payment_country] == 'BR'
|
193
|
+
buyer[:cnpj] = buyer_hash[:cnpj] if @options[:payment_country] == 'BR'
|
195
194
|
buyer[:emailAddress] = buyer_hash[:email]
|
196
195
|
buyer[:contactPhone] = (options[:billing_address][:phone] if options[:billing_address]) || (options[:shipping_address][:phone] if options[:shipping_address]) || ''
|
197
196
|
buyer[:shippingAddress] = shipping_address_fields(options) if options[:shipping_address]
|
@@ -199,7 +198,7 @@ module ActiveMerchant #:nodoc:
|
|
199
198
|
buyer[:fullName] = payment_method.name.strip
|
200
199
|
buyer[:dniNumber] = options[:dni_number]
|
201
200
|
buyer[:dniType] = options[:dni_type]
|
202
|
-
buyer[:cnpj] = options[:cnpj] if options[:payment_country] == 'BR'
|
201
|
+
buyer[:cnpj] = options[:cnpj] if @options[:payment_country] == 'BR'
|
203
202
|
buyer[:emailAddress] = options[:email]
|
204
203
|
buyer[:contactPhone] = (options[:billing_address][:phone] if options[:billing_address]) || (options[:shipping_address][:phone] if options[:shipping_address]) || ''
|
205
204
|
buyer[:shippingAddress] = shipping_address_fields(options) if options[:shipping_address]
|
@@ -235,8 +234,8 @@ module ActiveMerchant #:nodoc:
|
|
235
234
|
|
236
235
|
additional_values = {}
|
237
236
|
additional_values[:TX_VALUE] = tx_value
|
238
|
-
additional_values[:TX_TAX] = tx_tax if options[:payment_country] == 'CO'
|
239
|
-
additional_values[:TX_TAX_RETURN_BASE] = tx_tax_return_base if options[:payment_country] == 'CO'
|
237
|
+
additional_values[:TX_TAX] = tx_tax if @options[:payment_country] == 'CO'
|
238
|
+
additional_values[:TX_TAX_RETURN_BASE] = tx_tax_return_base if @options[:payment_country] == 'CO'
|
240
239
|
|
241
240
|
post[:transaction][:order][:additionalValues] = additional_values
|
242
241
|
end
|
@@ -358,7 +357,7 @@ module ActiveMerchant #:nodoc:
|
|
358
357
|
response["code"] == "SUCCESS" && response["creditCardToken"] && response["creditCardToken"]["creditCardTokenId"].present?
|
359
358
|
when 'verify_credentials'
|
360
359
|
response["code"] == "SUCCESS"
|
361
|
-
when 'refund'
|
360
|
+
when 'refund', 'void'
|
362
361
|
response["code"] == "SUCCESS" && response["transactionResponse"] && (response["transactionResponse"]["state"] == "PENDING" || response["transactionResponse"]["state"] == "APPROVED")
|
363
362
|
else
|
364
363
|
response["code"] == "SUCCESS" && response["transactionResponse"] && (response["transactionResponse"]["state"] == "APPROVED")
|
@@ -375,8 +374,10 @@ module ActiveMerchant #:nodoc:
|
|
375
374
|
return "VERIFIED" if success
|
376
375
|
"FAILED"
|
377
376
|
else
|
378
|
-
|
379
|
-
|
377
|
+
if response["transactionResponse"]
|
378
|
+
response_message = response["transactionResponse"]["responseMessage"]
|
379
|
+
response_code = response["transactionResponse"]["responseCode"] || response["transactionResponse"]["pendingReason"]
|
380
|
+
end
|
380
381
|
return response_code if success
|
381
382
|
response["error"] || response_message || response_code || "FAILED"
|
382
383
|
end
|
@@ -78,6 +78,7 @@ module ActiveMerchant #:nodoc:
|
|
78
78
|
post = {}
|
79
79
|
capture_uri = "#{ENDPOINT}/#{CGI.escape(authorization)}/capture"
|
80
80
|
post[:amount] = localized_amount(money, currency(money))
|
81
|
+
add_context(post, options)
|
81
82
|
|
82
83
|
commit(capture_uri, post)
|
83
84
|
end
|
@@ -85,6 +86,7 @@ module ActiveMerchant #:nodoc:
|
|
85
86
|
def refund(money, authorization, options = {})
|
86
87
|
post = {}
|
87
88
|
post[:amount] = localized_amount(money, currency(money))
|
89
|
+
add_context(post, options)
|
88
90
|
|
89
91
|
commit(refund_uri(authorization), post)
|
90
92
|
end
|
@@ -137,6 +139,7 @@ module ActiveMerchant #:nodoc:
|
|
137
139
|
|
138
140
|
def add_payment(post, payment, options = {})
|
139
141
|
add_creditcard(post, payment, options)
|
142
|
+
add_context(post, options)
|
140
143
|
end
|
141
144
|
|
142
145
|
def add_creditcard(post, creditcard, options = {})
|
@@ -151,6 +154,13 @@ module ActiveMerchant #:nodoc:
|
|
151
154
|
post[:card] = card
|
152
155
|
end
|
153
156
|
|
157
|
+
def add_context(post, options = {})
|
158
|
+
post[:context] = {
|
159
|
+
mobile: options.fetch(:mobile, false),
|
160
|
+
isEcommerce: options.fetch(:ecommerce, true)
|
161
|
+
}
|
162
|
+
end
|
163
|
+
|
154
164
|
def parse(body)
|
155
165
|
JSON.parse(body)
|
156
166
|
end
|
@@ -22,7 +22,9 @@ module ActiveMerchant #:nodoc:
|
|
22
22
|
|
23
23
|
def purchase(money, payment, options={})
|
24
24
|
post = {}
|
25
|
-
|
25
|
+
post[:sg_APIType] = 1 if options[:three_d_secure]
|
26
|
+
trans_type = options[:three_d_secure] ? "Sale3D" : "Sale"
|
27
|
+
add_transaction_data(trans_type, post, money, options)
|
26
28
|
add_payment(post, payment)
|
27
29
|
add_customer_details(post, payment, options)
|
28
30
|
|
@@ -120,6 +122,9 @@ module ActiveMerchant #:nodoc:
|
|
120
122
|
post[:sg_UserID] = options[:user_id] if options[:user_id]
|
121
123
|
post[:sg_AuthType] = options[:auth_type] if options[:auth_type]
|
122
124
|
post[:sg_ExpectedFulfillmentCount] = options[:expected_fulfillment_count] if options[:expected_fulfillment_count]
|
125
|
+
post[:sg_WebsiteID] = options[:website_id] if options[:website_id]
|
126
|
+
post[:sg_IPAddress] = options[:ip] if options[:ip]
|
127
|
+
post[:sg_VendorID] = options[:vendor_id] if options[:vendor_id]
|
123
128
|
end
|
124
129
|
|
125
130
|
def add_payment(post, payment)
|
@@ -150,21 +155,32 @@ module ActiveMerchant #:nodoc:
|
|
150
155
|
|
151
156
|
doc = Nokogiri::XML(xml)
|
152
157
|
doc.root.xpath('*').each do |node|
|
153
|
-
|
158
|
+
if node.elements.size == 0
|
159
|
+
response[node.name.underscore.downcase.to_sym] = node.text
|
160
|
+
else
|
161
|
+
node.traverse do |childnode|
|
162
|
+
childnode_to_response(response, childnode)
|
163
|
+
end
|
164
|
+
end
|
154
165
|
end
|
155
|
-
|
156
166
|
response
|
157
167
|
end
|
158
168
|
|
159
|
-
def childnode_to_response(response,
|
160
|
-
|
161
|
-
|
162
|
-
response[name.to_sym] = Hash.from_xml(childnode.to_s).values.first
|
169
|
+
def childnode_to_response(response, childnode)
|
170
|
+
if childnode.elements.size == 0
|
171
|
+
element_name_to_symbol(response, childnode)
|
163
172
|
else
|
164
|
-
|
173
|
+
childnode.traverse do |childnode|
|
174
|
+
element_name_to_symbol(response, childnode)
|
175
|
+
end
|
165
176
|
end
|
166
177
|
end
|
167
178
|
|
179
|
+
def element_name_to_symbol(response, childnode)
|
180
|
+
name = "#{childnode.name.downcase}"
|
181
|
+
response[name.to_sym] = childnode.text
|
182
|
+
end
|
183
|
+
|
168
184
|
def commit(parameters)
|
169
185
|
url = (test? ? test_url : live_url)
|
170
186
|
response = parse(ssl_post(url, post_data(parameters)))
|
@@ -37,13 +37,20 @@ module ActiveMerchant #:nodoc:
|
|
37
37
|
:jcb => "JCB"
|
38
38
|
}
|
39
39
|
|
40
|
-
|
40
|
+
AVS_CODE = {
|
41
41
|
"NOTPROVIDED" => nil,
|
42
42
|
"NOTCHECKED" => 'X',
|
43
43
|
"MATCHED" => 'Y',
|
44
44
|
"NOTMATCHED" => 'N'
|
45
45
|
}
|
46
46
|
|
47
|
+
CVV_CODE = {
|
48
|
+
"NOTPROVIDED" => 'S',
|
49
|
+
"NOTCHECKED" => 'X',
|
50
|
+
"MATCHED" => 'M',
|
51
|
+
"NOTMATCHED" => 'N'
|
52
|
+
}
|
53
|
+
|
47
54
|
OPTIONAL_REQUEST_FIELDS = {
|
48
55
|
paypal_callback_url: :PayPalCallbackURL,
|
49
56
|
basket: :Basket,
|
@@ -348,10 +355,10 @@ module ActiveMerchant #:nodoc:
|
|
348
355
|
:test => test?,
|
349
356
|
:authorization => authorization_from(response, parameters, action),
|
350
357
|
:avs_result => {
|
351
|
-
:street_match =>
|
352
|
-
:postal_match =>
|
358
|
+
:street_match => AVS_CODE[ response["AddressResult"] ],
|
359
|
+
:postal_match => AVS_CODE[ response["PostCodeResult"] ],
|
353
360
|
},
|
354
|
-
:cvv_result =>
|
361
|
+
:cvv_result => CVV_CODE[ response["CV2Result"] ]
|
355
362
|
)
|
356
363
|
end
|
357
364
|
|
@@ -25,7 +25,7 @@ module ActiveMerchant
|
|
25
25
|
attr_accessor :ca_path
|
26
26
|
attr_accessor :pem
|
27
27
|
attr_accessor :pem_password
|
28
|
-
|
28
|
+
attr_reader :wiredump_device
|
29
29
|
attr_accessor :logger
|
30
30
|
attr_accessor :tag
|
31
31
|
attr_accessor :ignore_http_status
|
@@ -48,6 +48,11 @@ module ActiveMerchant
|
|
48
48
|
@proxy_port = nil
|
49
49
|
end
|
50
50
|
|
51
|
+
def wiredump_device=(device)
|
52
|
+
raise ArgumentError, "can't wiredump to frozen #{device.class}" if device && device.frozen?
|
53
|
+
@wiredump_device = device
|
54
|
+
end
|
55
|
+
|
51
56
|
def request(method, body, headers = {})
|
52
57
|
request_start = Process.clock_gettime(Process::CLOCK_MONOTONIC)
|
53
58
|
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: activemerchant
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.
|
4
|
+
version: 1.76.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Tobias Luetke
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2018-01-03 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: activesupport
|
@@ -190,6 +190,7 @@ files:
|
|
190
190
|
- lib/active_merchant/billing/gateways/card_save.rb
|
191
191
|
- lib/active_merchant/billing/gateways/card_stream.rb
|
192
192
|
- lib/active_merchant/billing/gateways/cardknox.rb
|
193
|
+
- lib/active_merchant/billing/gateways/cardprocess.rb
|
193
194
|
- lib/active_merchant/billing/gateways/cashnet.rb
|
194
195
|
- lib/active_merchant/billing/gateways/cc5.rb
|
195
196
|
- lib/active_merchant/billing/gateways/cecabank.rb
|
@@ -307,6 +308,7 @@ files:
|
|
307
308
|
- lib/active_merchant/billing/gateways/payflow_express_uk.rb
|
308
309
|
- lib/active_merchant/billing/gateways/payflow_uk.rb
|
309
310
|
- lib/active_merchant/billing/gateways/payment_express.rb
|
311
|
+
- lib/active_merchant/billing/gateways/paymentez.rb
|
310
312
|
- lib/active_merchant/billing/gateways/paymill.rb
|
311
313
|
- lib/active_merchant/billing/gateways/paypal.rb
|
312
314
|
- lib/active_merchant/billing/gateways/paypal/paypal_common_api.rb
|