solidus_paypal_braintree 0.2.0 → 1.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (168) hide show
  1. checksums.yaml +5 -5
  2. data/.circleci/config.yml +40 -0
  3. data/.gem_release.yml +5 -0
  4. data/.github/stale.yml +17 -0
  5. data/.gitignore +18 -0
  6. data/.rspec +2 -0
  7. data/.rubocop.yml +76 -0
  8. data/CHANGELOG.md +258 -0
  9. data/Gemfile +41 -0
  10. data/LICENSE +2 -2
  11. data/README.md +208 -48
  12. data/Rakefile +4 -28
  13. data/app/assets/config/solidus_paypal_braintree_manifest.js +1 -0
  14. data/app/assets/images/solidus_paypal_braintree/venmo/venmo_active_blue_button_280x48.svg +19 -0
  15. data/app/assets/images/solidus_paypal_braintree/venmo/venmo_active_blue_button_320x48.svg +19 -0
  16. data/app/assets/images/solidus_paypal_braintree/venmo/venmo_active_blue_button_375x48.svg +19 -0
  17. data/app/assets/images/solidus_paypal_braintree/venmo/venmo_active_white_button_280x48.svg +19 -0
  18. data/app/assets/images/solidus_paypal_braintree/venmo/venmo_active_white_button_320x48.svg +19 -0
  19. data/app/assets/images/solidus_paypal_braintree/venmo/venmo_active_white_button_375x48.svg +19 -0
  20. data/app/assets/images/solidus_paypal_braintree/venmo/venmo_blue_acceptance_mark.svg +15 -0
  21. data/app/assets/images/solidus_paypal_braintree/venmo/venmo_blue_button_280x48.svg +19 -0
  22. data/app/assets/images/solidus_paypal_braintree/venmo/venmo_blue_button_320x48.svg +19 -0
  23. data/app/assets/images/solidus_paypal_braintree/venmo/venmo_blue_button_375x48.svg +19 -0
  24. data/app/assets/images/solidus_paypal_braintree/venmo/venmo_blue_logo.svg +18 -0
  25. data/app/assets/images/solidus_paypal_braintree/venmo/venmo_white_acceptance_mark.svg +20 -0
  26. data/app/assets/images/solidus_paypal_braintree/venmo/venmo_white_button_280x48.svg +19 -0
  27. data/app/assets/images/solidus_paypal_braintree/venmo/venmo_white_button_320x48.svg +19 -0
  28. data/app/assets/images/solidus_paypal_braintree/venmo/venmo_white_button_375x48.svg +19 -0
  29. data/app/assets/images/solidus_paypal_braintree/venmo/venmo_white_logo.svg +18 -0
  30. data/app/assets/javascripts/solidus_paypal_braintree/checkout.js +32 -3
  31. data/app/assets/javascripts/solidus_paypal_braintree/client.js +58 -5
  32. data/app/assets/javascripts/solidus_paypal_braintree/constants.js +36 -5
  33. data/app/assets/javascripts/solidus_paypal_braintree/frontend.js +2 -0
  34. data/app/assets/javascripts/solidus_paypal_braintree/hosted_form.js +15 -5
  35. data/app/assets/javascripts/solidus_paypal_braintree/paypal_button.js +90 -26
  36. data/app/assets/javascripts/solidus_paypal_braintree/paypal_messaging.js +22 -0
  37. data/app/assets/javascripts/solidus_paypal_braintree/venmo_button.js +86 -0
  38. data/app/assets/javascripts/spree/backend/solidus_paypal_braintree.js +2 -2
  39. data/app/assets/javascripts/spree/frontend/paypal_button.js +15 -13
  40. data/app/assets/stylesheets/spree/frontend/solidus_paypal_braintree.css +12 -0
  41. data/app/decorators/controllers/solidus_paypal_braintree/admin_payments_controller_decorator.rb +11 -0
  42. data/app/decorators/controllers/solidus_paypal_braintree/checkout_controller_decorator.rb +11 -0
  43. data/app/decorators/controllers/solidus_paypal_braintree/client_tokens_controller.rb +41 -0
  44. data/app/decorators/controllers/solidus_paypal_braintree/orders_controller_decorator.rb +11 -0
  45. data/app/decorators/models/solidus_paypal_braintree/spree/store_decorator.rb +20 -0
  46. data/app/decorators/models/solidus_paypal_braintree/spree/user_decorator.rb +13 -0
  47. data/app/helpers/solidus_paypal_braintree/braintree_admin_helper.rb +23 -0
  48. data/app/helpers/solidus_paypal_braintree/braintree_checkout_helper.rb +60 -0
  49. data/app/models/application_record.rb +2 -0
  50. data/app/models/solidus_paypal_braintree/address.rb +64 -0
  51. data/app/models/solidus_paypal_braintree/avs_result.rb +69 -0
  52. data/app/models/solidus_paypal_braintree/configuration.rb +39 -3
  53. data/app/models/solidus_paypal_braintree/customer.rb +7 -3
  54. data/app/models/solidus_paypal_braintree/gateway.rb +150 -43
  55. data/app/models/solidus_paypal_braintree/response.rb +49 -21
  56. data/app/models/solidus_paypal_braintree/source.rb +70 -10
  57. data/app/models/solidus_paypal_braintree/transaction.rb +3 -2
  58. data/app/models/solidus_paypal_braintree/transaction_address.rb +36 -15
  59. data/app/models/solidus_paypal_braintree/transaction_import.rb +18 -12
  60. data/app/overrides/spree/payments/payment/add_paypal_funding_source_to_payment.rb +9 -0
  61. data/app/views/spree/api/payments/source_views/_paypal_braintree.json.jbuilder +3 -0
  62. data/app/views/spree/checkout/existing_payment/_paypal_braintree.html.erb +10 -0
  63. data/app/views/spree/shared/_apple_pay_button.html.erb +27 -0
  64. data/app/views/spree/shared/_braintree_errors.html.erb +16 -0
  65. data/app/views/spree/shared/_braintree_hosted_fields.html.erb +25 -8
  66. data/app/views/spree/shared/_paypal_braintree_head_scripts.html.erb +26 -0
  67. data/app/views/spree/shared/_paypal_cart_button.html.erb +38 -0
  68. data/app/views/spree/shared/_paypal_messaging.html.erb +13 -0
  69. data/app/views/spree/shared/_venmo_button.html.erb +33 -0
  70. data/bin/console +17 -0
  71. data/bin/rails +15 -0
  72. data/bin/setup +8 -0
  73. data/config/locales/en.yml +66 -0
  74. data/config/locales/it.yml +56 -0
  75. data/config/routes.rb +2 -0
  76. data/db/migrate/20160906201711_create_solidus_paypal_braintree_customers.rb +3 -1
  77. data/db/migrate/20161125172005_add_braintree_configuration_to_stores.rb +5 -7
  78. data/db/migrate/20170505193712_add_null_constraint_to_sources.rb +3 -1
  79. data/db/migrate/20190705115327_add_paypal_button_preferences_to_braintree_configurations.rb +5 -0
  80. data/db/migrate/20190911141712_add_3d_secure_to_braintree_configuration.rb +5 -0
  81. data/db/migrate/20211222170950_add_paypal_funding_source_to_solidus_paypal_braintree_sources.rb +5 -0
  82. data/db/migrate/20220104150301_add_venmo_to_braintree_configuration.rb +5 -0
  83. data/lib/controllers/backend/solidus_paypal_braintree/configurations_controller.rb +23 -5
  84. data/lib/controllers/frontend/solidus_paypal_braintree/checkouts_controller.rb +25 -21
  85. data/lib/controllers/frontend/solidus_paypal_braintree/transactions_controller.rb +56 -50
  86. data/lib/generators/solidus_paypal_braintree/install/install_generator.rb +7 -6
  87. data/lib/solidus_paypal_braintree/country_mapper.rb +4 -2
  88. data/lib/solidus_paypal_braintree/engine.rb +34 -22
  89. data/lib/solidus_paypal_braintree/factories.rb +41 -6
  90. data/lib/solidus_paypal_braintree/request_protection.rb +21 -0
  91. data/lib/solidus_paypal_braintree/version.rb +3 -1
  92. data/lib/solidus_paypal_braintree.rb +5 -1
  93. data/lib/views/backend/solidus_paypal_braintree/configurations/list.html.erb +38 -5
  94. data/lib/views/backend/spree/admin/payments/source_forms/_paypal_braintree.html.erb +2 -2
  95. data/lib/views/backend/spree/admin/payments/source_views/_paypal_braintree.html.erb +7 -2
  96. data/lib/views/backend/spree/admin/shared/preference_fields/_preference_select.html.erb +13 -0
  97. data/lib/views/backend_v1.2/spree/admin/payments/source_forms/_paypal_braintree.html.erb +2 -2
  98. data/lib/views/backend_v2.4/spree/admin/shared/preference_fields/_hash.html.erb +12 -0
  99. data/lib/views/frontend/solidus_paypal_braintree/payments/_payment.html.erb +12 -0
  100. data/lib/views/frontend/spree/checkout/payment/_paypal_braintree.html.erb +10 -77
  101. data/lib/views/frontend/spree/shared/_paypal_checkout_button.html.erb +32 -0
  102. data/solidus_paypal_braintree.gemspec +43 -0
  103. data/spec/controllers/solidus_paypal_braintree/checkouts_controller_spec.rb +99 -0
  104. data/spec/controllers/solidus_paypal_braintree/client_tokens_controller_spec.rb +55 -0
  105. data/spec/controllers/solidus_paypal_braintree/configurations_controller_spec.rb +73 -0
  106. data/spec/controllers/solidus_paypal_braintree/transactions_controller_spec.rb +183 -0
  107. data/spec/features/backend/configuration_spec.rb +23 -0
  108. data/spec/features/backend/new_payment_spec.rb +137 -0
  109. data/spec/features/frontend/braintree_credit_card_checkout_spec.rb +191 -0
  110. data/spec/features/frontend/paypal_checkout_spec.rb +166 -0
  111. data/spec/features/frontend/venmo_checkout_spec.rb +189 -0
  112. data/spec/fixtures/cassettes/admin/invalid_credit_card.yml +63 -0
  113. data/spec/fixtures/cassettes/admin/resubmit_credit_card.yml +352 -0
  114. data/spec/fixtures/cassettes/admin/valid_credit_card.yml +412 -0
  115. data/spec/fixtures/cassettes/braintree/create_profile.yml +71 -0
  116. data/spec/fixtures/cassettes/braintree/generate_token.yml +63 -0
  117. data/spec/fixtures/cassettes/braintree/token.yml +63 -0
  118. data/spec/fixtures/cassettes/checkout/invalid_credit_card.yml +63 -0
  119. data/spec/fixtures/cassettes/checkout/resubmit_credit_card.yml +216 -0
  120. data/spec/fixtures/cassettes/checkout/update.yml +71 -0
  121. data/spec/fixtures/cassettes/checkout/valid_credit_card.yml +156 -0
  122. data/spec/fixtures/cassettes/checkout/valid_venmo_transaction.yml +599 -0
  123. data/spec/fixtures/cassettes/gateway/authorize/credit_card/address.yml +86 -0
  124. data/spec/fixtures/cassettes/gateway/authorize/merchant_account/EUR.yml +154 -0
  125. data/spec/fixtures/cassettes/gateway/authorize/paypal/EUR.yml +90 -0
  126. data/spec/fixtures/cassettes/gateway/authorize/paypal/address.yml +90 -0
  127. data/spec/fixtures/cassettes/gateway/authorize.yml +86 -0
  128. data/spec/fixtures/cassettes/gateway/authorized_transaction.yml +73 -0
  129. data/spec/fixtures/cassettes/gateway/cancel/missing.yml +63 -0
  130. data/spec/fixtures/cassettes/gateway/cancel/refunds.yml +272 -0
  131. data/spec/fixtures/cassettes/gateway/cancel/void.yml +201 -0
  132. data/spec/fixtures/cassettes/gateway/capture.yml +141 -0
  133. data/spec/fixtures/cassettes/gateway/complete.yml +157 -0
  134. data/spec/fixtures/cassettes/gateway/credit.yml +208 -0
  135. data/spec/fixtures/cassettes/gateway/purchase.yml +87 -0
  136. data/spec/fixtures/cassettes/gateway/settled_transaction.yml +140 -0
  137. data/spec/fixtures/cassettes/gateway/void.yml +137 -0
  138. data/spec/fixtures/cassettes/source/card_type.yml +267 -0
  139. data/spec/fixtures/cassettes/source/last4.yml +267 -0
  140. data/spec/fixtures/cassettes/transaction/import/valid/capture.yml +224 -0
  141. data/spec/fixtures/cassettes/transaction/import/valid.yml +71 -0
  142. data/spec/fixtures/views/spree/orders/edit.html.erb +50 -0
  143. data/spec/helpers/solidus_paypal_braintree/braintree_admin_helper_spec.rb +17 -0
  144. data/spec/helpers/solidus_paypal_braintree/braintree_checkout_helper_spec.rb +70 -0
  145. data/spec/models/solidus_paypal_braintree/address_spec.rb +71 -0
  146. data/spec/models/solidus_paypal_braintree/avs_result_spec.rb +317 -0
  147. data/spec/models/solidus_paypal_braintree/gateway_spec.rb +692 -0
  148. data/spec/models/solidus_paypal_braintree/response_spec.rb +280 -0
  149. data/spec/models/solidus_paypal_braintree/source_spec.rb +499 -0
  150. data/spec/models/solidus_paypal_braintree/transaction_address_spec.rb +235 -0
  151. data/spec/models/solidus_paypal_braintree/transaction_import_spec.rb +300 -0
  152. data/spec/models/solidus_paypal_braintree/transaction_spec.rb +85 -0
  153. data/spec/models/spree/store_spec.rb +14 -0
  154. data/spec/requests/spree/api/orders_controller_spec.rb +36 -0
  155. data/spec/spec_helper.rb +29 -0
  156. data/spec/support/capybara.rb +7 -0
  157. data/spec/support/factories.rb +2 -0
  158. data/spec/support/gateway_helpers.rb +29 -0
  159. data/spec/support/order_ready_for_payment.rb +37 -0
  160. data/spec/support/vcr.rb +42 -0
  161. data/spec/support/views.rb +1 -0
  162. metadata +226 -166
  163. data/app/controllers/solidus_paypal_braintree/client_tokens_controller.rb +0 -21
  164. data/app/helpers/braintree_admin_helper.rb +0 -18
  165. data/app/models/spree/store_decorator.rb +0 -11
  166. data/app/overrides/admin_navigation_menu.rb +0 -6
  167. data/config/initializers/braintree.rb +0 -1
  168. data/lib/views/backend/solidus_paypal_braintree/configurations/_admin_tab.html.erb +0 -3
