solidus_paypal_commerce_platform 0.1.0 → 0.3.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (41) hide show
  1. checksums.yaml +4 -4
  2. data/.github/stale.yml +4 -4
  3. data/.github_changelog_generator +2 -0
  4. data/.rubocop.yml +5 -14
  5. data/CHANGELOG.md +181 -0
  6. data/README.md +26 -25
  7. data/app/controllers/solidus_paypal_commerce_platform/orders_controller.rb +8 -5
  8. data/app/decorators/models/solidus_paypal_commerce_platform/spree/address_decorator.rb +17 -0
  9. data/app/jobs/solidus_paypal_commerce_platform/webhook_job.rb +3 -3
  10. data/app/models/solidus_paypal_commerce_platform/payment_method.rb +4 -1
  11. data/app/models/solidus_paypal_commerce_platform/paypal_address.rb +19 -20
  12. data/app/models/solidus_paypal_commerce_platform/paypal_order.rb +3 -3
  13. data/app/models/solidus_paypal_commerce_platform/pricing_options.rb +1 -1
  14. data/app/models/solidus_paypal_commerce_platform/state_guesser.rb +1 -1
  15. data/bin/sandbox +1 -1
  16. data/lib/generators/solidus_paypal_commerce_platform/install/install_generator.rb +9 -0
  17. data/lib/generators/solidus_paypal_commerce_platform/install/templates/initializer.rb +6 -0
  18. data/lib/solidus_paypal_commerce_platform.rb +7 -5
  19. data/lib/solidus_paypal_commerce_platform/client.rb +2 -2
  20. data/lib/solidus_paypal_commerce_platform/configuration.rb +4 -0
  21. data/lib/solidus_paypal_commerce_platform/{factories.rb → testing_support/factories.rb} +0 -0
  22. data/lib/solidus_paypal_commerce_platform/version.rb +1 -1
  23. data/lib/views/frontend/solidus_paypal_commerce_platform/shared/_javascript_sdk_tag.html.erb +6 -0
  24. data/lib/views/frontend/spree/checkout/payment/_paypal_commerce_platform.html.erb +6 -1
  25. data/lib/views/frontend/spree/orders/payment/_paypal_commerce_platform.html.erb +3 -2
  26. data/lib/views/frontend/spree/products/payment/_paypal_commerce_platform.html.erb +3 -2
  27. data/solidus_paypal_commerce_platform.gemspec +7 -7
  28. data/spec/features/frontend/cart_spec.rb +21 -13
  29. data/spec/features/frontend/checkout_spec.rb +21 -13
  30. data/spec/features/frontend/product_spec.rb +23 -15
  31. data/spec/lib/solidus_paypal_commerce_platform/client_spec.rb +1 -1
  32. data/spec/lib/solidus_paypal_commerce_platform/configuration_spec.rb +10 -4
  33. data/spec/models/solidus_paypal_commerce_platform/payment_method_spec.rb +19 -0
  34. data/spec/models/solidus_paypal_commerce_platform/paypal_address_spec.rb +17 -5
  35. data/spec/requests/solidus_paypal_commerce_platform/orders_controller_spec.rb +2 -2
  36. data/spec/requests/solidus_paypal_commerce_platform/shipping_rates_controller_spec.rb +3 -3
  37. data/spec/requests/solidus_paypal_commerce_platform/wizard_controller_spec.rb +1 -1
  38. data/spec/spec_helper.rb +2 -2
  39. data/spec/support/paypal_sdk_script_tag_helper.rb +13 -0
  40. metadata +33 -21
  41. data/app/decorators/solidus_paypal_commerce_platform/remove_required_phone_from_address.rb +0 -13
@@ -19,7 +19,7 @@ module SolidusPaypalCommercePlatform
19
19
  end
20
20
 
21
21
  def update(paypal_address)
22
- formatted_address = format_address(paypal_address)
22
+ formatted_address = address_attributes(paypal_address[:updated_address], paypal_address[:recipient])
23
23
  new_address = @order.ship_address.dup || ::Spree::Address.new
24
24
  new_address.assign_attributes(formatted_address)
