solidus_paypal_commerce_platform 0.1.0 → 0.3.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (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 = {}")