solidus_stripe 2.0.0 → 2.1.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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 20cb6dc5a1a623991ffb0903a8135ef20993fa54858bf1f58c19eaf5fefdea35
4
- data.tar.gz: 823bc46c1d66e7f6a85a7c7b50bee7ffa978e3e0daaf4454a2b2d89130595f59
3
+ metadata.gz: b4105fb7ad047aa377a29ebc364dc19d861ce07e4bbcb264fb5494fcf9bbb8f1
4
+ data.tar.gz: 43fa8a0106162cd0c26f7ff1e6fc65da2547137d98a1e4650aff04d639daae7d
5
5
  SHA512:
6
- metadata.gz: e6820bf570104f254774f6504ebb7ce0a1d3ed8a9f35d0a09f2c38e9d00a41006f94d89ed774ecf8f9ddcb58d7947cfa12433bc03d11c6df603280094c744a4b
7
- data.tar.gz: e4ad550366c57a70990576c1c17257bea819b2a89154cdb6e4fa0cad1d1254d84ea716a72d18232b3102070b02b323f656c08437ad6df1d94c3358361961ff56
6
+ metadata.gz: 2c891474a71412e3a03443ece9b16be6e49a0e7c6c1f6b6ad69f56d09608976fdc816211e779ce45556cfbc573c380334a65f7747170a3071763cb65b768dad6
7
+ data.tar.gz: cf52ef3d344bb3335f795b6e708d1b35151b80159e6a52ced595c09b0339c47b85a2bbf89932d14ff8661b35a3cbd22fb8da0b1cebcb8a95736221e6645609e8
data/CHANGELOG.md CHANGED
@@ -1,8 +1,8 @@
1
1
  # Changelog
2
2
 
3
- ## [Unreleased](https://github.com/solidusio/solidus_stripe/tree/HEAD)
3
+ ## [v2.0.0](https://github.com/solidusio/solidus_stripe/tree/v2.0.0) (2020-03-03)
4
4
 
