spree_gateway 2.2.1 → 3.0.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.
Files changed (65) hide show
  1. checksums.yaml +4 -4
  2. data/.travis.yml +5 -17
  3. data/Gemfile +1 -1
  4. data/README.md +9 -3
  5. data/app/models/spree/billing_integration.rb +21 -0
  6. data/app/models/spree/gateway/authorize_net.rb +31 -1
  7. data/app/models/spree/gateway/authorize_net_cim.rb +128 -47
  8. data/app/models/spree/gateway/balanced_gateway.rb +3 -5
  9. data/app/models/spree/gateway/braintree_gateway.rb +55 -18
  10. data/app/models/spree/gateway/cyber_source.rb +10 -0
  11. data/app/models/spree/gateway/migs.rb +11 -0
  12. data/app/models/spree/gateway/payflow_pro.rb +1 -0
  13. data/app/models/spree/gateway/pin_gateway.rb +45 -0
  14. data/app/models/spree/gateway/spreedly_core_gateway.rb +10 -0
  15. data/app/models/spree/gateway/stripe_gateway.rb +29 -6
  16. data/app/models/spree/gateway/usa_epay_transaction.rb +9 -0
  17. data/config/routes.rb +1 -1
  18. data/db/migrate/20111118164631_create_skrill_transactions.rb +1 -2
  19. data/lib/assets/javascripts/spree/frontend/spree_gateway.js +1 -0
  20. data/{app → lib}/assets/stylesheets/spree/frontend/spree_gateway.css +0 -0
  21. data/{app/controllers → lib/controllers/frontend}/spree/checkout_controller_decorator.rb +1 -1
  22. data/{app/controllers → lib/controllers/frontend}/spree/skrill_status_controller.rb +0 -0
  23. data/lib/spree_gateway.rb +1 -1
  24. data/lib/spree_gateway/engine.rb +56 -25
  25. data/{app/views → lib/views/backend}/spree/admin/log_entries/_braintree.html.erb +0 -0
  26. data/{app/views → lib/views/backend}/spree/admin/log_entries/_stripe.html.erb +0 -0
  27. data/{app/views → lib/views/backend}/spree/admin/payments/source_forms/_quickcheckout.html.erb +0 -0
  28. data/lib/views/backend/spree/admin/payments/source_forms/_stripe.html.erb +1 -0
  29. data/{app/views → lib/views/backend}/spree/admin/payments/source_views/_quickcheckout.html.erb +0 -0
  30. data/{app/views → lib/views/backend}/spree/admin/payments/source_views/_stripe.html.erb +0 -0
  31. data/{app/views → lib/views/frontend}/spree/checkout/payment/_quickcheckout.html.erb +2 -2
  32. data/lib/views/frontend/spree/checkout/payment/_stripe.html.erb +90 -0
  33. data/spec/factories/payment_method_factory.rb +0 -1
  34. data/spec/features/stripe_checkout_spec.rb +15 -4
  35. data/spec/models/gateway/authorize_net_cim_spec.rb +6 -6
  36. data/spec/models/gateway/authorize_net_spec.rb +6 -6
  37. data/spec/models/gateway/balanced_gateway_spec.rb +1 -1
  38. data/spec/models/gateway/beanstream_spec.rb +1 -1
  39. data/spec/models/gateway/braintree_gateway_spec.rb +147 -31
  40. data/spec/models/gateway/cyber_source_spec.rb +11 -0
  41. data/spec/models/gateway/eway_spec.rb +3 -3
  42. data/spec/models/gateway/maxipago_spec.rb +1 -1
  43. data/spec/models/gateway/pay_junction_spec.rb +2 -2
  44. data/spec/models/gateway/payflow_pro_spec.rb +2 -2
  45. data/spec/models/gateway/pin_gateway_spec.rb +4 -6
  46. data/spec/models/gateway/stripe_gateway_spec.rb +90 -9
  47. data/spec/models/gateway/{usa_epay_spec.rb → usa_epay_transaction_spec.rb} +9 -9
  48. data/spec/spec_helper.rb +5 -2
  49. data/spree_gateway.gemspec +15 -16
  50. metadata +89 -98
  51. data/Versionfile +0 -7
  52. data/app/assets/javascripts/spree/frontend/spree_gateway.js +0 -3
  53. data/app/assets/javascripts/store/gateway/stripe.js.coffee +0 -58
  54. data/app/assets/javascripts/store/spree_gateway.js +0 -2
  55. data/app/models/spree/gateway/fatzebra.rb +0 -15
  56. data/app/models/spree/gateway/linkpoint.rb +0 -28
  57. data/app/models/spree/gateway/samurai.rb +0 -63
  58. data/app/models/spree/gateway/usa_epay.rb +0 -9
  59. data/app/views/spree/admin/payments/source_forms/_stripe.html.erb +0 -1
  60. data/app/views/spree/checkout/payment/_stripe.html.erb +0 -21
  61. data/config/initializers/savon.rb +0 -3
  62. data/spec/models/gateway/fatzebra_spec.rb +0 -51
  63. data/spec/models/gateway/linkpoint_spec.rb +0 -62
  64. data/spec/models/gateway/samurai_spec.rb +0 -17
  65. data/spec/models/savon_spec.rb +0 -9
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 95c7ba85f1dc043286f155159fb7b99920b5380c
4
- data.tar.gz: 0b3b9ea6327a6dd7e9bd178da097d4328806520b
3
+ metadata.gz: 0cb78725c48779b76c00a60061c407ee89c83f7c
4
+ data.tar.gz: 1a0480cb3b860dd2b93b3dcb1b1f29de35f62881
5
5
  SHA512:
