activemerchant 1.57.0 → 1.58.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG +21 -0
- data/README.md +2 -1
- data/lib/active_merchant/billing/credit_card_methods.rb +36 -0
- data/lib/active_merchant/billing/gateways/card_stream.rb +17 -15
- data/lib/active_merchant/billing/gateways/clearhaus.rb +6 -1
- data/lib/active_merchant/billing/gateways/mercury.rb +12 -4
- data/lib/active_merchant/billing/gateways/ncr_secure_pay.rb +1 -1
- data/lib/active_merchant/billing/gateways/paypal_express.rb +1 -1
- data/lib/active_merchant/billing/gateways/sage_pay.rb +1 -4
- data/lib/active_merchant/billing/gateways/stripe.rb +58 -7
- data/lib/active_merchant/billing/gateways/trans_first.rb +15 -10
- data/lib/active_merchant/version.rb +1 -1
- metadata +2 -3
- data/lib/active_merchant/billing/gateways/app55.rb +0 -176
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: da3af9432d84476a6bb80c8c2ce551def7cb9aad
|
4
|
+
data.tar.gz: f0fca6c6c9aea70ec6fe8ba476aee0e0087bab14
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: d2d71c5586712ab174a2aea4da55ce52e10e4df6d11207ee46d85e3ea337feb698137e5b9c80b9f764f33e7d157bd31f15e3f097e5aaa866c60df2c48960525e
|
7
|
+
data.tar.gz: 831bc61882f81730b31b6f46d29e45a4d41e239c15209ff40a20abca24fe89bee9a1b04e31df0a900ccab1edd0a12ad501b46c7ae818c19dadcde21930c00da9
|
data/CHANGELOG
CHANGED
@@ -1,5 +1,20 @@
|
|
1
1
|
= ActiveMerchant CHANGELOG
|
2
2
|
|
3
|
+
== Version 1.58.0 (March 1, 2016)
|
4
|
+
* Move Electron check out of CreditCard into CreditCardMethods [ThereExistsX]
|
5
|
+
* CardStream: Add AED and NZD currencies [sdball]
|
6
|
+
* App55: Remove Gateway [ThereExistsX]
|
7
|
+
* Mercury: Stripping the start and end sentinels on card-present track data for max-length track1 requests [ryanbalsdon]
|
8
|
+
* SagePay: Update VISA Electron ranges [sdball]
|
9
|
+
* Clearhaus: Make request signing more transparent & robust [sdball]
|
10
|
+
* NCRSecurePay: Fix production URL [rwdaigle]
|
11
|
+
* Add ACH support to Stripe [sdball]
|
12
|
+
* PayPal Express: Fixing list of currencies without fractions [Krystosterone]
|
13
|
+
* Cashnet: Default custcode option and proper redirect handling [rwdaigle]
|
14
|
+
* TransFirst: Fix missing address and remove CC only fields for ACH [davidsantoso]
|
15
|
+
* More prominent links to contribution docs [rwdaigle]
|
16
|
+
|
17
|
+
|
3
18
|
== Version 1.57.0 (February 1, 2016)
|
4
19
|
* AuthorizeNetCim: Add unmaskExpirationDate option [RamilGilmanov]
|
5
20
|
* Element: Add gateway support [davidsantoso]
|
@@ -37,6 +52,12 @@
|
|
37
52
|
* Stripe: Add `stripe_account` header option [anellis]
|
38
53
|
* Cardstream: Add AVS code and message [anellis]
|
39
54
|
* Barclaycard Smartpay: New gateway support [curiousepic]
|
55
|
+
* Transfirst: Fix missing address and remove CC only fields for ACH [davidsantoso]
|
56
|
+
* Stripe: Support ACH payments [sdball]
|
57
|
+
* NCRSecurePay: Fix production URL [rwdaigle]
|
58
|
+
* Clearhaus: Make request signing more transparent & robust [sdball]
|
59
|
+
* SagePay: Properly detect Electron brand [sdball]
|
60
|
+
* Mercury: Fix for max-length track 1 [ryanbalsdon]
|
40
61
|
|
41
62
|
|
42
63
|
== Version 1.56.0 (December 1, 2015)
|
data/README.md
CHANGED
@@ -17,6 +17,8 @@ from an ever-growing set of contributors.
|
|
17
17
|
See [GettingStarted.md](GettingStarted.md) if you want to learn more about using Active Merchant in your
|
18
18
|
applications.
|
19
19
|
|
20
|
+
If you'd like to contribute to Active Merchant, please start with our [contribution guide](CONTRIBUTING.md).
|
21
|
+
|
20
22
|
## Installation
|
21
23
|
|
22
24
|
### From Git
|
@@ -82,7 +84,6 @@ For more in-depth documentation and tutorials, see [GettingStarted.md](GettingSt
|
|
82
84
|
|
83
85
|
The [ActiveMerchant Wiki](http://github.com/activemerchant/active_merchant/wikis) contains a [table of features supported by each gateway](http://github.com/activemerchant/active_merchant/wikis/gatewayfeaturematrix).
|
84
86
|
|
85
|
-
* [App55](https://www.app55.com/) - AU, BR, CA, CH, CL, CN, CO, CZ, DK, EU, GB, HK, HU, ID, IS, JP, KE, KR, MX, MY, NO, NZ, PH, PL, TH, TW, US, VN, ZA
|
86
87
|
* [Authorize.Net CIM](http://www.authorize.net/) - US
|
87
88
|
* [Authorize.Net](http://www.authorize.net/) - AD, AT, AU, BE, BG, CA, CH, CY, CZ, DE, DK, ES, FI, FR, GB, GB, GI, GR, HU, IE, IT, LI, LU, MC, MT, NL, NO, PL, PT, RO, SE, SI, SK, SM, TR, US, VA
|
88
89
|
* [Axcess MS](http://www.axcessms.com/) - AD, AT, BE, BG, BR, CA, CH, CY, CZ, DE, DK, EE, ES, FI, FO, FR, GB, GI, GR, HR, HU, IE, IL, IM, IS, IT, LI, LT, LU, LV, MC, MT, MX, NL, NO, PL, PT, RO, RU, SE, SI, SK, TR, US, VA
|
@@ -17,6 +17,26 @@ module ActiveMerchant #:nodoc:
|
|
17
17
|
'laser' => /^(6304|6706|6709|6771(?!89))\d{8}(\d{4}|\d{6,7})?$/
|
18
18
|
}
|
19
19
|
|
20
|
+
# http://www.barclaycard.co.uk/business/files/bin_rules.pdf
|
21
|
+
ELECTRON_RANGES = [
|
22
|
+
[400115],
|
23
|
+
(400837..400839),
|
24
|
+
(412921..412923),
|
25
|
+
[417935],
|
26
|
+
(419740..419741),
|
27
|
+
(419773..419775),
|
28
|
+
[424519],
|
29
|
+
(424962..424963),
|
30
|
+
[437860],
|
31
|
+
[444000],
|
32
|
+
[459472],
|
33
|
+
(484406..484411),
|
34
|
+
(484413..484414),
|
35
|
+
(484418..484418),
|
36
|
+
(484428..484455),
|
37
|
+
(491730..491759),
|
38
|
+
]
|
39
|
+
|
20
40
|
def self.included(base)
|
21
41
|
base.extend(ClassMethods)
|
22
42
|
end
|
@@ -58,6 +78,11 @@ module ActiveMerchant #:nodoc:
|
|
58
78
|
(number.to_s =~ /^\d{1,2}$/)
|
59
79
|
end
|
60
80
|
|
81
|
+
# Returns if the card matches known Electron BINs
|
82
|
+
def electron?
|
83
|
+
self.class.electron?(number)
|
84
|
+
end
|
85
|
+
|
61
86
|
module ClassMethods
|
62
87
|
# Returns true if it validates. Optionally, you can pass a card brand as an argument and
|
63
88
|
# make sure it is of the correct brand.
|
@@ -106,6 +131,17 @@ module ActiveMerchant #:nodoc:
|
|
106
131
|
return nil
|
107
132
|
end
|
108
133
|
|
134
|
+
def electron?(number)
|
135
|
+
return false unless [16, 19].include?(number.length)
|
136
|
+
|
137
|
+
# don't recalculate for each range
|
138
|
+
bank_identification_number = first_digits(number).to_i
|
139
|
+
|
140
|
+
ELECTRON_RANGES.any? do |range|
|
141
|
+
range.include?(bank_identification_number)
|
142
|
+
end
|
143
|
+
end
|
144
|
+
|
109
145
|
def type?(number)
|
110
146
|
ActiveMerchant.deprecated "CreditCard#type? is deprecated and will be removed from a future release of ActiveMerchant. Please use CreditCard#brand? instead."
|
111
147
|
brand?(number)
|
@@ -13,21 +13,23 @@ module ActiveMerchant #:nodoc:
|
|
13
13
|
self.display_name = 'CardStream'
|
14
14
|
|
15
15
|
CURRENCY_CODES = {
|
16
|
-
"
|
17
|
-
"
|
18
|
-
"
|
19
|
-
"
|
20
|
-
"
|
21
|
-
"
|
22
|
-
"
|
23
|
-
"
|
24
|
-
"
|
25
|
-
"
|
26
|
-
"
|
27
|
-
"
|
28
|
-
"
|
29
|
-
"
|
30
|
-
"
|
16
|
+
"AED" => "784",
|
17
|
+
"AUD" => "036",
|
18
|
+
"BRL" => "986",
|
19
|
+
"CAD" => "124",
|
20
|
+
"CHF" => "756",
|
21
|
+
"CZK" => "203",
|
22
|
+
"DKK" => "208",
|
23
|
+
"EUR" => "978",
|
24
|
+
"GBP" => "826",
|
25
|
+
"HKD" => "344",
|
26
|
+
"ICK" => "352",
|
27
|
+
"JPY" => "392",
|
28
|
+
"NOK" => "578",
|
29
|
+
"NZD" => "554",
|
30
|
+
"SEK" => "752",
|
31
|
+
"SGD" => "702",
|
32
|
+
"USD" => "840",
|
31
33
|
}
|
32
34
|
|
33
35
|
CVV_CODE = {
|
@@ -44,6 +44,7 @@ module ActiveMerchant #:nodoc:
|
|
44
44
|
# :signing_key - merchant's private key for optionally signing request
|
45
45
|
def initialize(options={})
|
46
46
|
requires!(options, :api_key)
|
47
|
+
options[:signing_key].strip! if options[:signing_key]
|
47
48
|
super
|
48
49
|
end
|
49
50
|
|
@@ -183,7 +184,11 @@ module ActiveMerchant #:nodoc:
|
|
183
184
|
body = parameters.to_query
|
184
185
|
|
185
186
|
if signing_key = @options[:signing_key]
|
186
|
-
|
187
|
+
begin
|
188
|
+
headers["Signature"] = generate_signature(@options[:api_key], signing_key, body)
|
189
|
+
rescue OpenSSL::PKey::RSAError => e
|
190
|
+
return Response.new(false, e.message)
|
191
|
+
end
|
187
192
|
end
|
188
193
|
|
189
194
|
response = begin
|
@@ -197,12 +197,20 @@ module ActiveMerchant #:nodoc:
|
|
197
197
|
if credit_card.track_data.present?
|
198
198
|
# Track 1 has a start sentinel (STX) of '%' and track 2 is ';'
|
199
199
|
# Track 1 and 2 have identical end sentinels (ETX) of '?'
|
200
|
+
# Tracks may or may not have checksum (LRC) after the ETX
|
200
201
|
# If the track has no STX or is corrupt, we send it as track 1, to let Mercury
|
201
202
|
#handle with the validation error as it sees fit.
|
202
|
-
# Track 2 requires having the
|
203
|
-
|
204
|
-
|
205
|
-
|
203
|
+
# Track 2 requires having the STX and ETX stripped. Track 1 does not.
|
204
|
+
# Max-length track 1s require having the STX and ETX stripped. Max is 79 bytes including LRC.
|
205
|
+
is_track_2 = credit_card.track_data[0] == ';'
|
206
|
+
etx_index = credit_card.track_data.rindex('?') || credit_card.track_data.length
|
207
|
+
is_max_track1 = etx_index >= 77
|
208
|
+
|
209
|
+
if is_track_2
|
210
|
+
xml.tag! 'Track2', credit_card.track_data[1...etx_index]
|
211
|
+
elsif is_max_track1
|
212
|
+
xml.tag! 'Track1', credit_card.track_data[1...etx_index]
|
213
|
+
else
|
206
214
|
xml.tag! 'Track1', credit_card.track_data
|
207
215
|
end
|
208
216
|
else
|
@@ -4,7 +4,7 @@ module ActiveMerchant #:nodoc:
|
|
4
4
|
module Billing #:nodoc:
|
5
5
|
class NcrSecurePayGateway < Gateway
|
6
6
|
self.test_url = 'https://testbox.monetra.com:8665/'
|
7
|
-
self.live_url = 'https://
|
7
|
+
self.live_url = 'https://portal.ncrsecurepay.com:8444/'
|
8
8
|
|
9
9
|
self.supported_countries = ['US']
|
10
10
|
self.default_currency = 'USD'
|
@@ -26,7 +26,7 @@ module ActiveMerchant #:nodoc:
|
|
26
26
|
'TW' => 'zh_TW'
|
27
27
|
}
|
28
28
|
|
29
|
-
CURRENCIES_WITHOUT_FRACTIONS = %w(
|
29
|
+
CURRENCIES_WITHOUT_FRACTIONS = %w(HUF JPY TWD)
|
30
30
|
|
31
31
|
self.test_redirect_url = 'https://www.sandbox.paypal.com/cgi-bin/webscr'
|
32
32
|
self.supported_countries = ['US']
|
@@ -36,8 +36,6 @@ module ActiveMerchant #:nodoc:
|
|
36
36
|
:jcb => "JCB"
|
37
37
|
}
|
38
38
|
|
39
|
-
ELECTRON = /^(424519|42496[23]|450875|48440[6-8]|4844[1-5][1-5]|4917[3-5][0-9]|491880)\d{10}(\d{3})?$/
|
40
|
-
|
41
39
|
AVS_CVV_CODE = {
|
42
40
|
"NOTPROVIDED" => nil,
|
43
41
|
"NOTCHECKED" => 'X',
|
@@ -292,8 +290,7 @@ module ActiveMerchant #:nodoc:
|
|
292
290
|
|
293
291
|
card_type = card_brand(credit_card).to_sym
|
294
292
|
|
295
|
-
|
296
|
-
if card_type == :visa && credit_card.number =~ ELECTRON
|
293
|
+
if card_type == :visa && credit_card.electron?
|
297
294
|
CREDIT_CARDS[:electron]
|
298
295
|
else
|
299
296
|
CREDIT_CARDS[card_type]
|
@@ -46,6 +46,11 @@ module ActiveMerchant #:nodoc:
|
|
46
46
|
'incorrect_pin' => STANDARD_ERROR_CODE[:incorrect_pin]
|
47
47
|
}
|
48
48
|
|
49
|
+
BANK_ACCOUNT_HOLDER_TYPE_MAPPING = {
|
50
|
+
"personal" => "individual",
|
51
|
+
"business" => "company",
|
52
|
+
}
|
53
|
+
|
49
54
|
def initialize(options = {})
|
50
55
|
requires!(options, :login)
|
51
56
|
@api_key = options[:login]
|
@@ -80,6 +85,11 @@ module ActiveMerchant #:nodoc:
|
|
80
85
|
#
|
81
86
|
# purchase(money, nil, { :customer => id, ... })
|
82
87
|
def purchase(money, payment, options = {})
|
88
|
+
if ach?(payment)
|
89
|
+
direct_bank_error = "Direct bank account transactions are not supported. Bank accounts must be stored and verified before use."
|
90
|
+
return Response.new(false, direct_bank_error)
|
91
|
+
end
|
92
|
+
|
83
93
|
MultiResponse.run do |r|
|
84
94
|
if payment.is_a?(ApplePayPaymentToken)
|
85
95
|
r.process { tokenize_apple_pay_token(payment) }
|
@@ -155,26 +165,34 @@ module ActiveMerchant #:nodoc:
|
|
155
165
|
|
156
166
|
# Note: creating a new credit card will not change the customer's existing default credit card (use :set_default => true)
|
157
167
|
def store(payment, options = {})
|
158
|
-
|
168
|
+
params = {}
|
159
169
|
post = {}
|
160
170
|
|
161
|
-
if payment
|
171
|
+
if card_brand(payment) == "check"
|
172
|
+
bank_token_response = tokenize_bank_account(payment)
|
173
|
+
if bank_token_response.success?
|
174
|
+
params = { source: bank_token_response.params["token"]["id"] }
|
175
|
+
else
|
176
|
+
return bank_token_response
|
177
|
+
end
|
178
|
+
elsif payment.is_a?(ApplePayPaymentToken)
|
162
179
|
token_exchange_response = tokenize_apple_pay_token(payment)
|
163
|
-
|
180
|
+
params = { card: token_exchange_response.params["token"]["id"] } if token_exchange_response.success?
|
164
181
|
else
|
165
|
-
add_creditcard(
|
182
|
+
add_creditcard(params, payment, options)
|
166
183
|
end
|
167
184
|
|
168
185
|
post[:validate] = options[:validate] unless options[:validate].nil?
|
169
186
|
post[:description] = options[:description] if options[:description]
|
170
187
|
post[:email] = options[:email] if options[:email]
|
188
|
+
|
171
189
|
if options[:account]
|
172
|
-
add_external_account(post,
|
190
|
+
add_external_account(post, params, payment)
|
173
191
|
commit(:post, "accounts/#{CGI.escape(options[:account])}/external_accounts", post, options)
|
174
192
|
elsif options[:customer]
|
175
193
|
MultiResponse.run(:first) do |r|
|
176
194
|
# The /cards endpoint does not update other customer parameters.
|
177
|
-
r.process { commit(:post, "customers/#{CGI.escape(options[:customer])}/cards",
|
195
|
+
r.process { commit(:post, "customers/#{CGI.escape(options[:customer])}/cards", params, options) }
|
178
196
|
|
179
197
|
if options[:set_default] and r.success? and !r.params['id'].blank?
|
180
198
|
post[:default_card] = r.params['id']
|
@@ -185,7 +203,7 @@ module ActiveMerchant #:nodoc:
|
|
185
203
|
end
|
186
204
|
end
|
187
205
|
else
|
188
|
-
commit(:post, 'customers', post.merge(
|
206
|
+
commit(:post, 'customers', post.merge(params), options)
|
189
207
|
end
|
190
208
|
end
|
191
209
|
|
@@ -542,6 +560,39 @@ module ActiveMerchant #:nodoc:
|
|
542
560
|
error_code ||= STANDARD_ERROR_CODE_MAPPING[code]
|
543
561
|
error_code
|
544
562
|
end
|
563
|
+
|
564
|
+
def tokenize_bank_account(bank_account, options = {})
|
565
|
+
account_holder_type = BANK_ACCOUNT_HOLDER_TYPE_MAPPING[bank_account.account_holder_type]
|
566
|
+
|
567
|
+
post = {
|
568
|
+
bank_account: {
|
569
|
+
account_number: bank_account.account_number,
|
570
|
+
country: 'US',
|
571
|
+
currency: 'usd',
|
572
|
+
routing_number: bank_account.routing_number,
|
573
|
+
name: bank_account.name,
|
574
|
+
account_holder_type: account_holder_type,
|
575
|
+
}
|
576
|
+
}
|
577
|
+
|
578
|
+
token_response = api_request(:post, "tokens?#{post_data(post)}")
|
579
|
+
success = token_response["error"].nil?
|
580
|
+
|
581
|
+
if success && token_response["id"]
|
582
|
+
Response.new(success, nil, token: token_response)
|
583
|
+
else
|
584
|
+
Response.new(success, token_response["error"]["message"])
|
585
|
+
end
|
586
|
+
end
|
587
|
+
|
588
|
+
def ach?(payment_method)
|
589
|
+
case payment_method
|
590
|
+
when String, nil
|
591
|
+
false
|
592
|
+
else
|
593
|
+
card_brand(payment_method) == "check"
|
594
|
+
end
|
595
|
+
end
|
545
596
|
end
|
546
597
|
end
|
547
598
|
end
|
@@ -38,24 +38,27 @@ module ActiveMerchant #:nodoc:
|
|
38
38
|
post = {}
|
39
39
|
|
40
40
|
add_amount(post, money)
|
41
|
-
add_invoice(post, options)
|
42
41
|
add_payment(post, payment)
|
43
42
|
add_address(post, options)
|
43
|
+
add_invoice(post, options) if payment.is_a?(CreditCard)
|
44
|
+
add_pair(post, :RefID, options[:order_id], required: true)
|
44
45
|
|
45
46
|
commit((payment.is_a?(Check) ? :purchase_echeck : :purchase), post)
|
46
47
|
end
|
47
48
|
|
48
49
|
def refund(money, authorization, options={})
|
49
50
|
post = {}
|
51
|
+
|
50
52
|
transaction_id, payment_type = split_authorization(authorization)
|
51
53
|
add_amount(post, money)
|
52
|
-
add_invoice(post, options)
|
53
54
|
add_pair(post, :TransID, transaction_id)
|
55
|
+
|
54
56
|
commit((payment_type == "check" ? :refund_echeck : :refund), post)
|
55
57
|
end
|
56
58
|
|
57
59
|
def void(authorization, options={})
|
58
60
|
post = {}
|
61
|
+
|
59
62
|
transaction_id, _ = split_authorization(authorization)
|
60
63
|
add_pair(post, :TransID, transaction_id)
|
61
64
|
|
@@ -85,13 +88,15 @@ module ActiveMerchant #:nodoc:
|
|
85
88
|
address = options[:billing_address] || options[:address]
|
86
89
|
|
87
90
|
if address
|
88
|
-
add_pair(post, :Address, address[:address1])
|
89
|
-
add_pair(post, :ZipCode, address[:zip])
|
91
|
+
add_pair(post, :Address, address[:address1], required: true)
|
92
|
+
add_pair(post, :ZipCode, address[:zip], required: true)
|
93
|
+
else
|
94
|
+
add_pair(post, :Address, "", required: true)
|
95
|
+
add_pair(post, :ZipCode, "", required: true)
|
90
96
|
end
|
91
97
|
end
|
92
98
|
|
93
99
|
def add_invoice(post, options)
|
94
|
-
add_pair(post, :RefID, options[:order_id], required: true)
|
95
100
|
add_pair(post, :SECCCode, options[:invoice], required: true)
|
96
101
|
add_pair(post, :PONumber, options[:invoice], required: true)
|
97
102
|
add_pair(post, :SaleTaxAmount, amount(options[:tax] || 0))
|
@@ -130,8 +135,8 @@ module ActiveMerchant #:nodoc:
|
|
130
135
|
return default_value
|
131
136
|
end
|
132
137
|
|
133
|
-
def add_unused_fields(post)
|
134
|
-
return
|
138
|
+
def add_unused_fields(action, post)
|
139
|
+
return unless action == :purchase
|
135
140
|
|
136
141
|
UNUSED_CREDIT_CARD_FIELDS.each do |f|
|
137
142
|
post[f] = ""
|
@@ -163,7 +168,7 @@ module ActiveMerchant #:nodoc:
|
|
163
168
|
end
|
164
169
|
|
165
170
|
def commit(action, params)
|
166
|
-
response = parse(ssl_post(url(action), post_data(params)))
|
171
|
+
response = parse(ssl_post(url(action), post_data(action, params)))
|
167
172
|
|
168
173
|
Response.new(
|
169
174
|
success_from(response),
|
@@ -208,8 +213,8 @@ module ActiveMerchant #:nodoc:
|
|
208
213
|
end
|
209
214
|
end
|
210
215
|
|
211
|
-
def post_data(params = {})
|
212
|
-
add_unused_fields(params)
|
216
|
+
def post_data(action, params = {})
|
217
|
+
add_unused_fields(action, params)
|
213
218
|
params[:MerchantID] = @options[:login]
|
214
219
|
params[:RegKey] = @options[:password]
|
215
220
|
|
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.58.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: 2016-
|
11
|
+
date: 2016-03-01 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: activesupport
|
@@ -162,7 +162,6 @@ files:
|
|
162
162
|
- lib/active_merchant/billing/gateway.rb
|
163
163
|
- lib/active_merchant/billing/gateways.rb
|
164
164
|
- lib/active_merchant/billing/gateways/allied_wallet.rb
|
165
|
-
- lib/active_merchant/billing/gateways/app55.rb
|
166
165
|
- lib/active_merchant/billing/gateways/authorize_net.rb
|
167
166
|
- lib/active_merchant/billing/gateways/authorize_net_arb.rb
|
168
167
|
- lib/active_merchant/billing/gateways/authorize_net_cim.rb
|
@@ -1,176 +0,0 @@
|
|
1
|
-
module ActiveMerchant #:nodoc:
|
2
|
-
module Billing #:nodoc:
|
3
|
-
class App55Gateway < Gateway
|
4
|
-
self.test_url = 'https://sandbox.app55.com/v1/'
|
5
|
-
self.live_url = 'https://api.app55.com/v1/'
|
6
|
-
|
7
|
-
self.supported_countries = ['AU', 'BR', 'CA', 'CH', 'CL', 'CN', 'CO', 'CZ', 'DK', 'GB', 'HK', 'HU', 'ID', 'IS', 'JP', 'KE', 'KR', 'MX', 'MY', 'NO', 'NZ', 'PH', 'PL', 'TH', 'TW', 'US', 'VN', 'ZA']
|
8
|
-
self.supported_cardtypes = [:visa, :master, :american_express, :jcb, :maestro, :solo]
|
9
|
-
self.default_currency = 'UKP'
|
10
|
-
self.money_format = :dollars
|
11
|
-
self.homepage_url = 'https://www.app55.com/'
|
12
|
-
self.display_name = 'App55'
|
13
|
-
|
14
|
-
# Create gateway
|
15
|
-
#
|
16
|
-
# options:
|
17
|
-
# :api_key - merchants App55 API Key
|
18
|
-
# :api_secret - merchants App55 Secret Key
|
19
|
-
def initialize(options = {})
|
20
|
-
requires!(options, :api_key, :api_secret)
|
21
|
-
@api_key = options[:api_key]
|
22
|
-
@api_secret = options[:api_secret]
|
23
|
-
super
|
24
|
-
end
|
25
|
-
|
26
|
-
# Make a purchase (authorize and commit)
|
27
|
-
#
|
28
|
-
# money - The monetary amount of the transaction in cents.
|
29
|
-
# payment_method - The CreditCard or the App55 card token.
|
30
|
-
# options - A standard ActiveMerchant options hash
|
31
|
-
def purchase(money, payment_method, options = {})
|
32
|
-
authorize(money, payment_method, options.merge(commit: true))
|
33
|
-
end
|
34
|
-
|
35
|
-
# Authorize a transaction.
|
36
|
-
#
|
37
|
-
# money - The monetary amount of the transaction in cents.
|
38
|
-
# payment_method - The CreditCard or the App55 card token.
|
39
|
-
# options - A standard ActiveMerchant options hash
|
40
|
-
def authorize(money, payment_method, options = {})
|
41
|
-
post = {}
|
42
|
-
add_creditcard(post, payment_method, options)
|
43
|
-
add_transaction(post, money, options)
|
44
|
-
|
45
|
-
commit(:post, 'transaction', post)
|
46
|
-
end
|
47
|
-
|
48
|
-
# Commit a pre-authorized transaction.
|
49
|
-
#
|
50
|
-
# money - The monetary amount of the transaction in cents.
|
51
|
-
# authorization - The App55 transaction id string.
|
52
|
-
# options - A standard ActiveMerchant options hash
|
53
|
-
def capture(money, authorization, options = {})
|
54
|
-
commit(:post, "transaction/#{authorization}")
|
55
|
-
end
|
56
|
-
|
57
|
-
private
|
58
|
-
|
59
|
-
def add_customer_data(post, options)
|
60
|
-
metadata_options = [:description, :browser_ip, :user_agent, :referrer]
|
61
|
-
post.update(options.slice(*metadata_options))
|
62
|
-
end
|
63
|
-
|
64
|
-
def add_creditcard(post, creditcard, options)
|
65
|
-
card = {}
|
66
|
-
card[:number] = creditcard.number
|
67
|
-
card[:expiry] = ("%02d". % creditcard.month) + '/' + creditcard.year.to_s
|
68
|
-
card[:security_code] = creditcard.verification_value if creditcard.verification_value?
|
69
|
-
card[:holder_name] = creditcard.name if creditcard.name
|
70
|
-
add_address(card, options)
|
71
|
-
post[:card] = card
|
72
|
-
end
|
73
|
-
|
74
|
-
def add_address(card, options)
|
75
|
-
return unless card && card.kind_of?(Hash)
|
76
|
-
address_hash = {}
|
77
|
-
if address = (options[:billing_address] || options[:address])
|
78
|
-
address_hash[:street] = address[:address1] if address[:address1]
|
79
|
-
address_hash[:street2] = address[:address2] if address[:address2]
|
80
|
-
address_hash[:country] = address[:country] if address[:country]
|
81
|
-
address_hash[:postal_code] = address[:zip] if address[:zip]
|
82
|
-
address_hash[:city] = address[:city] if address[:city]
|
83
|
-
card[:address] = address_hash
|
84
|
-
end
|
85
|
-
end
|
86
|
-
|
87
|
-
def add_transaction(post, money, options)
|
88
|
-
transaction = {}
|
89
|
-
add_amount(transaction, money, options)
|
90
|
-
transaction[:description] = (options[:description] || options[:email])
|
91
|
-
transaction[:commit] = options[:commit]
|
92
|
-
post[:transaction] = transaction
|
93
|
-
end
|
94
|
-
|
95
|
-
def add_amount(obj, money, options)
|
96
|
-
obj[:amount] = amount(money)
|
97
|
-
obj[:currency] = (options[:currency] || currency(money))
|
98
|
-
end
|
99
|
-
|
100
|
-
def parse(body)
|
101
|
-
JSON.parse(body)
|
102
|
-
rescue JSON::ParserError
|
103
|
-
json_error(raw_response)
|
104
|
-
end
|
105
|
-
|
106
|
-
def commit(method, resource, parameters=nil, meta={})
|
107
|
-
success = false
|
108
|
-
begin
|
109
|
-
raw_response = ssl_request(
|
110
|
-
method,
|
111
|
-
url(resource),
|
112
|
-
post_data(parameters),
|
113
|
-
headers
|
114
|
-
)
|
115
|
-
response = parse(raw_response)
|
116
|
-
success = response.key?("sig")
|
117
|
-
rescue ResponseError => e
|
118
|
-
response = parse(e.response.body)
|
119
|
-
end
|
120
|
-
|
121
|
-
Response.new(
|
122
|
-
success,
|
123
|
-
(success ? "OK" : response["error"]["message"]),
|
124
|
-
response,
|
125
|
-
test: test?,
|
126
|
-
authorization: authorization_from(response)
|
127
|
-
)
|
128
|
-
end
|
129
|
-
|
130
|
-
def authorization_from(response)
|
131
|
-
if response.key?("transaction")
|
132
|
-
response["transaction"]["id"]
|
133
|
-
elsif response.key?("card")
|
134
|
-
response["card"]["token"]
|
135
|
-
end
|
136
|
-
end
|
137
|
-
|
138
|
-
def json_error(raw_response)
|
139
|
-
msg = "Invalid response from app55 server: Received: #{raw_response.inspect})"
|
140
|
-
{
|
141
|
-
"error" => {
|
142
|
-
"message" => msg
|
143
|
-
}
|
144
|
-
}
|
145
|
-
end
|
146
|
-
|
147
|
-
def url(resource)
|
148
|
-
(test? ? self.test_url : self.live_url) + resource
|
149
|
-
end
|
150
|
-
|
151
|
-
def post_data(params)
|
152
|
-
return nil unless params
|
153
|
-
|
154
|
-
params.map do |key, value|
|
155
|
-
next if value.blank?
|
156
|
-
if value.is_a?(Hash)
|
157
|
-
h = {}
|
158
|
-
value.each do |k, v|
|
159
|
-
h["#{key}.#{k}"] = v unless v.blank?
|
160
|
-
end
|
161
|
-
post_data(h)
|
162
|
-
else
|
163
|
-
"#{key}=#{CGI.escape(value.to_s)}"
|
164
|
-
end
|
165
|
-
end.compact.join("&")
|
166
|
-
end
|
167
|
-
|
168
|
-
def headers
|
169
|
-
{
|
170
|
-
"Authorization" => "Basic " + Base64.strict_encode64(@options[:api_key].to_s + ":" + @options[:api_secret].to_s),
|
171
|
-
"User-Agent" => user_agent,
|
172
|
-
}
|
173
|
-
end
|
174
|
-
end
|
175
|
-
end
|
176
|
-
end
|