@@ -15,7 +15,9 @@ class AddNullConstraintToSources < SolidusSupport::Migration[4.2]
15
15
 
16
16
  Spree::Payment.joins(join_sources).find_each do |payment|
17
17
  Rails.logger.info("Updating source #{payment.source_id} with payment method id #{payment.payment_method_id}")
18
- SolidusPaypalBraintree::Source.where(id: payment.source_id).update_all(payment_method_id: payment.payment_method_id)
18
+ SolidusPaypalBraintree::Source.where(id: payment.source_id).update_all(
19
+ payment_method_id: payment.payment_method_id
20
+ )
19
21
  end
20
22
 
21
23
  # We use a foreign key constraint on the model,
@@ -0,0 +1,5 @@
1
+ class AddPaypalButtonPreferencesToBraintreeConfigurations < ActiveRecord::Migration[5.1]
2
+ def change
3
+ add_column :solidus_paypal_braintree_configurations, :preferences, :text
4
+ end
5
+ end
@@ -0,0 +1,5 @@
1
+ class Add3dSecureToBraintreeConfiguration < SolidusSupport::Migration[4.2]
2
+ def change
3
+ add_column :solidus_paypal_braintree_configurations, :three_d_secure, :boolean, null: false, default: false
4
+ end
5
+ end
@@ -0,0 +1,5 @@
1
+ class AddPaypalFundingSourceToSolidusPaypalBraintreeSources < ActiveRecord::Migration[5.0]
2
+ def change
3
+ add_column :solidus_paypal_braintree_sources, :paypal_funding_source, :integer
4
+ end
5
+ end
@@ -0,0 +1,5 @@
1
+ class AddVenmoToBraintreeConfiguration < ActiveRecord::Migration[5.0]
2
+ def change
3
+ add_column :solidus_paypal_braintree_configurations, :venmo, :boolean, null: false, default: false
4
+ end
5
+ end
@@ -1,18 +1,21 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module SolidusPaypalBraintree
2
- class ConfigurationsController < Spree::Admin::BaseController
3
- helper Spree::Core::Engine.routes.url_helpers
4
+ class ConfigurationsController < ::Spree::Admin::BaseController
5
+ helper ::Spree::Core::Engine.routes.url_helpers
4
6
 
