solidus_stripe 4.3.0 → 5.0.0.alpha.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (153) hide show
  1. checksums.yaml +4 -4
  2. data/.circleci/config.yml +98 -23
  3. data/.github/stale.yml +1 -17
  4. data/.gitignore +3 -0
  5. data/.rubocop.yml +94 -2
  6. data/.yardopts +1 -0
  7. data/CHANGELOG.md +1 -231
  8. data/Gemfile +10 -25
  9. data/LICENSE +2 -2
  10. data/Procfile.dev +3 -0
  11. data/README.md +155 -223
  12. data/Rakefile +7 -3
  13. data/app/assets/javascripts/spree/backend/solidus_stripe.js +2 -0
  14. data/app/assets/stylesheets/spree/backend/solidus_stripe.css +4 -0
  15. data/app/controllers/solidus_stripe/intents_controller.rb +36 -52
  16. data/app/controllers/solidus_stripe/webhooks_controller.rb +28 -0
  17. data/app/models/concerns/solidus_stripe/log_entries.rb +31 -0
  18. data/app/models/solidus_stripe/customer.rb +21 -0
  19. data/app/models/solidus_stripe/gateway.rb +231 -0
  20. data/app/models/solidus_stripe/payment_intent.rb +111 -0
  21. data/app/models/solidus_stripe/payment_method.rb +106 -0
  22. data/app/models/solidus_stripe/payment_source.rb +31 -0
  23. data/app/models/solidus_stripe/slug_entry.rb +20 -0
  24. data/app/models/solidus_stripe.rb +7 -0
  25. data/app/subscribers/solidus_stripe/webhook/charge_subscriber.rb +28 -0
  26. data/app/subscribers/solidus_stripe/webhook/payment_intent_subscriber.rb +112 -0
  27. data/app/views/spree/admin/payments/source_forms/_stripe.html.erb +29 -0
  28. data/app/views/spree/admin/payments/source_forms/existing_payment/_stripe.html.erb +14 -0
  29. data/app/views/spree/admin/payments/source_forms/existing_payment/stripe/_card.html.erb +8 -0
  30. data/app/views/spree/admin/payments/source_forms/existing_payment/stripe/_default.html.erb +7 -0
  31. data/app/views/spree/admin/payments/source_views/_stripe.html.erb +15 -0
  32. data/app/views/spree/api/payments/source_views/_stripe.json.jbuilder +8 -0
  33. data/bin/dev +13 -0
  34. data/bin/dummy-app +29 -0
  35. data/bin/rails +38 -3
  36. data/bin/rails-dummy-app +3 -0
  37. data/bin/rails-engine +1 -11
  38. data/bin/rails-new +55 -0
  39. data/bin/rails-sandbox +1 -14
  40. data/bin/rspec +10 -0
  41. data/bin/sandbox +12 -74
  42. data/bin/setup +1 -0
  43. data/bin/update-migrations +56 -0
  44. data/codecov.yml +12 -0
  45. data/config/locales/en.yml +16 -1
  46. data/config/routes.rb +5 -11
  47. data/coverage.rb +42 -0
  48. data/db/migrate/20230109183332_create_solidus_stripe_payment_sources.rb +10 -0
  49. data/db/migrate/20230303154931_create_solidus_stripe_setup_intent.rb +10 -0
  50. data/db/migrate/20230306105520_create_solidus_stripe_payment_intents.rb +10 -0
  51. data/db/migrate/20230308122414_create_solidus_stripe_webhook_endpoints.rb +10 -0
  52. data/db/migrate/20230310152615_add_payment_method_reference_to_stripe_intents.rb +6 -0
  53. data/db/migrate/20230310171444_normalize_stripe_intent_id_attributes.rb +6 -0
  54. data/db/migrate/20230313150008_create_solidus_stripe_customers.rb +16 -0
  55. data/db/migrate/20230323154931_drop_solidus_stripe_setup_intent.rb +13 -0
  56. data/db/migrate/20230403094916_rename_webhook_endpoint_to_payment_method_slug_entries.rb +5 -0
  57. data/db/seeds.rb +6 -24
  58. data/lib/generators/solidus_stripe/install/install_generator.rb +121 -14
  59. data/lib/generators/solidus_stripe/install/templates/app/assets/stylesheets/spree/frontend/solidus_stripe.css +13 -0
  60. data/lib/generators/solidus_stripe/install/templates/app/javascript/controllers/solidus_stripe_confirm_controller.js +39 -0
  61. data/lib/generators/solidus_stripe/install/templates/app/javascript/controllers/solidus_stripe_payment_controller.js +89 -0
  62. data/lib/generators/solidus_stripe/install/templates/app/views/checkouts/existing_payment/_stripe.html.erb +16 -0
  63. data/lib/generators/solidus_stripe/install/templates/app/views/checkouts/existing_payment/stripe/_card.html.erb +8 -0
  64. data/lib/generators/solidus_stripe/install/templates/app/views/checkouts/existing_payment/stripe/_default.html.erb +7 -0
  65. data/lib/generators/solidus_stripe/install/templates/app/views/checkouts/payment/_stripe.html.erb +39 -0
  66. data/lib/generators/solidus_stripe/install/templates/app/views/orders/payment_info/_stripe.html.erb +20 -0
  67. data/lib/generators/solidus_stripe/install/templates/config/initializers/solidus_stripe.rb +31 -0
  68. data/lib/solidus_stripe/configuration.rb +24 -3
  69. data/lib/solidus_stripe/engine.rb +19 -6
  70. data/lib/solidus_stripe/money_to_stripe_amount_converter.rb +109 -0
  71. data/lib/solidus_stripe/refunds_synchronizer.rb +96 -0
  72. data/lib/solidus_stripe/seeds.rb +19 -0
  73. data/lib/solidus_stripe/testing_support/factories.rb +153 -0
  74. data/lib/solidus_stripe/version.rb +1 -1
  75. data/lib/solidus_stripe/webhook/event.rb +90 -0
  76. data/lib/solidus_stripe.rb +0 -2
  77. data/solidus_stripe.gemspec +29 -5
  78. data/spec/lib/solidus_stripe/configuration_spec.rb +21 -0
  79. data/spec/lib/solidus_stripe/money_to_stripe_amount_converter_spec.rb +133 -0
  80. data/spec/lib/solidus_stripe/refunds_synchronizer_spec.rb +238 -0
  81. data/spec/lib/solidus_stripe/seeds_spec.rb +43 -0
  82. data/spec/lib/solidus_stripe/webhook/event_spec.rb +134 -0
  83. data/spec/models/concerns/solidus_stripe/log_entries_spec.rb +54 -0
  84. data/spec/models/solidus_stripe/customer_spec.rb +47 -0
  85. data/spec/models/solidus_stripe/gateway_spec.rb +283 -0
  86. data/spec/models/solidus_stripe/payment_intent_spec.rb +17 -0
  87. data/spec/models/solidus_stripe/payment_method_spec.rb +137 -0
  88. data/spec/models/solidus_stripe/payment_source_spec.rb +25 -0
  89. data/spec/requests/solidus_stripe/intents_controller_spec.rb +29 -0
  90. data/spec/requests/solidus_stripe/webhooks_controller/charge/refunded_spec.rb +31 -0
  91. data/spec/requests/solidus_stripe/webhooks_controller/payment_intent/canceled_spec.rb +23 -0
  92. data/spec/requests/solidus_stripe/webhooks_controller/payment_intent/payment_failed_spec.rb +23 -0
  93. data/spec/requests/solidus_stripe/webhooks_controller/payment_intent/succeeded_spec.rb +29 -0
  94. data/spec/requests/solidus_stripe/webhooks_controller_spec.rb +52 -0
  95. data/spec/solidus_stripe_spec_helper.rb +10 -0
  96. data/spec/subscribers/solidus_stripe/webhook/charge_subscriber_spec.rb +33 -0
  97. data/spec/subscribers/solidus_stripe/webhook/payment_intent_subscriber_spec.rb +297 -0
  98. data/spec/support/solidus_stripe/backend_test_helper.rb +210 -0
  99. data/spec/support/solidus_stripe/checkout_test_helper.rb +339 -0
  100. data/spec/support/solidus_stripe/factories.rb +5 -0
  101. data/spec/support/solidus_stripe/webhook/data_fixtures.rb +106 -0
  102. data/spec/support/solidus_stripe/webhook/event_with_context_factory.rb +82 -0
  103. data/spec/support/solidus_stripe/webhook/request_helper.rb +32 -0
  104. data/spec/system/backend/solidus_stripe/orders/payments_spec.rb +119 -0
  105. data/spec/system/frontend/.keep +0 -0
  106. data/spec/system/frontend/solidus_stripe/checkout_spec.rb +187 -0
  107. data/tmp/.keep +0 -0
  108. metadata +210 -69
  109. data/.travis.yml +0 -28
  110. data/app/assets/javascripts/spree/frontend/solidus_stripe/stripe-cart-page-checkout.js +0 -122
  111. data/app/assets/javascripts/spree/frontend/solidus_stripe/stripe-elements.js +0 -148
  112. data/app/assets/javascripts/spree/frontend/solidus_stripe/stripe-init.js +0 -20
  113. data/app/assets/javascripts/spree/frontend/solidus_stripe/stripe-payment-intents.js +0 -84
  114. data/app/assets/javascripts/spree/frontend/solidus_stripe/stripe-payment-request-button-shared.js +0 -160
  115. data/app/assets/javascripts/spree/frontend/solidus_stripe/stripe-payment.js +0 -16
  116. data/app/assets/javascripts/spree/frontend/solidus_stripe.js +0 -6
  117. data/app/controllers/solidus_stripe/payment_request_controller.rb +0 -52
  118. data/app/controllers/spree/stripe_controller.rb +0 -13
  119. data/app/decorators/models/spree/order_update_attributes_decorator.rb +0 -39
  120. data/app/decorators/models/spree/payment_decorator.rb +0 -11
  121. data/app/decorators/models/spree/refund_decorator.rb +0 -9
  122. data/app/models/solidus_stripe/address_from_params_service.rb +0 -72
  123. data/app/models/solidus_stripe/create_intents_payment_service.rb +0 -114
  124. data/app/models/solidus_stripe/prepare_order_for_payment_service.rb +0 -46
  125. data/app/models/solidus_stripe/shipping_rates_service.rb +0 -46
  126. data/app/models/spree/payment_method/stripe_credit_card.rb +0 -217
  127. data/bin/r +0 -13
  128. data/bin/sandbox_rails +0 -18
  129. data/db/migrate/20181010123508_update_stripe_payment_method_type_to_credit_card.rb +0 -21
  130. data/lib/assets/stylesheets/spree/frontend/solidus_stripe.scss +0 -11
  131. data/lib/solidus_stripe/testing_support/card_input_helper.rb +0 -34
  132. data/lib/tasks/solidus_stripe/db/seed.rake +0 -14
  133. data/lib/views/api/spree/api/payments/source_views/_stripe.json.jbuilder +0 -3
  134. data/lib/views/backend/spree/admin/log_entries/_stripe.html.erb +0 -28
  135. data/lib/views/backend/spree/admin/payments/source_forms/_stripe.html.erb +0 -1
  136. data/lib/views/backend/spree/admin/payments/source_views/_stripe.html.erb +0 -1
  137. data/lib/views/frontend/spree/checkout/existing_payment/_stripe.html.erb +0 -1
  138. data/lib/views/frontend/spree/checkout/payment/_stripe.html.erb +0 -8
  139. data/lib/views/frontend/spree/checkout/payment/v2/_javascript.html.erb +0 -78
  140. data/lib/views/frontend/spree/checkout/payment/v3/_elements.html.erb +0 -1
  141. data/lib/views/frontend/spree/checkout/payment/v3/_form_elements.html.erb +0 -40
  142. data/lib/views/frontend/spree/checkout/payment/v3/_intents.html.erb +0 -1
  143. data/lib/views/frontend/spree/checkout/payment/v3/_stripe.html.erb +0 -2
  144. data/lib/views/frontend/spree/orders/_stripe_payment_request_button.html.erb +0 -14
  145. data/spec/features/stripe_checkout_spec.rb +0 -486
  146. data/spec/models/solidus_stripe/address_from_params_service_spec.rb +0 -87
  147. data/spec/models/solidus_stripe/create_intents_payment_service_spec.rb +0 -127
  148. data/spec/models/solidus_stripe/prepare_order_for_payment_service_spec.rb +0 -65
  149. data/spec/models/solidus_stripe/shipping_rates_service_spec.rb +0 -54
  150. data/spec/models/spree/payment_method/stripe_credit_card_spec.rb +0 -316
  151. data/spec/requests/payment_requests_spec.rb +0 -152
  152. data/spec/spec_helper.rb +0 -37
  153. data/spec/support/solidus_address_helper.rb +0 -15