25
25
 
@@ -51,36 +51,35 @@ module SolidusPaypalCommercePlatform
51
51
  end
52
52
 
53
53
  def format_simulated_address(paypal_address)
54
- country = ::Spree::Country.find_by(iso: paypal_address[:country_code])
55
- # Also adds fake information for a few fields, so validations can run
54
+ # Adds fake information for a few fields, so validations can run
55
+ paypal_address[:address_line_1] = "123 Fake St."
56
+
56
57
  ::Spree::Address.new(
57
- city: paypal_address[:city],
58
- state: find_state(paypal_address[:state], country),
59
- state_name: paypal_address[:state],
60
- zipcode: paypal_address[:postal_code],
61
- country: country,
62
- address1: "123 Fake St.",
63
- phone: "123456789",
64
- firstname: "Fake"
58
+ address_attributes(paypal_address, { name: { given_name: "Fake" } })
65
59
  )
66
60
  end
67
61
 
68
- def format_address(paypal_address)
69
- address = paypal_address[:updated_address]
70
- recipient = paypal_address[:recipient]
62
+ def address_attributes(address, recipient)
71
63
  country = ::Spree::Country.find_by(iso: address[:country_code])
72
64
 
73
- {
65
+ attributes = {
74
66
  address1: address[:address_line_1],
75
67
  address2: address[:address_line_2],
76
- state: find_state(address[:admin_area_1], country),
77
- state_name: address[:admin_area_1],
78
- city: address[:admin_area_2],
68
+ state: find_state(address[:admin_area_1] || address[:state], country),
69
+ state_name: address[:admin_area_1] || address[:state],
70
+ city: address[:admin_area_2] || address[:city],
79
71
  country: country,
80
72
  zipcode: address[:postal_code],
81
- firstname: recipient[:name][:given_name],
82
- lastname: recipient[:name][:surname]
83
73
  }
74
+
75
+ if SolidusSupport.combined_first_and_last_name_in_address?
76
+ attributes[:name] = "#{recipient[:name][:given_name]} #{recipient[:name][:surname]}"
77
+ else
78
+ attributes[:firstname] = recipient[:name][:given_name]
79
+ attributes[:lastname] = recipient[:name][:surname]
80
+ end
81
+
82
+ attributes
84
83
  end
85
84
  end
86
85
  end
@@ -18,7 +18,7 @@ module SolidusPaypalCommercePlatform
18
18
  {
19
19
  op: 'replace',
20
20
  path: '/purchase_units/@reference_id==\'default\'',
21
- value: purchase_units[0]
21
+ value: purchase_units(include_shipping_address: false)[0]
22
22
  }
23
23
  end
24
24
 
@@ -50,12 +50,12 @@ module SolidusPaypalCommercePlatform
50
50
  }
51
51
  end
52
52
 
53
- def purchase_units
53
+ def purchase_units(include_shipping_address: true)
54
54
  [
55
55
  {
56
56
  amount: amount,
57
57
  items: line_items,
58
- shipping: (shipping_info if @order.ship_address)
58
+ shipping: (shipping_info if @order.ship_address && include_shipping_address)
59
59
  }
60
60
  ]
61
61
  end
@@ -1,7 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module SolidusPaypalCommercePlatform
4
- class PricingOptions < Spree::Variant::PricingOptions
4
+ class PricingOptions < ::Spree::Variant::PricingOptions
5
5
  def cache_key
6
6
  SolidusPaypalCommercePlatform::PaymentMethod.active.map(&:cache_key_with_version).sort + [super]
7
7
  end
@@ -22,7 +22,7 @@ module SolidusPaypalCommercePlatform
22
22
  end
23
23
 
24
24
  def spree_state(name)
25
- Spree::State.find_by(name: name)
25
+ ::Spree::State.find_by(name: name)
26
26
  end
27
27
  end
28
28
  end
data/bin/sandbox CHANGED
@@ -72,7 +72,7 @@ unbundled bundle exec rails generate spree:install \
72
72
  --user_class=Spree::User \
73
73
  --enforce_available_locales=true \
74
74
  --with-authentication=false \
