activemerchant 1.66.0 → 1.67.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 +28 -0
- data/lib/active_merchant/billing/gateways/authorize_net.rb +74 -7
- data/lib/active_merchant/billing/gateways/checkout_v2.rb +1 -0
- data/lib/active_merchant/billing/gateways/credorax.rb +8 -1
- data/lib/active_merchant/billing/gateways/cyber_source.rb +14 -7
- data/lib/active_merchant/billing/gateways/ebanx.rb +234 -0
- data/lib/active_merchant/billing/gateways/elavon.rb +23 -92
- data/lib/active_merchant/billing/gateways/fat_zebra.rb +1 -27
- data/lib/active_merchant/billing/gateways/firstdata_e4.rb +5 -3
- data/lib/active_merchant/billing/gateways/jetpay_v2.rb +410 -0
- data/lib/active_merchant/billing/gateways/nmi.rb +10 -1
- data/lib/active_merchant/billing/gateways/opp.rb +124 -114
- data/lib/active_merchant/billing/gateways/orbital.rb +15 -4
- data/lib/active_merchant/billing/gateways/payeezy.rb +9 -6
- data/lib/active_merchant/billing/gateways/quickpay/quickpay_v10.rb +19 -14
- data/lib/active_merchant/billing/gateways/realex.rb +2 -5
- data/lib/active_merchant/billing/gateways/safe_charge.rb +2 -1
- data/lib/active_merchant/billing/gateways/wepay.rb +11 -6
- 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: 8d1e9a2bf41a0e836aba8e3d1296464f62d7765e
|
4
|
+
data.tar.gz: 6cd30371be55f49a0beef1eb5a3a8796cf226db0
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 4c0426a9d705e5b7c29031ac35ccdb1a2bf062efe8693760b485f9ece001e6149f64bbfa11dcc8cc23310ac5a13586b66683762cb0db98bd300d3eb5c8cd27d7
|
7
|
+
data.tar.gz: 54b90b7a5e2235c16e5ea1e91a161437b50081b2b19ccd7938f35f8398f65eafffee05eca2317c19f4cda4007986b59f9daea99db36e184b2a357a4aed437ebf
|
data/CHANGELOG
CHANGED
@@ -2,6 +2,22 @@
|
|
2
2
|
|
3
3
|
== HEAD
|
4
4
|
|
5
|
+
== Version 1.67.0 (June 8, 2017)
|
6
|
+
* Acapture: Pass 3D Secure fields [davidsantoso] #2451
|
7
|
+
* Authorize.net: Pass Level 2 Data Fields [curiousepic] #2444
|
8
|
+
* Credorax: Add 3D Secure authentication fields [davidsantoso] #2446
|
9
|
+
* Ebanx: Add gateway support [davidsantoso] #2447
|
10
|
+
* Ebanx: Reduce supported countries to Brazil and Mexico [davidsantoso]
|
11
|
+
* FirstData Payeezy: Set default ECI value for auth/purchase transactions [jasonwebster] #2448
|
12
|
+
* JetPay V2: Add new gateway [shasum] #2442
|
13
|
+
* JetPay V2: Add optional tax data to capture calls [shasum] #2445
|
14
|
+
* NMI: Add Network Tokenization support [shasum] #2431
|
15
|
+
* Orbital: Pass soft descriptors from options hash [curiousepic]
|
16
|
+
* Orbital: Update test and production urls [jcowhigjr] #2436
|
17
|
+
* Payeezy: Add client_email field for telecheck [davidsantoso] #2455
|
18
|
+
* Payeezy: Add customer_id_type and customer_id_number fields [davidsantoso] #2454
|
19
|
+
* Quickpay V10: Fix store and token use for recurring payments [wsmoak] #2180
|
20
|
+
|
5
21
|
== Version 1.66.0 (May 4, 2017)
|
6
22
|
* Support Rails 5.1 [jhawthorn] #2407
|
7
23
|
* ProPay: Add Canada as supported country [davidsantoso]
|
@@ -10,6 +26,18 @@
|
|
10
26
|
* WePay: Add scrub method [shasum] #2406
|
11
27
|
* iVeri: Add gateway support [curiousepic] #2400
|
12
28
|
* iVeri: Support 3DSecure data fields [davidsantoso] #2412
|
29
|
+
* Opp: Fix transaction success criteria and clean up options [shasum] #2414
|
30
|
+
* Elavon: Support custom fields [curiousepic] #2416
|
31
|
+
* WePay: Support risk headers [shasum] #2419
|
32
|
+
* WePay: Add Canada as supported country [shasum] #2419
|
33
|
+
* Fat Zebra: Fix xid 3D Secure field [curiousepic]
|
34
|
+
* SafeCharge: Mark support for European countries [curiousepic]
|
35
|
+
* Checkout V2: Pass customer ip option [curiousepic]
|
36
|
+
* Realex: Map AVS and CVV response codes [davidsantoso] #2424
|
37
|
+
* Opp: Send disable3DSecure custom parameter if present [davidsantoso] #2432
|
38
|
+
* SafeCharge: Map standard Active Merchant order_id field [davidsantoso] #2434
|
39
|
+
* Payeezy: Default check number to 001 if not present [davidsantoso] #2439
|
40
|
+
* Opp: Fix incorrect customParameter key to disable 3DS [davidsantoso]
|
13
41
|
|
14
42
|
== Version 1.65.0 (April 26, 2017)
|
15
43
|
* Adyen: Add Adyen v18 gateway [adyenpayments] #2272
|
@@ -166,7 +166,7 @@ module ActiveMerchant
|
|
166
166
|
xml.amount(amount(amount))
|
167
167
|
|
168
168
|
add_payment_source(xml, payment)
|
169
|
-
add_invoice(xml, options)
|
169
|
+
add_invoice(xml, 'refundTransaction', options)
|
170
170
|
add_customer_data(xml, payment, options)
|
171
171
|
add_settings(xml, payment, options)
|
172
172
|
add_user_fields(xml, amount, options)
|
@@ -244,7 +244,12 @@ module ActiveMerchant
|
|
244
244
|
xml.transactionType(transaction_type)
|
245
245
|
xml.amount(amount(amount))
|
246
246
|
add_payment_source(xml, payment)
|
247
|
-
add_invoice(xml, options)
|
247
|
+
add_invoice(xml, transaction_type, options)
|
248
|
+
add_tax_fields(xml, options)
|
249
|
+
add_duty_fields(xml, options)
|
250
|
+
add_shipping_fields(xml, options)
|
251
|
+
add_tax_exempt_status(xml, options)
|
252
|
+
add_po_number(xml, options)
|
248
253
|
add_customer_data(xml, payment, options)
|
249
254
|
add_market_type_device_type(xml, payment, options)
|
250
255
|
add_settings(xml, payment, options)
|
@@ -257,8 +262,12 @@ module ActiveMerchant
|
|
257
262
|
xml.transaction do
|
258
263
|
xml.send(transaction_type) do
|
259
264
|
xml.amount(amount(amount))
|
265
|
+
add_tax_fields(xml, options)
|
266
|
+
add_shipping_fields(xml, options)
|
267
|
+
add_duty_fields(xml, options)
|
260
268
|
add_payment_source(xml, payment)
|
261
|
-
add_invoice(xml, options)
|
269
|
+
add_invoice(xml, transaction_type, options)
|
270
|
+
add_tax_exempt_status(xml, options)
|
262
271
|
end
|
263
272
|
end
|
264
273
|
end
|
@@ -269,6 +278,9 @@ module ActiveMerchant
|
|
269
278
|
xml.transaction do
|
270
279
|
xml.profileTransPriorAuthCapture do
|
271
280
|
xml.amount(amount(amount))
|
281
|
+
add_tax_fields(xml, options)
|
282
|
+
add_shipping_fields(xml, options)
|
283
|
+
add_duty_fields(xml, options)
|
272
284
|
xml.transId(transaction_id_from(authorization))
|
273
285
|
end
|
274
286
|
end
|
@@ -281,8 +293,13 @@ module ActiveMerchant
|
|
281
293
|
xml.transactionRequest do
|
282
294
|
xml.transactionType('priorAuthCaptureTransaction')
|
283
295
|
xml.amount(amount(amount))
|
296
|
+
add_tax_fields(xml, options)
|
297
|
+
add_duty_fields(xml, options)
|
298
|
+
add_shipping_fields(xml, options)
|
299
|
+
add_tax_exempt_status(xml, options)
|
300
|
+
add_po_number(xml, options)
|
284
301
|
xml.refTransId(transaction_id_from(authorization))
|
285
|
-
add_invoice(xml, options)
|
302
|
+
add_invoice(xml, "capture", options)
|
286
303
|
add_user_fields(xml, amount, options)
|
287
304
|
end
|
288
305
|
end
|
@@ -296,8 +313,11 @@ module ActiveMerchant
|
|
296
313
|
xml.transaction do
|
297
314
|
xml.profileTransRefund do
|
298
315
|
xml.amount(amount(amount))
|
316
|
+
add_tax_fields(xml, options)
|
317
|
+
add_shipping_fields(xml, options)
|
318
|
+
add_duty_fields(xml, options)
|
299
319
|
xml.creditCardNumberMasked(card_number)
|
300
|
-
add_invoice(xml, options)
|
320
|
+
add_invoice(xml, "profileTransRefund", options)
|
301
321
|
xml.transId(transaction_id)
|
302
322
|
end
|
303
323
|
end
|
@@ -319,7 +339,12 @@ module ActiveMerchant
|
|
319
339
|
end
|
320
340
|
xml.refTransId(transaction_id)
|
321
341
|
|
322
|
-
add_invoice(xml, options)
|
342
|
+
add_invoice(xml, 'refundTransaction', options)
|
343
|
+
add_tax_fields(xml, options)
|
344
|
+
add_duty_fields(xml, options)
|
345
|
+
add_shipping_fields(xml, options)
|
346
|
+
add_tax_exempt_status(xml, options)
|
347
|
+
add_po_number(xml, options)
|
323
348
|
add_customer_data(xml, nil, options)
|
324
349
|
add_user_fields(xml, amount, options)
|
325
350
|
end
|
@@ -570,10 +595,11 @@ module ActiveMerchant
|
|
570
595
|
xml.refId(truncate(options[:order_id], 20))
|
571
596
|
end
|
572
597
|
|
573
|
-
def add_invoice(xml, options)
|
598
|
+
def add_invoice(xml, transaction_type, options)
|
574
599
|
xml.order do
|
575
600
|
xml.invoiceNumber(truncate(options[:order_id], 20))
|
576
601
|
xml.description(truncate(options[:description], 255))
|
602
|
+
xml.purchaseOrderNumber(options[:po_number]) if options[:po_number] && transaction_type.start_with?("profileTrans")
|
577
603
|
end
|
578
604
|
|
579
605
|
# Authorize.net API requires lineItems to be placed directly after order tag
|
@@ -590,6 +616,47 @@ module ActiveMerchant
|
|
590
616
|
end
|
591
617
|
end
|
592
618
|
|
619
|
+
def add_tax_fields(xml, options)
|
620
|
+
tax = options[:tax]
|
621
|
+
if tax.is_a?(Hash)
|
622
|
+
xml.tax do
|
623
|
+
xml.amount(amount(tax[:amount].to_i))
|
624
|
+
xml.name(tax[:name])
|
625
|
+
xml.description(tax[:description])
|
626
|
+
end
|
627
|
+
end
|
628
|
+
end
|
629
|
+
|
630
|
+
def add_duty_fields(xml, options)
|
631
|
+
duty = options[:duty]
|
632
|
+
if duty.is_a?(Hash)
|
633
|
+
xml.duty do
|
634
|
+
xml.amount(amount(duty[:amount].to_i))
|
635
|
+
xml.name(duty[:name])
|
636
|
+
xml.description(duty[:description])
|
637
|
+
end
|
638
|
+
end
|
639
|
+
end
|
640
|
+
|
641
|
+
def add_shipping_fields(xml, options)
|
642
|
+
shipping = options[:shipping]
|
643
|
+
if shipping.is_a?(Hash)
|
644
|
+
xml.shipping do
|
645
|
+
xml.amount(amount(shipping[:amount].to_i))
|
646
|
+
xml.name(shipping[:name])
|
647
|
+
xml.description(shipping[:description])
|
648
|
+
end
|
649
|
+
end
|
650
|
+
end
|
651
|
+
|
652
|
+
def add_tax_exempt_status(xml, options)
|
653
|
+
xml.taxExempt(options[:tax_exempt]) if options[:tax_exempt]
|
654
|
+
end
|
655
|
+
|
656
|
+
def add_po_number(xml, options)
|
657
|
+
xml.poNumber(options[:po_number]) if options[:po_number]
|
658
|
+
end
|
659
|
+
|
593
660
|
def create_customer_payment_profile(credit_card, options)
|
594
661
|
commit(:cim_store_update) do |xml|
|
595
662
|
xml.customerProfileId options[:customer_profile_id]
|
@@ -94,6 +94,7 @@ module ActiveMerchant #:nodoc:
|
|
94
94
|
|
95
95
|
def add_customer_data(post, options)
|
96
96
|
post[:email] = options[:email] || "unspecified@example.com"
|
97
|
+
post[:customerIp] = options[:ip] if options[:ip]
|
97
98
|
address = options[:billing_address]
|
98
99
|
if(address && post[:card])
|
99
100
|
post[:card][:billingDetails] = {}
|
@@ -108,6 +108,7 @@ module ActiveMerchant #:nodoc:
|
|
108
108
|
add_payment_method(post, payment_method)
|
109
109
|
add_customer_data(post, options)
|
110
110
|
add_email(post, options)
|
111
|
+
add_3d_secure(post, options)
|
111
112
|
add_echo(post, options)
|
112
113
|
|
113
114
|
commit(:purchase, post)
|
@@ -119,6 +120,7 @@ module ActiveMerchant #:nodoc:
|
|
119
120
|
add_payment_method(post, payment_method)
|
120
121
|
add_customer_data(post, options)
|
121
122
|
add_email(post, options)
|
123
|
+
add_3d_secure(post, options)
|
122
124
|
add_echo(post, options)
|
123
125
|
|
124
126
|
commit(:authorize, post)
|
@@ -230,6 +232,11 @@ module ActiveMerchant #:nodoc:
|
|
230
232
|
post[:c3] = options[:email] || 'unspecified@example.com'
|
231
233
|
end
|
232
234
|
|
235
|
+
def add_3d_secure(post, options)
|
236
|
+
return unless options[:eci] && options[:xid]
|
237
|
+
post[:i8] = "#{options[:eci]}:#{(options[:cavv] || "none")}:#{options[:xid]}"
|
238
|
+
end
|
239
|
+
|
233
240
|
def add_echo(post, options)
|
234
241
|
# The d2 parameter is used during the certification process
|
235
242
|
# See remote tests for full certification test suite
|
@@ -240,7 +247,7 @@ module ActiveMerchant #:nodoc:
|
|
240
247
|
purchase: '1',
|
241
248
|
authorize: '2',
|
242
249
|
capture: '3',
|
243
|
-
authorize_void:'4',
|
250
|
+
authorize_void: '4',
|
244
251
|
refund: '5',
|
245
252
|
credit: '6',
|
246
253
|
purchase_void: '7',
|
@@ -691,7 +691,8 @@ module ActiveMerchant #:nodoc:
|
|
691
691
|
end
|
692
692
|
|
693
693
|
success = response[:decision] == "ACCEPT"
|
694
|
-
message =
|
694
|
+
message = response[:message]
|
695
|
+
|
695
696
|
authorization = success ? [ options[:order_id], response[:requestID], response[:requestToken], action, amount, options[:currency]].compact.join(";") : nil
|
696
697
|
|
697
698
|
Response.new(success, message, response,
|
@@ -709,9 +710,10 @@ module ActiveMerchant #:nodoc:
|
|
709
710
|
xml = REXML::Document.new(xml)
|
710
711
|
if root = REXML::XPath.first(xml, "//c:replyMessage")
|
711
712
|
root.elements.to_a.each do |node|
|
712
|
-
case node.
|
713
|
+
case node.expanded_name
|
713
714
|
when 'c:reasonCode'
|
714
|
-
reply[:
|
715
|
+
reply[:reasonCode] = node.text
|
716
|
+
reply[:message] = reason_message(node.text)
|
715
717
|
else
|
716
718
|
parse_element(reply, node)
|
717
719
|
end
|
@@ -728,14 +730,19 @@ module ActiveMerchant #:nodoc:
|
|
728
730
|
node.elements.each{|e| parse_element(reply, e) }
|
729
731
|
else
|
730
732
|
if node.parent.name =~ /item/
|
731
|
-
parent = node.parent.name
|
732
|
-
|
733
|
-
|
734
|
-
reply[node.name.to_sym] = node.text
|
733
|
+
parent = node.parent.name
|
734
|
+
parent += '_' + node.parent.attributes["id"] if node.parent.attributes["id"]
|
735
|
+
parent += '_'
|
735
736
|
end
|
737
|
+
reply["#{parent}#{node.name}".to_sym] ||= node.text
|
736
738
|
end
|
737
739
|
return reply
|
738
740
|
end
|
741
|
+
|
742
|
+
def reason_message(reason_code)
|
743
|
+
return if reason_code.blank?
|
744
|
+
@@response_codes[:"r#{reason_code}"]
|
745
|
+
end
|
739
746
|
end
|
740
747
|
end
|
741
748
|
end
|
@@ -0,0 +1,234 @@
|
|
1
|
+
module ActiveMerchant #:nodoc:
|
2
|
+
module Billing #:nodoc:
|
3
|
+
class EbanxGateway < Gateway
|
4
|
+
self.test_url = 'https://sandbox.ebanx.com/ws/'
|
5
|
+
self.live_url = 'https://api.ebanx.com/ws/'
|
6
|
+
|
7
|
+
self.supported_countries = ['BR', 'MX']
|
8
|
+
self.default_currency = 'USD'
|
9
|
+
self.supported_cardtypes = [:visa, :master, :american_express, :discover, :diners_club]
|
10
|
+
|
11
|
+
self.homepage_url = 'http://www.ebanx.com/'
|
12
|
+
self.display_name = 'Ebanx'
|
13
|
+
|
14
|
+
CARD_BRAND = {
|
15
|
+
visa: "visa",
|
16
|
+
master: "master_card",
|
17
|
+
american_express: "amex",
|
18
|
+
discover: "discover",
|
19
|
+
diners_club: "diners"
|
20
|
+
}
|
21
|
+
|
22
|
+
URL_MAP = {
|
23
|
+
purchase: "direct",
|
24
|
+
authorize: "direct",
|
25
|
+
capture: "capture",
|
26
|
+
refund: "refund",
|
27
|
+
void: "cancel"
|
28
|
+
}
|
29
|
+
|
30
|
+
HTTP_METHOD = {
|
31
|
+
purchase: :post,
|
32
|
+
authorize: :post,
|
33
|
+
capture: :get,
|
34
|
+
refund: :post,
|
35
|
+
void: :get
|
36
|
+
}
|
37
|
+
|
38
|
+
def initialize(options={})
|
39
|
+
requires!(options, :integration_key)
|
40
|
+
super
|
41
|
+
end
|
42
|
+
|
43
|
+
def purchase(money, payment, options={})
|
44
|
+
post = { payment: {} }
|
45
|
+
add_integration_key(post)
|
46
|
+
add_operation(post)
|
47
|
+
add_invoice(post, money, options)
|
48
|
+
add_customer_data(post, payment, options)
|
49
|
+
add_payment(post, payment)
|
50
|
+
add_address(post, options)
|
51
|
+
|
52
|
+
commit(:purchase, post)
|
53
|
+
end
|
54
|
+
|
55
|
+
def authorize(money, payment, options={})
|
56
|
+
post = { payment: {} }
|
57
|
+
add_integration_key(post)
|
58
|
+
add_operation(post)
|
59
|
+
add_invoice(post, money, options)
|
60
|
+
add_customer_data(post, payment, options)
|
61
|
+
add_payment(post, payment)
|
62
|
+
add_address(post, options)
|
63
|
+
post[:payment][:creditcard][:auto_capture] = false
|
64
|
+
|
65
|
+
commit(:authorize, post)
|
66
|
+
end
|
67
|
+
|
68
|
+
def capture(money, authorization, options={})
|
69
|
+
post = {}
|
70
|
+
add_integration_key(post)
|
71
|
+
post[:hash] = authorization
|
72
|
+
post[:amount] = amount(money)
|
73
|
+
|
74
|
+
commit(:capture, post)
|
75
|
+
end
|
76
|
+
|
77
|
+
def refund(money, authorization, options={})
|
78
|
+
post = {}
|
79
|
+
add_integration_key(post)
|
80
|
+
add_operation(post)
|
81
|
+
add_authorization(post, authorization)
|
82
|
+
post[:amount] = amount(money)
|
83
|
+
post[:description] = options[:description]
|
84
|
+
|
85
|
+
commit(:refund, post)
|
86
|
+
end
|
87
|
+
|
88
|
+
def void(authorization, options={})
|
89
|
+
post = {}
|
90
|
+
add_integration_key(post)
|
91
|
+
add_authorization(post, authorization)
|
92
|
+
|
93
|
+
commit(:void, post)
|
94
|
+
end
|
95
|
+
|
96
|
+
def verify(credit_card, options={})
|
97
|
+
MultiResponse.run(:use_first_response) do |r|
|
98
|
+
r.process { authorize(100, credit_card, options) }
|
99
|
+
r.process(:ignore_result) { void(r.authorization, options) }
|
100
|
+
end
|
101
|
+
end
|
102
|
+
|
103
|
+
def supports_scrubbing?
|
104
|
+
true
|
105
|
+
end
|
106
|
+
|
107
|
+
def scrub(transcript)
|
108
|
+
transcript.
|
109
|
+
gsub(/(integration_key\\?":\\?")(\d*)/, '\1[FILTERED]').
|
110
|
+
gsub(/(card_number\\?":\\?")(\d*)/, '\1[FILTERED]').
|
111
|
+
gsub(/(card_cvv\\?":\\?")(\d*)/, '\1[FILTERED]')
|
112
|
+
end
|
113
|
+
|
114
|
+
private
|
115
|
+
|
116
|
+
def add_integration_key(post)
|
117
|
+
post[:integration_key] = @options[:integration_key].to_s
|
118
|
+
end
|
119
|
+
|
120
|
+
def add_operation(post)
|
121
|
+
post[:operation] = "request"
|
122
|
+
end
|
123
|
+
|
124
|
+
def add_authorization(post, authorization)
|
125
|
+
post[:hash] = authorization
|
126
|
+
end
|
127
|
+
|
128
|
+
def add_customer_data(post, payment, options)
|
129
|
+
post[:payment][:name] = payment.name
|
130
|
+
post[:payment][:email] = options[:email] || "unspecified@example.com"
|
131
|
+
post[:payment][:document] = options[:document]
|
132
|
+
end
|
133
|
+
|
134
|
+
def add_address(post, options)
|
135
|
+
if address = options[:billing_address] || options[:address]
|
136
|
+
post[:payment][:address] = address[:address1].split[1..-1].join(" ") if address[:address1]
|
137
|
+
post[:payment][:street_number] = address[:address1].split.first if address[:address1]
|
138
|
+
post[:payment][:city] = address[:city]
|
139
|
+
post[:payment][:state] = address[:state]
|
140
|
+
post[:payment][:zipcode] = address[:zip]
|
141
|
+
post[:payment][:country] = address[:country]
|
142
|
+
post[:payment][:phone_number] = address[:phone]
|
143
|
+
end
|
144
|
+
end
|
145
|
+
|
146
|
+
def add_invoice(post, money, options)
|
147
|
+
post[:payment][:amount_total] = amount(money)
|
148
|
+
post[:payment][:currency_code] = (options[:currency] || currency(money))
|
149
|
+
post[:payment][:merchant_payment_code] = options[:order_id]
|
150
|
+
end
|
151
|
+
|
152
|
+
def add_payment(post, payment)
|
153
|
+
post[:payment][:payment_type_code] = CARD_BRAND[payment.brand.to_sym]
|
154
|
+
post[:payment][:creditcard] = {
|
155
|
+
card_number: payment.number,
|
156
|
+
card_name: payment.name,
|
157
|
+
card_due_date: "#{payment.month}/#{payment.year}",
|
158
|
+
card_cvv: payment.verification_value
|
159
|
+
}
|
160
|
+
end
|
161
|
+
|
162
|
+
def parse(body)
|
163
|
+
JSON.parse(body)
|
164
|
+
end
|
165
|
+
|
166
|
+
def commit(action, parameters)
|
167
|
+
url = url_for((test? ? test_url : live_url), action, parameters)
|
168
|
+
response = parse(ssl_request(HTTP_METHOD[action], url, post_data(action, parameters), {}))
|
169
|
+
|
170
|
+
success = success_from(action, response)
|
171
|
+
|
172
|
+
Response.new(
|
173
|
+
success,
|
174
|
+
message_from(response),
|
175
|
+
response,
|
176
|
+
authorization: authorization_from(response),
|
177
|
+
test: test?,
|
178
|
+
error_code: error_code_from(response, success)
|
179
|
+
)
|
180
|
+
end
|
181
|
+
|
182
|
+
def success_from(action, response)
|
183
|
+
if [:purchase, :capture, :refund].include?(action)
|
184
|
+
response.try(:[], "payment").try(:[], "status") == "CO"
|
185
|
+
elsif action == :authorize
|
186
|
+
response.try(:[], "payment").try(:[], "status") == "PE"
|
187
|
+
elsif action == :void
|
188
|
+
response.try(:[], "payment").try(:[], "status") == "CA"
|
189
|
+
else
|
190
|
+
false
|
191
|
+
end
|
192
|
+
end
|
193
|
+
|
194
|
+
def message_from(response)
|
195
|
+
return response["status_message"] if response["status"] == "ERROR"
|
196
|
+
response.try(:[], "payment").try(:[], "transaction_status").try(:[], "description")
|
197
|
+
end
|
198
|
+
|
199
|
+
def authorization_from(response)
|
200
|
+
response.try(:[], "payment").try(:[], "hash")
|
201
|
+
end
|
202
|
+
|
203
|
+
def post_data(action, parameters = {})
|
204
|
+
return nil if requires_http_get(action)
|
205
|
+
return convert_to_url_form_encoded(parameters) if action == :refund
|
206
|
+
"request_body=#{parameters.to_json}"
|
207
|
+
end
|
208
|
+
|
209
|
+
def url_for(hostname, action, parameters)
|
210
|
+
return hostname + URL_MAP[action] + "?#{convert_to_url_form_encoded(parameters)}" if requires_http_get(action)
|
211
|
+
hostname + URL_MAP[action]
|
212
|
+
end
|
213
|
+
|
214
|
+
def requires_http_get(action)
|
215
|
+
return true if [:capture, :void].include?(action)
|
216
|
+
false
|
217
|
+
end
|
218
|
+
|
219
|
+
def convert_to_url_form_encoded(parameters)
|
220
|
+
parameters.map do |key, value|
|
221
|
+
next if value != false && value.blank?
|
222
|
+
"#{key}=#{value}"
|
223
|
+
end.compact.join("&")
|
224
|
+
end
|
225
|
+
|
226
|
+
def error_code_from(response, success)
|
227
|
+
unless success
|
228
|
+
return response["status_code"] if response["status"] == "ERROR"
|
229
|
+
response.try(:[], "payment").try(:[], "transaction_status").try(:[], "code")
|
230
|
+
end
|
231
|
+
end
|
232
|
+
end
|
233
|
+
end
|
234
|
+
end
|