5
7
  def list
6
8
  authorize! :list, SolidusPaypalBraintree::Configuration
7
9
 
8
- @configurations = Spree::Store.all.map(&:braintree_configuration)
10
+ @configurations = ::Spree::Store.all.map { |s| s.braintree_configuration || s.create_braintree_configuration }
9
11
  end
10
12
 
11
13
  def update
12
14
  authorize! :update, SolidusPaypalBraintree::Configuration
13
15
 
14
16
  params = configurations_params[:configuration_fields]
15
- if SolidusPaypalBraintree::Configuration.update(params.keys, params.values)
17
+ results = SolidusPaypalBraintree::Configuration.update(params.keys, params.values)
18
+ if results.all?(&:valid?)
16
19
  flash[:success] = t('update_success', scope: 'solidus_paypal_braintree.configurations')
17
20
  else
18
21
  flash[:error] = t('update_error', scope: 'solidus_paypal_braintree.configurations')
@@ -24,7 +27,22 @@ module SolidusPaypalBraintree
24
27
 
25
28
  def configurations_params
26
29
  params.require(:configurations).
27
- permit(configuration_fields: [:paypal, :apple_pay, :credit_card])
30
+ permit(configuration_fields: [
31
+ :paypal,
32
+ :apple_pay,
33
+ :venmo,
34
+ :credit_card,
35
+ :three_d_secure,
36
+ :preferred_paypal_button_locale,
37
+ :preferred_paypal_button_color,
38
+ :preferred_paypal_button_shape,
39
+ :preferred_paypal_button_label,
40
+ :preferred_paypal_button_tagline,
41
+ :preferred_paypal_button_layout,
42
+ :preferred_paypal_button_messaging,
43
+ :preferred_venmo_button_color,
44
+ :preferred_venmo_button_width
45
+ ])
28
46
  end