75
- --payment-method=none
75
+ --payment-method=none \
76
76
  $@
77
77
 
78
78
  unbundled bundle exec rails generate solidus:auth:install
@@ -4,6 +4,13 @@ module SolidusPaypalCommercePlatform
4
4
  module Generators
5
5
  class InstallGenerator < Rails::Generators::Base
6
6
  class_option :auto_run_migrations, type: :boolean, default: false
7
+ class_option :skip_migrations, type: :boolean, default: false
8
+
9
+ source_root File.expand_path('templates', __dir__)
10
+
11
+ def copy_initializer
12
+ template 'initializer.rb', 'config/initializers/solidus_paypal_commerce_platform.rb'
13
+ end
7
14
 
8
15
  def add_javascripts
9
16
  append_file 'vendor/assets/javascripts/spree/frontend/all.js', "//= require spree/frontend/solidus_paypal_commerce_platform\n" # rubocop:disable Layout/LineLength
@@ -26,6 +33,8 @@ module SolidusPaypalCommercePlatform
26
33
  end
27
34
 
28
35
  def run_migrations
36
+ return if options[:skip_migrations]
37
+
29
38
  run_migrations = options[:auto_run_migrations] || ['', 'y', 'Y'].include?(ask('Would you like to run the migrations now? [Y/n]')) # rubocop:disable Layout/LineLength
30
39
  if run_migrations
31
40
  run 'bin/rails db:migrate'
@@ -0,0 +1,6 @@
1
+ # frozen_string_literal: true
2
+
3
+ SolidusPaypalCommercePlatform.configure do |config|
4
+ # TODO: Remember to change this with the actual preferences you have implemented!
5
+ # config.sample_preference = 'sample_value'
6
+ end
@@ -3,19 +3,21 @@
3
3
  require 'solidus_core'
4
4
  require 'solidus_support'
5
5
 
6
- require 'solidus_paypal_commerce_platform/version'
7
- require 'solidus_paypal_commerce_platform/configuration'
8
6
  require 'solidus_paypal_commerce_platform/client'
7
+ require 'solidus_paypal_commerce_platform/configuration'
8
+ require 'solidus_paypal_commerce_platform/version'
9
9
  require 'solidus_paypal_commerce_platform/engine'
10
10
 
11
11
  module SolidusPaypalCommercePlatform
12
12
  class << self
13
- def config
14
- @config ||= Configuration.new
13
+ def configuration
14
+ @configuration ||= Configuration.new
15
15
  end
16
16
 
17
+ alias config configuration
18
+
17
19
  def configure
18
- yield config
20
+ yield configuration
19
21
  end
20
22
  end
21
23
  end
@@ -10,12 +10,12 @@ module SolidusPaypalCommercePlatform
10
10
  SUCCESS_STATUS_CODES = [201, 204].freeze
11
11
 
12
12
  PARTNER_ATTRIBUTION_INJECTOR = ->(request) {
13
- request.headers["PayPal-Partner-Attribution-Id"] = "Solidus_PCP_SP"
13
+ request.headers["PayPal-Partner-Attribution-Id"] = SolidusPaypalCommercePlatform.config.partner_code
14
14
  }.freeze
15
15
 
16
16
  attr_reader :environment
17
17
 
18
- def initialize(test_mode: nil, client_id:, client_secret: "")
18
+ def initialize(client_id:, client_secret: "", test_mode: nil)
19
19
  test_mode = SolidusPaypalCommercePlatform.config.env.sandbox? if test_mode.nil?
20
20
  env_class = test_mode ? PayPal::SandboxEnvironment : PayPal::LiveEnvironment
21
21
 
@@ -66,5 +66,9 @@ module SolidusPaypalCommercePlatform
66
66
  def partner_client_id
67
67
  @partner_client_id ||= ENV['PAYPAL_PARTNER_CLIENT_ID'] || DEFAULT_PARTNER_CLIENT_ID[env.to_sym]
68
68
  end
69
+
70
+ def partner_code
71
+ "Solidus_PCP_SP"
72
+ end
69
73
  end
70
74
  end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module SolidusPaypalCommercePlatform