5
- [Full Changelog](https://github.com/solidusio/solidus_stripe/compare/v1.2.0...HEAD)
5
+ [Full Changelog](https://github.com/solidusio/solidus_stripe/compare/v1.2.0...v2.0.0)
6
6
 
7
7
  **Implemented enhancements:**
8
8
 
data/README.md CHANGED
@@ -73,10 +73,20 @@ Using Stripe Payment Intents API
73
73
  --------------------------------
74
74
 
75
75
  If you want to use the new SCA-ready Stripe Payment Intents API you need
76
- to change the `v3_intents` preference from the code above to true and,
77
- if you want to allow also Apple Pay and Google Pay payments, set the
78
- `stripe_country` preference, which represents the two-letter country
79
- code of your Stripe account:
76
+ to change the `v3_intents` preference from the code above to true.
77
+
78
+ Also, if you want to allow Apple Pay and Google Pay payments using the
79
+ Stripe payment request button API, you only need to set the `stripe_country`
80
+ preference, which represents the two-letter country code of your Stripe
81
+ account. Conversely, if you need to disable the button you can simply remove
82
+ the `stripe_country` preference.
83
+
84
+ Please refer to Stripe official
85
+ [documentation](https://stripe.com/docs/stripe-js/elements/payment-request-button)
86
+ for further instructions on how to make this work properly.
87
+
88
+ The following configuration will use both Payment Intents and the
89
+ payment request button API on the store payment page:
80
90
 
81
91
 
82
92
  ```ruby
@@ -120,8 +130,8 @@ payment method configured for Stripe via the local variable
120
130
  <%= render 'stripe_payment_request_button', cart_checkout_payment_method: Spree::PaymentMethod::StripeCreditCard.first %>
121
131
  ```
122
132
 
123
- Of course, rules stated in the paragraph above (remember to add the stripe country
124
- config value, for example) apply also for this payment method.
133
+ Of course, the rules listed in the Payment Intents section (adding the stripe
134
+ country config value, for example) apply also for this feature.
125
135
 
126
136
 
127
137
  Migrating from solidus_gateway
@@ -0,0 +1,88 @@
1
+ SolidusStripe.CartPageCheckout = function() {
2
+ SolidusStripe.Payment.call(this);
3
+
4
+ this.errorElement = $('#card-errors');
5
+ };
6
+
7
+ SolidusStripe.CartPageCheckout.prototype = Object.create(SolidusStripe.Payment.prototype);
8
+ Object.defineProperty(SolidusStripe.CartPageCheckout.prototype, 'constructor', {
9
+ value: SolidusStripe.CartPageCheckout,
10
+ enumerable: false,
11
+ writable: true
12
+ });
13
+
14
+ SolidusStripe.CartPageCheckout.prototype.init = function() {
15
+ this.setUpPaymentRequest({requestShipping: true});
16
+ };
17
+
18
+ SolidusStripe.CartPageCheckout.prototype.showError = function(error) {
19
+ this.errorElement.text(error).show();
20
+ };
21
+
22
+ SolidusStripe.CartPageCheckout.prototype.submitPayment = function(payment) {
23
+ var showError = this.showError.bind(this);
24
+
25
+ $.ajax({
26
+ url: $('[data-submit-url]').data('submit-url'),
27
+ headers: {
28
+ 'X-Spree-Order-Token': $('[data-order-token]').data('order-token')
29
+ },
30
+ type: 'PATCH',
31
+ contentType: 'application/json',
32
+ data: JSON.stringify(this.prTokenHandler(payment.paymentMethod)),
33
+ success: function() {
34
+ window.location = $('[data-complete-url]').data('complete-url');
35
+ },
36
+ error: function(xhr,status,error) {
37
+ showError(xhr.responseJSON.error);
38
+ }
39
+ });
40
+ };
41
+
42
+ SolidusStripe.CartPageCheckout.prototype.onPrPayment = function(result) {
43
+ var handleServerResponse = this.handleServerResponse.bind(this);
44
+
45
+ fetch('/stripe/update_order', {
46
+ method: 'POST',
47
+ headers: { 'Content-Type': 'application/json' },
48
+ body: JSON.stringify({
49
+ shipping_address: result.shippingAddress,
50
+ shipping_option: result.shippingOption,
51
+ email: result.payerEmail,
52
+ name: result.payerName,
53
+ authenticity_token: this.authToken
54
+ })
55
+ }).then(function(response) {
56
+ response.json().then(function(json) {
57
+ handleServerResponse(json, result);
58
+ })
59
+ });
60
+ };
61
+
62
+ SolidusStripe.CartPageCheckout.prototype.onPrButtonMounted = function(buttonId, success) {
63
+ var container = document.getElementById(buttonId).parentElement;
64
+
65
+ if (success) {
66
+ container.style.display = '';
67
+ } else {
68
+ container.style.display = 'none';
69
+ }
70
+ };
71
+
72
+ SolidusStripe.CartPageCheckout.prototype.prTokenHandler = function(token) {
73
+ return {
74
+ order: {
75
+ payments_attributes: [
76
+ {
77
+ payment_method_id: this.config.id,
78
+ source_attributes: {
79
+ gateway_payment_profile_id: token.id,
80
+ last_digits: token.card.last4,
81
+ month: token.card.exp_month,
82
+ year: token.card.exp_year
83
+ }
84
+ }
85
+ ]
86
+ }
87
+ }
88
+ };
@@ -0,0 +1,108 @@
1
+ SolidusStripe.Elements = function() {
2
+ SolidusStripe.Payment.call(this);
3
+
4
+ this.form = this.element.parents('form');
5
+ this.errorElement = this.form.find('#card-errors');
6
+ this.submitButton = this.form.find('input[type="submit"]');
7
+ };
8
+
9
+ SolidusStripe.Elements.prototype = Object.create(SolidusStripe.Payment.prototype);
10
+ Object.defineProperty(SolidusStripe.Elements.prototype, 'constructor', {
11
+ value: SolidusStripe.Elements,
12
+ enumerable: false,
13
+ writable: true
14
+ });
15
+
16
+ SolidusStripe.Elements.prototype.init = function() {
17
+ this.initElements();
18
+ };
19
+
20
+ SolidusStripe.Elements.prototype.initElements = function() {
21
+ var buildElements = function(elements) {
22
+ var style = {
23
+ base: {
24
+ color: 'black',
25
+ fontFamily: '"Helvetica Neue", Helvetica, sans-serif',
26
+ fontSmoothing: 'antialiased',
27
+ fontSize: '14px',
28
+ '::placeholder': {
29
+ color: 'silver'
30
+ }
31
+ },
32
+ invalid: {
33
+ color: 'red',
34
+ iconColor: 'red'
35
+ }
36
+ };
37
+
38
+ elements.create('cardExpiry', {style: style}).mount('#card_expiry');
39
+ elements.create('cardCvc', {style: style}).mount('#card_cvc');
40
+
41
+ var cardNumber = elements.create('cardNumber', {style: style});
42
+ cardNumber.mount('#card_number');
43
+
44
+ return cardNumber;
45
+ };
46
+
47
+ this.cardNumber = buildElements(this.elements);
48
+
49
+ var cardChange = function(event) {
50
+ if (event.error) {
51
+ this.showError(event.error.message);
52
+ } else {
53
+ this.errorElement.hide().text('');
54
+ }
55
+ };
56
+ this.cardNumber.addEventListener('change', cardChange.bind(this));
57
+ this.form.bind('submit', this.onFormSubmit.bind(this));
58
+ };
59
+
60
+ SolidusStripe.Elements.prototype.showError = function(error) {
61
+ var message = error.message || error;
62
+
63
+ this.errorElement.text(message).show();
64
+ this.submitButton.removeAttr('disabled').removeClass('disabled');
65
+ };
66
+
67
+ SolidusStripe.Elements.prototype.onFormSubmit = function(event) {
68
+ if (this.element.is(':visible')) {
69
+ event.preventDefault();
70
+
71
+ var onTokenCreate = function(result) {
72
+ if (result.error) {
73
+ this.showError(result.error.message);
74
+ } else {
75
+ this.elementsTokenHandler(result.token);
76
+ this.form[0].submit();
77
+ }
78
+ };
79
+
80
+ this.stripe.createToken(this.cardNumber).then(onTokenCreate.bind(this));
81
+ }
82
+ };
83
+
84
+ SolidusStripe.Elements.prototype.elementsTokenHandler = function(token) {
85
+ var mapCC = function(ccType) {
86
+ if (ccType === 'MasterCard') {
87
+ return 'mastercard';
88
+ } else if (ccType === 'Visa') {
89
+ return 'visa';
90
+ } else if (ccType === 'American Express') {
91
+ return 'amex';
92
+ } else if (ccType === 'Discover') {
93
+ return 'discover';
94
+ } else if (ccType === 'Diners Club') {
95
+ return 'dinersclub';
96
+ } else if (ccType === 'JCB') {
97
+ return 'jcb';
98
+ }
99
+ };
100
+
101
+ var baseSelector = `<input type='hidden' class='stripeToken' name='payment_source[${this.config.id}]`;
102
+
103
+ this.element.append(`${baseSelector}[gateway_payment_profile_id]' value='${token.id}'/>`);
104
+ this.element.append(`${baseSelector}[last_digits]' value='${token.card.last4}'/>`);
105
+ this.element.append(`${baseSelector}[month]' value='${token.card.exp_month}'/>`);
106
+ this.element.append(`${baseSelector}[year]' value='${token.card.exp_year}'/>`);
107
+ this.form.find('input#cc_type').val(mapCC(token.card.brand || token.card.type));
108
+ };
@@ -0,0 +1,82 @@
1
+ SolidusStripe.PaymentIntents = function() {
2
+ SolidusStripe.Elements.call(this);
3
+ };
4
+
5
+ SolidusStripe.PaymentIntents.prototype = Object.create(SolidusStripe.Elements.prototype);
6
+ Object.defineProperty(SolidusStripe.PaymentIntents.prototype, 'constructor', {
7
+ value: SolidusStripe.PaymentIntents,
8
+ enumerable: false,
9
+ writable: true
10
+ });
11
+
12
+ SolidusStripe.PaymentIntents.prototype.init = function() {
13
+ this.setUpPaymentRequest();
14
+ this.initElements();
15
+ };
16
+
17
+ SolidusStripe.PaymentIntents.prototype.onPrPayment = function(payment) {
18
+ if (payment.error) {
19
+ this.showError(payment.error.message);
20
+ } else {
21
+ var that = this;
22
+
23
+ this.elementsTokenHandler(payment.paymentMethod);
24
+ fetch('/stripe/confirm_payment', {
25
+ method: 'POST',
26
+ headers: {
27
+ 'Content-Type': 'application/json'
28
+ },
29
+ body: JSON.stringify({
30
+ spree_payment_method_id: this.config.id,
31
+ stripe_payment_method_id: payment.paymentMethod.id,
32
+ authenticity_token: this.authToken
33
+ })
34
+ }).then(function(response) {
35
+ response.json().then(function(json) {
36
+ that.handleServerResponse(json, payment);
37
+ })
38
+ });
39
+ }
40
+ };
41
+
42
+ SolidusStripe.PaymentIntents.prototype.onFormSubmit = function(event) {
43
+ if (this.element.is(':visible')) {
44
+ event.preventDefault();
45
+
46
+ this.errorElement.text('').hide();
47
+
48
+ this.stripe.createPaymentMethod(
49
+ 'card',
50
+ this.cardNumber
51
+ ).then(this.onIntentsPayment.bind(this));
52
+ }
53
+ };
54
+
55
+ SolidusStripe.PaymentIntents.prototype.submitPayment = function(_payment) {
56
+ this.form.unbind('submit').submit();
57
+ };
58
+
59
+ SolidusStripe.PaymentIntents.prototype.onIntentsPayment = function(payment) {
60
+ if (payment.error) {
61
+ this.showError(payment.error.message);
62
+ } else {
63
+ var that = this;
64
+
65
+ this.elementsTokenHandler(payment.paymentMethod);
66
+ fetch('/stripe/confirm_intents', {
67
+ method: 'POST',
68
+ headers: {
69
+ 'Content-Type': 'application/json'
70
+ },
71
+ body: JSON.stringify({
72
+ spree_payment_method_id: this.config.id,
73
+ stripe_payment_method_id: payment.paymentMethod.id,
74
+ authenticity_token: this.authToken
75
+ })
76
+ }).then(function(response) {
77
+ response.json().then(function(json) {
78
+ that.handleServerResponse(json, payment);
79
+ })
80
+ });
81
+ }
82
+ };
@@ -0,0 +1,122 @@
1
+ // Shared code between Payment Intents and Payment Request Button on cart page
2
+
3
+ (function() {
4
+ var PaymentRequestButtonShared;
5
+
6
+ PaymentRequestButtonShared = {
7
+ authToken: $('meta[name="csrf-token"]').attr('content'),
8
+
9
+ setUpPaymentRequest: function(opts) {
10
+ var opts = opts || {};
11
+ var config = this.config.payment_request;
12
+
13
+ if (config) {
14
+ config.requestShipping = opts.requestShipping || false;
15
+
16
+ var paymentRequest = this.stripe.paymentRequest({
17
+ country: config.country,
18
+ currency: config.currency,
19
+ total: {
20
+ label: config.label,
21
+ amount: config.amount
22
+ },
23
+ requestPayerName: true,
24
+ requestPayerEmail: true,
25
+ requestShipping: config.requestShipping,
26
+ shippingOptions: []
27
+ });
28
+
29
+ var prButton = this.elements.create('paymentRequestButton', {
30
+ paymentRequest: paymentRequest
31
+ });
32
+
33
+ var onButtonMount = function(result) {
34
+ var id = 'payment-request-button';
35
+
36
+ if (result) {
37
+ prButton.mount('#' + id);
38
+ } else {
39
+ document.getElementById(id).style.display = 'none';
40
+ }
41
+ if (typeof this.onPrButtonMounted === 'function') {
42
+ this.onPrButtonMounted(id, result);
43
+ }
44
+ }
45
+ paymentRequest.canMakePayment().then(onButtonMount.bind(this));
46
+
47
+ var onPrPaymentMethod = function(result) {
48
+ this.errorElement.text('').hide();
49
+ this.onPrPayment(result);
50
+ };
51
+ paymentRequest.on('paymentmethod', onPrPaymentMethod.bind(this));
52
+
53
+ onShippingAddressChange = function(ev) {
54
+ var showError = this.showError.bind(this);
55
+
56
+ fetch('/stripe/shipping_rates', {
57
+ method: 'POST',
58
+ headers: { 'Content-Type': 'application/json' },
59
+ body: JSON.stringify({
60
+ authenticity_token: this.authToken,
61
+ shipping_address: ev.shippingAddress
62
+ })
63
+ }).then(function(response) {
64
+ return response.json();
65
+ }).then(function(result) {
66
+ if (result.error) {
67
+ showError(result.error);
68
+ return false;
69
+ } else {
70
+ ev.updateWith({
71
+ status: 'success',
72
+ shippingOptions: result.shipping_rates
73
+ });
74
+ }
75
+ });
76
+ };
77
+ paymentRequest.on('shippingaddresschange', onShippingAddressChange.bind(this));
78
+ }
79
+ },
80
+
81
+ handleServerResponse: function(response, payment) {
82
+ if (response.error) {
83
+ this.showError(response.error);
84
+ this.completePaymentRequest(payment, 'fail');
85
+ } else if (response.requires_action) {
86
+ this.stripe.handleCardAction(
87
+ response.stripe_payment_intent_client_secret
88
+ ).then(this.onIntentsClientSecret.bind(this));
89
+ } else {
90
+ this.completePaymentRequest(payment, 'success');
91
+ this.submitPayment(payment);
92
+ }
93
+ },
94
+
95
+ onIntentsClientSecret: function(result) {
96
+ if (result.error) {
97
+ this.showError(result.error);
98
+ } else {
99
+ fetch('/stripe/confirm_intents', {
100
+ method: 'POST',
101
+ headers: { 'Content-Type': 'application/json' },
102
+ body: JSON.stringify({
103
+ spree_payment_method_id: this.config.id,
104
+ stripe_payment_intent_id: result.paymentIntent.id,
105
+ authenticity_token: this.authToken
106
+ })
107
+ }).then(function(confirmResult) {
108
+ return confirmResult.json();
109
+ }).then(this.handleServerResponse.bind(this));
110
+ }
111
+ },
112
+
113
+ completePaymentRequest: function(payment, state) {
114
+ if (payment && typeof payment.complete === 'function') {
115
+ payment.complete(state);
116
+ }
117
+ }
118
+ };
119
+
120
+ Object.assign(SolidusStripe.PaymentIntents.prototype, PaymentRequestButtonShared);
121
+ Object.assign(SolidusStripe.CartPageCheckout.prototype, PaymentRequestButtonShared);
122
+ })()
@@ -0,0 +1,10 @@
1
+ window.SolidusStripe = window.SolidusStripe || {};
2
+
3
+ SolidusStripe.Payment = function() {
4
+ this.config = $('[data-stripe-config]').data('stripe-config');
5
+ this.element = $('#payment_method_' + this.config.id);
6
+ this.authToken = $('meta[name="csrf-token"]').attr('content');
7
+
8
+ this.stripe = Stripe(this.config.publishable_key);
9
+ this.elements = this.stripe.elements({locale: 'en'});
10
+ };
@@ -0,0 +1,5 @@
1
+ //= require ./stripe-payments/stripe-payment
2
+ //= require ./stripe-payments/stripe-elements
3
+ //= require ./stripe-payments/stripe-payment-intents
4
+ //= require ./stripe-payments/stripe-cart-page-checkout
5
+ //= require ./stripe-payments/stripe-payment-request-button-shared
@@ -21,7 +21,7 @@ module SolidusStripe
21
21
 
22
22
  if SolidusSupport.frontend_available?
23
23
  paths["app/views"] << "lib/views/frontend"
24
- config.assets.precompile += ['solidus_stripe/stripe-init.js']
24
+ config.assets.precompile += ['spree/stripe-v3-payments.js']
25
25
  end
26
26
 
27
27
  if SolidusSupport.api_available?
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module SolidusStripe
4
- VERSION = "2.0.0"
4
+ VERSION = "2.1.0"
5
5
  end
@@ -1,5 +1,9 @@
1
1
  <%= render 'spree/checkout/payment/v3/form_elements', payment_method: payment_method %>
2
2
 
3
- <%= javascript_include_tag "solidus_stripe/stripe-init.js" %>
3
+ <%= javascript_include_tag 'spree/stripe-v3-payments' %>
4
4
 
5
- <%= render "spree/checkout/payment/v3/intents_js" %>
5
+ <script>
6
+ $(function() {
7
+ new SolidusStripe.PaymentIntents().init();
8
+ });
9
+ </script>
@@ -1,5 +1,9 @@
1
1
  <%= render 'spree/checkout/payment/v3/form_elements', payment_method: payment_method %>
2
2
 
3
- <%= javascript_include_tag "solidus_stripe/stripe-init.js" %>
3
+ <%= javascript_include_tag 'spree/stripe-v3-payments' %>
4
4
 
5
- <%= render "spree/checkout/payment/v3/elements_js" %>
5
+ <script>
6
+ $(function() {
7
+ new SolidusStripe.Elements().init();
8
+ });
9
+ </script>
@@ -13,80 +13,11 @@
13
13
  </div>
14
14
 
15
15
  <script src="https://js.stripe.com/v3/"></script>
16
- <%= javascript_include_tag "solidus_stripe/stripe-init" %>
17
16
 
17
+ <%= javascript_include_tag 'spree/stripe-v3-payments' %>
18
18
  <script>
19
- var paymentRequestConfig = SolidusStripe.paymentMethod.config.payment_request;
20
- var errorElement = $('#card-errors');
21
-
22
- if (typeof paymentRequestConfig !== 'undefined') {
23
- paymentRequestConfig.requestShipping = true;
24
-
25
- var onPrButtonMounted = function(buttonId, success) {
26
- var container = document.getElementById('stripe-payment-request');
27
-
28
- if (success) {
29
- container.style.display = '';
30
- } else {
31
- container.style.display = 'none';
32
- }
33
- };
34
-
35
- var paymentRequest = setUpPaymentRequest(paymentRequestConfig, onPrButtonMounted);
36
-
37
- function handlePayment(result) {
38
- fetch('/stripe/update_order', {
39
- method: 'POST',
40
- headers: { 'Content-Type': 'application/json' },
41
- body: JSON.stringify({
42
- shipping_address: result.shippingAddress,
43
- shipping_option: result.shippingOption,
44
- email: result.payerEmail,
45
- name: result.payerName,
46
- authenticity_token: authToken
47
- })
48
- }).then(function(response) {
49
- response.json().then(function(json) {
50
- handleServerResponse(json, result);
51
- })
52
- });
53
- };
54
-
55
- function stripeTokenHandler(token) {
56
- return {
57
- order: {
58
- payments_attributes: [
59
- {
60
- payment_method_id: SolidusStripe.paymentMethod.config.id,
61
- source_attributes: {
62
- gateway_payment_profile_id: token.id,
63
- last_digits: token.card.last4,
64
- month: token.card.exp_month,
65
- year: token.card.exp_year
66
- }
67
- }
68
- ]
69
- }
70
- }
71
- };
72
-
73
- function submitPayment(payment) {
74
- $.ajax({
75
- url : $('[data-submit-url]').data('submit-url'),
76
- headers: {
77
- 'X-Spree-Order-Token': $('[data-order-token]').data('order-token')
78
- },
79
- type : 'PATCH',
80
- contentType: 'application/json',
81
- data : JSON.stringify(stripeTokenHandler(payment.paymentMethod)),
82
- success: function() {
83
- window.location = $('[data-complete-url]').data('complete-url');
84
- },
85
- error: function(xhr,status,error) {
86
- showError(xhr.responseJSON.error);
87
- }
88
- });
89
- };
90
- }
19
+ $(function() {
20
+ new SolidusStripe.CartPageCheckout().init()
21
+ });
91
22
  </script>
92
23
  <% end %>
@@ -41,8 +41,7 @@ RSpec.describe "Stripe checkout", type: :feature do
41
41
  expect(page).to have_current_path("/checkout/address")
42
42
 
43
43
  within("#billing") do
44
- fill_in "First Name", with: "Han"
45
- fill_in "Last Name", with: "Solo"
44
+ fill_in_name
46
45
  fill_in "Street Address", with: "YT-1300"
47
46
  fill_in "City", with: "Mos Eisley"
48
47
  select "United States of America", from: "Country"
@@ -100,8 +99,7 @@ RSpec.describe "Stripe checkout", type: :feature do
100
99
  expect(page).to have_current_path("/checkout/address")
101
100
 
102
101
  within("#billing") do
103
- fill_in "First Name", with: "Han"
104
- fill_in "Last Name", with: "Solo"
102
+ fill_in_name
105
103
  fill_in "Street Address", with: "YT-1300"
106
104
  fill_in "City", with: "Mos Eisley"
107
105
  select "United States of America", from: "Country"
@@ -264,8 +262,7 @@ RSpec.describe "Stripe checkout", type: :feature do
264
262
  expect(page).to have_current_path("/checkout/address")
265
263
 
266
264
  within("#billing") do
267
- fill_in "First Name", with: "Han"
268
- fill_in "Last Name", with: "Solo"
265
+ fill_in_name
269
266
  fill_in "Street Address", with: "YT-1300"
270
267
  fill_in "City", with: "Mos Eisley"
271
268
  select "United States of America", from: "Country"
@@ -400,8 +397,7 @@ RSpec.describe "Stripe checkout", type: :feature do
400
397
  expect(page).to have_current_path("/checkout/address")
401
398
 
402
399
  within("#billing") do
403
- fill_in "First Name", with: "Han"
404
- fill_in "Last Name", with: "Solo"
400
+ fill_in_name
405
401
  fill_in "Street Address", with: "YT-1300"
406
402
  fill_in "City", with: "Mos Eisley"
407
403
  select "United States of America", from: "Country"
data/spec/spec_helper.rb CHANGED
@@ -19,4 +19,5 @@ RSpec.configure do |config|
19
19
  config.infer_spec_type_from_file_location!
20
20
  FactoryBot.find_definitions
21
21
  config.use_transactional_fixtures = false
22
+ config.include SolidusAddressNameHelper, type: :feature
22
23
  end
@@ -0,0 +1,15 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Since https://github.com/solidusio/solidus/pull/3524 was merged,
4
+ # we need to verify if we're using the single "Name" field or the
5
+ # previous first/last name combination.
6
+ module SolidusAddressNameHelper
7
+ def fill_in_name
8
+ if Spree::Config.preferences[:use_combined_first_and_last_name_in_address]
9
+ fill_in "Name", with: "Han Solo"
10
+ else
11
+ fill_in "First Name", with: "Han"
12
+ fill_in "Last Name", with: "Solo"
13
+ end
14
+ end
15
+ end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: solidus_stripe
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.0.0
4
+ version: 2.1.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Solidus Team
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2020-03-03 00:00:00.000000000 Z
11
+ date: 2020-03-11 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: solidus_core
@@ -91,8 +91,12 @@ files:
91
91
  - LICENSE.md
92
92
  - README.md
93
93
  - Rakefile
94
- - app/assets/javascripts/solidus_stripe/stripe-init.js
95
- - app/assets/javascripts/solidus_stripe/stripe-init/base.js
94
+ - app/assets/javascripts/spree/stripe-payments/stripe-cart-page-checkout.js
95
+ - app/assets/javascripts/spree/stripe-payments/stripe-elements.js
96
+ - app/assets/javascripts/spree/stripe-payments/stripe-payment-intents.js
97
+ - app/assets/javascripts/spree/stripe-payments/stripe-payment-request-button-shared.js
98
+ - app/assets/javascripts/spree/stripe-payments/stripe-payment.js
99
+ - app/assets/javascripts/spree/stripe-v3-payments.js
96
100
  - app/controllers/solidus_stripe/intents_controller.rb
97
101
  - app/controllers/solidus_stripe/payment_request_controller.rb
98
102
  - app/controllers/spree/stripe_controller.rb
@@ -119,10 +123,8 @@ files:
119
123
  - lib/views/frontend/spree/checkout/existing_payment/_stripe.html.erb
120
124
  - lib/views/frontend/spree/checkout/payment/_stripe.html.erb
121
125
  - lib/views/frontend/spree/checkout/payment/v2/_javascript.html.erb
122
- - lib/views/frontend/spree/checkout/payment/v3/_elements_js.html.erb
123
126
  - lib/views/frontend/spree/checkout/payment/v3/_form_elements.html.erb
124
127
  - lib/views/frontend/spree/checkout/payment/v3/_intents.html.erb
125
- - lib/views/frontend/spree/checkout/payment/v3/_intents_js.html.erb
126
128
  - lib/views/frontend/spree/checkout/payment/v3/_stripe.html.erb
127
129
  - lib/views/frontend/spree/orders/_stripe_payment_request_button.html.erb
128
130
  - solidus_stripe.gemspec
@@ -132,6 +134,7 @@ files:
132
134
  - spec/models/solidus_stripe/shipping_rates_service_spec.rb
133
135
  - spec/models/spree/payment_method/stripe_credit_card_spec.rb
134
136
  - spec/spec_helper.rb
137
+ - spec/support/solidus_address_helper.rb
135
138
  homepage: https://solidus.io
136
139
  licenses:
137
140
  - BSD-3
@@ -165,3 +168,4 @@ test_files:
165
168
  - spec/models/solidus_stripe/shipping_rates_service_spec.rb
166
169
  - spec/models/spree/payment_method/stripe_credit_card_spec.rb
167
170
  - spec/spec_helper.rb
171
+ - spec/support/solidus_address_helper.rb
@@ -1 +0,0 @@
1
- //= require ./stripe-init/base
@@ -1,180 +0,0 @@
1
- window.SolidusStripe = window.SolidusStripe || {};
2
-
3
- SolidusStripe.paymentMethod = {
4
- config: $('[data-stripe-config').data('stripe-config'),
5
- requestShipping: false
6
- }
7
-
8
- var authToken = $('meta[name="csrf-token"]').attr('content');
9
-
10
- var stripe = Stripe(SolidusStripe.paymentMethod.config.publishable_key)
11
- var elements = stripe.elements({locale: 'en'});
12
-
13
- var element = $('#payment_method_' + SolidusStripe.paymentMethod.config.id);
14
- var form = element.parents('form');
15
- var errorElement = form.find('#card-errors');
16
- var submitButton = form.find('input[type="submit"]');
17
-
18
- function stripeTokenHandler(token) {
19
- var baseSelector = `<input type='hidden' class='stripeToken' name='payment_source[${SolidusStripe.paymentMethod.config.id}]`;
20
-
21
- element.append(`${baseSelector}[gateway_payment_profile_id]' value='${token.id}'/>`);
22
- element.append(`${baseSelector}[last_digits]' value='${token.card.last4}'/>`);
23
- element.append(`${baseSelector}[month]' value='${token.card.exp_month}'/>`);
24
- element.append(`${baseSelector}[year]' value='${token.card.exp_year}'/>`);
25
- form.find('input#cc_type').val(mapCC(token.card.brand || token.card.type));
26
- };
27
-
28
- function initElements() {
29
- var style = {
30
- base: {
31
- color: 'black',
32
- fontFamily: '"Helvetica Neue", Helvetica, sans-serif',
33
- fontSmoothing: 'antialiased',
34
- fontSize: '14px',
35
- '::placeholder': {
36
- color: 'silver'
37
- }
38
- },
39
- invalid: {
40
- color: 'red',
41
- iconColor: 'red'
42
- }
43
- };
44
-
45
- elements.create('cardExpiry', {style: style}).mount('#card_expiry');
46
- elements.create('cardCvc', {style: style}).mount('#card_cvc');
47
-
48
- var cardNumber = elements.create('cardNumber', {style: style});
49
- cardNumber.mount('#card_number');
50
-
51
- return cardNumber;
52
- }
53
-
54
- function setUpPaymentRequest(config, onPrButtonMounted) {
55
- if (typeof config !== 'undefined') {
56
- var paymentRequest = stripe.paymentRequest({
57
- country: config.country,
58
- currency: config.currency,
59
- total: {
60
- label: config.label,
61
- amount: config.amount
62
- },
63
- requestPayerName: true,
64
- requestPayerEmail: true,
65
- requestShipping: config.requestShipping,
66
- shippingOptions: [
67
- ]
68
- });
69
-
70
- var prButton = elements.create('paymentRequestButton', {
71
- paymentRequest: paymentRequest
72
- });
73
-
74
- paymentRequest.canMakePayment().then(function(result) {
75
- var id = 'payment-request-button';
76
-
77
- if (result) {
78
- prButton.mount('#' + id);
79
- } else {
80
- document.getElementById(id).style.display = 'none';
81
- }
82
- if (typeof onPrButtonMounted === 'function') {
83
- onPrButtonMounted(id, result);
84
- }
85
- });
86
-
87
- paymentRequest.on('paymentmethod', function(result) {
88
- errorElement.text('').hide();
89
- handlePayment(result);
90
- });
91
-
92
- paymentRequest.on('shippingaddresschange', function(ev) {
93
- fetch('/stripe/shipping_rates', {
94
- method: 'POST',
95
- headers: { 'Content-Type': 'application/json' },
96
- body: JSON.stringify({
97
- authenticity_token: authToken,
98
- shipping_address: ev.shippingAddress
99
- })
100
- }).then(function(response) {
101
- return response.json();
102
- }).then(function(result) {
103
- if (result.error) {
104
- showError(result.error);
105
- return false;
106
- } else {
107
- ev.updateWith({
108
- status: 'success',
109
- shippingOptions: result.shipping_rates
110
- });
111
- }
112
- });
113
- });
114
-
115
- return paymentRequest;
116
- }
117
- };
118
-
119
- function handleServerResponse(response, payment) {
120
- if (response.error) {
121
- showError(response.error);
122
- completePaymentRequest(payment, 'fail');
123
- } else if (response.requires_action) {
124
- stripe.handleCardAction(
125
- response.stripe_payment_intent_client_secret
126
- ).then(function(result) {
127
- if (result.error) {
128
- showError(result.error.message);
129
- } else {
130
- fetch('/stripe/confirm_intents', {
131
- method: 'POST',
132
- headers: { 'Content-Type': 'application/json' },
133
- body: JSON.stringify({
134
- spree_payment_method_id: SolidusStripe.paymentMethod.config.id,
135
- stripe_payment_intent_id: result.paymentIntent.id,
136
- authenticity_token: authToken
137
- })
138
- }).then(function(confirmResult) {
139
- return confirmResult.json();
140
- }).then(handleServerResponse);
141
- }
142
- });
143
- } else {
144
- completePaymentRequest(payment, 'success');
145
- submitPayment(payment);
146
- }
147
- }
148
-
149
- function completePaymentRequest(payment, state) {
150
- if (payment && typeof payment.complete === 'function') {
151
- payment.complete(state);
152
- }
153
- }
154
-
155
- function showError(error) {
156
- errorElement.text(error).show();
157
-
158
- if (submitButton.length) {
159
- setTimeout(function() {
160
- $.rails.enableElement(submitButton[0]);
161
- submitButton.removeAttr('disabled').removeClass('disabled');
162
- }, 100);
163
- }
164
- };
165
-
166
- function mapCC(ccType) {
167
- if (ccType === 'MasterCard') {
168
- return 'mastercard';
169
- } else if (ccType === 'Visa') {
170
- return 'visa';
171
- } else if (ccType === 'American Express') {
172
- return 'amex';
173
- } else if (ccType === 'Discover') {
174
- return 'discover';
175
- } else if (ccType === 'Diners Club') {
176
- return 'dinersclub';
177
- } else if (ccType === 'JCB') {
178
- return 'jcb';
179
- }
180
- };
@@ -1,28 +0,0 @@
1
- <script>
2
- // Stripe V3 elements specific JS code
3
-
4
- var cardNumber = initElements();
5
-
6
- cardNumber.addEventListener('change', function(event) {
7
- if (event.error) {
8
- showError(event.error.message);
9
- } else {
10
- errorElement.hide().text('');
11
- }
12
- });
13
-
14
- form.bind('submit', function(event) {
15
- if (element.is(':visible')) {
16
- event.preventDefault();
17
-
18
- stripe.createToken(cardNumber).then(function(result) {
19
- if (result.error) {
20
- showError(result.error.message);
21
- } else {
22
- stripeTokenHandler(result.token);
23
- form[0].submit();
24
- }
25
- });
26
- }
27
- });
28
- </script>
@@ -1,48 +0,0 @@
1
- <script>
2
- // Stripe Intents JS code
3
-
4
- var cardNumber = initElements();
5
- var paymentRequest = setUpPaymentRequest(SolidusStripe.paymentMethod.config.payment_request);
6
-
7
- form.bind('submit', function(event) {
8
- if (element.is(':visible')) {
9
- event.preventDefault();
10
-
11
- errorElement.text('').hide();
12
-
13
- stripe.createPaymentMethod(
14
- 'card',
15
- cardNumber
16
- ).then(function(result) {
17
- handlePayment(result);
18
- });
19
- }
20
- });
21
-
22
- function handlePayment(payment) {
23
- if (payment.error) {
24
- showError(payment.error.message);
25
- } else {
26
- stripeTokenHandler(payment.paymentMethod);
27
- fetch('/stripe/confirm_intents', {
28
- method: 'POST',
29
- headers: {
30
- 'Content-Type': 'application/json'
31
- },
32
- body: JSON.stringify({
33
- spree_payment_method_id: SolidusStripe.paymentMethod.config.id,
34
- stripe_payment_method_id: payment.paymentMethod.id,
35
- authenticity_token: authToken
36
- })
37
- }).then(function(response) {
38
- response.json().then(function(json) {
39
- handleServerResponse(json, payment);
40
- })
41
- });
42
- }
43
- };
44
-
45
- function submitPayment(_payment) {
46
- form.unbind('submit').submit();
47
- }
48
- </script>