spree_gateway 2.2.1 → 3.0.0

Sign up to get free protection for your applications and to get access to all the features.
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