4
- VERSION = '0.1.0'
4
+ VERSION = '0.3.1'
5
5
  end
@@ -0,0 +1,6 @@
1
+ <% currency = @order ? @order.currency : current_pricing_options.currency %>
2
+
3
+ <script
4
+ src="<%= payment_method.javascript_sdk_url(order: @order, currency: currency) %>"
5
+ data-partner-attribution-id="<%= SolidusPaypalCommercePlatform.config.partner_code %>">
6
+ </script>
@@ -1,10 +1,15 @@
1
- <script src="<%= payment_method.javascript_sdk_url(order: @order) %>"></script>
1
+ <%= render partial: "solidus_paypal_commerce_platform/shared/javascript_sdk_tag", locals: {payment_method: payment_method} %>
2
2
 
3
3
  <div id="paypal-button-container"></div>
4
+
5
+ <div data-pp-message data-pp-placement="payment" data-pp-amount="<%= @order.total %>"></div>
6
+
4
7
  <input type="hidden" name="payment_source[<%= payment_method.id %>][paypal_order_id]" id="payments_source_paypal_order_id">
5
8
  <input type="hidden" name="payment_source[<%= payment_method.id %>][paypal_email]" id="payments_source_paypal_email">
6
9
 
7
10
  <script>
11
+ Spree.current_order_id = "<%= @order.number %>"
12
+ Spree.current_order_token = "<%= @order.guest_token %>"
8
13
  $( document ).ready(function() {
9
14
  SolidusPaypalCommercePlatform.renderButton("<%= payment_method.id %>",<%= raw payment_method.button_style.to_json %>)
10
15
  })
@@ -1,9 +1,10 @@
1
1
  <div style="margin-left:auto;margin-right:auto;width:50%;margin-top:20px;">
2
- <script src="<%= payment_method.javascript_sdk_url(order: @order) %>">
3
- </script>
2
+ <%= render partial: "solidus_paypal_commerce_platform/shared/javascript_sdk_tag", locals: {payment_method: payment_method} %>
4
3
 
5
4
  <div id="paypal-button-container"></div>
6
5
 
6
+ <div data-pp-message data-pp-placement="cart" data-pp-amount="<%= @order.total %>"></div>
7
+
7
8
  <script>
8
9
  Spree.current_order_id = "<%= @order.number %>"
9
10
  Spree.current_order_token = "<%= @order.guest_token %>"
@@ -1,9 +1,10 @@
1
1
  <div style="margin-top:20px;">
2
- <script src="<%= payment_method.javascript_sdk_url %>">
3
- </script>
2
+ <%= render partial: "solidus_paypal_commerce_platform/shared/javascript_sdk_tag", locals: {payment_method: payment_method} %>
4
3
 
5
4
  <div id="paypal-button-container"></div>
6
5
 
6
+ <div data-pp-message data-pp-placement="product" data-pp-amount="<%= @product.price %>"></div>
7
+
7
8
  <script>
8
9
  SolidusPaypalCommercePlatform.checkout_url = "<%= checkout_url %>"