29
47
  end
30
48
  end
@@ -1,27 +1,31 @@
1
- class SolidusPaypalBraintree::CheckoutsController < Spree::CheckoutController
2
- PERMITTED_PAYMENT_PARAMS = [
3
- :payment_method_id,
4
- source_attributes: [
5
- :nonce,
6
- :payment_type
7
- ]
8
- ].freeze
1
+ # frozen_string_literal: true
9
2
 
10
- def update
11
- @payment = Spree::PaymentCreate.new(@order, payment_params).build
3
+ module SolidusPaypalBraintree
4
+ class CheckoutsController < ::Spree::CheckoutController
5
+ PERMITTED_PAYMENT_PARAMS = [
6
+ :payment_method_id,
7
+ { source_attributes: [
8
+ :nonce,
9
+ :payment_type
10
+ ] }
11
+ ].freeze
12
12
 
13
- if @payment.save
14
- render plain: "ok"
15
- else
16
- render plain: "not-ok"
13
+ def update
14
+ @payment = ::Spree::PaymentCreate.new(@order, payment_params).build
15
+
16
+ if @payment.save
17
+ render plain: "ok"
18
+ else
19
+ render plain: "not-ok"
20
+ end
17
21
  end
18
- end
19
22
 
20
- def payment_params
21
- params.
22
- require(:order).
23
- require(:payments_attributes).
24
- first.
25
- permit(PERMITTED_PAYMENT_PARAMS)
23
+ def payment_params
24
+ params.
25
+ require(:order).
26
+ require(:payments_attributes).
27
+ first.
28
+ permit(PERMITTED_PAYMENT_PARAMS)
29
+ end
26
30
  end
27
31
  end
