solidus_stripe 1.0.0

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 (34) hide show
  1. checksums.yaml +7 -0
  2. data/.circleci/config.yml +35 -0
  3. data/.gem_release.yml +8 -0
  4. data/.gitignore +11 -0
  5. data/.rspec +1 -0
  6. data/.rubocop.yml +319 -0
  7. data/.travis.yml +28 -0
  8. data/Gemfile +25 -0
  9. data/LICENSE.md +26 -0
  10. data/README.md +115 -0
  11. data/Rakefile +23 -0
  12. data/app/models/spree/payment_method/stripe_credit_card.rb +136 -0
  13. data/bin/rails +7 -0
  14. data/db/migrate/20181010123508_update_stripe_payment_method_type_to_credit_card.rb +21 -0
  15. data/db/seeds.rb +26 -0
  16. data/lib/assets/stylesheets/spree/frontend/solidus_stripe.scss +6 -0
  17. data/lib/generators/solidus_stripe/install/install_generator.rb +46 -0
  18. data/lib/solidus_stripe.rb +7 -0
  19. data/lib/solidus_stripe/engine.rb +23 -0
  20. data/lib/solidus_stripe/version.rb +5 -0
  21. data/lib/tasks/solidus_stripe/db/seed.rake +14 -0
  22. data/lib/views/api/spree/api/payments/source_views/_stripe.json.jbuilder +3 -0
  23. data/lib/views/backend/spree/admin/log_entries/_stripe.html.erb +28 -0
  24. data/lib/views/backend/spree/admin/payments/source_forms/_stripe.html.erb +1 -0
  25. data/lib/views/backend/spree/admin/payments/source_views/_stripe.html.erb +1 -0
  26. data/lib/views/frontend/spree/checkout/existing_payment/_stripe.html.erb +1 -0
  27. data/lib/views/frontend/spree/checkout/payment/_stripe.html.erb +6 -0
  28. data/lib/views/frontend/spree/checkout/payment/v2/_javascript.html.erb +77 -0
  29. data/lib/views/frontend/spree/checkout/payment/v3/_stripe.html.erb +133 -0
  30. data/solidus_stripe.gemspec +45 -0
  31. data/spec/features/stripe_checkout_spec.rb +279 -0
  32. data/spec/models/spree/payment_method/stripe_credit_card_spec.rb +205 -0
  33. data/spec/spec_helper.rb +20 -0
  34. metadata +264 -0