9
10
  $( document ).ready(function() {
@@ -9,14 +9,14 @@ Gem::Specification.new do |spec|
9
9
  spec.email = 'contact@solidus.io'
10
10
 
11
11
  spec.summary = 'Integrate Solidus with Paypal Commerce Platform'
12
- spec.homepage = 'https://github.com/solidusio-contrib/solidus_paypal_commerce_platform#readme'
12
+ spec.homepage = 'https://github.com/solidusio-contrib/solidus_paypal_commerce_platform'
13
13
  spec.license = 'BSD-3-Clause'
14
14
 
15
15
  spec.metadata['homepage_uri'] = spec.homepage
16
- spec.metadata['source_code_uri'] = 'https://github.com/solidusio-contrib/solidus_paypal_commerce_platform#readme'
16
+ spec.metadata['source_code_uri'] = 'https://github.com/solidusio-contrib/solidus_paypal_commerce_platform'
17
17
  spec.metadata['changelog_uri'] = 'https://github.com/solidusio-contrib/solidus_paypal_commerce_platform/releases'
18
18
 
19
- spec.required_ruby_version = Gem::Requirement.new('~> 2.5')
19
+ spec.required_ruby_version = Gem::Requirement.new('>= 2.5')
20
20
 
21
21
  # Specify which files should be added to the gem when it is released.
22
22
  # The `git ls-files -z` loads the files in the RubyGem that have been added into git.
@@ -29,12 +29,12 @@ Gem::Specification.new do |spec|
29
29
  spec.require_paths = ["lib"]
30
30
 
31
31
  spec.add_dependency 'deface', '~> 1.5'
32
- spec.add_dependency 'solidus_core', ['>= 2.0.0', '< 3']
33
- spec.add_dependency 'solidus_support', '~> 0.5'
34
- spec.add_dependency 'solidus_webhooks', '~> 0.2.0'
32
+ spec.add_dependency 'solidus_core', ['>= 2.0.0', '< 4']
33
+ spec.add_dependency 'solidus_support', [">= 0.8.0", "< 1"]
34
+ spec.add_dependency 'solidus_webhooks', '~> 0.2'
35
35
 
36
36
  spec.add_dependency 'paypal-checkout-sdk'
37
37
 
38
38
  spec.add_development_dependency 'cuprite'
39
- spec.add_development_dependency 'solidus_dev_support'
39
+ spec.add_development_dependency 'solidus_dev_support', '~> 2.1'
40
40
  end
@@ -16,22 +16,30 @@ RSpec.describe "Cart page" do
16
16
  )
17
17
  end
18
18
 
19
- def paypal_script_options
20
- script_tag_url = URI(page.find('script[src*="sdk/js?"]', visible: false)[:src])
21
- script_tag_url.query.split('&')
22
- end
19
+ context "when generating a script tag" do
20
+ it "generates a url with the correct credentials attached" do
21
+ visit '/cart'
22
+ expect(js_sdk_script_query).to include("client-id=#{paypal_payment_method.preferences[:client_id]}")
23
+ end
23
24
 
24
- it "generate a js file with the correct credentials and intent attached" do
25
- visit '/cart'
26
- expect(paypal_script_options).to include("client-id=#{paypal_payment_method.preferences[:client_id]}")
27
- end
25
+ it "generates a partner_id attribute with the correct partner code attached" do
26
+ visit '/cart'
27
+ expect(js_sdk_script_partner_id).to eq("Solidus_PCP_SP")
28
+ end
28
29
 
29
- context "when auto-capture is set to true" do
30
- it "generate a js file with intent capture" do
31
- paypal_payment_method.update(auto_capture: true)
30
+ it "generates a URL with the correct currency" do
31
+ allow(order).to receive(:currency).and_return "EUR"
32
32
  visit '/cart'
33
- expect(paypal_script_options).to include("client-id=#{paypal_payment_method.preferences[:client_id]}")
34
- expect(paypal_script_options).to include("intent=capture")
33
+ expect(js_sdk_script_query).to include("currency=EUR")
34
+ end
35
+
36
+ context "when auto-capture is set to true" do
37
+ it "generates a url with intent capture" do
38
+ paypal_payment_method.update(auto_capture: true)
39
+ visit '/cart'
40
+ expect(js_sdk_script_query).to include("client-id=#{paypal_payment_method.preferences[:client_id]}")
41
+ expect(js_sdk_script_query).to include("intent=capture")
42
+ end
35
43
  end
36
44
  end
37
45
  end
@@ -17,22 +17,30 @@ RSpec.describe "Checkout" do
17
17
  )
18
18
  end
19
19
 
20
- def paypal_script_options
21
- script_tag_url = URI(page.find('script[src*="sdk/js?"]', visible: false)[:src])
22
- script_tag_url.query.split('&')
23
- end
20
+ context "when generating a script tag" do
21
+ it "generates a url with the correct credentials attached" do
22
+ visit '/checkout/payment'
23
+ expect(js_sdk_script_query).to include("client-id=#{paypal_payment_method.preferences[:client_id]}")
24
+ end
24
25
 
