solidus_stripe 4.4.1 → 5.0.0.alpha.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.
- checksums.yaml +4 -4
- data/.circleci/config.yml +92 -52
- data/.gitignore +3 -0
- data/.rubocop.yml +94 -4
- data/.yardopts +1 -0
- data/Gemfile +10 -30
- data/LICENSE +2 -2
- data/Procfile.dev +3 -0
- data/README.md +145 -215
- data/Rakefile +5 -44
- data/app/assets/javascripts/spree/backend/solidus_stripe.js +2 -0
- data/app/assets/stylesheets/spree/backend/solidus_stripe.css +4 -0
- data/app/controllers/solidus_stripe/intents_controller.rb +36 -52
- data/app/controllers/solidus_stripe/webhooks_controller.rb +28 -0
- data/app/models/concerns/solidus_stripe/log_entries.rb +31 -0
- data/app/models/solidus_stripe/customer.rb +21 -0
- data/app/models/solidus_stripe/gateway.rb +231 -0
- data/app/models/solidus_stripe/payment_intent.rb +111 -0
- data/app/models/solidus_stripe/payment_method.rb +106 -0
- data/app/models/solidus_stripe/payment_source.rb +31 -0
- data/app/models/solidus_stripe/slug_entry.rb +20 -0
- data/app/models/solidus_stripe.rb +7 -0
- data/app/subscribers/solidus_stripe/webhook/charge_subscriber.rb +28 -0
- data/app/subscribers/solidus_stripe/webhook/payment_intent_subscriber.rb +112 -0
- data/app/views/spree/admin/payments/source_forms/_stripe.html.erb +29 -0
- data/app/views/spree/admin/payments/source_forms/existing_payment/_stripe.html.erb +14 -0
- data/app/views/spree/admin/payments/source_forms/existing_payment/stripe/_card.html.erb +8 -0
- data/app/views/spree/admin/payments/source_forms/existing_payment/stripe/_default.html.erb +7 -0
- data/app/views/spree/admin/payments/source_views/_stripe.html.erb +15 -0
- data/app/views/spree/api/payments/source_views/_stripe.json.jbuilder +8 -0
- data/bin/dev +13 -0
- data/bin/dummy-app +29 -0
- data/bin/rails +38 -3
- data/bin/rails-dummy-app +3 -0
- data/bin/rails-engine +1 -11
- data/bin/rails-new +55 -0
- data/bin/rails-sandbox +1 -14
- data/bin/rspec +10 -0
- data/bin/sandbox +12 -74
- data/bin/setup +1 -0
- data/bin/update-migrations +56 -0
- data/codecov.yml +12 -0
- data/config/locales/en.yml +16 -1
- data/config/routes.rb +5 -11
- data/coverage.rb +42 -0
- data/db/migrate/20230109183332_create_solidus_stripe_payment_sources.rb +10 -0
- data/db/migrate/20230303154931_create_solidus_stripe_setup_intent.rb +10 -0
- data/db/migrate/20230306105520_create_solidus_stripe_payment_intents.rb +10 -0
- data/db/migrate/20230308122414_create_solidus_stripe_webhook_endpoints.rb +10 -0
- data/db/migrate/20230310152615_add_payment_method_reference_to_stripe_intents.rb +6 -0
- data/db/migrate/20230310171444_normalize_stripe_intent_id_attributes.rb +6 -0
- data/db/migrate/20230313150008_create_solidus_stripe_customers.rb +16 -0
- data/db/migrate/20230323154931_drop_solidus_stripe_setup_intent.rb +13 -0
- data/db/migrate/20230403094916_rename_webhook_endpoint_to_payment_method_slug_entries.rb +5 -0
- data/db/seeds.rb +6 -24
- data/lib/generators/solidus_stripe/install/install_generator.rb +121 -14
- data/lib/generators/solidus_stripe/install/templates/app/assets/stylesheets/spree/frontend/solidus_stripe.css +13 -0
- data/lib/generators/solidus_stripe/install/templates/app/javascript/controllers/solidus_stripe_confirm_controller.js +39 -0
- data/lib/generators/solidus_stripe/install/templates/app/javascript/controllers/solidus_stripe_payment_controller.js +89 -0
- data/lib/generators/solidus_stripe/install/templates/app/views/checkouts/existing_payment/_stripe.html.erb +16 -0
- data/lib/generators/solidus_stripe/install/templates/app/views/checkouts/existing_payment/stripe/_card.html.erb +8 -0
- data/lib/generators/solidus_stripe/install/templates/app/views/checkouts/existing_payment/stripe/_default.html.erb +7 -0
- data/lib/generators/solidus_stripe/install/templates/app/views/checkouts/payment/_stripe.html.erb +39 -0
- data/lib/generators/solidus_stripe/install/templates/app/views/orders/payment_info/_stripe.html.erb +20 -0
- data/lib/generators/solidus_stripe/install/templates/config/initializers/solidus_stripe.rb +31 -0
- data/lib/solidus_stripe/configuration.rb +24 -3
- data/lib/solidus_stripe/engine.rb +19 -6
- data/lib/solidus_stripe/money_to_stripe_amount_converter.rb +109 -0
- data/lib/solidus_stripe/refunds_synchronizer.rb +96 -0
- data/lib/solidus_stripe/seeds.rb +19 -0
- data/lib/solidus_stripe/testing_support/factories.rb +153 -0
- data/lib/solidus_stripe/version.rb +1 -1
- data/lib/solidus_stripe/webhook/event.rb +90 -0
- data/lib/solidus_stripe.rb +0 -2
- data/solidus_stripe.gemspec +29 -6
- data/spec/lib/solidus_stripe/configuration_spec.rb +21 -0
- data/spec/lib/solidus_stripe/money_to_stripe_amount_converter_spec.rb +133 -0
- data/spec/lib/solidus_stripe/refunds_synchronizer_spec.rb +238 -0
- data/spec/lib/solidus_stripe/seeds_spec.rb +43 -0
- data/spec/lib/solidus_stripe/webhook/event_spec.rb +134 -0
- data/spec/models/concerns/solidus_stripe/log_entries_spec.rb +54 -0
- data/spec/models/solidus_stripe/customer_spec.rb +47 -0
- data/spec/models/solidus_stripe/gateway_spec.rb +283 -0
- data/spec/models/solidus_stripe/payment_intent_spec.rb +17 -0
- data/spec/models/solidus_stripe/payment_method_spec.rb +137 -0
- data/spec/models/solidus_stripe/payment_source_spec.rb +25 -0
- data/spec/requests/solidus_stripe/intents_controller_spec.rb +29 -0
- data/spec/requests/solidus_stripe/webhooks_controller/charge/refunded_spec.rb +31 -0
- data/spec/requests/solidus_stripe/webhooks_controller/payment_intent/canceled_spec.rb +23 -0
- data/spec/requests/solidus_stripe/webhooks_controller/payment_intent/payment_failed_spec.rb +23 -0
- data/spec/requests/solidus_stripe/webhooks_controller/payment_intent/succeeded_spec.rb +29 -0
- data/spec/requests/solidus_stripe/webhooks_controller_spec.rb +52 -0
- data/spec/solidus_stripe_spec_helper.rb +10 -0
- data/spec/subscribers/solidus_stripe/webhook/charge_subscriber_spec.rb +33 -0
- data/spec/subscribers/solidus_stripe/webhook/payment_intent_subscriber_spec.rb +297 -0
- data/spec/support/solidus_stripe/backend_test_helper.rb +210 -0
- data/spec/support/solidus_stripe/checkout_test_helper.rb +339 -0
- data/spec/support/solidus_stripe/factories.rb +5 -0
- data/spec/support/solidus_stripe/webhook/data_fixtures.rb +106 -0
- data/spec/support/solidus_stripe/webhook/event_with_context_factory.rb +82 -0
- data/spec/support/solidus_stripe/webhook/request_helper.rb +32 -0
- data/spec/system/backend/solidus_stripe/orders/payments_spec.rb +119 -0
- data/spec/system/frontend/.keep +0 -0
- data/spec/system/frontend/solidus_stripe/checkout_spec.rb +187 -0
- data/tmp/.keep +0 -0
- metadata +202 -78
- data/.rubocop_todo.yml +0 -298
- data/.travis.yml +0 -28
- data/app/assets/javascripts/spree/frontend/solidus_stripe/stripe-cart-page-checkout.js +0 -122
- data/app/assets/javascripts/spree/frontend/solidus_stripe/stripe-elements.js +0 -148
- data/app/assets/javascripts/spree/frontend/solidus_stripe/stripe-init.js +0 -20
- data/app/assets/javascripts/spree/frontend/solidus_stripe/stripe-payment-intents.js +0 -84
- data/app/assets/javascripts/spree/frontend/solidus_stripe/stripe-payment-request-button-shared.js +0 -160
- data/app/assets/javascripts/spree/frontend/solidus_stripe/stripe-payment.js +0 -16
- data/app/assets/javascripts/spree/frontend/solidus_stripe.js +0 -6
- data/app/controllers/solidus_stripe/payment_request_controller.rb +0 -52
- data/app/controllers/spree/stripe_controller.rb +0 -13
- data/app/decorators/models/spree/order_update_attributes_decorator.rb +0 -39
- data/app/decorators/models/spree/payment_decorator.rb +0 -11
- data/app/decorators/models/spree/refund_decorator.rb +0 -9
- data/app/models/solidus_stripe/address_from_params_service.rb +0 -72
- data/app/models/solidus_stripe/create_intents_payment_service.rb +0 -114
- data/app/models/solidus_stripe/prepare_order_for_payment_service.rb +0 -46
- data/app/models/solidus_stripe/shipping_rates_service.rb +0 -46
- data/app/models/spree/payment_method/stripe_credit_card.rb +0 -230
- data/bin/r +0 -13
- data/bin/sandbox_rails +0 -18
- data/db/migrate/20181010123508_update_stripe_payment_method_type_to_credit_card.rb +0 -21
- data/lib/assets/stylesheets/spree/frontend/solidus_stripe.scss +0 -11
- data/lib/solidus_stripe/testing_support/card_input_helper.rb +0 -34
- data/lib/tasks/solidus_stripe/db/seed.rake +0 -14
- data/lib/views/api/spree/api/payments/source_views/_stripe.json.jbuilder +0 -3
- data/lib/views/backend/spree/admin/log_entries/_stripe.html.erb +0 -28
- data/lib/views/backend/spree/admin/payments/source_forms/_stripe.html.erb +0 -1
- data/lib/views/backend/spree/admin/payments/source_views/_stripe.html.erb +0 -1
- data/lib/views/frontend/spree/checkout/existing_payment/_stripe.html.erb +0 -1
- data/lib/views/frontend/spree/checkout/payment/_stripe.html.erb +0 -8
- data/lib/views/frontend/spree/checkout/payment/v2/_javascript.html.erb +0 -78
- data/lib/views/frontend/spree/checkout/payment/v3/_elements.html.erb +0 -1
- data/lib/views/frontend/spree/checkout/payment/v3/_form_elements.html.erb +0 -40
- data/lib/views/frontend/spree/checkout/payment/v3/_intents.html.erb +0 -1
- data/lib/views/frontend/spree/checkout/payment/v3/_stripe.html.erb +0 -2
- data/lib/views/frontend/spree/orders/_stripe_payment_request_button.html.erb +0 -14
- data/spec/features/stripe_checkout_spec.rb +0 -486
- data/spec/models/solidus_stripe/address_from_params_service_spec.rb +0 -87
- data/spec/models/solidus_stripe/create_intents_payment_service_spec.rb +0 -127
- data/spec/models/solidus_stripe/prepare_order_for_payment_service_spec.rb +0 -65
- data/spec/models/solidus_stripe/shipping_rates_service_spec.rb +0 -54
- data/spec/models/spree/payment_method/stripe_credit_card_spec.rb +0 -354
- data/spec/requests/payment_requests_spec.rb +0 -152
- data/spec/solidus_frontend_app_template.rb +0 -17
- data/spec/spec_helper.rb +0 -37
- data/spec/support/solidus_address_helper.rb +0 -15
data/README.md
CHANGED
|
@@ -1,260 +1,200 @@
|
|
|
1
|
+
## 🚧 **WARNING** 🚧 Work In Progress
|
|
2
|
+
|
|
3
|
+
You're looking at the source for `solidus_stripe` v5, which will only support the **starter frontend**
|
|
4
|
+
but at the moment **it is not ready to be used**.
|
|
5
|
+
|
|
6
|
+
Please use [`solidus_stripe` v4 on the corresponding branch](https://github.com/solidusio/solidus_stripe/tree/v4).
|
|
7
|
+
|
|
8
|
+
## 🚧 **WARNING** 🚧 Supporting `solidus_frontend`
|
|
9
|
+
|
|
10
|
+
If you need support for `solidus_frontend` please add `< 5` as a version requirement in your gemfile:
|
|
11
|
+
`gem 'solidus_stripe', '< 5'`
|
|
12
|
+
or if your tracking the github version please switch to the `v4` branch:
|
|
13
|
+
`gem 'solidus_stripe', git: 'https://github.com/solidusio/solidus_stripe.git', branch: 'v4'`
|
|
14
|
+
|
|
15
|
+
---
|
|
16
|
+
|
|
1
17
|
# Solidus Stripe
|
|
2
18
|
|
|
3
19
|
[](https://circleci.com/gh/solidusio/solidus_stripe)
|
|
4
20
|
[](https://codecov.io/gh/solidusio/solidus_stripe)
|
|
5
21
|
|
|
6
|
-
|
|
22
|
+
<!-- Explain what your extension does. -->
|
|
7
23
|
|
|
8
24
|
## Installation
|
|
9
25
|
|
|
26
|
+
Add solidus_stripe to your Gemfile:
|
|
10
27
|
|
|
11
|
-
|
|
28
|
+
```ruby
|
|
29
|
+
gem 'solidus_stripe'
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
Bundle your dependencies and run the installation generator:
|
|
12
33
|
|
|
13
34
|
```shell
|
|
14
|
-
|
|
15
|
-
bundle exec rails g solidus_stripe:install
|
|
35
|
+
bin/rails generate solidus_stripe:install
|
|
16
36
|
```
|
|
17
37
|
|
|
18
|
-
|
|
19
|
-
-----
|
|
38
|
+
### Webhooks
|
|
20
39
|
|
|
21
|
-
|
|
22
|
-
You can now create a new payment method that uses Stripe by selecting
|
|
23
|
-
`Stripe credit card` under Type in the New Payment Method form and saving.
|
|
24
|
-
The Stripe payment method's extra fields will be now shown in the form.
|
|
40
|
+
This library makes use of some [Stripe webhooks](https://stripe.com/docs/webhooks).
|
|
25
41
|
|
|
26
|
-
|
|
42
|
+
Every Solidus Stripe payment method you create will get a slug assigned. You
|
|
43
|
+
need to append it to a generic webhook endpoint to get the URL for that payment
|
|
44
|
+
method. For example:
|
|
27
45
|
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
**Configure via static configuration**
|
|
46
|
+
```ruby
|
|
47
|
+
SolidusStripe::PaymentMethod.last.slug
|
|
48
|
+
# "365a8435cd11300e87de864c149516e0"
|
|
49
|
+
```
|
|
33
50
|
|
|
34
|
-
|
|
35
|
-
|
|
51
|
+
For the above example, and if you mounted the `SolidusStripe::Engine` routes on
|
|
52
|
+
the default scope, the webhook endpoint would look like:
|
|
36
53
|
|
|
37
|
-
```
|
|
38
|
-
|
|
39
|
-
Rails.application.config.to_prepare do
|
|
40
|
-
Spree::Config.static_model_preferences.add(
|
|
41
|
-
Spree::PaymentMethod::StripeCreditCard,
|
|
42
|
-
'stripe_env_credentials',
|
|
43
|
-
secret_key: ENV['STRIPE_SECRET_KEY'],
|
|
44
|
-
publishable_key: ENV['STRIPE_PUBLISHABLE_KEY'],
|
|
45
|
-
stripe_country: 'US',
|
|
46
|
-
v3_elements: false,
|
|
47
|
-
v3_intents: false
|
|
48
|
-
)
|
|
49
|
-
end
|
|
54
|
+
```
|
|
55
|
+
/solidus_stripe/webhooks/365a8435cd11300e87de864c149516e0
|
|
50
56
|
```
|
|
51
57
|
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
Stripe payments.
|
|
58
|
+
Besides, you also need to configure the webhook signing secret for that payment
|
|
59
|
+
method. You can do that through the `webhook_endpoint_signing_secret`
|
|
60
|
+
preference on the payment method.
|
|
56
61
|
|
|
62
|
+
Before going to production, you'll need to [register the webhook endpoint with
|
|
63
|
+
Stripe](https://stripe.com/docs/webhooks/go-live), and make sure to subscribe
|
|
64
|
+
to the events listed in [the `SolidusStripe::Webhook::Event::CORE`
|
|
65
|
+
constant](https://github.com/solidusio/solidus_stripe/blob/master/lib/solidus_stripe/webhook/event.rb).
|
|
57
66
|
|
|
58
|
-
|
|
59
|
-
|
|
67
|
+
On development, you can
|
|
68
|
+
[test webhooks by using Stripe CLI](https://stripe.com/docs/webhooks/test).
|
|
60
69
|
|
|
61
|
-
|
|
62
|
-
to change the `v3_intents` preference from the code above to true.
|
|
70
|
+
## Usage
|
|
63
71
|
|
|
64
|
-
|
|
65
|
-
Stripe payment request button API, you only need to set the `stripe_country`
|
|
66
|
-
preference, which represents the two-letter country code of your Stripe
|
|
67
|
-
account. Conversely, if you need to disable the button you can simply remove
|
|
68
|
-
the `stripe_country` preference.
|
|
72
|
+
### Showing reusable sources in the checkout
|
|
69
73
|
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
for further instructions on how to make this work properly.
|
|
74
|
+
When saving stripe payment methods for future usage the checkout requires
|
|
75
|
+
a partial for each supported payment method type.
|
|
73
76
|
|
|
74
|
-
|
|
75
|
-
payment request button API on the store payment page:
|
|
77
|
+
For the full list of types see: https://stripe.com/docs/api/payment_methods/object#payment_method_object-type.
|
|
76
78
|
|
|
79
|
+
The extension will only install a partial for the `card` type, located in `app/views/checkouts/existing_payment/stripe/_card.html.erb`,
|
|
80
|
+
and fall back to a `default` partial otherwise (see `app/views/checkouts/existing_payment/stripe/_default.html.erb`).
|
|
77
81
|
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
config.static_model_preferences.add(
|
|
83
|
-
Spree::PaymentMethod::StripeCreditCard,
|
|
84
|
-
'stripe_env_credentials',
|
|
85
|
-
secret_key: ENV['STRIPE_SECRET_KEY'],
|
|
86
|
-
publishable_key: ENV['STRIPE_PUBLISHABLE_KEY'],
|
|
87
|
-
stripe_country: 'US',
|
|
88
|
-
v3_elements: false,
|
|
89
|
-
v3_intents: true
|
|
90
|
-
)
|
|
91
|
-
end
|
|
92
|
-
```
|
|
82
|
+
As an example, in order to show a wallet source connected to a
|
|
83
|
+
[SEPA Debit payment method](https://stripe.com/docs/api/payment_methods/object#payment_method_object-sepa_debit)
|
|
84
|
+
the following partial should be added:
|
|
93
85
|
|
|
94
|
-
|
|
95
|
-
different than when using the old V2 API or Elements. It's advisable that all
|
|
96
|
-
Payment Intents charges are captured only by using the Solidus backend, as it is
|
|
97
|
-
the final source of truth in regards of Solidus orders payments.
|
|
98
|
-
|
|
99
|
-
A Payment Intent is created as soon as the customer enters their credit card
|
|
100
|
-
data. A tentative charge will be created on Stripe, easily recognizable by its
|
|
101
|
-
description: `Solidus Order ID: R987654321 (pending)`. As soon as the credit
|
|
102
|
-
card is confirmed (ie. when the customer passes the 3DSecure authorization, when
|
|
103
|
-
required) then the charge description gets updated to include the Solidus payment
|
|
104
|
-
number: `Solidus Order ID: R987654321-Z4VYUDB3`.
|
|
105
|
-
|
|
106
|
-
These charges are created `uncaptured` and will need to be captured in Solidus
|
|
107
|
-
backend later, after the customer confirms the order. If the customer never
|
|
108
|
-
completes the checkout, that charge must remain uncaptured. If the customer
|
|
109
|
-
decides to change their payment method after creating a Payment Request, then
|
|
110
|
-
that Payment Request charge will be canceled.
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
Apple Pay and Google Pay
|
|
114
|
-
-----------------------
|
|
115
|
-
|
|
116
|
-
The Payment Intents API now supports also Apple Pay and Google Pay via
|
|
117
|
-
the [payment request button API](https://stripe.com/docs/stripe-js/elements/payment-request-button).
|
|
118
|
-
Check the Payment Intents section for setup details. Also, please
|
|
119
|
-
refer to the official Stripe documentation for configuring your
|
|
120
|
-
Stripe account to receive payments via Apple Pay.
|
|
121
|
-
|
|
122
|
-
It's possible to pay with Apple Pay and Google Pay directly from the cart
|
|
123
|
-
page. The functionality is self-contained in the view partial
|
|
124
|
-
`_stripe_payment_request_button.html.erb`. In order to use it, you need
|
|
125
|
-
to render that partial in the `orders#edit` frontend page, and pass it the
|
|
126
|
-
payment method configured for Stripe via the local variable
|
|
127
|
-
`cart_checkout_payment_method`:
|
|
86
|
+
`app/views/checkouts/existing_payment/stripe/_sepa_debit.html.erb`
|
|
128
87
|
|
|
129
|
-
```
|
|
130
|
-
|
|
88
|
+
```erb
|
|
89
|
+
<% sepa_debit = stripe_payment_method.sepa_debit %>
|
|
90
|
+
🏦 <%= sepa_debit.bank_code %> / <%= sepa_debit.branch_code %><br>
|
|
91
|
+
IBAN: **** **** **** **** **** <%= sepa_debit.last4 %>
|
|
131
92
|
```
|
|
132
93
|
|
|
133
|
-
|
|
134
|
-
country config value, for example) apply also for this feature.
|
|
135
|
-
|
|
136
|
-
Customizing the V3 API javascript
|
|
137
|
-
---------------------------------
|
|
138
|
-
|
|
139
|
-
Stripe V3 JS code is now managed via Sprockets. If you need to customize the JS,
|
|
140
|
-
you can simply override or/and add new methods to the relevant object prototype.
|
|
141
|
-
Make sure you load your customizations after Stripe initalization code from
|
|
142
|
-
`spree/frontend/solidus_stripe`.
|
|
143
|
-
|
|
144
|
-
For example, the following code adds a callback method in order to print a debug
|
|
145
|
-
message on the console:
|
|
146
|
-
|
|
147
|
-
```js
|
|
148
|
-
SolidusStripe.CartPageCheckout.prototype.onPrButtonMounted = function(id, result) {
|
|
149
|
-
if (result) {
|
|
150
|
-
$('#' + id).parent().show();
|
|
151
|
-
console.log('Payment request button is now mounted on element with id #' + id);
|
|
152
|
-
} else {
|
|
153
|
-
console.log('Payment request button failed initalization.');
|
|
154
|
-
}
|
|
155
|
-
}
|
|
156
|
-
```
|
|
94
|
+
### Showing reusable sources in the admin interface
|
|
157
95
|
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
### Styling input fields
|
|
162
|
-
|
|
163
|
-
The default style this gem provides for Stripe Elements input fields is defined in `SolidusStripe.Elements.prototype.baseStyle`. You can override this method to return your own custom style (make sure it returns a valid [Stripe Style](https://stripe.com/docs/js/appendix/style)
|
|
164
|
-
object):
|
|
165
|
-
|
|
166
|
-
```js
|
|
167
|
-
SolidusStripe.Elements.prototype.baseStyle = function () {
|
|
168
|
-
return {
|
|
169
|
-
base: {
|
|
170
|
-
iconColor: '#c4f0ff',
|
|
171
|
-
color: '#fff',
|
|
172
|
-
fontWeight: 500,
|
|
173
|
-
fontFamily: 'Roboto, Open Sans, Segoe UI, sans-serif',
|
|
174
|
-
fontSize: '16px',
|
|
175
|
-
fontSmoothing: 'antialiased',
|
|
176
|
-
':-webkit-autofill': {
|
|
177
|
-
color: '#fce883',
|
|
178
|
-
},
|
|
179
|
-
'::placeholder': {
|
|
180
|
-
color: '#87BBFD',
|
|
181
|
-
},
|
|
182
|
-
},
|
|
183
|
-
invalid: {
|
|
184
|
-
iconColor: '#FFC7EE',
|
|
185
|
-
color: '#FFC7EE',
|
|
186
|
-
}
|
|
187
|
-
}
|
|
188
|
-
};
|
|
189
|
-
```
|
|
96
|
+
Refer to the previous section for information on how to set up a new payment method type.
|
|
97
|
+
However, it's important to note that if you have to display a wallet source connected to a
|
|
98
|
+
Stripe Payment Method other than "card" on the admin interface, you must include the partial in:
|
|
190
99
|
|
|
191
|
-
|
|
100
|
+
`app/views/spree/admin/payments/source_forms/existing_payment/stripe/`
|
|
192
101
|
|
|
193
|
-
|
|
194
|
-
.StripeElement {
|
|
195
|
-
border: 1px solid transparent;
|
|
196
|
-
}
|
|
102
|
+
### Custom webhooks
|
|
197
103
|
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
}
|
|
104
|
+
You can also use [Stripe webhooks](https://stripe.com/docs/webhooks) to trigger
|
|
105
|
+
custom actions in your application.
|
|
201
106
|
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
}
|
|
107
|
+
First, you need to register the event you want to listen to, both [in
|
|
108
|
+
Stripe](https://stripe.com/docs/webhooks/go-live) and in your application:
|
|
205
109
|
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
110
|
+
```ruby
|
|
111
|
+
# config/initializers/solidus_stripe.rb
|
|
112
|
+
SolidusStripe.configure do |config|
|
|
113
|
+
config.webhook_events = %i[charge.succeeded]
|
|
114
|
+
end
|
|
209
115
|
```
|
|
210
116
|
|
|
211
|
-
|
|
117
|
+
That will register a new `:"stripe.charge.succeeded"` event in the [Solidus
|
|
118
|
+
bus](https://guides.solidus.io/customization/subscribing-to-events). The
|
|
119
|
+
Solidus event will be published whenever a matching incoming webhook event is
|
|
120
|
+
received. You can subscribe to it as regular:
|
|
212
121
|
|
|
213
|
-
|
|
122
|
+
```ruby
|
|
123
|
+
# app/subscribers/update_account_balance_subscriber.rb
|
|
124
|
+
class UpdateAccountBalanceSubscriber
|
|
125
|
+
include Omnes::Subscriber
|
|
214
126
|
|
|
215
|
-
|
|
216
|
-
* `SolidusStripe.Elements.prototype.cardExpiryElementOptions`
|
|
217
|
-
* `SolidusStripe.Elements.prototype.cardCvcElementOptions`
|
|
127
|
+
handle :"stripe.charge.succeeded", with: :call
|
|
218
128
|
|
|
219
|
-
|
|
129
|
+
def call(event)
|
|
130
|
+
# ...
|
|
131
|
+
end
|
|
132
|
+
end
|
|
220
133
|
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
placeholder: "I'm a custom placeholder!"
|
|
227
|
-
}
|
|
228
|
-
}
|
|
134
|
+
# config/initializers/solidus_stripe.rb
|
|
135
|
+
# ...
|
|
136
|
+
Rails.application.config.to_prepare do
|
|
137
|
+
UpdateAccountBalanceSubscriber.new.subscribe_to(Spree::Bus)
|
|
138
|
+
end
|
|
229
139
|
```
|
|
230
140
|
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
141
|
+
The passed event object is a thin wrapper around the [Stripe
|
|
142
|
+
event](https://www.rubydoc.info/gems/stripe/Stripe/Event) and the associated
|
|
143
|
+
Solidus Stripe payment method. It will delegate all unknown methods to the
|
|
144
|
+
underlying stripe event object. It can also be used in async [
|
|
145
|
+
adapters](https://github.com/nebulab/omnes#adapters), which is recommended as
|
|
146
|
+
otherwise the response to Stripe will be delayed until subscribers are done.
|
|
234
147
|
|
|
235
|
-
|
|
148
|
+
You can also configure the signature verification tolerance in seconds (it
|
|
149
|
+
defaults to the [same value as Stripe
|
|
150
|
+
default](https://stripe.com/docs/webhooks/signatures#replay-attacks)):
|
|
236
151
|
|
|
237
|
-
```
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
{
|
|
243
|
-
cssSrc: 'https://fonts.googleapis.com/css?family=Source+Sans+Pro:400,600'
|
|
244
|
-
}
|
|
245
|
-
]
|
|
246
|
-
};
|
|
247
|
-
};
|
|
152
|
+
```ruby
|
|
153
|
+
# config/initializers/solidus_stripe.rb
|
|
154
|
+
SolidusStripe.configure do |config|
|
|
155
|
+
config.webhook_signature_tolerance = 150
|
|
156
|
+
end
|
|
248
157
|
```
|
|
249
158
|
|
|
250
|
-
##
|
|
159
|
+
## Implementation
|
|
160
|
+
|
|
161
|
+
### Payment state-machine vs. PaymentIntent statuses
|
|
162
|
+
|
|
163
|
+
When compared to the Payment state machine, Stripe payment intents have different set of states and transitions.
|
|
164
|
+
The most important difference is that on Stripe a failure is not a final state, rather just a way to start over.
|
|
165
|
+
|
|
166
|
+
In order to map these concepts SolidusStripe will match states in a slightly unexpected way, as shown below.
|
|
167
|
+
|
|
168
|
+
| Stripe PaymentIntent Status | Solidus Payment State |
|
|
169
|
+
| --------------------------- | --------------------- |
|
|
170
|
+
| requires_payment_method | checkout |
|
|
171
|
+
| requires_action | checkout |
|
|
172
|
+
| processing | checkout |
|
|
173
|
+
| requires_confirmation | checkout |
|
|
174
|
+
| requires_capture | pending |
|
|
175
|
+
| succeeded | completed |
|
|
176
|
+
|
|
177
|
+
Reference:
|
|
251
178
|
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
that describes how to handle this migration.
|
|
179
|
+
- https://stripe.com/docs/payments/intents?intent=payment
|
|
180
|
+
- https://github.com/solidusio/solidus/blob/master/core/lib/spree/core/state_machines/payment.rb
|
|
255
181
|
|
|
256
182
|
## Development
|
|
257
183
|
|
|
184
|
+
Retrieve your API Key and Publishable Key from your [Stripe testing dashboard](https://stripe.com/docs/testing). You can
|
|
185
|
+
get your webhook signing secret executing the `stripe listen` command.
|
|
186
|
+
|
|
187
|
+
Set `SOLIDUS_STRIPE_API_KEY`, `SOLIDUS_STRIPE_PUBLISHABLE_KEY` and `SOLIDUS_STRIPE_WEBHOOK_SIGNING_SECRET` environment
|
|
188
|
+
variables (e.g. via `direnv`), this will trigger the default initializer to create a static preference for SolidusStripe.
|
|
189
|
+
|
|
190
|
+
Run `bin/dev` to start both the sandbox rail server and the file watcher through Foreman. That will update the sandbox whenever
|
|
191
|
+
a file is changed. When using `bin/dev` you can safely add `debugger` statements, even if Foreman won't provide a TTY, by connecting
|
|
192
|
+
to the debugger session through `rdbg --attach` from another terminal.
|
|
193
|
+
|
|
194
|
+
Visit `/admin/payments` and create a new Stripe payment using the static preferences.
|
|
195
|
+
|
|
196
|
+
See the [Webhooks section](#webhooks) to learn how to configure Stripe webhooks.
|
|
197
|
+
|
|
258
198
|
### Testing the extension
|
|
259
199
|
|
|
260
200
|
First bundle your dependencies, then run `bin/rake`. `bin/rake` will default to building the dummy
|
|
@@ -301,21 +241,11 @@ $ bin/rails server
|
|
|
301
241
|
Use Ctrl-C to stop
|
|
302
242
|
```
|
|
303
243
|
|
|
304
|
-
### Updating the changelog
|
|
305
|
-
|
|
306
|
-
Before and after releases the changelog should be updated to reflect the up-to-date status of
|
|
307
|
-
the project:
|
|
308
|
-
|
|
309
|
-
```shell
|
|
310
|
-
bin/rake changelog
|
|
311
|
-
git add CHANGELOG.md
|
|
312
|
-
git commit -m "Update the changelog"
|
|
313
|
-
```
|
|
314
|
-
|
|
315
244
|
### Releasing new versions
|
|
316
245
|
|
|
317
246
|
Please refer to the dedicated [page](https://github.com/solidusio/solidus/wiki/How-to-release-extensions) on Solidus wiki.
|
|
318
247
|
|
|
319
248
|
## License
|
|
249
|
+
|
|
320
250
|
Copyright (c) 2014 Spree Commerce Inc., released under the New BSD License
|
|
321
|
-
Copyright (c) 2021 Solidus Team, released under the New BSD License
|
|
251
|
+
Copyright (c) 2021 Solidus Team, released under the New BSD License.
|
data/Rakefile
CHANGED
|
@@ -1,49 +1,10 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
-
# Don't build a dummy app with solidus_bolt enabled
|
|
4
|
-
ENV['SKIP_SOLIDUS_BOLT'] = 'true'
|
|
5
|
-
|
|
6
|
-
require 'solidus_dev_support/rake_tasks'
|
|
7
|
-
SolidusDevSupport::RakeTasks.install
|
|
8
|
-
|
|
9
3
|
require 'bundler/gem_tasks'
|
|
10
4
|
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
require 'solidus_stripe'
|
|
18
|
-
|
|
19
|
-
Rails.env = ENV["RAILS_ENV"] = 'test'
|
|
20
|
-
|
|
21
|
-
Spree::DummyGenerator.start ["--lib-name=solidus_stripe"]
|
|
22
|
-
|
|
23
|
-
# While the dummy app is generated the current directory
|
|
24
|
-
# within ruby is changed to that of the dummy app.
|
|
25
|
-
sh({
|
|
26
|
-
'FRONTEND' => ENV['FRONTEND'] || "#{__dir__}/spec/solidus_frontend_app_template.rb",
|
|
27
|
-
}, [
|
|
28
|
-
'bin/rails',
|
|
29
|
-
'generate',
|
|
30
|
-
'solidus:install',
|
|
31
|
-
Dir.pwd, # use the current dir as Rails.root
|
|
32
|
-
"--auto-accept",
|
|
33
|
-
"--authentication=none",
|
|
34
|
-
"--payment-method=none",
|
|
35
|
-
"--migrate=false",
|
|
36
|
-
"--seed=false",
|
|
37
|
-
"--sample=false",
|
|
38
|
-
"--user-class=Spree::LegacyUser",
|
|
39
|
-
].shelljoin)
|
|
40
|
-
|
|
41
|
-
puts "Setting up dummy database..."
|
|
42
|
-
sh "bin/rails db:environment:set RAILS_ENV=test"
|
|
43
|
-
sh "bin/rails db:drop db:create db:migrate VERBOSE=false RAILS_ENV=test"
|
|
44
|
-
|
|
45
|
-
puts 'Running extension installation generator...'
|
|
46
|
-
sh "bin/rails generate solidus_stripe:install --auto-run-migrations"
|
|
5
|
+
task :default do
|
|
6
|
+
require 'bundler'
|
|
7
|
+
Bundler.with_unbundled_env do
|
|
8
|
+
sh 'bin/rspec'
|
|
9
|
+
end
|
|
47
10
|
end
|
|
48
|
-
|
|
49
|
-
task default: ['extension:specs']
|
|
@@ -1,66 +1,50 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
class IntentsController < Spree::BaseController
|
|
5
|
-
include Spree::Core::ControllerHelpers::Order
|
|
3
|
+
require 'stripe'
|
|
6
4
|
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
generate_payment_response
|
|
10
|
-
end
|
|
5
|
+
class SolidusStripe::IntentsController < Spree::BaseController
|
|
6
|
+
include Spree::Core::ControllerHelpers::Order
|
|
11
7
|
|
|
12
|
-
|
|
13
|
-
create_payment_service = SolidusStripe::CreateIntentsPaymentService.new(
|
|
14
|
-
params[:stripe_payment_intent_id],
|
|
15
|
-
stripe,
|
|
16
|
-
self
|
|
17
|
-
)
|
|
8
|
+
before_action :load_payment_method
|
|
18
9
|
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
render json: { error: "Could not create payment" }, status: :internal_server_error
|
|
23
|
-
end
|
|
10
|
+
def after_confirmation
|
|
11
|
+
unless params[:payment_intent]
|
|
12
|
+
return head :unprocessable_entity
|
|
24
13
|
end
|
|
25
14
|
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
@stripe ||= Spree::PaymentMethod::StripeCreditCard.find(params[:spree_payment_method_id])
|
|
15
|
+
unless current_order.confirm?
|
|
16
|
+
redirect_to main_app.checkout_state_path(current_order.state)
|
|
17
|
+
return
|
|
30
18
|
end
|
|
31
19
|
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
}
|
|
41
|
-
elsif response['status'] == 'requires_capture'
|
|
42
|
-
render json: {
|
|
43
|
-
success: true,
|
|
44
|
-
requires_capture: true,
|
|
45
|
-
stripe_payment_intent_id: response['id']
|
|
46
|
-
}
|
|
47
|
-
else
|
|
48
|
-
render json: { error: response['error']['message'] }, status: :internal_server_error
|
|
49
|
-
end
|
|
50
|
-
end
|
|
20
|
+
intent = SolidusStripe::PaymentIntent.find_by!(
|
|
21
|
+
payment_method: @payment_method,
|
|
22
|
+
order: current_order,
|
|
23
|
+
stripe_intent_id: params[:payment_intent],
|
|
24
|
+
)
|
|
25
|
+
|
|
26
|
+
if intent.process_payment
|
|
27
|
+
flash.notice = t('spree.order_processed_successfully')
|
|
51
28
|
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
confirmation_method: 'automatic',
|
|
59
|
-
capture_method: 'manual',
|
|
60
|
-
confirm: true,
|
|
61
|
-
setup_future_usage: 'off_session',
|
|
62
|
-
metadata: { order_id: current_order.id }
|
|
29
|
+
flash['order_completed'] = true
|
|
30
|
+
|
|
31
|
+
redirect_to(
|
|
32
|
+
spree_current_user ?
|
|
33
|
+
main_app.order_path(current_order) :
|
|
34
|
+
main_app.token_order_path(current_order, current_order.guest_token)
|
|
63
35
|
)
|
|
36
|
+
else
|
|
37
|
+
flash[:error] = params[:error_message] || t('spree.payment_processing_failed')
|
|
38
|
+
redirect_to(main_app.checkout_state_path(:payment))
|
|
64
39
|
end
|
|
65
40
|
end
|
|
41
|
+
|
|
42
|
+
private
|
|
43
|
+
|
|
44
|
+
def load_payment_method
|
|
45
|
+
@payment_method = current_order(create_order_if_necessary: true)
|
|
46
|
+
.available_payment_methods
|
|
47
|
+
.merge(SolidusStripe::PaymentMethod.with_slug(params[:slug]))
|
|
48
|
+
.first!
|
|
49
|
+
end
|
|
66
50
|
end
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "solidus_stripe/webhook/event"
|
|
4
|
+
require "stripe"
|
|
5
|
+
|
|
6
|
+
module SolidusStripe
|
|
7
|
+
class WebhooksController < Spree::BaseController
|
|
8
|
+
SIGNATURE_HEADER = "HTTP_STRIPE_SIGNATURE"
|
|
9
|
+
|
|
10
|
+
skip_before_action :verify_authenticity_token, only: :create
|
|
11
|
+
|
|
12
|
+
respond_to :json
|
|
13
|
+
|
|
14
|
+
def create
|
|
15
|
+
event = Webhook::Event.from_request(payload: request.body.read, signature_header: signature_header,
|
|
16
|
+
slug: params[:slug])
|
|
17
|
+
return head(:bad_request) unless event
|
|
18
|
+
|
|
19
|
+
Spree::Bus.publish(event) && head(:ok)
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
private
|
|
23
|
+
|
|
24
|
+
def signature_header
|
|
25
|
+
request.headers[SIGNATURE_HEADER]
|
|
26
|
+
end
|
|
27
|
+
end
|
|
28
|
+
end
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module SolidusStripe::LogEntries
|
|
4
|
+
extend ActiveSupport::Concern
|
|
5
|
+
extend self
|
|
6
|
+
|
|
7
|
+
# Builds an ActiveMerchant::Billing::Response
|
|
8
|
+
#
|
|
9
|
+
# @option [true,false] :success
|
|
10
|
+
# @option [String] :message
|
|
11
|
+
# @option [String] :response_code
|
|
12
|
+
# @option [#to_json] :data
|
|
13
|
+
#
|
|
14
|
+
# @return [return type] return description
|
|
15
|
+
def build_payment_log(success:, message:, response_code: nil, data: nil)
|
|
16
|
+
ActiveMerchant::Billing::Response.new(
|
|
17
|
+
success,
|
|
18
|
+
message,
|
|
19
|
+
{ 'data' => data.to_json },
|
|
20
|
+
{ authorization: response_code },
|
|
21
|
+
)
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
def payment_log(payment, **options)
|
|
25
|
+
payment.log_entries.create!(details: YAML.safe_dump(
|
|
26
|
+
build_payment_log(**options),
|
|
27
|
+
permitted_classes: Spree::LogEntry.permitted_classes,
|
|
28
|
+
aliases: Spree::Config.log_entry_allow_aliases,
|
|
29
|
+
))
|
|
30
|
+
end
|
|
31
|
+
end
|