solidus_braintree 0.2.1 → 1.0.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.travis.yml +18 -2
- data/CHANGELOG.md +2 -0
- data/Gemfile +6 -1
- data/README.md +7 -0
- data/app/controllers/spree/api/braintree_client_token_controller.rb +2 -0
- data/app/helpers/braintree_view_helpers.rb +20 -0
- data/app/models/concerns/solidus_braintree/add_name_validation_concern.rb +8 -0
- data/app/models/concerns/solidus_braintree/inject_device_data_concern.rb +18 -0
- data/app/models/concerns/solidus_braintree/payment_braintree_nonce_concern.rb +8 -0
- data/app/models/concerns/solidus_braintree/permitted_attributes_concern.rb +11 -0
- data/app/models/concerns/solidus_braintree/skip_require_card_numbers_concern.rb +14 -0
- data/app/models/concerns/solidus_braintree/use_data_field_concern.rb +23 -0
- data/app/models/payment_decorator.rb +1 -0
- data/app/models/solidus/gateway/braintree_gateway.rb +46 -5
- data/app/overrides/spree/checkout/_confirm/braintree_security.html.erb.deface +9 -0
- data/app/views/spree/admin/payments/source_forms/_braintree.html.erb +38 -0
- data/app/views/spree/admin/payments/source_views/_braintree.html.erb +30 -0
- data/app/views/spree/checkout/payment/_braintree.html.erb +55 -0
- data/app/views/spree/checkout/payment/_braintree_initialization.html.erb +12 -0
- data/config/initializers/braintree.rb +1 -0
- data/config/locales/en.yml +4 -0
- data/db/migrate/20150910170527_add_data_to_credit_card.rb +1 -1
- data/db/migrate/20160426221931_add_braintree_device_data_to_order.rb +5 -0
- data/lib/assets/javascripts/spree/backend/braintree/solidus_braintree.js +15 -12
- data/lib/assets/javascripts/spree/frontend/braintree/solidus_braintree.js +144 -0
- data/lib/assets/javascripts/vendor/braintree.js +8 -0
- data/lib/assets/stylesheets/spree/frontend/solidus_braintree.scss +26 -0
- data/lib/generators/solidus_braintree/install/install_generator.rb +9 -0
- data/lib/solidus_braintree/version.rb +1 -1
- data/solidus_braintree.gemspec +9 -6
- metadata +78 -22
- data/Guardfile +0 -70
- data/app/models/concerns/add_name_validation_concern.rb +0 -6
- data/app/models/concerns/payment_braintree_nonce_concern.rb +0 -6
- data/app/models/concerns/permitted_attributes_concern.rb +0 -5
- data/app/models/concerns/skip_require_card_numbers_concern.rb +0 -12
- data/app/models/concerns/use_data_field_concern.rb +0 -21
- data/app/overrides/admin_payment_add_braintree_dropin.rb +0 -10
- data/app/overrides/admin_payment_remove_credit_card_fields.rb +0 -5
- data/lib/assets/javascripts/vendor/braintree-2.14.0.js +0 -7
- data/out.json +0 -0
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 28f5f6d8e3a10296a22d9b5d9bf9f96f7146b5bb
|
4
|
+
data.tar.gz: f4718eedf1bcc717672fc6b97ff5cf9542f48566
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 54b07c41d17e102b686ff466b4361b07bc6b0b051c53953ee229ea163e05b0dc19f8841e9f866c5ac9bc169b8098f816ae7e3e39fd0d6dff12fc773343c7e4fc
|
7
|
+
data.tar.gz: 7875589e8a6034511cbeed423e44f83cd9adb66de4bea5f94fe5b5d45bbd7ced33c7f58f1f4dce6a339e36979a11afd8224f6582f4c0d55adf8768ec0a119ffa
|
data/.travis.yml
CHANGED
@@ -1,4 +1,20 @@
|
|
1
|
+
sudo: false
|
2
|
+
cache: bundler
|
1
3
|
language: ruby
|
4
|
+
addons:
|
5
|
+
postgresql: "9.3"
|
6
|
+
env:
|
7
|
+
matrix:
|
8
|
+
- SOLIDUS_BRANCH=v1.1 DB=postgres
|
9
|
+
- SOLIDUS_BRANCH=v1.2 DB=postgres
|
10
|
+
- SOLIDUS_BRANCH=v1.3 DB=postgres
|
11
|
+
- SOLIDUS_BRANCH=master DB=postgres
|
12
|
+
- SOLIDUS_BRANCH=v1.1 DB=mysql
|
13
|
+
- SOLIDUS_BRANCH=v1.2 DB=mysql
|
14
|
+
- SOLIDUS_BRANCH=v1.3 DB=mysql
|
15
|
+
- SOLIDUS_BRANCH=master DB=mysql
|
16
|
+
script:
|
17
|
+
- bundle exec rake test_app
|
18
|
+
- bundle exec rspec
|
2
19
|
rvm:
|
3
|
-
- 2.1.
|
4
|
-
before_install: gem install bundler -v 1.10.5
|
20
|
+
- 2.1.8
|
data/CHANGELOG.md
CHANGED
data/Gemfile
CHANGED
@@ -1,5 +1,10 @@
|
|
1
1
|
source 'https://rubygems.org'
|
2
2
|
|
3
3
|
# Specify your gem's dependencies in solidus_braintree.gemspec
|
4
|
-
|
4
|
+
branch = ENV.fetch('SOLIDUS_BRANCH', 'master')
|
5
|
+
gem "solidus", github: "solidusio/solidus", branch: branch
|
6
|
+
|
7
|
+
gem 'pg'
|
8
|
+
gem 'mysql2'
|
9
|
+
|
5
10
|
gemspec
|
data/README.md
CHANGED
@@ -19,6 +19,13 @@ And then execute:
|
|
19
19
|
$ bundle
|
20
20
|
$ bundle exec rails g solidus_braintree:install
|
21
21
|
|
22
|
+
|
23
|
+
## Fraud detection
|
24
|
+
|
25
|
+
This gem has support for the advanced fraud tools flow from Braintree, to activate
|
26
|
+
fully the associated Braintree account must enable advanced fraud tools in the
|
27
|
+
Control Panel.
|
28
|
+
|
22
29
|
## Usage
|
23
30
|
|
24
31
|
This gem extends your solidus application by adding a `POST /api/payment_client_token` endpoint to you application to generate Braintree payment client token. This endpoint requires an authentication token in your request header.
|
@@ -0,0 +1,20 @@
|
|
1
|
+
module BraintreeViewHelpers
|
2
|
+
# Returns a link to the Braintree web UI for the given Braintree +payment_id+
|
3
|
+
# (e.g. from Spree::Payment#response_code), or just the +payment_id+ if
|
4
|
+
# Braintree's merchant ID is not configured or +payment_id+ is blank
|
5
|
+
def braintree_transaction_link(payment_id)
|
6
|
+
env = ENV['BRAINTREE_ENV'] == 'production' ? 'www' : 'sandbox'
|
7
|
+
merchant = ENV['BRAINTREE_MERCHANT_ID']
|
8
|
+
|
9
|
+
if payment_id.present? && merchant.present?
|
10
|
+
link_to(
|
11
|
+
payment_id,
|
12
|
+
"https://#{env}.braintreegateway.com/merchants/#{merchant}/transactions/#{payment_id}",
|
13
|
+
title: 'Show payment on Braintree',
|
14
|
+
target: '_blank'
|
15
|
+
)
|
16
|
+
else
|
17
|
+
payment_id
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
module SolidusBraintree
|
2
|
+
module InjectDeviceDataConcern
|
3
|
+
extend ActiveSupport::Concern
|
4
|
+
included do
|
5
|
+
prepend(InstanceMethods)
|
6
|
+
end
|
7
|
+
|
8
|
+
module InstanceMethods
|
9
|
+
def gateway_options
|
10
|
+
options = super
|
11
|
+
|
12
|
+
options[:device_data] = order.braintree_device_data if order.braintree_device_data
|
13
|
+
|
14
|
+
options
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
@@ -0,0 +1,14 @@
|
|
1
|
+
module SolidusBraintree
|
2
|
+
module SkipRequireCardNumbersConcern
|
3
|
+
extend ActiveSupport::Concern
|
4
|
+
included do
|
5
|
+
prepend(InstanceMethods)
|
6
|
+
end
|
7
|
+
|
8
|
+
module InstanceMethods
|
9
|
+
def require_card_numbers?
|
10
|
+
super && !self.payment_method.kind_of?(Solidus::Gateway::BraintreeGateway)
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
module SolidusBraintree
|
2
|
+
module UseDataFieldConcern
|
3
|
+
extend ActiveSupport::Concern
|
4
|
+
included do
|
5
|
+
prepend(InstanceMethods)
|
6
|
+
end
|
7
|
+
|
8
|
+
module InstanceMethods
|
9
|
+
|
10
|
+
def email
|
11
|
+
data["email"]
|
12
|
+
end
|
13
|
+
|
14
|
+
def display_number
|
15
|
+
cc_type == 'paypal' ? email : super
|
16
|
+
end
|
17
|
+
|
18
|
+
def data
|
19
|
+
super.is_a?(String) ? JSON.parse(super) : super
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
@@ -21,6 +21,10 @@ module Solidus
|
|
21
21
|
'Visa' => 'visa',
|
22
22
|
}
|
23
23
|
|
24
|
+
def method_type
|
25
|
+
'braintree'
|
26
|
+
end
|
27
|
+
|
24
28
|
def gateway_options
|
25
29
|
{
|
26
30
|
environment: preferred_environment.to_sym,
|
@@ -49,12 +53,13 @@ module Solidus
|
|
49
53
|
return if source.gateway_customer_profile_id.present? || payment.payment_method_nonce.nil?
|
50
54
|
|
51
55
|
user = payment.order.user
|
56
|
+
email = user ? user.email : payment.order.email
|
52
57
|
address = (payment.source.address || payment.order.bill_address).try(:active_merchant_hash)
|
53
58
|
|
54
59
|
params = {
|
55
60
|
first_name: source.first_name,
|
56
61
|
last_name: source.last_name,
|
57
|
-
email:
|
62
|
+
email: email,
|
58
63
|
credit_card: {
|
59
64
|
cardholder_name: source.name,
|
60
65
|
billing_address: map_address(address),
|
@@ -63,6 +68,7 @@ module Solidus
|
|
63
68
|
verify_card: true,
|
64
69
|
},
|
65
70
|
},
|
71
|
+
device_data: payment.order.braintree_device_data
|
66
72
|
}
|
67
73
|
|
68
74
|
result = braintree_gateway.customer.create(params)
|
@@ -119,9 +125,19 @@ module Solidus
|
|
119
125
|
end
|
120
126
|
|
121
127
|
def void(authorization_code, source = {}, options = {})
|
122
|
-
|
123
|
-
|
124
|
-
|
128
|
+
# Allows voiding payments that are in a checkout state
|
129
|
+
if authorization_code.nil?
|
130
|
+
# Fake response since we don't need to void anything with Braintree
|
131
|
+
ActiveMerchant::Billing::Response.new(
|
132
|
+
true,
|
133
|
+
"OK",
|
134
|
+
{},
|
135
|
+
{}
|
136
|
+
)
|
137
|
+
else
|
138
|
+
result = braintree_gateway.transaction.void(authorization_code)
|
139
|
+
handle_result(result)
|
140
|
+
end
|
125
141
|
end
|
126
142
|
|
127
143
|
def credit(cents, source, authorization_code, options = {})
|
@@ -137,6 +153,18 @@ module Solidus
|
|
137
153
|
].include?(transaction.status)
|
138
154
|
end
|
139
155
|
|
156
|
+
def card_number_placeholder
|
157
|
+
'4141 4141 4141 4141'
|
158
|
+
end
|
159
|
+
|
160
|
+
def expiration_date_placeholder
|
161
|
+
'01/2020'
|
162
|
+
end
|
163
|
+
|
164
|
+
def card_code_placeholder
|
165
|
+
'123'
|
166
|
+
end
|
167
|
+
|
140
168
|
private
|
141
169
|
def message_from_result(result)
|
142
170
|
if result.success?
|
@@ -150,12 +178,25 @@ module Solidus
|
|
150
178
|
end
|
151
179
|
end
|
152
180
|
|
181
|
+
def build_results_hash(result)
|
182
|
+
if result.success?
|
183
|
+
{
|
184
|
+
authorization: result.transaction.id,
|
185
|
+
avs_result: {
|
186
|
+
code: result.transaction.avs_street_address_response_code
|
187
|
+
}
|
188
|
+
}
|
189
|
+
else
|
190
|
+
{}
|
191
|
+
end
|
192
|
+
end
|
193
|
+
|
153
194
|
def handle_result(result)
|
154
195
|
ActiveMerchant::Billing::Response.new(
|
155
196
|
result.success?,
|
156
197
|
message_from_result(result),
|
157
198
|
{},
|
158
|
-
|
199
|
+
build_results_hash(result)
|
159
200
|
)
|
160
201
|
end
|
161
202
|
|
@@ -0,0 +1,9 @@
|
|
1
|
+
<!-- insert_before "erb[loud]:contains('place_order')" -->
|
2
|
+
|
3
|
+
<%
|
4
|
+
# Currently we assume we only have one braintree
|
5
|
+
# payment method. In practice this should be true and it simplifies the code.
|
6
|
+
braintree_payment = @order.unprocessed_payments.find {|p| p.payment_method.class == Solidus::Gateway::BraintreeGateway }
|
7
|
+
if braintree_payment %>
|
8
|
+
<%= render 'spree/checkout/payment/braintree_initialization', payment_method: braintree_payment.payment_method %>
|
9
|
+
<% end %>
|
@@ -0,0 +1,38 @@
|
|
1
|
+
<fieldset data-id='credit-card' class="no-border-bottom">
|
2
|
+
<div class="field" data-hook="previous_cards">
|
3
|
+
<% if previous_cards.any? %>
|
4
|
+
<% previous_cards.each do |card| %>
|
5
|
+
<label><%= radio_button_tag :card, card.id, card == previous_cards.first %> <%= card.display_number %><br /></label>
|
6
|
+
<% end %>
|
7
|
+
<label><%= radio_button_tag :card, 'new', false, { id: "card_new#{payment_method.id}" } %> <%= Spree.t(:use_new_cc) %></label>
|
8
|
+
<% end %>
|
9
|
+
</div>
|
10
|
+
|
11
|
+
<div id="card_form<%= payment_method.id %>" data-hook>
|
12
|
+
<% param_prefix = "payment_source[#{payment_method.id}]" %>
|
13
|
+
|
14
|
+
<div class="clear"></div>
|
15
|
+
|
16
|
+
<div class="alpha four columns">
|
17
|
+
<div data-hook="card_name">
|
18
|
+
<div class="field">
|
19
|
+
<%= label_tag "card_name#{payment_method.id}", Spree::CreditCard.human_attribute_name(:name), class: 'required' %>
|
20
|
+
<%= text_field_tag "#{param_prefix}[name]", '', id: "card_name#{payment_method.id}", class: 'required fullwidth', maxlength: 19 %>
|
21
|
+
</div>
|
22
|
+
</div>
|
23
|
+
</div>
|
24
|
+
|
25
|
+
<div id="braintree-dropin"></div>
|
26
|
+
<input type="hidden" id="payment_method_nonce" name="payment[payment_method_nonce]">
|
27
|
+
|
28
|
+
<div class="clear"></div>
|
29
|
+
|
30
|
+
<%= label_tag "card_address#{payment_method.id}", Spree.t(:billing_address) %>
|
31
|
+
<% address = @order.bill_address || @order.ship_address || Spree::Address.build_default %>
|
32
|
+
<%= fields_for "#{param_prefix}[address_attributes]", address do |f| %>
|
33
|
+
<%= render :partial => 'spree/admin/shared/address_form', :locals => { :f => f, :type => "billing" } %>
|
34
|
+
<% end %>
|
35
|
+
|
36
|
+
<div class="clear"></div>
|
37
|
+
</div>
|
38
|
+
</fieldset>
|
@@ -0,0 +1,30 @@
|
|
1
|
+
<fieldset data-hook="credit_card">
|
2
|
+
<legend align="center"><%= Spree::CreditCard.model_name.human %></legend>
|
3
|
+
|
4
|
+
<div class="row">
|
5
|
+
<div class="alpha six columns">
|
6
|
+
<dl>
|
7
|
+
<dt><%= Spree.t(:identifier) %>:</dt>
|
8
|
+
<dd><%= payment.number %></dd>
|
9
|
+
|
10
|
+
<dt><%= Spree.t(:response_code) %>:</dt>
|
11
|
+
<dd><%= braintree_transaction_link(payment.response_code) %></dd>
|
12
|
+
|
13
|
+
<dt><%= Spree.t(:name_on_card) %>:</dt>
|
14
|
+
<dd><%= payment.source.name %></dd>
|
15
|
+
|
16
|
+
<dt><%= Spree::CreditCard.human_attribute_name(:cc_type) %>:</dt>
|
17
|
+
<dd><%= payment.source.cc_type %></dd>
|
18
|
+
|
19
|
+
<dt><%= Spree::CreditCard.human_attribute_name(:number) %>:</dt>
|
20
|
+
<dd><%= payment.source.display_number %></dd>
|
21
|
+
|
22
|
+
<dt><%= Spree::CreditCard.human_attribute_name(:expiration) %>:</dt>
|
23
|
+
<dd><%= payment.source.month %>/<%= payment.source.year %></dd>
|
24
|
+
</dl>
|
25
|
+
<% if payment.source.address %>
|
26
|
+
<%= render partial: 'spree/admin/shared/address', locals: {address: payment.source.address} %>
|
27
|
+
<% end %>
|
28
|
+
</div>
|
29
|
+
</div>
|
30
|
+
</fieldset>
|
@@ -0,0 +1,55 @@
|
|
1
|
+
<div class="braintree-payment">
|
2
|
+
<%= render 'spree/checkout/payment/braintree_initialization', payment_method: payment_method %>
|
3
|
+
|
4
|
+
<div class="braintree-paypal-input">
|
5
|
+
<div class="braintree-paypal-header">
|
6
|
+
<%= t('solidus_braintree.paypal_header_html') %>
|
7
|
+
</div>
|
8
|
+
<div id="#braintree_paypal_container"></div>
|
9
|
+
</div>
|
10
|
+
|
11
|
+
<div class="braintree-cc-input">
|
12
|
+
<div class="braintree-cc-header">
|
13
|
+
<%= t('solidus_braintree.creditcard_header_html') %>
|
14
|
+
<%= image_tag 'credit_cards/credit_card.gif', :id => 'credit-card-image' %>
|
15
|
+
</div>
|
16
|
+
<% param_prefix = "payment_source[#{payment_method.id}]" %>
|
17
|
+
|
18
|
+
<p class="field">
|
19
|
+
<%= label_tag "name_on_card_#{payment_method.id}", Spree.t(:name_on_card) %><span class="required">*</span><br />
|
20
|
+
<%= text_field_tag "#{param_prefix}[name]", "#{@order.billing_firstname} #{@order.billing_lastname}", { id: "name_on_card_#{payment_method.id}", :autocomplete => "cc-name" } %>
|
21
|
+
</p>
|
22
|
+
|
23
|
+
<p class="field" data-hook="card_number">
|
24
|
+
<%= label_tag "braintree_card_number", Spree.t(:card_number) %><span class="required">*</span><br />
|
25
|
+
<label for="braintree_card_number" id="braintree_card_number" class="braintree-hosted-field"></label>
|
26
|
+
|
27
|
+
<span id="card_type" style="display:none;">
|
28
|
+
( <span id="looks_like" ><%= Spree.t(:card_type_is) %> <span id="type"></span></span>
|
29
|
+
<span id="unrecognized"><%= Spree.t(:unrecognized_card_type) %></span>
|
30
|
+
)
|
31
|
+
</span>
|
32
|
+
</p>
|
33
|
+
|
34
|
+
<p class="field" data-hook="card_expiration">
|
35
|
+
<%= label_tag "braintree_card_expiry", Spree.t(:expiration) %><span class="required">*</span><br />
|
36
|
+
<label for="braintree_card_expiry" id="braintree_card_expiry" class="braintree-hosted-field"></label>
|
37
|
+
</p>
|
38
|
+
|
39
|
+
<p class="field" data-hook="card_code">
|
40
|
+
<%= label_tag "braintree_card_code", Spree.t(:card_code) %><span class="required">*</span><br />
|
41
|
+
|
42
|
+
<label for="braintree_card_code" id="braintree_card_code" class="braintree-hosted-field card-code"></label>
|
43
|
+
<%= link_to "(#{Spree.t(:what_is_this)})", spree.cvv_path, :target => '_blank', "data-hook" => "cvv_link", :id => "cvv_link" %>
|
44
|
+
</p>
|
45
|
+
</div>
|
46
|
+
|
47
|
+
<% if @order.bill_address %>
|
48
|
+
<%= fields_for "#{param_prefix}[address_attributes]", @order.bill_address do |f| %>
|
49
|
+
<%= render :partial => 'spree/address/form_hidden', :locals => { :form => f } %>
|
50
|
+
<% end %>
|
51
|
+
<% end %>
|
52
|
+
|
53
|
+
<%= hidden_field_tag "#{param_prefix}[cc_type]", '', :id => "cc_type", :class => 'ccType' %>
|
54
|
+
<%= hidden_field_tag "order[payments_attributes][][payment_method_nonce]", '', :id => "payment_method_nonce" %>
|
55
|
+
</div>
|
@@ -0,0 +1,12 @@
|
|
1
|
+
<% content_for :head do %>
|
2
|
+
<%= javascript_tag do %>
|
3
|
+
braintree.environment = "<%= payment_method.preferred_environment %>"
|
4
|
+
braintree.placeholders = {
|
5
|
+
"number": "<%= payment_method.card_number_placeholder %>",
|
6
|
+
"expirationDate": "<%= payment_method.expiration_date_placeholder %>",
|
7
|
+
"cvv": "<%= payment_method.card_code_placeholder %>"
|
8
|
+
}
|
9
|
+
<% end %>
|
10
|
+
<% end %>
|
11
|
+
|
12
|
+
<%= hidden_field_tag "order[braintree_device_data]", '', :id => "device_data" %>
|