@@ -1,61 +1,67 @@
1
- class SolidusPaypalBraintree::TransactionsController < Spree::StoreController
2
- class InvalidImportError < StandardError; end
3
-
4
- PERMITTED_BRAINTREE_TRANSACTION_PARAMS = [
5
- :nonce,
6
- :payment_type,
7
- :phone,
8
- :email,
9
- address_attributes: [
10
- :country_code, :country_name, :last_name, :first_name,
11
- :city, :zip, :state_code, :address_line_1, :address_line_2
12
- ]
13
- ]
14
-
15
- def create
16
- transaction = SolidusPaypalBraintree::Transaction.new transaction_params
17
- import = SolidusPaypalBraintree::TransactionImport.new(current_order, transaction)
18
-
19
- respond_to do |format|
20
- if import.valid?
21
- import.import!(import_state)
22
-
23
- format.html { redirect_to redirect_url(import) }
24
- format.json { render json: { redirectUrl: redirect_url(import) } }
25
- else
26
- status = 422
27
- format.html { import_error(import) }
28
- format.json { render json: { errors: import.errors, status: status }, status: status }
1
+ # frozen_string_literal: true
2
+
3
+ module SolidusPaypalBraintree
4
+ class TransactionsController < ::Spree::StoreController
5
+ class InvalidImportError < StandardError; end
6
+
7
+ PERMITTED_BRAINTREE_TRANSACTION_PARAMS = [
8
+ :nonce,
9
+ :payment_type,
10
+ :paypal_funding_source,
11
+ :phone,
12
+ :email,
13
+ { address_attributes: [
14
+ :country_code, :country_name, :name, :city, :zip, :state_code,
15
+ :address_line_1, :address_line_2, :first_name, :last_name
16
+ ] }
17
+ ].freeze
18
+
19
+ def create
20
+ transaction = SolidusPaypalBraintree::Transaction.new transaction_params
21
+ import = SolidusPaypalBraintree::TransactionImport.new(current_order, transaction)
22
+ restart_checkout = params[:options] && params[:options][:restart_checkout] == "true"
23
+
24
+ respond_to do |format|
25
+ if import.valid?
26
+ import.import!(import_state, restart_checkout: restart_checkout)
27
+
28
+ format.html { redirect_to redirect_url(import) }
29
+ format.json { render json: { redirectUrl: redirect_url(import) } }
30
+ else
31
+ status = 422
32
+ format.html { import_error(import) }
33
+ format.json { render json: { errors: import.errors, status: status }, status: status }
34
+ end
29
35
  end
30
36
  end
31
- end
32
37
 
33
- private
38
+ private
34
39
 
35
- def import_state
36
- params[:state] || 'confirm'
37
- end
40
+ def import_state
41
+ params[:state] || 'confirm'
42
+ end
38
43
 
39
- def import_error(import)
40
- raise InvalidImportError,
41
- "Import invalid: #{import.errors.full_messages.join(', ')}"
42
- end
44
+ def import_error(import)
45
+ raise InvalidImportError,
46
+ "Import invalid: #{import.errors.full_messages.join(', ')}"
47
+ end
43
48
 
44
- def redirect_url(import)
45
- if import.order.complete?
46
- spree.order_url(import.order)
47
- else
48
- spree.checkout_state_url(import.order.state)
49
+ def redirect_url(import)
50
+ if import.order.complete?
51
+ spree.order_url(import.order)
52
+ else
53
+ spree.checkout_state_url(import.order.state)
54
+ end
49
55
  end
50
- end
51
56
 
52
- def transaction_params
53
- params.require(:transaction)
54
- .permit(PERMITTED_BRAINTREE_TRANSACTION_PARAMS)
55
- .merge({ payment_method: payment_method })
56
- end
57
+ def transaction_params
58
+ params.require(:transaction)
59
+ .permit(PERMITTED_BRAINTREE_TRANSACTION_PARAMS)
60
+ .merge({ payment_method: payment_method })
61
+ end
57
62
 
58
- def payment_method
59
- SolidusPaypalBraintree::Gateway.find(params[:payment_method_id])
63
+ def payment_method
64
+ SolidusPaypalBraintree::Gateway.find(params[:payment_method_id])
65
+ end
60
66
  end
61
67
  end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module SolidusPaypalBraintree
2
4
  module Generators
3
5
  class InstallGenerator < Rails::Generators::Base
@@ -5,13 +7,12 @@ module SolidusPaypalBraintree
5
7
 
6
8
  def add_javascripts
7
9
  append_file 'vendor/assets/javascripts/spree/frontend/all.js', "//= require solidus_paypal_braintree/frontend\n"
8
- append_file 'vendor/assets/javascripts/spree/frontend/all.js', "//= require spree/frontend/paypal_button\n"
9
- append_file 'vendor/assets/javascripts/spree/backend/all.js', "//= require spree/backend/solidus_paypal_braintree\n"
10
+ append_file 'vendor/assets/javascripts/spree/backend/all.js', "//= require spree/backend/solidus_paypal_braintree\n" # rubocop:disable Layout/LineLength
10
11
  end
11
12
 
12
13
  def add_stylesheets
13
- inject_into_file 'vendor/assets/stylesheets/spree/frontend/all.css', " *= require spree/frontend/solidus_paypal_braintree\n", before: /\*\//, verbose: true
14
- inject_into_file 'vendor/assets/stylesheets/spree/backend/all.css', " *= require spree/backend/solidus_paypal_braintree\n", before: /\*\//, verbose: true
14
+ inject_into_file 'vendor/assets/stylesheets/spree/frontend/all.css', " *= require spree/frontend/solidus_paypal_braintree\n", before: %r{\*/}, verbose: true # rubocop:disable Layout/LineLength
15
+ inject_into_file 'vendor/assets/stylesheets/spree/backend/all.css', " *= require spree/backend/solidus_paypal_braintree\n", before: %r{\*/}, verbose: true # rubocop:disable Layout/LineLength
15
16
  end