@@ -0,0 +1,115 @@
1
+ Solidus Stripe
2
+ ===============
3
+
4
+ [![CircleCI](https://circleci.com/gh/solidusio/solidus_stripe.svg?style=svg)](https://circleci.com/gh/solidusio/solidus_stripe)
5
+
6
+ Stripe Payment Method for Solidus. It works as a wrapper for the ActiveMerchant Stripe gateway.
7
+
8
+ ---
9
+
10
+ Installation
11
+ ------------
12
+
13
+ In your Gemfile:
14
+
15
+ ```ruby
16
+ gem "solidus_stripe", github: "solidusio/solidus_stripe"
17
+ ```
18
+
19
+ Then run from the command line:
20
+
21
+ ```shell
22
+ bundle install
23
+ bundle exec rails g solidus_stripe:install
24
+ bundle exec rails db:migrate
25
+ ```
26
+
27
+ Usage
28
+ -----
29
+
30
+ Navigate to *Settings > Payments > Payment Methods* in the admin panel.
31
+ You can now create a new payment method that uses Stripe by selecting
32
+ `Stripe credit card` under Type in the New Payment Method form and saving.
33
+ The Stripe payment method's extra fields will be now shown in the form.
34
+
35
+ **Configure via database configuration**
36
+
37
+ If you want to store your Stripe credentials in the database just
38
+ fill the new fields in the form, selecting `custom` (default) in the
39
+ Preference Source field.
40
+
41
+ **Configure via static configuration**
42
+
43
+ If you want to store your credentials into your codebase or use ENV
44
+ variables you can create the following static configuration:
45
+
46
+ ```ruby
47
+ # config/initializers/spree.rb
48
+
49
+ Spree.config do |config|
50
+ # ...
51
+
52
+ config.static_model_preferences.add(
53
+ Spree::PaymentMethod::StripeCreditCard,
54
+ 'stripe_env_credentials',
55
+ secret_key: ENV['STRIPE_SECRET_KEY'],
56
+ publishable_key: ENV['STRIPE_PUBLISHABLE_KEY'],
57
+ v3_elements: false,
58
+ server: Rails.env.production? ? 'production' : 'test',
59
+ test_mode: !Rails.env.production?
60
+ )
61
+ end
62
+ ```
63
+
64
+ Once your server has been restarted, you can select in the Preference
65
+ Source field a new entry called `stripe_env_credentials`. After saving,
66
+ your application will start using the static configuration to process
67
+ Stripe payments.
68
+
69
+
70
+ Migrating from solidus_gateway
71
+ ------------------------------
72
+
73
+ If you were previously using `solidus_gateway` gem you might want to
74
+ check out our [Wiki page](https://github.com/solidusio/solidus_stripe/wiki/Migrating-from-solidus_gateway)
75
+ that describes how to handle this migration.
76
+
77
+ Testing
78
+ -------
79
+
80
+ Then just run the following to automatically build a dummy app if necessary and
81
+ run the tests:
82
+
83
+ ```shell
84
+ bundle exec rake
85
+ ```
86
+
87
+ Releasing
88
+ ---------
89
+
90
+ We use [gem-release](https://github.com/svenfuchs/gem-release) to release this
91
+ extension with ease.
92
+
93
+ Supposing you are on the master branch and you are working on a fork of this
94
+ extension, `upstream` is the main remote and you have write access to it, you
95
+ can simply run:
96
+
97
+ ```
98
+ gem bump --version minor --tag --release --remote upstream
99
+ ```
100
+
101
+ This command will:
102
+
103
+ - bump the gem version to the next minor (changing the `version.rb` file)
104
+ - commit the change and push it to upstream master
105
+ - create a git tag
106
+ - push the tag to the upstream remote
107
+ - release the new version on RubyGems
108
+
109
+ Or you can run these commands individually:
110
+
111
+ ```
112
+ gem bump --version minor --remote upstream
113
+ gem tag --remote upstream
114
+ gem release
115
+ ```
@@ -0,0 +1,23 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'bundler'
4
+ Bundler::GemHelper.install_tasks
5
+
6
+ require 'rspec/core/rake_task'
7
+ require 'spree/testing_support/common_rake'
8
+
9
+ RSpec::Core::RakeTask.new
10
+
11
+ task :default do
12
+ if Dir["spec/dummy"].empty?
13
+ Rake::Task[:test_app].invoke
14
+ Dir.chdir("../../")
15
+ end
16
+ Rake::Task[:spec].invoke
17
+ end
18
+
19
+ desc "Generates a dummy app for testing"
20
+ task :test_app do
21
+ ENV['LIB_NAME'] = 'solidus_stripe'
22
+ Rake::Task['common:test_app'].invoke
23
+ end
@@ -0,0 +1,136 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Spree
4
+ class PaymentMethod
5
+ class StripeCreditCard < Spree::PaymentMethod::CreditCard
6
+ preference :secret_key, :string
7
+ preference :publishable_key, :string
8
+ preference :v3_elements, :boolean
9
+
10
+ CARD_TYPE_MAPPING = {
11
+ 'American Express' => 'american_express',
12
+ 'Diners Club' => 'diners_club',
13
+ 'Visa' => 'visa'
14
+ }
15
+
16
+ def partial_name
17
+ 'stripe'
18
+ end
19
+
20
+ def v3_elements?
21
+ !!preferred_v3_elements
22
+ end
23
+
24
+ def gateway_class
25
+ ActiveMerchant::Billing::StripeGateway
26
+ end
27
+
28
+ def payment_profiles_supported?
29
+ true
30
+ end
31
+
32
+ def purchase(money, creditcard, transaction_options)
33
+ gateway.purchase(*options_for_purchase_or_auth(money, creditcard, transaction_options))
34
+ end
35
+
36
+ def authorize(money, creditcard, transaction_options)
37
+ gateway.authorize(*options_for_purchase_or_auth(money, creditcard, transaction_options))
38
+ end
39
+
40
+ def capture(money, response_code, transaction_options)
41
+ gateway.capture(money, response_code, transaction_options)
42
+ end
43
+
44
+ def credit(money, _creditcard, response_code, _transaction_options)
45
+ gateway.refund(money, response_code, {})
46
+ end
47
+
48
+ def void(response_code, _creditcard, _transaction_options)
49
+ gateway.void(response_code, {})
50
+ end
51
+
52
+ def cancel(response_code)
53
+ gateway.void(response_code, {})
54
+ end
55
+
56
+ def create_profile(payment)
57
+ return unless payment.source.gateway_customer_profile_id.nil?
58
+
59
+ options = {
60
+ email: payment.order.email,
61
+ login: preferred_secret_key,
62
+ }.merge! address_for(payment)
63
+
64
+ source = update_source!(payment.source)
65
+ if source.number.blank? && source.gateway_payment_profile_id.present?
66
+ creditcard = source.gateway_payment_profile_id
67
+ else
68
+ creditcard = source
69
+ end
70
+
71
+ response = gateway.store(creditcard, options)
72
+ if response.success?
73
+ payment.source.update_attributes!({
74
+ cc_type: payment.source.cc_type, # side-effect of update_source!
75
+ gateway_customer_profile_id: response.params['id'],
76
+ gateway_payment_profile_id: response.params['default_source'] || response.params['default_card']
77
+ })
78
+
79
+ else
80
+ payment.send(:gateway_error, response.message)
81
+ end
82
+ end
83
+
84
+ private
85
+
86
+ # In this gateway, what we call 'secret_key' is the 'login'
87
+ def options
88
+ options = super
89
+ options.merge(login: preferred_secret_key)
90
+ end
91
+
92
+ def options_for_purchase_or_auth(money, creditcard, transaction_options)
93
+ options = {}
94
+ options[:description] = "Spree Order ID: #{transaction_options[:order_id]}"
95
+ options[:currency] = transaction_options[:currency]
96
+
97
+ if customer = creditcard.gateway_customer_profile_id
98
+ options[:customer] = customer
99
+ end
100
+ if token_or_card_id = creditcard.gateway_payment_profile_id
101
+ # The Stripe ActiveMerchant gateway supports passing the token directly as the creditcard parameter
102
+ # The Stripe ActiveMerchant gateway supports passing the customer_id and credit_card id
103
+ # https://github.com/Shopify/active_merchant/issues/770
104
+ creditcard = token_or_card_id
105
+ end
106
+ [money, creditcard, options]
107
+ end
108
+
109
+ def address_for(payment)
110
+ {}.tap do |options|
111
+ if address = payment.order.bill_address
112
+ options[:address] = {
113
+ address1: address.address1,
114
+ address2: address.address2,
115
+ city: address.city,
116
+ zip: address.zipcode
117
+ }
118
+
119
+ if country = address.country
120
+ options[:address][:country] = country.name
121
+ end
122
+
123
+ if state = address.state
124
+ options[:address].merge!(state: state.name)
125
+ end
126
+ end
127
+ end
128
+ end
129
+
130
+ def update_source!(source)
131
+ source.cc_type = CARD_TYPE_MAPPING[source.cc_type] if CARD_TYPE_MAPPING.include?(source.cc_type)
132
+ source
133
+ end
134
+ end
135
+ end
136
+ end
@@ -0,0 +1,7 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ ENGINE_ROOT = File.expand_path('../..', __FILE__)
4
+ ENGINE_PATH = File.expand_path('../../lib/solidus_stripe/engine', __FILE__)
5
+
6
+ require 'rails/all'
7
+ require 'rails/engine/commands'
@@ -0,0 +1,21 @@
1
+ # frozen_string_literal: true
2
+
3
+ class UpdateStripePaymentMethodTypeToCreditCard < SolidusSupport::Migration[5.1]
4
+ def up
5
+ Spree::PaymentMethod.where(type: 'Spree::Gateway::StripeGateway').update_all(type: 'Spree::PaymentMethod::StripeCreditCard')
6
+
7
+ Spree::Preference.where("#{ActiveRecord::Base.connection.quote_column_name('key')} LIKE 'spree/gateway/stripe_gateway'").each do |pref|
8
+ pref.key = pref.key.gsub('spree/gateway/stripe_gateway', 'spree/payment_method/stripe_credit_card')
9
+ pref.save
10
+ end
11
+ end
12
+
13
+ def down
14
+ Spree::PaymentMethod.where(type: 'Spree::PaymentMethod::StripeCreditCard').update_all(type: 'Spree::Gateway::StripeGateway')
15
+
16
+ Spree::Preference.where("#{ActiveRecord::Base.connection.quote_column_name('key')} LIKE 'spree/payment_method/stripe_credit_card'").each do |pref|
17
+ pref.key = pref.key.gsub('spree/payment_method/stripe_credit_card', 'spree/gateway/stripe_gateway')
18
+ pref.save
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,26 @@
1
+ # frozen_string_literal: true
2
+
3
+ secret_key = ENV['STRIPE_SEEDS_SECRET_KEY']
4
+ publishable_key = ENV['STRIPE_SEEDS_PUBLISHABLE_KEY']
5
+
6
+ puts "Loading seed: solidus_stripe/stripe_payment_method"
7
+
8
+ if secret_key.blank? || publishable_key.blank?
9
+ puts "Failure: You have to set both STRIPE_SEEDS_SECRET_KEY and STRIPE_SEEDS_PUBLISHABLE_KEY environment variables."
10
+ else
11
+ stripe_payment_method = Spree::PaymentMethod::StripeCreditCard.new do |payment_method|
12
+ payment_method.name = 'Credit Card'
13
+ payment_method.preferred_test_mode = true
14
+ payment_method.preferred_secret_key = secret_key
15
+ payment_method.preferred_publishable_key = publishable_key
16
+ end
17
+
18
+ if stripe_payment_method.save
19
+ puts "Stripe Payment Method correctly created."
20
+ else
21
+ puts "There was some problems with creating Stripe Payment Method:"
22
+ stripe_payment_method.errors.full_messages.each do |error|
23
+ puts error
24
+ end
25
+ end
26
+ end
@@ -0,0 +1,6 @@
1
+ #card_number.StripeElement,
2
+ #card_expiry.StripeElement,
3
+ #card_cvc.StripeElement {
4
+ border: 1px solid #d9d9db;
5
+ padding: 5px;
6
+ }
@@ -0,0 +1,46 @@
1
+ # frozen_string_literal: true
2
+
3
+ module SolidusStripe
4
+ module Generators
5
+ class InstallGenerator < Rails::Generators::Base
6
+ class_option :migrate, type: :boolean, default: true
7
+ class_option :auto_run_migrations, type: :boolean, default: false
8
+ class_option :auto_run_seeds, type: :boolean, default: false
9
+
10
+ def add_stylesheets
11
+ filename = 'vendor/assets/stylesheets/spree/frontend/all.css'
12
+ if File.file? filename
13
+ inject_into_file filename, " *= require spree/frontend/solidus_stripe\n", before: '*/', verbose: true
14
+ end
15
+ end
16
+
17
+ def add_migrations
18
+ run 'bundle exec rake railties:install:migrations FROM=solidus_stripe'
19
+ end
20
+
21
+ def run_migrations
22
+ if options.migrate? && running_migrations?
23
+ run 'bundle exec rake db:migrate'
24
+ else
25
+ puts "Skiping rake db:migrate, don't forget to run it!"
26
+ end
27
+ end
28
+
29
+ def populate_seed_data
30
+ return unless options.auto_run_seeds?
31
+
32
+ say_status :loading, 'stripe seed data'
33
+ rake('db:seed:solidus_stripe')
34
+ end
35
+
36
+ private
37
+
38
+ def running_migrations?
39
+ options.auto_run_migrations? || begin
40
+ response = ask 'Would you like to run the migrations now? [Y/n]'
41
+ ['', 'y'].include? response.downcase
42
+ end
43
+ end
44
+ end
45
+ end
46
+ end
@@ -0,0 +1,7 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "active_merchant"
4
+ require "solidus_core"
5
+ require "solidus_support"
6
+ require "solidus_stripe/engine"
7
+ require "solidus_stripe/version"
@@ -0,0 +1,23 @@
1
+ # frozen_string_literal: true
2
+
3
+ module SolidusStripe
4
+ class Engine < Rails::Engine
5
+ engine_name 'solidus_stripe'
6
+
7
+ initializer "spree.payment_method.add_stripe_credit_card", after: "spree.register.payment_methods" do |app|
8
+ app.config.spree.payment_methods << Spree::PaymentMethod::StripeCreditCard
9
+ end
10
+
11
+ if SolidusSupport.backend_available?
12
+ paths["app/views"] << "lib/views/backend"
13
+ end
14
+
15
+ if SolidusSupport.frontend_available?
16
+ paths["app/views"] << "lib/views/frontend"
17
+ end
18
+
19
+ if SolidusSupport.api_available?
20
+ paths["app/views"] << "lib/views/api"
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,5 @@
1
+ # frozen_string_literal: true
2
+
3
+ module SolidusStripe
4
+ VERSION = "1.0.0"
5
+ end
@@ -0,0 +1,14 @@
1
+ # frozen_string_literal: true
2
+
3
+ namespace :db do
4
+ namespace :seed do
5
+ desc 'Loads stripe sample data'
6
+ task solidus_stripe: :environment do
7
+ seed_file = Dir[SolidusStripe::Engine.root.join('db', 'seeds.rb')][0]
8
+ return unless File.exist?(seed_file)
9
+
10
+ puts "Seeding #{seed_file}..."
11
+ load(seed_file)
12
+ end
13
+ end
14
+ end
@@ -0,0 +1,3 @@
1
+ # frozen_string_literal: true
2
+
3
+ json.partial!('spree/api/payments/source_views/gateway', payment_source: payment_source)