@@ -0,0 +1,238 @@
1
+ # frozen-string-literal: true
2
+
3
+ require "solidus_stripe_spec_helper"
4
+ require "solidus_stripe/refunds_synchronizer"
5
+ require "solidus_stripe/seeds"
6
+
7
+ RSpec.describe SolidusStripe::RefundsSynchronizer do
8
+ def mock_refund_list(payment_intent_id, refunds)
9
+ allow(Stripe::Refund).to receive(:list).with(payment_intent: payment_intent_id).and_return(
10
+ Stripe::ListObject.construct_from(
11
+ data: refunds
12
+ )
13
+ )
14
+ end
15
+
16
+ describe "#call" do
17
+ let(:payment_method) { create(:stripe_payment_method) }
18
+
19
+ it "creates missing refunds on Solidus" do
20
+ SolidusStripe::Seeds.refund_reasons
21
+ payment_intent_id = "pi_123"
22
+ payment = create(:payment, response_code: payment_intent_id, amount: 10, payment_method: payment_method)
23
+ mock_refund_list(payment_intent_id, [
24
+ {
25
+ id: "re_123",
26
+ amount: 1000,
27
+ currency: "usd",
28
+ metadata: {}
29
+ }
30
+ ])
31
+
32
+ described_class.new(payment_method).call(payment_intent_id)
33
+
34
+ expect(payment.refunds.count).to eq(1)
35
+ end
36
+
37
+ it "uses the stripe refund id as created Solidus refund transaction_id field" do
38
+ SolidusStripe::Seeds.refund_reasons
39
+ payment_intent_id = "pi_123"
40
+ payment = create(:payment, response_code: payment_intent_id, amount: 10, payment_method: payment_method)
41
+ mock_refund_list(payment_intent_id, [
42
+ {
43
+ id: "re_123",
44
+ amount: 1000,
45
+ currency: "usd",
46
+ metadata: {}
47
+ }
48
+ ])
49
+
50
+ described_class.new(payment_method).call(payment_intent_id)
51
+
52
+ refund = payment.refunds.first
53
+ expect(refund.transaction_id).to eq("re_123")
54
+ end
55
+
56
+ it "uses the stripe amount as created Solidus refund amount" do
57
+ SolidusStripe::Seeds.refund_reasons
58
+ payment_intent_id = "pi_123"
59
+ payment = create(:payment, response_code: payment_intent_id, amount: 10, payment_method: payment_method)
60
+ mock_refund_list(payment_intent_id, [
61
+ {
62
+ id: "re_123",
63
+ amount: 1000,
64
+ currency: "usd",
65
+ metadata: {}
66
+ }
67
+ ])
68
+
69
+ described_class.new(payment_method).call(payment_intent_id)
70
+
71
+ refund = payment.refunds.first
72
+ expect(refund.amount).to eq(10)
73
+ end
74
+
75
+ it "uses the configured reason for created Solidus refunds" do
76
+ SolidusStripe::Seeds.refund_reasons
77
+ payment_intent_id = "pi_123"
78
+ payment = create(:payment, response_code: payment_intent_id, amount: 10, payment_method: payment_method)
79
+ mock_refund_list(payment_intent_id, [
80
+ {
81
+ id: "re_123",
82
+ amount: 1000,
83
+ currency: "usd",
84
+ metadata: {}
85
+ }
86
+ ])
87
+
88
+ described_class.new(payment_method).call(payment_intent_id)
89
+
90
+ refund = payment.refunds.first
91
+ expect(refund.reason).to eq(SolidusStripe::PaymentMethod.refund_reason)
92
+ end
93
+
94
+ it "skips the creation of Solidus refunds with transaction_id matching some stripe refund id" do
95
+ payment_intent_id = "pi_123"
96
+ payment = create(:payment, response_code: payment_intent_id, amount: 10, payment_method: payment_method)
97
+ mock_refund_list(payment_intent_id, [
98
+ {
99
+ id: "re_123",
100
+ amount: 1000,
101
+ currency: "usd",
102
+ metadata: {}
103
+ }
104
+ ])
105
+ create(:refund, amount: 10, payment: payment, transaction_id: "re_123")
106
+
107
+ described_class.new(payment_method).call(payment_intent_id)
108
+
109
+ expect(payment.refunds.count).to be(1)
110
+ end
111
+
112
+ it "skips the creation of Solidus refunds when specified in their metadata" do
113
+ payment_intent_id = "pi_123"
114
+ payment = create(:payment, response_code: payment_intent_id, amount: 10, payment_method: payment_method)
115
+ mock_refund_list(payment_intent_id, [
116
+ {
117
+ id: "re_123",
118
+ amount: 1000,
119
+ currency: "usd",
120
+ metadata: {
121
+ solidus_skip_sync: 'true'
122
+ }
123
+ }
124
+ ])
125
+
126
+ described_class.new(payment_method).call(payment_intent_id)
127
+
128
+ expect(payment.refunds.count).to be(0)
129
+ end
130
+
131
+ it "creates multiple Solidus refunds if needed" do
132
+ SolidusStripe::Seeds.refund_reasons
133
+ payment_intent_id = "pi_123"
134
+ payment = create(:payment, response_code: payment_intent_id, amount: 10, payment_method: payment_method)
135
+ mock_refund_list(payment_intent_id, [
136
+ {
137
+ id: "re_123",
138
+ amount: 500,
139
+ currency: "usd",
140
+ metadata: {}
141
+ },
142
+ {
143
+ id: "re_456",
144
+ amount: 500,
145
+ currency: "usd",
146
+ metadata: {}
147
+ }
148
+ ])
149
+
150
+ described_class.new(payment_method).call(payment_intent_id)
151
+
152
+ expect(payment.refunds.count).to be(2)
153
+ end
154
+
155
+ it "creates only the missing Solidus refunds when there're multiple Stripe refunds" do
156
+ SolidusStripe::Seeds.refund_reasons
157
+ payment_intent_id = "pi_123"
158
+ payment = create(:payment, response_code: payment_intent_id, amount: 10, payment_method: payment_method)
159
+ mock_refund_list(payment_intent_id, [
160
+ {
161
+ id: "re_123",
162
+ amount: 500,
163
+ currency: "usd",
164
+ metadata: {}
165
+ },
166
+ {
167
+ id: "re_456",
168
+ amount: 500,
169
+ currency: "usd",
170
+ metadata: {}
171
+ }
172
+ ])
173
+ create(:refund, amount: 5, payment: payment, transaction_id: "re_123")
174
+
175
+ described_class.new(payment_method).call(payment_intent_id)
176
+
177
+ expect(payment.refunds.pluck(:transaction_id)).to contain_exactly("re_123", "re_456")
178
+ end
179
+
180
+ it "adds a log entry for created Solidus refund" do
181
+ SolidusStripe::Seeds.refund_reasons
182
+ payment_intent_id = "pi_123"
183
+ payment = create(:payment, response_code: payment_intent_id, amount: 10, payment_method: payment_method)
184
+ mock_refund_list(payment_intent_id, [
185
+ {
186
+ id: "re_123",
187
+ amount: 1000,
188
+ currency: "usd",
189
+ metadata: {}
190
+ }
191
+ ])
192
+
193
+ described_class.new(payment_method).call(payment_intent_id)
194
+
195
+ expect(payment.log_entries.count).to eq(1)
196
+ end
197
+
198
+ it "sets created log entry as successful" do
199
+ SolidusStripe::Seeds.refund_reasons
200
+ payment_intent_id = "pi_123"
201
+ payment = create(:payment, response_code: payment_intent_id, amount: 10, payment_method: payment_method)
202
+ mock_refund_list(payment_intent_id, [
203
+ {
204
+ id: "re_123",
205
+ amount: 1000,
206
+ currency: "usd",
207
+ metadata: {}
208
+ }
209
+ ])
210
+
211
+ described_class.new(payment_method).call(payment_intent_id)
212
+
213
+ expect(
214
+ payment.log_entries.first.parsed_details.success?
215
+ ).to be(true)
216
+ end
217
+
218
+ it "uses a meaningful message with the refunded amount in created log entry" do
219
+ SolidusStripe::Seeds.refund_reasons
220
+ payment_intent_id = "pi_123"
221
+ payment = create(:payment, response_code: payment_intent_id, amount: 10, payment_method: payment_method)
222
+ mock_refund_list(payment_intent_id, [
223
+ {
224
+ id: "re_123",
225
+ amount: 500,
226
+ currency: "usd",
227
+ metadata: {}
228
+ }
229
+ ])
230
+
231
+ described_class.new(payment_method).call(payment_intent_id)
232
+
233
+ expect(
234
+ payment.log_entries.first.parsed_details.message
235
+ ).to include("after Stripe event ($5.00)")
236
+ end
237
+ end
238
+ end
@@ -0,0 +1,43 @@
1
+ # frozen-string-literal: true
2
+
3
+ require "solidus_stripe_spec_helper"
4
+
5
+ RSpec.describe SolidusStripe::Seeds do
6
+ describe ".refund_reasons" do
7
+ it "creates a refund reason" do
8
+ expect do
9
+ described_class.refund_reasons
10
+ end.to change(Spree::RefundReason, :count).from(0).to(1)
11
+ end
12
+
13
+ it "uses default name for the refund reason name" do
14
+ described_class.refund_reasons
15
+
16
+ expect(Spree::RefundReason.last.name).to eq(described_class::DEFAULT_STRIPE_REFUND_REASON_NAME)
17
+ end
18
+
19
+ it "makes the refund reason immutable" do
20
+ described_class.refund_reasons
21
+
22
+ expect(Spree::RefundReason.last.mutable).to be(false)
23
+ end
24
+
25
+ it "does not duplicate refund reasons" do
26
+ described_class.refund_reasons
27
+
28
+ expect do
29
+ described_class.refund_reasons
30
+ end.not_to change(Spree::RefundReason, :count)
31
+ end
32
+
33
+ it "does not change the mutable attribute of existing refund reasons" do
34
+ described_class.refund_reasons
35
+ refund_reason = Spree::RefundReason.last
36
+ refund_reason.update_column(:mutable, true)
37
+
38
+ described_class.refund_reasons
39
+
40
+ expect(refund_reason.reload.mutable).to be(true)
41
+ end
42
+ end
43
+ end
@@ -0,0 +1,134 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "solidus_stripe_spec_helper"
4
+ require "solidus_stripe/webhook/event"
5
+ require "omnes/bus"
6
+
7
+ RSpec.describe SolidusStripe::Webhook::Event do
8
+ describe ".register" do
9
+ it "registers core events prepending with 'stripe'" do
10
+ bus = Omnes::Bus.new
11
+
12
+ described_class.register(bus: bus, core_events: %i[foo], user_events: [])
13
+
14
+ expect(bus.registry.registered?(:"stripe.foo")).to be(true)
15
+ end
16
+
17
+ it "registers user events prepending with 'stripe'" do
18
+ bus = Omnes::Bus.new
19
+
20
+ described_class.register(bus: bus, user_events: %i[foo])
21
+
22
+ expect(bus.registry.registered?(:"stripe.foo")).to be(true)
23
+ end
24
+ end
25
+
26
+ describe ".from_request" do
27
+ let(:context) do
28
+ SolidusStripe::Webhook::EventWithContextFactory.from_data(
29
+ data: SolidusStripe::Webhook::DataFixtures.charge_succeeded,
30
+ payment_method: create(:stripe_payment_method)
31
+ )
32
+ end
33
+
34
+ context "with a valid event" do
35
+ it "returns an event" do
36
+ event = described_class.from_request(
37
+ payload: context.json, signature_header: context.signature_header, slug: context.slug
38
+ )
39
+
40
+ expect(event).to be_a(described_class)
41
+ end
42
+ end
43
+
44
+ context "when the signature is invalid" do
45
+ it "returns nil" do
46
+ signature_header = "t=1,v1=1"
47
+
48
+ event = described_class.from_request(
49
+ payload: context.json, signature_header: signature_header, slug: context.slug
50
+ )
51
+
52
+ expect(event).to be(nil)
53
+ end
54
+ end
55
+
56
+ context "when the tolerance has expired" do
57
+ it "returns nil" do
58
+ event = described_class.from_request(
59
+ payload: context.json, signature_header: context.signature_header, tolerance: 0, slug: context.slug
60
+ )
61
+
62
+ expect(event).to be(nil)
63
+ end
64
+ end
65
+
66
+ context "when the payload is malformed" do
67
+ it "returns nil" do
68
+ event = described_class.from_request(
69
+ payload: "invalid", signature_header: context.signature_header, slug: context.slug
70
+ )
71
+
72
+ expect(event).to be(nil)
73
+ end
74
+ end
75
+
76
+ context "when the slug is not known" do
77
+ it "returns nil" do
78
+ event = described_class.from_request(
79
+ payload: context.json, signature_header: context.signature_header, slug: "foo"
80
+ )
81
+
82
+ expect(event).to be(nil)
83
+ end
84
+ end
85
+ end
86
+
87
+ describe "#initialize" do
88
+ let(:context) do
89
+ SolidusStripe::Webhook::EventWithContextFactory.new(
90
+ data: SolidusStripe::Webhook::DataFixtures.charge_succeeded,
91
+ payment_method: create(:stripe_payment_method)
92
+ )
93
+ end
94
+
95
+ it "sets the payment method" do
96
+ event = described_class.new(stripe_event: context.stripe_object, spree_payment_method: context.payment_method)
97
+
98
+ expect(event.spree_payment_method).to be(context.payment_method)
99
+ end
100
+
101
+ it "sets the omnes_event_name from the event type field" do
102
+ event = described_class.new(stripe_event: context.stripe_object, spree_payment_method: context.payment_method)
103
+
104
+ expect(event.omnes_event_name).to be(:"stripe.charge.succeeded")
105
+ end
106
+
107
+ it "delegates all other methods to the stripe event" do
108
+ event = described_class.new(stripe_event: context.stripe_object, spree_payment_method: context.payment_method)
109
+
110
+ expect(event.type).to eq("charge.succeeded")
111
+ end
112
+ end
113
+
114
+ describe "#payload" do
115
+ let(:context) do
116
+ SolidusStripe::Webhook::EventWithContextFactory.new(
117
+ data: SolidusStripe::Webhook::DataFixtures.charge_succeeded,
118
+ payment_method: create(:stripe_payment_method)
119
+ )
120
+ end
121
+
122
+ it "includes stripe event Hash representation" do
123
+ event = described_class.new(stripe_event: context.stripe_object, spree_payment_method: context.payment_method)
124
+
125
+ expect(event.payload["stripe_event"]).to eq(context.stripe_object.as_json)
126
+ end
127
+
128
+ it "includes spree payment method id" do
129
+ event = described_class.new(stripe_event: context.stripe_object, spree_payment_method: context.payment_method)
130
+
131
+ expect(event.payload["spree_payment_method_id"]).to be(context.payment_method.id)
132
+ end
133
+ end
134
+ end
@@ -0,0 +1,54 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'solidus_stripe_spec_helper'
4
+
5
+ RSpec.describe SolidusStripe::LogEntries do
6
+ describe '#payment_log' do
7
+ it 'creates a new Spree::LogEntry associated to the payment' do
8
+ payment = create(:payment)
9
+
10
+ expect {
11
+ described_class.payment_log(
12
+ payment,
13
+ message: "Hi there!",
14
+ success: true,
15
+ )
16
+ }.to change(Spree::LogEntry, :count).by(1)
17
+
18
+ details = payment.log_entries.last.parsed_details
19
+
20
+ expect(details).to respond_to(:success?)
21
+ expect(details).to respond_to(:message)
22
+ expect(details.message).to eq("Hi there!")
23
+ expect(details.success?).to eq(true)
24
+ end
25
+ end
26
+
27
+ describe '#build_payment_log' do
28
+ it 'creates an object suitable for serialization in a Spree::LogEntry' do
29
+ details = described_class.build_payment_log(
30
+ message: "Hi there!",
31
+ success: true,
32
+ )
33
+
34
+ expect(details).to respond_to(:success?)
35
+ expect(details).to respond_to(:message)
36
+ expect(details.message).to eq("Hi there!")
37
+ expect(details.success?).to eq(true)
38
+ end
39
+
40
+ it 'accepts data and a response_code' do
41
+ details = described_class.build_payment_log(
42
+ message: "Hi there!",
43
+ success: true,
44
+ response_code: 'foo_123',
45
+ data: { foo: :Bar },
46
+ )
47
+
48
+ expect(details.message).to eq("Hi there!")
49
+ expect(details.success?).to eq(true)
50
+ expect(details.authorization).to eq('foo_123')
51
+ expect(details.params).to eq("data" => '{"foo":"Bar"}')
52
+ end
53
+ end
54
+ end
@@ -0,0 +1,47 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'solidus_stripe_spec_helper'
4
+
5
+ RSpec.describe SolidusStripe::Customer, type: :model do
6
+ describe ".retrieve_or_create_stripe_customer_id" do
7
+ context 'with an existing customer' do
8
+ it 'returns the customer_id' do
9
+ user = create(:user)
10
+ order = create(:order, user: user)
11
+ customer = create(:stripe_customer, stripe_id: 'cus_123', source: user)
12
+
13
+ expect(customer.source).to be_a(Spree::User)
14
+ expect(
15
+ described_class.retrieve_or_create_stripe_customer_id(order: order, payment_method: customer.payment_method)
16
+ ).to eq('cus_123')
17
+ end
18
+ end
19
+
20
+ context 'without an existing customer' do
21
+ it 'creates the customer from a user' do
22
+ user = create(:user, email: 'registered@example.com')
23
+ order = create(:order, user: user)
24
+ payment_method = create(:stripe_payment_method)
25
+
26
+ stripe_customer = Stripe::Customer.construct_from(id: 'cus_123')
27
+ allow(Stripe::Customer).to receive(:create).with(email: 'registered@example.com').and_return(stripe_customer)
28
+
29
+ expect(
30
+ described_class.retrieve_or_create_stripe_customer_id(order: order, payment_method: payment_method)
31
+ ).to eq('cus_123')
32
+ end
33
+
34
+ it 'creates the customer from a guest order' do
35
+ payment_method = create(:stripe_payment_method)
36
+ order = create(:order, user: nil, email: 'guest@example.com')
37
+
38
+ stripe_customer = Stripe::Customer.construct_from(id: 'cus_123')
39
+ allow(Stripe::Customer).to receive(:create).with(email: 'guest@example.com').and_return(stripe_customer)
40
+
41
+ expect(
42
+ described_class.retrieve_or_create_stripe_customer_id(order: order, payment_method: payment_method)
43
+ ).to eq('cus_123')
44
+ end
45
+ end
46
+ end
47
+ end