6
- metadata.gz: f8ae2294899c1db7f01b118c7a627233bb16653bef5878e7e9b4ca50521ebc9b1a86e05f45bf2b43c3fea2e6dee6315ac4087caad57d58e19dc5f31dd0f30949
7
- data.tar.gz: 460ffbd59ecea4aef14c93a052dc1ef011d8c1f48ae95c88213a4dcf05209071f7600ecb8a4cbaa05eabcbae136f5b1dab0bf004208da574e590a047dafa7f0a
6
+ metadata.gz: 5f2750bae6c95b1e2017c9eebb9a9c4a21c0210e972cf3d9a3a96fdab474bfe4c92f264f2e7174d7513ae6a9365d1b09dc3ba71b097f6d5c725796e9f3227c08
7
+ data.tar.gz: 35898a84a069e3ee90bdb97f77f155bc53208dc581b8c2cbef016d1214a1616c9d58dfff450d67154ed55cb2a704168670cb0721283645f41744d7ebcdfbb358
@@ -1,23 +1,11 @@
1
- language: ruby
2
1
  before_script:
3
- - sh -e /etc/init.d/xvfb start
4
- - export DISPLAY=:99.0
5
2
  - bundle exec rake test_app
3
+ - export DISPLAY=:99.0
4
+ - sh -e /etc/init.d/xvfb start
6
5
  env:
7
- - DB=sqlite
8
6
  - DB=mysql
9
7
  - DB=postgres
10
- script:
11
- - bundle exec rspec spec
12
- notifications:
13
- email:
14
- - ryan@spreecommerce.com
15
- irc:
16
- use_notice: true
17
- skip_join: true
18
- channels:
19
- - "irc.freenode.org#spree"
8
+ language: ruby
20
9
  rvm:
21
- - 1.9.3
22
- - 2.0.0
23
- - 2.1.0
10
+ - 2.1
11
+ sudo: false
data/Gemfile CHANGED
@@ -1,5 +1,5 @@
1
1
  source 'https://rubygems.org'
2
2
 
3
- gem 'spree', github: 'spree/spree', branch: '2-2-stable'
3
+ gem 'spree', github: 'spree/spree', branch: '3-0-stable'
4
4
 
5
5
  gemspec
