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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 763b8ca398277831841d2b263a482a46e2f8793b
4
- data.tar.gz: 6acb014413ea74d8b36ebe9a2a40ae04e60de312
3
+ metadata.gz: da3af9432d84476a6bb80c8c2ce551def7cb9aad
4
+ data.tar.gz: f0fca6c6c9aea70ec6fe8ba476aee0e0087bab14
5
5
  SHA512:
6
- metadata.gz: fce7249de3a503a61123f020bf72a374d5fe3fc9368c786e939135995ff5f4d5a392f31026325d7844ffd6458bc832d7c845e56d1f892c21b4e567ce322b5ec7
7
- data.tar.gz: 204553110484e103828c9767405bf11cd704810a5689f1150bace201316445168ce9f523ba67278f9e3ff2010906ca2237cd8a6d58ddd99192671cffd08d36d3
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
- "AUD" => '036',
17
- "BRL" => '986',
18
- "CAD" => '124',
19
- "CZK" => '203',
20
- "DKK" => '208',
21
- "HKD" => '344',
22
- "ICK" => '352',
23
- "JPY" => '392',
24
- "NOK" => '578',
25
- "SGD" => '702',
26
- "SEK" => '752',
27
- "CHF" => '756',
28
- "GBP" => '826',
29
- "USD" => '840',
30
- "EUR" => '978'
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
- headers["Signature"] = generate_signature(@options[:api_key], signing_key, body)
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 start and end sentinels stripped. Track 1 does not.
203
- if credit_card.track_data[0] == ';' # track 2 start sentinel (STX)
204
- xml.tag! 'Track2', credit_card.track_data[1..-2]
205
- else # track 1 or a corrupt track
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://ps.ncrsecurepay.com:8444/'
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(BRL HUF JPY MYR TWD TRY)
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
- # Check if it is an electron card
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
- card_params = {}
168
+ params = {}
159
169
  post = {}
160
170
 
161
- if payment.is_a?(ApplePayPaymentToken)
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
- card_params = { card: token_exchange_response.params["token"]["id"] } if token_exchange_response.success?
180
+ params = { card: token_exchange_response.params["token"]["id"] } if token_exchange_response.success?
164
181
  else
165
- add_creditcard(card_params, payment, options)
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, card_params, payment)
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", card_params, options) }
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(card_params), options)
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 if post[:TransRoute]
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
 
@@ -1,3 +1,3 @@
1
1
  module ActiveMerchant
2
- VERSION = "1.57.0"
2
+ VERSION = "1.58.0"
3
3
  end
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.57.0
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-02-01 00:00:00.000000000 Z
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