16
17
 
17
18
  def add_migrations
@@ -25,11 +26,11 @@ module SolidusPaypalBraintree
25
26
  end
26
27
 
27
28
  def run_migrations
28
- run_migrations = options[:auto_run_migrations] || ['', 'y', 'Y'].include?(ask('Would you like to run the migrations now? [Y/n]'))
29
+ run_migrations = options[:auto_run_migrations] || ['', 'y', 'Y'].include?(ask('Would you like to run the migrations now? [Y/n]')) # rubocop:disable Layout/LineLength
29
30
  if run_migrations
30
31
  run 'bundle exec rake db:migrate'
31
32
  else
32
- puts 'Skipping rake db:migrate, don\'t forget to run it!'
33
+ say_status :skipping, 'rake db:migrate, don\'t forget to run it!'
33
34
  end
34
35
  end
35
36
  end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module SolidusPaypalBraintree
2
4
  module CountryMapper
3
5
  extend ActiveSupport::Concern
@@ -12,12 +14,12 @@ module SolidusPaypalBraintree
12
14
  "usa",
13
15
  "u.s.",
14
16
  "us"
15
- ]
17
+ ].freeze
16
18
 
17
19
  CANADA_VARIANTS = [
18
20
  "canada",
19
21
  "ca"
20
- ]
22
+ ].freeze
21
23
 
22
24
  # Generates a hash mapping each variant of the country name to the same ISO
23
25
  # ie: { "usa" => "US", "united states" => "US", "canada" => "CA", ... }
@@ -1,8 +1,18 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'solidus_support'
4
+
1
5
  module SolidusPaypalBraintree
2
6
  class Engine < Rails::Engine
7
+ include SolidusSupport::EngineExtensions
8
+
3
9
  isolate_namespace SolidusPaypalBraintree
4
10
  engine_name 'solidus_paypal_braintree'
5
11
 
12
+ ActiveSupport::Inflector.inflections do |inflect|
13
+ inflect.acronym 'AVS'
14
+ end
15
+
6
16
  # use rspec for tests
7
17
  config.generators do |g|
8
18
  g.test_framework :rspec
@@ -10,45 +20,47 @@ module SolidusPaypalBraintree
10
20
 
11
21
  initializer "register_solidus_paypal_braintree_gateway", after: "spree.register.payment_methods" do |app|
12
22
  app.config.spree.payment_methods << SolidusPaypalBraintree::Gateway
13
- Spree::PermittedAttributes.source_attributes.concat [:nonce, :payment_type]
23
+ SolidusPaypalBraintree::Gateway.allowed_admin_form_preference_types << :preference_select
24
+ Spree::PermittedAttributes.source_attributes.concat [:nonce, :payment_type, :paypal_funding_source]
14
25
  end
15
26
 
16
- def self.activate
17
- Dir.glob(File.join(File.dirname(__FILE__), '../../app/**/*_decorator*.rb')) do |c|
18
- Rails.configuration.cache_classes ? require(c) : load(c)
19
- end
20
- end
21
-
22
- config.to_prepare(&method(:activate).to_proc)
23
-
24
- def self.frontend_available?
25
- defined?(Spree::Frontend::Engine) == "constant"
26
- end
27
-
28
- def self.backend_available?
29
- defined?(Spree::Backend::Engine) == "constant"
30
- end
31
-
32
- if frontend_available?
27
+ if SolidusSupport.frontend_available?
33
28
  config.assets.precompile += [
34
29
  'solidus_paypal_braintree/checkout.js',
35
30
  'solidus_paypal_braintree/frontend.js',
36
- 'spree/frontend/paypal_button.js',
37
- 'spree/frontend/apple_pay_button.js'
31
+ 'spree/frontend/apple_pay_button.js',
32
+ 'solidus_paypal_braintree_manifest.js'
38
33
  ]
39
34
  paths["app/controllers"] << "lib/controllers/frontend"
40
35
  paths["app/views"] << "lib/views/frontend"
41
36
  end
42
37
 
43
- if backend_available?
38
+ if SolidusSupport.backend_available?
44
39
  config.assets.precompile += ["spree/backend/solidus_paypal_braintree.js"]
45
40
  paths["app/controllers"] << "lib/controllers/backend"
46
41
 
47
42
  # We support Solidus v1.2, which requires some different markup in the
48
43
  # source form partial. This will take precedence over lib/views/backend.
49
- paths["app/views"] << "lib/views/backend_v1.2" if Gem::Version.new(Spree.solidus_version) < Gem::Version.new('1.3')
44
+ paths["app/views"] << "lib/views/backend_v1.2" if Spree.solidus_gem_version < Gem::Version.new('1.3')
45
+
46
+ # Solidus v2.4 introduced preference field partials but does not ship a hash field type.
47
+ # This is solved in Solidus v2.5.
48
+ if Spree.solidus_gem_version <= Gem::Version.new('2.5.0')
49
+ paths["app/views"] << "lib/views/backend_v2.4"
50
+ end
50
51
 
51
52
  paths["app/views"] << "lib/views/backend"
