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.
Files changed (153) hide show
  1. checksums.yaml +4 -4
  2. data/.circleci/config.yml +92 -52
  3. data/.gitignore +3 -0
  4. data/.rubocop.yml +94 -4
  5. data/.yardopts +1 -0
  6. data/Gemfile +10 -30
  7. data/LICENSE +2 -2
  8. data/Procfile.dev +3 -0
  9. data/README.md +145 -215
  10. data/Rakefile +5 -44
  11. data/app/assets/javascripts/spree/backend/solidus_stripe.js +2 -0
  12. data/app/assets/stylesheets/spree/backend/solidus_stripe.css +4 -0
  13. data/app/controllers/solidus_stripe/intents_controller.rb +36 -52
  14. data/app/controllers/solidus_stripe/webhooks_controller.rb +28 -0
  15. data/app/models/concerns/solidus_stripe/log_entries.rb +31 -0
  16. data/app/models/solidus_stripe/customer.rb +21 -0
  17. data/app/models/solidus_stripe/gateway.rb +231 -0
  18. data/app/models/solidus_stripe/payment_intent.rb +111 -0
  19. data/app/models/solidus_stripe/payment_method.rb +106 -0
  20. data/app/models/solidus_stripe/payment_source.rb +31 -0
  21. data/app/models/solidus_stripe/slug_entry.rb +20 -0
  22. data/app/models/solidus_stripe.rb +7 -0
  23. data/app/subscribers/solidus_stripe/webhook/charge_subscriber.rb +28 -0
  24. data/app/subscribers/solidus_stripe/webhook/payment_intent_subscriber.rb +112 -0
  25. data/app/views/spree/admin/payments/source_forms/_stripe.html.erb +29 -0
  26. data/app/views/spree/admin/payments/source_forms/existing_payment/_stripe.html.erb +14 -0
  27. data/app/views/spree/admin/payments/source_forms/existing_payment/stripe/_card.html.erb +8 -0
  28. data/app/views/spree/admin/payments/source_forms/existing_payment/stripe/_default.html.erb +7 -0
  29. data/app/views/spree/admin/payments/source_views/_stripe.html.erb +15 -0
  30. data/app/views/spree/api/payments/source_views/_stripe.json.jbuilder +8 -0
  31. data/bin/dev +13 -0
  32. data/bin/dummy-app +29 -0
  33. data/bin/rails +38 -3
  34. data/bin/rails-dummy-app +3 -0
  35. data/bin/rails-engine +1 -11
  36. data/bin/rails-new +55 -0
  37. data/bin/rails-sandbox +1 -14
  38. data/bin/rspec +10 -0
  39. data/bin/sandbox +12 -74
  40. data/bin/setup +1 -0
  41. data/bin/update-migrations +56 -0
  42. data/codecov.yml +12 -0
  43. data/config/locales/en.yml +16 -1
  44. data/config/routes.rb +5 -11
  45. data/coverage.rb +42 -0
  46. data/db/migrate/20230109183332_create_solidus_stripe_payment_sources.rb +10 -0
  47. data/db/migrate/20230303154931_create_solidus_stripe_setup_intent.rb +10 -0
  48. data/db/migrate/20230306105520_create_solidus_stripe_payment_intents.rb +10 -0
  49. data/db/migrate/20230308122414_create_solidus_stripe_webhook_endpoints.rb +10 -0
  50. data/db/migrate/20230310152615_add_payment_method_reference_to_stripe_intents.rb +6 -0
  51. data/db/migrate/20230310171444_normalize_stripe_intent_id_attributes.rb +6 -0
  52. data/db/migrate/20230313150008_create_solidus_stripe_customers.rb +16 -0
  53. data/db/migrate/20230323154931_drop_solidus_stripe_setup_intent.rb +13 -0
  54. data/db/migrate/20230403094916_rename_webhook_endpoint_to_payment_method_slug_entries.rb +5 -0
  55. data/db/seeds.rb +6 -24
  56. data/lib/generators/solidus_stripe/install/install_generator.rb +121 -14
  57. data/lib/generators/solidus_stripe/install/templates/app/assets/stylesheets/spree/frontend/solidus_stripe.css +13 -0
  58. data/lib/generators/solidus_stripe/install/templates/app/javascript/controllers/solidus_stripe_confirm_controller.js +39 -0
  59. data/lib/generators/solidus_stripe/install/templates/app/javascript/controllers/solidus_stripe_payment_controller.js +89 -0
  60. data/lib/generators/solidus_stripe/install/templates/app/views/checkouts/existing_payment/_stripe.html.erb +16 -0
  61. data/lib/generators/solidus_stripe/install/templates/app/views/checkouts/existing_payment/stripe/_card.html.erb +8 -0
  62. data/lib/generators/solidus_stripe/install/templates/app/views/checkouts/existing_payment/stripe/_default.html.erb +7 -0
  63. data/lib/generators/solidus_stripe/install/templates/app/views/checkouts/payment/_stripe.html.erb +39 -0
  64. data/lib/generators/solidus_stripe/install/templates/app/views/orders/payment_info/_stripe.html.erb +20 -0
  65. data/lib/generators/solidus_stripe/install/templates/config/initializers/solidus_stripe.rb +31 -0
  66. data/lib/solidus_stripe/configuration.rb +24 -3
  67. data/lib/solidus_stripe/engine.rb +19 -6
  68. data/lib/solidus_stripe/money_to_stripe_amount_converter.rb +109 -0
  69. data/lib/solidus_stripe/refunds_synchronizer.rb +96 -0
  70. data/lib/solidus_stripe/seeds.rb +19 -0
  71. data/lib/solidus_stripe/testing_support/factories.rb +153 -0
  72. data/lib/solidus_stripe/version.rb +1 -1
  73. data/lib/solidus_stripe/webhook/event.rb +90 -0
  74. data/lib/solidus_stripe.rb +0 -2
  75. data/solidus_stripe.gemspec +29 -6
  76. data/spec/lib/solidus_stripe/configuration_spec.rb +21 -0
  77. data/spec/lib/solidus_stripe/money_to_stripe_amount_converter_spec.rb +133 -0
  78. data/spec/lib/solidus_stripe/refunds_synchronizer_spec.rb +238 -0
  79. data/spec/lib/solidus_stripe/seeds_spec.rb +43 -0
  80. data/spec/lib/solidus_stripe/webhook/event_spec.rb +134 -0
  81. data/spec/models/concerns/solidus_stripe/log_entries_spec.rb +54 -0
  82. data/spec/models/solidus_stripe/customer_spec.rb +47 -0
  83. data/spec/models/solidus_stripe/gateway_spec.rb +283 -0
  84. data/spec/models/solidus_stripe/payment_intent_spec.rb +17 -0
  85. data/spec/models/solidus_stripe/payment_method_spec.rb +137 -0
  86. data/spec/models/solidus_stripe/payment_source_spec.rb +25 -0
  87. data/spec/requests/solidus_stripe/intents_controller_spec.rb +29 -0
  88. data/spec/requests/solidus_stripe/webhooks_controller/charge/refunded_spec.rb +31 -0
  89. data/spec/requests/solidus_stripe/webhooks_controller/payment_intent/canceled_spec.rb +23 -0
  90. data/spec/requests/solidus_stripe/webhooks_controller/payment_intent/payment_failed_spec.rb +23 -0
  91. data/spec/requests/solidus_stripe/webhooks_controller/payment_intent/succeeded_spec.rb +29 -0
  92. data/spec/requests/solidus_stripe/webhooks_controller_spec.rb +52 -0
  93. data/spec/solidus_stripe_spec_helper.rb +10 -0
  94. data/spec/subscribers/solidus_stripe/webhook/charge_subscriber_spec.rb +33 -0
  95. data/spec/subscribers/solidus_stripe/webhook/payment_intent_subscriber_spec.rb +297 -0
  96. data/spec/support/solidus_stripe/backend_test_helper.rb +210 -0
  97. data/spec/support/solidus_stripe/checkout_test_helper.rb +339 -0
  98. data/spec/support/solidus_stripe/factories.rb +5 -0
  99. data/spec/support/solidus_stripe/webhook/data_fixtures.rb +106 -0
  100. data/spec/support/solidus_stripe/webhook/event_with_context_factory.rb +82 -0
  101. data/spec/support/solidus_stripe/webhook/request_helper.rb +32 -0
  102. data/spec/system/backend/solidus_stripe/orders/payments_spec.rb +119 -0
  103. data/spec/system/frontend/.keep +0 -0
  104. data/spec/system/frontend/solidus_stripe/checkout_spec.rb +187 -0
  105. data/tmp/.keep +0 -0
  106. metadata +202 -78
  107. data/.rubocop_todo.yml +0 -298
  108. data/.travis.yml +0 -28
  109. data/app/assets/javascripts/spree/frontend/solidus_stripe/stripe-cart-page-checkout.js +0 -122
  110. data/app/assets/javascripts/spree/frontend/solidus_stripe/stripe-elements.js +0 -148
  111. data/app/assets/javascripts/spree/frontend/solidus_stripe/stripe-init.js +0 -20
  112. data/app/assets/javascripts/spree/frontend/solidus_stripe/stripe-payment-intents.js +0 -84
  113. data/app/assets/javascripts/spree/frontend/solidus_stripe/stripe-payment-request-button-shared.js +0 -160
  114. data/app/assets/javascripts/spree/frontend/solidus_stripe/stripe-payment.js +0 -16
  115. data/app/assets/javascripts/spree/frontend/solidus_stripe.js +0 -6
  116. data/app/controllers/solidus_stripe/payment_request_controller.rb +0 -52
  117. data/app/controllers/spree/stripe_controller.rb +0 -13
  118. data/app/decorators/models/spree/order_update_attributes_decorator.rb +0 -39
  119. data/app/decorators/models/spree/payment_decorator.rb +0 -11
  120. data/app/decorators/models/spree/refund_decorator.rb +0 -9
  121. data/app/models/solidus_stripe/address_from_params_service.rb +0 -72
  122. data/app/models/solidus_stripe/create_intents_payment_service.rb +0 -114
  123. data/app/models/solidus_stripe/prepare_order_for_payment_service.rb +0 -46
  124. data/app/models/solidus_stripe/shipping_rates_service.rb +0 -46
  125. data/app/models/spree/payment_method/stripe_credit_card.rb +0 -230
  126. data/bin/r +0 -13
  127. data/bin/sandbox_rails +0 -18
  128. data/db/migrate/20181010123508_update_stripe_payment_method_type_to_credit_card.rb +0 -21
  129. data/lib/assets/stylesheets/spree/frontend/solidus_stripe.scss +0 -11
  130. data/lib/solidus_stripe/testing_support/card_input_helper.rb +0 -34
  131. data/lib/tasks/solidus_stripe/db/seed.rake +0 -14
  132. data/lib/views/api/spree/api/payments/source_views/_stripe.json.jbuilder +0 -3
  133. data/lib/views/backend/spree/admin/log_entries/_stripe.html.erb +0 -28
  134. data/lib/views/backend/spree/admin/payments/source_forms/_stripe.html.erb +0 -1
  135. data/lib/views/backend/spree/admin/payments/source_views/_stripe.html.erb +0 -1
  136. data/lib/views/frontend/spree/checkout/existing_payment/_stripe.html.erb +0 -1
  137. data/lib/views/frontend/spree/checkout/payment/_stripe.html.erb +0 -8
  138. data/lib/views/frontend/spree/checkout/payment/v2/_javascript.html.erb +0 -78
  139. data/lib/views/frontend/spree/checkout/payment/v3/_elements.html.erb +0 -1
  140. data/lib/views/frontend/spree/checkout/payment/v3/_form_elements.html.erb +0 -40
  141. data/lib/views/frontend/spree/checkout/payment/v3/_intents.html.erb +0 -1
  142. data/lib/views/frontend/spree/checkout/payment/v3/_stripe.html.erb +0 -2
  143. data/lib/views/frontend/spree/orders/_stripe_payment_request_button.html.erb +0 -14
  144. data/spec/features/stripe_checkout_spec.rb +0 -486
  145. data/spec/models/solidus_stripe/address_from_params_service_spec.rb +0 -87
  146. data/spec/models/solidus_stripe/create_intents_payment_service_spec.rb +0 -127
  147. data/spec/models/solidus_stripe/prepare_order_for_payment_service_spec.rb +0 -65
  148. data/spec/models/solidus_stripe/shipping_rates_service_spec.rb +0 -54
  149. data/spec/models/spree/payment_method/stripe_credit_card_spec.rb +0 -354
  150. data/spec/requests/payment_requests_spec.rb +0 -152
  151. data/spec/solidus_frontend_app_template.rb +0 -17
  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