data/README.md CHANGED
@@ -3,7 +3,11 @@
3
3
  [![Build Status](https://api.travis-ci.org/spree/spree_gateway.png?branch=master)](https://travis-ci.org/spree/spree_gateway)
4
4
  [![Code Climate](https://codeclimate.com/github/spree/spree_gateway.png)](https://codeclimate.com/github/spree/spree_gateway)
5
5
 
6
- Community supported Spree Payment Method Gateways.
6
+ Community supported Spree Payment Method Gateways. It works as a wrapper for
7
+ active_merchant gateway. Note that for some gateways you might still need to
8
+ add another gem to your Gemfile to make it work. For example active_merchant
9
+ require `braintree` but it doesn't include that gem on its gemspec. So you
10
+ need to manually add it to your rails app Gemfile.
7
11
 
8
12
  These can be used with Spree >= 1.0.x (but see note below for necessary changes)
9
13
 
@@ -27,8 +31,6 @@ gem 'spree', '~> 1.3'
27
31
  gem 'spree_gateway', github: 'spree/spree_gateway', branch: '1-3-stable'
28
32
  ```
29
33
 
30
- **Note:** *Please consult the Versionfile at the root of the repository to determine which branch to use.*
31
-
32
34
  Then run from the command line:
33
35
 
34
36
  $ bundle install
@@ -56,12 +58,16 @@ Starting point:
56
58
 
57
59
  * Fork the repo
58
60
  * Clone your repo
61
+ * (You will need to `brew install mysql postgres` if you don't already have them installed)
59
62
  * Run `bundle`
63
+ * (You may need to `bundle update` if bundler gets stuck)
60
64
  * Run `bundle exec rake test_app` to create the test application in `spec/test_app`
61
65
  * Make your changes
62
66
  * Ensure specs pass by running `bundle exec rspec spec`
67
+ * (You will need to `brew install phantomjs` if you don't already have it installed)
63
68
  * Submit your pull request
64
69
 
70
+
65
71
  Copyright (c) 2014 [Spree Commerce][4] and other [contributors][5], released under the [New BSD License][3]
66
72
 
67
73
  [1]: http://www.fsf.org/licensing/essays/free-sw.html
@@ -0,0 +1,21 @@
1
+ module Spree
2
+ class BillingIntegration < PaymentMethod
3
+ validates :name, presence: true
4
+
5
+ preference :server, :string, default: 'test'
6
+ preference :test_mode, :boolean, default: true
7
+
8
+ def provider
9
+ integration_options = options
10
+ ActiveMerchant::Billing::Base.integration_mode = integration_options[:server].to_sym
11
+ integration_options[:test] = true if integration_options[:test_mode]
12
+ @provider ||= provider_class.new(integration_options)
13
+ end
14
+
15
+ def options
16
+ options_hash = {}
17
+ preferences.each { |key, value| options_hash[key.to_sym] = value }
18
+ options_hash
19
+ end
20
+ end
21
+ end
@@ -2,15 +2,45 @@ module Spree
2
2
  class Gateway::AuthorizeNet < Gateway
3
3
  preference :login, :string
4
4
  preference :password, :string
5
+ preference :server, :string, default: "test"
5
6
 
6
7
  def provider_class
7
8
  ActiveMerchant::Billing::AuthorizeNetGateway
8
9
  end
9
10
 
10
11
  def options_with_test_preference
11
- options_without_test_preference.merge(:test => self.preferred_test_mode)
12
+ if !['live','test'].include?(self.preferred_server)
13
+ raise "You must set the 'server' preference in your payment method (Gateway::AuthorizeNet) to either 'live' or 'test'"
14
+ end
15
+ options_without_test_preference.merge(test: (self.preferred_server != "live") )
12
16
  end
13
17
 
18
+ def cancel(response_code)
19
+ provider
20
+ # From: http://community.developer.authorize.net/t5/The-Authorize-Net-Developer-Blog/Refunds-in-Retail-A-user-friendly-approach-using-AIM/ba-p/9848
21
+ # DD: if unsettled, void needed
22
+ response = provider.void(response_code)
23
+ # DD: if settled, credit/refund needed (CAN'T DO WITHOUT CREDIT CARD ON AUTH.NET)
24
+ #response = provider.refund(response_code) unless response.success?
25
+
26
+ response
27
+ end
14
28
  alias_method_chain :options, :test_preference
29
+
30
+ def credit(amount, response_code, refund, gateway_options = {})
31
+ gateway_options[:card_number] = refund[:originator].payment.source.last_digits
32
+ auth_net_gateway.refund(amount, response_code, gateway_options)
33
+ end
34
+
35
+ private
36
+
37
+ def auth_net_gateway
38
+ @_auth_net_gateway ||= begin
39
+ ActiveMerchant::Billing::Base.gateway_mode = preferred_server.to_sym
40
+ gateway_options = options
41
+ gateway_options[:test_requests] = false # DD: never ever do test requests because just returns transaction_id = 0
42
+ ActiveMerchant::Billing::AuthorizeNetGateway.new(gateway_options)
43
+ end
44
+ end
15
45
  end
16
46
  end
@@ -2,8 +2,9 @@ module Spree
2
2
  class Gateway::AuthorizeNetCim < Gateway
3
3
  preference :login, :string
4
4
  preference :password, :string
5
- preference :test_mode, :boolean, :default => false
6
- preference :validate_on_profile_create, :boolean, :default => false
5
+ preference :server, :string, default: "test"
6
+ preference :test_mode, :boolean, default: false
7
+ preference :validate_on_profile_create, :boolean, default: false
7
8
 
8
9
  ActiveMerchant::Billing::Response.class_eval do
9
10
  attr_writer :authorization
@@ -14,76 +15,142 @@ module Spree
14
15
  end
15
16
 
16
17
  def options
17
- # add :test key in the options hash, as that is what the ActiveMerchant::Billing::AuthorizeNetGateway expects
18
- if self.preferred_test_mode
19
- self.class.preference :test, :boolean, :default => true
18
+ if !['live','test'].include?(self.preferred_server)
19
+ raise "You must set the 'server' preference in your payment method (Gateway::AuthorizeNetCim) to either 'live' or 'test'"
20
+ end
21
+
22
+ # add :test key in the options hash, as that is what the
23
+ # ActiveMerchant::Billing::AuthorizeNetGateway expects
24
+ if self.preferred_server != "live"
25
+ self.preferences[:test] = true
20
26
  else
21
- self.class.remove_preference :test
27
+ self.preferences.delete(:test)
22
28
  end
23
29
 
24
30
  super
25
31
  end
26
32
 
27
33
  def authorize(amount, creditcard, gateway_options)
28
- t_options = { :order => {:invoice_number => gateway_options[:order_id] } }
29
- create_transaction( amount, creditcard, :auth_only, t_options )
34
+ create_transaction(amount, creditcard, :auth_only, transaction_options(gateway_options))
30
35
  end
31
36
 
32
37
  def purchase(amount, creditcard, gateway_options)
33
- create_transaction(amount, creditcard, :auth_capture)
38
+ create_transaction(amount, creditcard, :auth_capture, transaction_options(gateway_options))
34
39
  end
35
40
 
36
- def capture(authorization, creditcard, gateway_options)
37
- create_transaction((authorization.amount * 100).round, creditcard, :prior_auth_capture, :trans_id => authorization.response_code)
41
+ # capture is only one where source is not passed in for payment profile
42
+ def capture(amount, response_code, gateway_options)
43
+ # no credit card needed
44
+ create_transaction(amount, nil, :prior_auth_capture, trans_id: response_code)
38
45
  end
39
46
 
40
- def credit(amount, creditcard, response_code, gateway_options)
41
- create_transaction(amount, creditcard, :refund, :trans_id => response_code)
47
+ def credit(amount, creditcard, response_code, gateway_options = {})
48
+ create_transaction(amount, creditcard, :refund, transaction_options(gateway_options).merge(trans_id: response_code))
42
49
  end
43
50
 
44
- def void(response_code, creditcard, gateway_options)
45
- create_transaction(nil, creditcard, :void, :trans_id => response_code)
51
+ def void(response_code, creditcard, gateway_options = {})
52
+ create_transaction(nil, creditcard, :void, transaction_options(gateway_options).merge(trans_id: response_code))
53
+ end
54
+
55
+ def cancel(response_code)
56
+ # From: http://community.developer.authorize.net/t5/The-Authorize-Net-Developer-Blog/Refunds-in-Retail-A-user-friendly-approach-using-AIM/ba-p/9848
57
+ # DD: if unsettled, void needed
58
+ response = void(response_code, nil)
59
+ # DD: if settled, credit/refund needed
60
+ response = credit(nil, nil, response_code) unless response.success?
61
+
62
+ response
46
63
  end
47
64
 
48
65
  def payment_profiles_supported?
49
66
  true
50
67
  end
51
68
 
52
- # Create a new CIM customer profile ready to accept a payment
69
+ # Create a new CIM customer profile ready to accept a payment. Called by Spree::Payment on after_save.
53
70
  def create_profile(payment)
54
71
  if payment.source.gateway_customer_profile_id.nil?
55
72
  profile_hash = create_customer_profile(payment)
56
- payment.source.update_attributes(:gateway_customer_profile_id => profile_hash[:customer_profile_id], :gateway_payment_profile_id => profile_hash[:customer_payment_profile_id])
73
+ payment.source.update_attributes(gateway_customer_profile_id: profile_hash[:customer_profile_id], gateway_payment_profile_id: profile_hash[:customer_payment_profile_id])
74
+ end
75
+ end
76
+
77
+ # Get the CIM payment profile; Needed for updates.
78
+ def get_profile(payment)
79
+ if payment.source.has_payment_profile?
80
+ profile = cim_gateway.get_customer_profile({
81
+ customer_profile_id: payment.source.gateway_customer_profile_id
82
+ })
83
+ if profile
84
+ profile.params['profile'].deep_symbolize_keys!
85
+ end
57
86
  end
58
87
  end
59
88
 
60
- # simpler form
61
- def create_profile_from_card(card)
62
- if card.gateway_customer_profile_id.nil?
63
- profile_hash = create_customer_profile(card)
64
- card.update_attributes(:gateway_customer_profile_id => profile_hash[:customer_profile_id], :gateway_payment_profile_id => profile_hash[:customer_payment_profile_id])
89
+ # Get the CIM payment profile; Needed for updates.
90
+ def get_payment_profile(payment)
91
+ if payment.source.has_payment_profile?
92
+ profile = cim_gateway.get_customer_payment_profile({
93
+ customer_profile_id: payment.source.gateway_customer_profile_id,
94
+ customer_payment_profile_id: payment.source.gateway_payment_profile_id
95
+ })
96
+ if profile
97
+ profile.params['payment_profile'].deep_symbolize_keys!
98
+ end
99
+ end
100
+ end
101
+
102
+ # Update billing address on the CIM payment profile
103
+ def update_payment_profile(payment)
104
+ if payment.source.has_payment_profile?
105
+ if hash = get_payment_profile(payment)
106
+ hash[:bill_to] = generate_address_hash(payment.order.bill_address)
107
+ if hash[:payment][:credit_card]
108
+ # activemerchant expects a credit card object with 'number', 'year', 'month', and 'verification_value?' defined
109
+ payment.source.define_singleton_method(:number) { "XXXXXXXXX#{payment.source.last_digits}" }
110
+ hash[:payment][:credit_card] = payment.source
111
+ end
112
+ cim_gateway.update_customer_payment_profile({
113
+ customer_profile_id: payment.source.gateway_customer_profile_id,
114
+ payment_profile: hash
115
+ })
116
+ end
65
117
  end
66
118
  end
67
119
 
68
120
  private
121
+
122
+ def transaction_options(gateway_options = {})
123
+ { order: { invoice_number: gateway_options[:order_id] } }
124
+ end
125
+
69
126
  # Create a transaction on a creditcard
70
127
  # Set up a CIM profile for the card if one doesn't exist
71
128
  # Valid transaction_types are :auth_only, :capture_only and :auth_capture
72
129
  def create_transaction(amount, creditcard, transaction_type, options = {})
73
- #create_profile(creditcard, creditcard.gateway_options)
74
- creditcard.save
130
+ creditcard.save if creditcard
131
+
132
+ transaction_options = {
133
+ type: transaction_type
134
+ }.update(options)
135
+
75
136
  if amount
76
137
  amount = "%.2f" % (amount / 100.0) # This gateway requires formated decimal, not cents
138
+ transaction_options.update({
139
+ amount: amount
140
+ })
77
141
  end
78
- transaction_options = {
79
- :type => transaction_type,
80
- :amount => amount,
81
- :customer_profile_id => creditcard.gateway_customer_profile_id,
82
- :customer_payment_profile_id => creditcard.gateway_payment_profile_id,
83
- }.update(options)
84
- t = cim_gateway.create_customer_profile_transaction(:transaction => transaction_options)
85
- logger.debug("\nAuthorize Net CIM Transaction")
142
+
143
+ if creditcard
144
+ transaction_options.update({
145
+ customer_profile_id: creditcard.gateway_customer_profile_id,
146
+ customer_payment_profile_id: creditcard.gateway_payment_profile_id
147
+ })
148
+ end
149
+
150
+ logger.debug("\nAuthorize Net CIM Request")
86
151
  logger.debug(" transaction_options: #{transaction_options.inspect}")
152
+ t = cim_gateway.create_customer_profile_transaction(transaction: transaction_options)
153
+ logger.debug("\nAuthorize Net CIM Response")
87
154
  logger.debug(" response: #{t.inspect}\n")
88
155
  t
89
156
  end
@@ -93,8 +160,8 @@ module Spree
93
160
  options = options_for_create_customer_profile(payment)
94
161
  response = cim_gateway.create_customer_profile(options)
95
162
  if response.success?
96
- { :customer_profile_id => response.params['customer_profile_id'],
97
- :customer_payment_profile_id => response.params['customer_payment_profile_id_list'].values.first }
163
+ { customer_profile_id: response.params['customer_profile_id'],
164
+ customer_payment_profile_id: response.params['customer_payment_profile_id_list'].values.first }
98
165
  else
99
166
  payment.send(:gateway_error, response)
100
167
  end
@@ -102,31 +169,45 @@ module Spree
102
169
 
103
170
  def options_for_create_customer_profile(payment)
104
171
  if payment.is_a? CreditCard
105
- info = { :bill_to => generate_address_hash(payment.address), :payment => { :credit_card => payment } }
172
+ info = { bill_to: generate_address_hash(payment.address),
173
+ payment: { credit_card: payment } }
106
174
  else
107
- info = { :bill_to => generate_address_hash(payment.order.bill_address),
108
- :payment => { :credit_card => payment.source } }
175
+ info = { bill_to: generate_address_hash(payment.order.bill_address),
176
+ payment: { credit_card: payment.source } }
109
177
  end
110
178
  validation_mode = preferred_validate_on_profile_create ? preferred_server.to_sym : :none
111
179
 
112
- { :profile => { :merchant_customer_id => "#{Time.now.to_f}",
113
- #:ship_to_list => generate_address_hash(creditcard.checkout.ship_address),
114
- :email => payment.order.email,
115
- :payment_profiles => info },
116
- :validation_mode => validation_mode }
180
+ { profile: { merchant_customer_id: "#{Time.now.to_f}",
181
+ ship_to_list: generate_address_hash(payment.order.ship_address),
182
+ email: payment.order.email,
183
+ payment_profiles: info },
184
+ validation_mode: validation_mode }
117
185
  end
118
186
 
119
187
  # As in PaymentGateway but with separate name fields
120
188
  def generate_address_hash(address)
121
189
  return {} if address.nil?
122
- {:first_name => address.firstname, :last_name => address.lastname, :address1 => address.address1, :address2 => address.address2, :city => address.city,
123
- :state => address.state_text, :zip => address.zipcode, :country => address.country.iso, :phone_number => address.phone}
190
+ {
191
+ first_name: address.firstname,
192
+ last_name: address.lastname,
193
+ address1: address.address1,
194
+ address2: address.address2,
195
+ city: address.city,
196
+ state: address.state_text,
197
+ zip: address.zipcode,
198
+ country: address.country.iso,
199
+ phone_number: address.phone
200
+ }
124
201
  end
125
202
 
126
203
  def cim_gateway
127
- ActiveMerchant::Billing::Base.gateway_mode = preferred_server.to_sym
128
- gateway_options = options
129
- ActiveMerchant::Billing::AuthorizeNetCimGateway.new(gateway_options)
204
+ @_cim_gateway ||= begin
205
+ ActiveMerchant::Billing::Base.gateway_mode = preferred_server.to_sym
206
+ gateway_options = options
207
+ gateway_options[:test_requests] = false # DD: never ever do test requests because just returns transaction_id = 0
208
+ ActiveMerchant::Billing::AuthorizeNetCimGateway.new(gateway_options)
209
+ end
130
210
  end
211
+
131
212
  end
132
213
  end
@@ -27,11 +27,9 @@ module Spree
27
27
  card_uri = card_store_response.authorization.split(';').first
28
28
 
29
29
  # A success just returns a string of the token. A failed request returns a bad request response with a message.
30
- if card_uri.is_a?(String)
31
- payment.source.update_attributes!(:gateway_payment_profile_id => card_uri)
32
- else
33
- payment.send(:gateway_error, card_uri.message)
34
- end
30
+ payment.source.update_attributes!(:gateway_payment_profile_id => card_uri)
31
+ rescue Error => ex
32
+ payment.send(:gateway_error, ex.message)
35
33
  end
36
34
 
37
35
  def options_with_test_preference
@@ -37,18 +37,25 @@ module Spree
37
37
 
38
38
  def authorize(money, creditcard, options = {})
39
39
  adjust_options_for_braintree(creditcard, options)
40
- payment_method = creditcard.gateway_customer_profile_id || creditcard
40
+
41
+ if creditcard.gateway_payment_profile_id
42
+ payment_method = creditcard.gateway_payment_profile_id
43
+ options[:payment_method_token] = true
44
+ else
45
+ payment_method = creditcard.gateway_customer_profile_id || creditcard
46
+ end
47
+
41
48
  provider.authorize(money, payment_method, options)
42
49
  end
43
50
 
44
- def capture(authorization, ignored_creditcard, ignored_options)
45
- amount = (authorization.amount * 100).to_i
46
- provider.capture(amount, authorization.response_code)
51
+ def capture(amount, authorization_code, ignored_options = {})
52
+ provider.capture(amount, authorization_code)
47
53
  end
48
54
 
49
55
  def create_profile(payment)
50
- if payment.source.gateway_customer_profile_id.nil?
51
- response = provider.store(payment.source)
56
+ if payment.source.gateway_customer_profile_id.nil? && payment.source.number.present?
57
+ response = provider.store(payment.source, options_for_payment(payment))
58
+
52
59
  if response.success?
53
60
  payment.source.update_attributes!(:gateway_customer_profile_id => response.params['customer_vault_id'])
54
61
  cc = response.params['braintree_customer'].fetch('credit_cards',[]).first
@@ -118,18 +125,17 @@ module Spree
118
125
  h
119
126
  end
120
127
 
121
- def preferences
122
- preferences = super.slice(:merchant_id,
123
- :merchant_account_id,
124
- :public_key,
125
- :private_key,
126
- :client_side_encryption_key,
127
- :environment)
128
-
129
- # Must be either :production or :sandbox, not their string equivalents.
130
- # Thanks to the Braintree gem.
131
- preferences[:environment] = preferences[:environment].try(:to_sym) || :sandbox
132
- preferences
128
+ def cancel(response_code)
129
+ provider
130
+ transaction = ::Braintree::Transaction.find(response_code)
131
+ # From: https://www.braintreepayments.com/docs/ruby/transactions/refund
132
+ # "A transaction can be refunded if its status is settled or settling.
133
+ # If the transaction has not yet begun settlement, it should be voided instead of refunded.
134
+ if transaction.status == Braintree::Transaction::Status::SubmittedForSettlement
135
+ provider.void(response_code)
136
+ else
137
+ provider.refund(response_code)
138
+ end
133
139
  end
134
140
 
135
141
  protected
@@ -143,5 +149,36 @@ module Spree
143
149
  def adjust_options_for_braintree(creditcard, options)
144
150
  adjust_billing_address(creditcard, options)
145
151
  end
152
+
153
+ def options_for_payment(p)
154
+ o = Hash.new
155
+ o[:email] = p.order.email
156
+
157
+ if p.source.gateway_customer_profile_id.present?
158
+ o[:customer] = p.source.gateway_customer_profile_id
159
+ end
160
+
161
+ if p.order.bill_address
162
+ bill_addr = p.order.bill_address
163
+
164
+ o[:first_name] = bill_addr.firstname
165
+ o[:last_name] = bill_addr.lastname
166
+
167
+ o[:billing_address] = {
168
+ address1: bill_addr.address1,
169
+ address2: bill_addr.address2,
170
+ company: bill_addr.company,
171
+ city: bill_addr.city,
172
+ state: bill_addr.state ? bill_addr.state.name : bill_addr.state_name,
173
+ country_code_alpha3: bill_addr.country.iso3,
174
+ zip: bill_addr.zipcode
175
+ }
176
+ end
177
+
178
+ o[:verify_card] = "true"
179
+
180
+ return o
181
+ end
182
+
146
183
  end
147
184
  end