53
+
54
+ initializer "solidus_paypal_braintree_admin_menu_item", after: "register_solidus_paypal_braintree_gateway" do
55
+ Spree::Backend::Config.configure do |config|
56
+ config.menu_items << config.class::MenuItem.new(
57
+ [:braintree],
58
+ 'cc-paypal',
59
+ url: '/solidus_paypal_braintree/configurations/list',
60
+ condition: -> { can?(:list, SolidusPaypalBraintree::Configuration) }
61
+ )
62
+ end
63
+ end
52
64
  end
53
65
  end
54
66
  end
@@ -1,18 +1,53 @@
1
- FactoryGirl.define do
2
- # Define your Spree extensions Factories within this file to enable applications, and other extensions to use and override them.
1
+ # frozen_string_literal: true
2
+
3
+ FactoryBot.define do
4
+ # Define your Spree extensions Factories within this file to enable applications,
5
+ # and other extensions to use and override them.
3
6
  #
4
7
  # Example adding this to your spec_helper will load these Factories for use:
5
8
  # require 'solidus_paypal_braintree/factories'
9
+
10
+ factory :solidus_paypal_braintree_payment_method, class: SolidusPaypalBraintree::Gateway do
11
+ name 'Solidus PayPal Braintree Gateway'
12
+ active true
13
+ end
14
+
15
+ factory :solidus_paypal_braintree_source, class: SolidusPaypalBraintree::Source do
16
+ association(:payment_method, factory: :solidus_paypal_braintree_payment_method)
17
+ user
18
+
19
+ trait :credit_card do
20
+ payment_type SolidusPaypalBraintree::Source::CREDIT_CARD
21
+ end
22
+
23
+ trait :paypal do
24
+ payment_type SolidusPaypalBraintree::Source::PAYPAL
25
+ end
26
+
27
+ trait :apple_pay do
28
+ payment_type SolidusPaypalBraintree::Source::APPLE_PAY
29
+ end
30
+ end
6
31
  end
7
32
 
8
- FactoryGirl.modify do
33
+ FactoryBot.modify do
9
34
  # The Solidus address factory randomizes the zipcode.
10
35
  # The OrderWalkThrough we use in the credit card checkout spec uses this factory for the user addresses.
11
36
  # For credit card payments we transmit the billing address to braintree, for paypal payments the shipping address.
12
- # As we match the body in our VCR settings VCR can not match the request anymore and therefore cannot replay existing cassettes.
37
+ # As we match the body in our VCR settings VCR can not match the request anymore and therefore cannot replay existing
38
+ # cassettes.
13
39
  #
40
+
14
41
  factory :address do
15
- zipcode '21088-0255'
16
- lastname "Doe"
42
+ zipcode { '21088-0255' }
43
+
44
+ if SolidusSupport.combined_first_and_last_name_in_address?
45
+ transient do
46
+ firstname { "John" }
47
+ lastname { "Doe" }
48
+ end
49
+
50
+ name { "#{firstname} #{lastname}" }
51
+ end
17
52
  end
18
53
  end
@@ -0,0 +1,21 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'active_merchant/network_connection_retries'
4
+
5
+ module SolidusPaypalBraintree
6
+ module RequestProtection
7
+ include ActiveMerchant::NetworkConnectionRetries
8
+
9
+ def protected_request
10
+ raise ArgumentError unless block_given?
11
+
12
+ options = {
13
+ connection_exceptions: {
14
+ Braintree::BraintreeError => 'Error while connecting to Braintree gateway'
15
+ },
16
+ logger: Rails.logger
17
+ }
18
+ retry_exceptions(options) { yield }
19
+ end
20
+ end
21
+ end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module SolidusPaypalBraintree
2
- VERSION = '0.2.0'
4
+ VERSION = '1.1.0'
3
5
  end
@@ -1,7 +1,11 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'solidus_core'
2
- require 'solidus_support'
4
+ require 'solidus_paypal_braintree/version'
3
5
  require 'solidus_paypal_braintree/engine'
4
6
  require 'solidus_paypal_braintree/country_mapper'
7
+ require 'solidus_paypal_braintree/request_protection'
8
+ require 'solidus_support'
5
9
 
6
10
  module SolidusPaypalBraintree
7
11
  def self.table_name_prefix
@@ -6,25 +6,58 @@
6
6
  <% @configurations.each do |config| %>
7
7
  <div class="row">
8
8
  <fieldset>
9
- <h1><%= config.store.name %></h1>
9
+ <legend><%= config.store.name %></legend>
10
10
 
11
11
  <%= f.fields_for 'configuration_fields[]', config do |c| %>
12
12
  <div class="field">
13
- <%= c.label :paypal %>
14
13
  <%= c.check_box :paypal %>
14
+ <%= c.label :paypal do %>
15
+ <%= tag.i class: 'fa fa-paypal' %>
16
+ <%= c.object.class.human_attribute_name(:paypal) %>
17
+ <% end %>
15
18
  </div>
19
+
16
20
  <div class="field">
17
- <%= c.label :apple_pay %>
18
21
  <%= c.check_box :apple_pay %>
22
+ <%= c.label :apple_pay do %>
23
+ <%= tag.i class: 'fa fa-apple' %>
24
+ <%= c.object.class.human_attribute_name(:apple_pay) %>
25
+ <% end %>
26
+ </div>
27
+
28
+ <div class="field">
29
+ <%= c.check_box :venmo %>
30
+ <%= c.label :venmo do %>
31
+ <%= tag.i class: 'fa fa-mobile' %>
32
+ <%= c.object.class.human_attribute_name(:venmo) %>
33
+ <% end %>
19
34
  </div>