25
- it "generates a js file with the correct credentials and intent attached" do
26
- visit '/checkout/payment'
27
- expect(paypal_script_options).to include("client-id=#{paypal_payment_method.preferences[:client_id]}")
28
- end
26
+ it "generates a partner_id attribute with the correct partner code attached" do
27
+ visit '/checkout/payment'
28
+ expect(js_sdk_script_partner_id).to eq("Solidus_PCP_SP")
29
+ end
29
30
 
30
- context "when auto-capture is set to true" do
31
- it "generates a js file with intent capture" do
32
- paypal_payment_method.update(auto_capture: true)
31
+ it "generates a URL with the correct currency" do
32
+ allow(order).to receive(:currency).and_return "EUR"
33
33
  visit '/checkout/payment'
34
- expect(paypal_script_options).to include("client-id=#{paypal_payment_method.preferences[:client_id]}")
35
- expect(paypal_script_options).to include("intent=capture")
34
+ expect(js_sdk_script_query).to include("currency=EUR")
35
+ end
36
+
37
+ context "when auto-capture is set to true" do
38
+ it "generates a url with intent capture" do
39
+ paypal_payment_method.update(auto_capture: true)
40
+ visit '/checkout/payment'
41
+ expect(js_sdk_script_query).to include("client-id=#{paypal_payment_method.preferences[:client_id]}")
42
+ expect(js_sdk_script_query).to include("intent=capture")
43
+ end
36
44
  end
37
45
  end
38
46
 
@@ -12,29 +12,37 @@ RSpec.describe "Product page", js: true do
12
12
  paypal_payment_method
13
13
  end
14
14
 
15
- def paypal_script_options
16
- script_tag_url = URI(page.find('script[src*="sdk/js?"]', visible: false)[:src])
17
- script_tag_url.query.split('&')
18
- end
15
+ context "when generating a script tag" do
16
+ it "generates a url with the correct credentials attached" do
17
+ visit "/products/#{product.slug}"
18
+ expect(js_sdk_script_query).to include("client-id=#{paypal_payment_method.preferences[:client_id]}")
19
+ end
19
20
 
20
- it "generates a js file with the correct credentials and intent attached" do
21
- visit '/products/' + product.slug
22
- expect(paypal_script_options).to include("client-id=#{paypal_payment_method.preferences[:client_id]}")
23
- end
21
+ it "generates a partner_id attribute with the correct partner code attached" do
22
+ visit "/products/#{product.slug}"
23
+ expect(js_sdk_script_partner_id).to eq("Solidus_PCP_SP")
24
+ end
25
+
26
+ it "generates a URL with the correct currency" do
27
+ allow_any_instance_of(SolidusPaypalCommercePlatform::PricingOptions).to receive(:currency).and_return "EUR"
28
+ visit "/products/#{product.slug}"
29
+ expect(js_sdk_script_query).to include("currency=EUR")
30
+ end
24
31
 
25
- context "when auto-capture is set to true" do
26
- it "generates a js file with intent capture" do
27
- paypal_payment_method.update(auto_capture: true)
28
- visit '/products/' + product.slug
29
- expect(paypal_script_options).to include("client-id=#{paypal_payment_method.preferences[:client_id]}")
30
- expect(paypal_script_options).to include("intent=capture")
32
+ context "when auto-capture is set to true" do
33
+ it "generates a url with intent capture" do
34
+ paypal_payment_method.update(auto_capture: true)
35
+ visit "/products/#{product.slug}"
36
+ expect(js_sdk_script_query).to include("client-id=#{paypal_payment_method.preferences[:client_id]}")
37
+ expect(js_sdk_script_query).to include("intent=capture")
38
+ end
31
39
  end
32
40
  end
33
41
 
34
42
  describe "order creation" do
35
43
  before do
36
44
  allow_any_instance_of(Spree::Core::ControllerHelpers::Store).to receive(:current_store) { store }
37
- visit '/products/' + product.slug
45
+ visit "/products/#{product.slug}"
38
46
 
39
47
  # Stubbing out paypal methods since their JS doesn't load in correctly on tests
40
48
  page.execute_script("paypal = {}")