35
+
20
36
  <div class="field">
21
- <%= c.label :credit_card %>
22
37
  <%= c.check_box :credit_card %>
38
+ <%= c.label :credit_card do %>
39
+ <%= tag.i class: 'fa fa-credit-card' %>
40
+ <%= c.object.class.human_attribute_name(:credit_card) %>
41
+ <% end %>
42
+ +
43
+ <%= c.check_box :three_d_secure %>
44
+ <%= c.label :three_d_secure do %>
45
+ <%= tag.i class: 'fa fa-shield' %>
46
+ <%= c.object.class.human_attribute_name(:three_d_secure) %>
47
+ <% end %>
23
48
  </div>
49
+
50
+ <% config.admin_form_preference_names.each do |name| %>
51
+ <%= render "spree/admin/shared/preference_fields/#{config.preference_type(name)}",
52
+ form: c, attribute: "preferred_#{name}",
53
+ label: t(name, scope: 'spree', default: name.to_s.humanize) %>
54
+ <% end %>
24
55
  <% end %>
25
56
  </fieldset>
26
57
  </div>
27
58
  <% end %>
28
59
 
29
- <%= submit_tag %>
60
+ <div class="form-buttons filter-actions actions">
61
+ <%= submit_tag "Update", class: 'btn btn-primary' %>
62
+ </div>
30
63
  <% end %>
@@ -6,11 +6,11 @@
6
6
  <% previous_cards.each do |card| %>
7
7
  <label><%= radio_button_tag :card, card.id, card == previous_cards.first %> <%= card.display_number %><br /></label>
8
8
  <% end %>
9
- <label><%= radio_button_tag :card, "new", false, { id: "card_new#{id}" } %> <%= Spree.t(:use_new_cc) %></label>
9
+ <label><%= radio_button_tag :card, "new", false, { id: "card_new#{id}" } %> <%= I18n.t("spree.use_new_cc") %></label>
10
10
  <% end %>
11
11
  </div>
12
12
 
13
13
  <div id="card_form<%= id %>" data-hook style="display: none;">
14
- <%= render partial: "spree/shared/braintree_hosted_fields", locals: { id: id } %>
14
+ <%= render partial: "spree/shared/braintree_hosted_fields", locals: { payment_method: payment_method } %>
15
15
  </div>
16
16
  </fieldset>
@@ -4,10 +4,10 @@
4
4
  <div class="row">
5
5
  <div class="alpha six columns">
6
6
  <dl>
7
- <dt><%= Spree.t(:identifier) %>:</dt>
7
+ <dt><%= I18n.t("spree.identifier") %>:</dt>
8
8
  <dd><%= payment.number %></dd>
9
9
 
10
- <dt><%= Spree.t(:response_code) %>:</dt>
10
+ <dt><%= I18n.t("spree.response_code") %>:</dt>
11
11
  <dd><%= braintree_transaction_link(payment) %></dd>
12
12
 
13
13
  <% if payment.source.token.present? %>
@@ -28,6 +28,11 @@
28
28
  <dt><%= Spree::CreditCard.human_attribute_name(:last_digits) %>:</dt>
29
29
  <dd><%= payment.source.last_digits %></dd>
30
30
  <% end %>
31
+
32
+ <% if payment.source.paypal? %>
33
+ <dt><%= I18n.t('spree.paypal_funding_source') %>:</dt>
34
+ <dd><%= payment.source.display_paypal_funding_source %></dd>
35
+ <% end %>
31
36
  </dl>
32
37
  </div>
33
38
  </div>
@@ -0,0 +1,13 @@
1
+ <% label = local_assigns[:label].presence %>
2
+ <% html_options = {class: 'custom-select fullwidth'}.update(local_assigns[:html_options] || {}) %>
3
+ <% options = form.object.send("#{attribute}_options") %>
4
+
5
+ <div class="field">
6
+ <% if local_assigns[:form] %>
7
+ <%= form.label attribute, label %>
8
+ <%= form.select attribute, options, {}, html_options %>
9
+ <% else %>
10
+ <%= label_tag name, label %>
11
+ <%= select_tag name, value, html_options %>
12
+ <% end %>
13
+ </div>
@@ -6,11 +6,11 @@
6
6
  <% previous_cards.each do |card| %>
7
7
  <label><%= radio_button_tag :card, card.id, card == previous_cards.first %> <%= card.display_number %><br /></label>
8
8
  <% end %>
9
- <label><%= radio_button_tag :card, "new", false, { id: "card_new#{id}" } %> <%= Spree.t(:use_new_cc) %></label>
9
+ <label><%= radio_button_tag :card, "new", false, { id: "card_new#{id}" } %> <%= I18n.t("spree.use_new_cc") %></label>
10
10
  <% end %>
11
11
  </div>
12
12
 
13
13
  <div id="card_form<%= id %>" data-hook style="display: none;">
14
- <%= render partial: "spree/shared/braintree_hosted_fields", locals: { id: id } %>
14
+ <%= render partial: "spree/shared/braintree_hosted_fields", locals: { payment_method: payment_method } %>
15
15
  </div>
16
16
  </fieldset>