solidus_braintree 1.4.0 → 2.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (204) hide show
  1. checksums.yaml +4 -4
  2. data/.circleci/config.yml +12 -0
  3. data/.gem_release.yml +5 -0
  4. data/.github_changelog_generator +2 -0
  5. data/.gitignore +20 -11
  6. data/.rspec +1 -1
  7. data/.rubocop.yml +79 -0
  8. data/CHANGELOG.md +178 -18
  9. data/Gemfile +31 -23
  10. data/LICENSE +26 -0
  11. data/README.md +387 -26
  12. data/Rakefile +4 -19
  13. data/app/assets/config/solidus_braintree_manifest.js +1 -0
  14. data/app/assets/images/solidus_braintree/venmo/venmo_active_blue_button_280x48.svg +19 -0
  15. data/app/assets/images/solidus_braintree/venmo/venmo_active_blue_button_320x48.svg +19 -0
  16. data/app/assets/images/solidus_braintree/venmo/venmo_active_blue_button_375x48.svg +19 -0
  17. data/app/assets/images/solidus_braintree/venmo/venmo_active_white_button_280x48.svg +19 -0
  18. data/app/assets/images/solidus_braintree/venmo/venmo_active_white_button_320x48.svg +19 -0
  19. data/app/assets/images/solidus_braintree/venmo/venmo_active_white_button_375x48.svg +19 -0
  20. data/app/assets/images/solidus_braintree/venmo/venmo_blue_acceptance_mark.svg +15 -0
  21. data/app/assets/images/solidus_braintree/venmo/venmo_blue_button_280x48.svg +19 -0
  22. data/app/assets/images/solidus_braintree/venmo/venmo_blue_button_320x48.svg +19 -0
  23. data/app/assets/images/solidus_braintree/venmo/venmo_blue_button_375x48.svg +19 -0
  24. data/app/assets/images/solidus_braintree/venmo/venmo_blue_logo.svg +18 -0
  25. data/app/assets/images/solidus_braintree/venmo/venmo_white_acceptance_mark.svg +20 -0
  26. data/app/assets/images/solidus_braintree/venmo/venmo_white_button_280x48.svg +19 -0
  27. data/app/assets/images/solidus_braintree/venmo/venmo_white_button_320x48.svg +19 -0
  28. data/app/assets/images/solidus_braintree/venmo/venmo_white_button_375x48.svg +19 -0
  29. data/app/assets/images/solidus_braintree/venmo/venmo_white_logo.svg +18 -0
  30. data/app/assets/javascripts/solidus_braintree/apple_pay_button.js +179 -0
  31. data/app/assets/javascripts/solidus_braintree/checkout.js +108 -0
  32. data/app/assets/javascripts/solidus_braintree/client.js +239 -0
  33. data/app/assets/javascripts/solidus_braintree/constants.js +89 -0
  34. data/app/assets/javascripts/solidus_braintree/frontend.js +14 -0
  35. data/app/assets/javascripts/solidus_braintree/hosted_form.js +46 -0
  36. data/app/assets/javascripts/solidus_braintree/paypal_button.js +178 -0
  37. data/app/assets/javascripts/solidus_braintree/paypal_messaging.js +22 -0
  38. data/app/assets/javascripts/solidus_braintree/promise.js +20 -0
  39. data/app/assets/javascripts/solidus_braintree/venmo_button.js +86 -0
  40. data/app/assets/javascripts/spree/backend/solidus_braintree.js +96 -0
  41. data/app/assets/javascripts/spree/frontend/paypal_button.js +34 -0
  42. data/app/assets/javascripts/spree/frontend/solidus_braintree.js +1 -0
  43. data/app/assets/stylesheets/spree/backend/solidus_braintree.scss +28 -0
  44. data/app/assets/stylesheets/spree/frontend/solidus_braintree.scss +51 -0
  45. data/app/decorators/controllers/solidus_braintree/admin_payments_controller_decorator.rb +11 -0
  46. data/app/decorators/controllers/solidus_braintree/checkout_controller_decorator.rb +11 -0
  47. data/app/decorators/controllers/solidus_braintree/client_tokens_controller.rb +41 -0
  48. data/app/decorators/controllers/solidus_braintree/orders_controller_decorator.rb +11 -0
  49. data/app/decorators/models/solidus_braintree/spree/store_decorator.rb +20 -0
  50. data/app/decorators/models/solidus_braintree/spree/user_decorator.rb +13 -0
  51. data/app/helpers/solidus_braintree/braintree_admin_helper.rb +23 -0
  52. data/app/helpers/solidus_braintree/braintree_checkout_helper.rb +60 -0
  53. data/app/models/application_record.rb +5 -0
  54. data/app/models/solidus_braintree/address.rb +64 -0
  55. data/app/models/solidus_braintree/avs_result.rb +69 -0
  56. data/app/models/solidus_braintree/configuration.rb +39 -0
  57. data/app/models/solidus_braintree/customer.rb +8 -0
  58. data/app/models/solidus_braintree/gateway.rb +433 -0
  59. data/app/models/solidus_braintree/response.rb +80 -0
  60. data/app/models/solidus_braintree/source.rb +135 -0
  61. data/app/models/solidus_braintree/transaction.rb +31 -0
  62. data/app/models/solidus_braintree/transaction_address.rb +88 -0
  63. data/app/models/solidus_braintree/transaction_import.rb +98 -0
  64. data/app/overrides/spree/payments/payment/add_paypal_funding_source_to_payment.rb +9 -0
  65. data/app/views/spree/api/payments/source_views/_braintree.json.jbuilder +1 -1
  66. data/app/views/spree/checkout/existing_payment/_braintree.html.erb +10 -0
  67. data/app/views/spree/shared/_apple_pay_button.html.erb +27 -0
  68. data/app/views/spree/shared/_braintree_errors.html.erb +16 -0
  69. data/app/views/spree/shared/_braintree_head_scripts.html.erb +26 -0
  70. data/app/views/spree/shared/_braintree_hosted_fields.html.erb +43 -0
  71. data/app/views/spree/shared/_paypal_cart_button.html.erb +38 -0
  72. data/app/views/spree/shared/_paypal_messaging.html.erb +13 -0
  73. data/app/views/spree/shared/_venmo_button.html.erb +33 -0
  74. data/bin/console +4 -1
  75. data/bin/rails +5 -5
  76. data/bin/rails-engine +13 -0
  77. data/bin/rails-sandbox +16 -0
  78. data/bin/rake +7 -0
  79. data/bin/sandbox +103 -0
  80. data/bin/setup +5 -4
  81. data/config/locales/en.yml +94 -2
  82. data/config/locales/it.yml +56 -0
  83. data/config/routes.rb +12 -3
  84. data/db/migrate/20160830061749_create_solidus_paypal_braintree_sources.rb +16 -0
  85. data/db/migrate/20160906201711_create_solidus_paypal_braintree_customers.rb +13 -0
  86. data/db/migrate/20161114231422_create_solidus_paypal_braintree_configurations.rb +11 -0
  87. data/db/migrate/20161125172005_add_braintree_configuration_to_stores.rb +7 -0
  88. data/db/migrate/20170203191030_add_credit_card_to_braintree_configuration.rb +6 -0
  89. data/db/migrate/20170505193712_add_null_constraint_to_sources.rb +38 -0
  90. data/db/migrate/20170508085402_add_not_null_constraint_to_sources_payment_type.rb +14 -0
  91. data/db/migrate/20190705115327_add_paypal_button_preferences_to_braintree_configurations.rb +5 -0
  92. data/db/migrate/20190911141712_add_3d_secure_to_braintree_configuration.rb +5 -0
  93. data/db/migrate/20211222170950_add_paypal_funding_source_to_solidus_paypal_braintree_sources.rb +5 -0
  94. data/db/migrate/20220104150301_add_venmo_to_braintree_configuration.rb +5 -0
  95. data/db/migrate/20230109080950_rename_solidus_paypal_braintree_source_type.rb +31 -0
  96. data/lib/controllers/backend/solidus_braintree/configurations_controller.rb +48 -0
  97. data/lib/controllers/frontend/solidus_braintree/checkouts_controller.rb +31 -0
  98. data/lib/controllers/frontend/solidus_braintree/transactions_controller.rb +67 -0
  99. data/lib/generators/solidus_braintree/install/install_generator.rb +54 -18
  100. data/lib/generators/solidus_braintree/install/templates/initializer.rb +6 -0
  101. data/lib/solidus_braintree/country_mapper.rb +37 -0
  102. data/lib/solidus_braintree/engine.rb +55 -10
  103. data/lib/solidus_braintree/extension_configuration.rb +23 -0
  104. data/lib/solidus_braintree/request_protection.rb +21 -0
  105. data/lib/solidus_braintree/testing_support/factories.rb +53 -0
  106. data/lib/solidus_braintree/version.rb +3 -1
  107. data/lib/solidus_braintree.rb +14 -2
  108. data/lib/solidus_paypal_braintree.rb +6 -0
  109. data/lib/views/backend/solidus_braintree/configurations/list.html.erb +63 -0
  110. data/lib/views/backend/spree/admin/payments/source_forms/_braintree.html.erb +16 -0
  111. data/lib/views/backend/spree/admin/payments/source_views/_braintree.html.erb +39 -0
  112. data/lib/views/backend/spree/admin/shared/preference_fields/_preference_select.html.erb +13 -0
  113. data/lib/views/backend_v1.2/spree/admin/payments/source_forms/_braintree.html.erb +16 -0
  114. data/lib/views/backend_v2.4/spree/admin/shared/preference_fields/_hash.html.erb +12 -0
  115. data/lib/views/frontend/solidus_braintree/payments/_payment.html.erb +12 -0
  116. data/lib/views/frontend/spree/checkout/payment/_braintree.html.erb +23 -0
  117. data/lib/views/frontend/spree/shared/_paypal_checkout_button.html.erb +32 -0
  118. data/solidus_braintree.gemspec +39 -38
  119. data/spec/controllers/solidus_braintree/checkouts_controller_spec.rb +99 -0
  120. data/spec/controllers/solidus_braintree/client_tokens_controller_spec.rb +55 -0
  121. data/spec/controllers/solidus_braintree/configurations_controller_spec.rb +73 -0
  122. data/spec/controllers/solidus_braintree/transactions_controller_spec.rb +183 -0
  123. data/spec/features/backend/configuration_spec.rb +23 -0
  124. data/spec/features/backend/new_payment_spec.rb +137 -0
  125. data/spec/features/frontend/braintree_credit_card_checkout_spec.rb +191 -0
  126. data/spec/features/frontend/paypal_checkout_spec.rb +166 -0
  127. data/spec/features/frontend/venmo_checkout_spec.rb +194 -0
  128. data/spec/fixtures/cassettes/admin/invalid_credit_card.yml +63 -0
  129. data/spec/fixtures/cassettes/admin/resubmit_credit_card.yml +352 -0
  130. data/spec/fixtures/cassettes/admin/valid_credit_card.yml +412 -0
  131. data/spec/fixtures/cassettes/braintree/create_profile.yml +71 -0
  132. data/spec/fixtures/cassettes/braintree/generate_token.yml +63 -0
  133. data/spec/fixtures/cassettes/braintree/token.yml +63 -0
  134. data/spec/fixtures/cassettes/checkout/invalid_credit_card.yml +63 -0
  135. data/spec/fixtures/cassettes/checkout/resubmit_credit_card.yml +216 -0
  136. data/spec/fixtures/cassettes/checkout/update.yml +71 -0
  137. data/spec/fixtures/cassettes/checkout/valid_credit_card.yml +171 -0
  138. data/spec/fixtures/cassettes/checkout/valid_venmo_transaction.yml +599 -0
  139. data/spec/fixtures/cassettes/gateway/authorize/credit_card/address.yml +86 -0
  140. data/spec/fixtures/cassettes/gateway/authorize/merchant_account/EUR.yml +154 -0
  141. data/spec/fixtures/cassettes/gateway/authorize/paypal/EUR.yml +90 -0
  142. data/spec/fixtures/cassettes/gateway/authorize/paypal/address.yml +90 -0
  143. data/spec/fixtures/cassettes/gateway/authorize.yml +86 -0
  144. data/spec/fixtures/cassettes/gateway/authorized_transaction.yml +73 -0
  145. data/spec/fixtures/cassettes/gateway/cancel/missing.yml +63 -0
  146. data/spec/fixtures/cassettes/gateway/cancel/refunds.yml +272 -0
  147. data/spec/fixtures/cassettes/gateway/cancel/void.yml +201 -0
  148. data/spec/fixtures/cassettes/gateway/capture.yml +141 -0
  149. data/spec/fixtures/cassettes/gateway/complete.yml +157 -0
  150. data/spec/fixtures/cassettes/gateway/credit.yml +208 -0
  151. data/spec/fixtures/cassettes/gateway/customer.yml +79 -0
  152. data/spec/fixtures/cassettes/gateway/purchase.yml +87 -0
  153. data/spec/fixtures/cassettes/gateway/settled_transaction.yml +140 -0
  154. data/spec/fixtures/cassettes/gateway/void.yml +137 -0
  155. data/spec/fixtures/cassettes/source/bin.yml +295 -0
  156. data/spec/fixtures/cassettes/source/card_type.yml +267 -0
  157. data/spec/fixtures/cassettes/source/last4.yml +267 -0
  158. data/spec/fixtures/cassettes/transaction/import/valid/capture.yml +224 -0
  159. data/spec/fixtures/cassettes/transaction/import/valid.yml +71 -0
  160. data/spec/fixtures/views/spree/orders/edit.html.erb +50 -0
  161. data/spec/helpers/solidus_braintree/braintree_admin_helper_spec.rb +17 -0
  162. data/spec/helpers/solidus_braintree/braintree_checkout_helper_spec.rb +70 -0
  163. data/spec/models/solidus_braintree/address_spec.rb +71 -0
  164. data/spec/models/solidus_braintree/avs_result_spec.rb +317 -0
  165. data/spec/models/solidus_braintree/gateway_spec.rb +742 -0
  166. data/spec/models/solidus_braintree/response_spec.rb +280 -0
  167. data/spec/models/solidus_braintree/source_spec.rb +539 -0
  168. data/spec/models/solidus_braintree/transaction_address_spec.rb +235 -0
  169. data/spec/models/solidus_braintree/transaction_import_spec.rb +302 -0
  170. data/spec/models/solidus_braintree/transaction_spec.rb +86 -0
  171. data/spec/models/spree/store_spec.rb +14 -0
  172. data/spec/requests/spree/api/orders_controller_spec.rb +36 -0
  173. data/spec/spec_helper.rb +32 -0
  174. data/spec/support/capybara.rb +7 -0
  175. data/spec/support/gateway_helpers.rb +29 -0
  176. data/spec/support/order_ready_for_payment.rb +37 -0
  177. data/spec/support/vcr.rb +42 -0
  178. data/spec/support/views.rb +1 -0
  179. metadata +276 -224
  180. data/LICENSE.txt +0 -21
  181. data/app/controllers/spree/api/braintree_client_token_controller.rb +0 -13
  182. data/app/decorators/lib/solidus_braintree/spree/permitted_attributes_decorator.rb +0 -9
  183. data/app/decorators/models/solidus_braintree/spree/credit_card_decorator.rb +0 -11
  184. data/app/decorators/models/solidus_braintree/spree/payment_decorator.rb +0 -10
  185. data/app/helpers/braintree_view_helpers.rb +0 -20
  186. data/app/models/concerns/solidus_braintree/add_name_validation_concern.rb +0 -8
  187. data/app/models/concerns/solidus_braintree/inject_device_data_concern.rb +0 -18
  188. data/app/models/concerns/solidus_braintree/payment_braintree_nonce_concern.rb +0 -8
  189. data/app/models/concerns/solidus_braintree/permitted_attributes_concern.rb +0 -11
  190. data/app/models/concerns/solidus_braintree/skip_require_card_numbers_concern.rb +0 -14
  191. data/app/models/concerns/solidus_braintree/use_data_field_concern.rb +0 -23
  192. data/app/models/solidus/gateway/braintree_gateway.rb +0 -306
  193. data/app/overrides/spree/checkout/_confirm/braintree_security.html.erb.deface +0 -9
  194. data/app/views/spree/admin/payments/source_forms/_braintree.html.erb +0 -38
  195. data/app/views/spree/admin/payments/source_views/_braintree.html.erb +0 -30
  196. data/app/views/spree/checkout/payment/_braintree.html.erb +0 -55
  197. data/app/views/spree/checkout/payment/_braintree_initialization.html.erb +0 -12
  198. data/config/initializers/braintree.rb +0 -3
  199. data/db/migrate/20150910170527_add_data_to_credit_card.rb +0 -5
  200. data/db/migrate/20160426221931_add_braintree_device_data_to_order.rb +0 -5
  201. data/lib/assets/javascripts/spree/backend/braintree/solidus_braintree.js +0 -59
  202. data/lib/assets/javascripts/spree/frontend/braintree/solidus_braintree.js +0 -144
  203. data/lib/assets/javascripts/vendor/braintree.js +0 -8
  204. data/lib/assets/stylesheets/spree/frontend/solidus_braintree.scss +0 -26
@@ -0,0 +1,235 @@
1
+ require 'spec_helper'
2
+
3
+ describe SolidusBraintree::TransactionAddress do
4
+ describe "#valid?" do
5
+ subject { address.valid? }
6
+
7
+ let(:address) { described_class.new(valid_attributes) }
8
+
9
+ let(:valid_attributes) do
10
+ {
11
+ name: "Bruce Wayne",
12
+ address_line_1: "42 Spruce Lane",
13
+ city: "Gotham",
14
+ zip: "98201",
15
+ state_code: "WA",
16
+ country_code: "US"
17
+ }
18
+ end
19
+
20
+ let(:country) { create :country, iso: 'US', states_required: true }
21
+
22
+ before do
23
+ create :state, abbr: "WA", country: country
24
+ end
25
+
26
+ it { is_expected.to be true }
27
+
28
+ context 'without country matches' do
29
+ let(:valid_attributes) { super().merge({ country_code: 'CA' }) }
30
+
31
+ it { is_expected.to be false }
32
+ end
33
+
34
+ context "without name" do
35
+ let(:valid_attributes) { super().except(:name) }
36
+
37
+ it { is_expected.to be false }
38
+ end
39
+
40
+ context "without address_line_1" do
41
+ let(:valid_attributes) { super().except(:address_line_1) }
42
+
43
+ it { is_expected.to be false }
44
+ end
45
+
46
+ context "without city" do
47
+ let(:valid_attributes) { super().except(:city) }
48
+
49
+ it { is_expected.to be false }
50
+ end
51
+
52
+ context "without zip" do
53
+ let(:valid_attributes) { super().except(:zip) }
54
+
55
+ it { is_expected.to be false }
56
+ end
57
+
58
+ context "without state_code" do
59
+ let(:valid_attributes) { super().except(:state_code) }
60
+
61
+ it { is_expected.to be false }
62
+
63
+ context "when country does not requires states" do
64
+ let(:country) { create :country, iso: 'US', states_required: false }
65
+
66
+ it { is_expected.to be true }
67
+ end
68
+ end
69
+
70
+ context "without country_code" do
71
+ let(:valid_attributes) { super().except(:country_code) }
72
+
73
+ it { is_expected.to be true }
74
+
75
+ it "defaults to the US" do
76
+ subject
77
+ expect(address.country_code).to eq "us"
78
+ end
79
+ end
80
+
81
+ context "with a one word name" do
82
+ let(:valid_attributes) { super().merge({ name: "Bruce" }) }
83
+
84
+ it { is_expected.to be true }
85
+ end
86
+ end
87
+
88
+ describe "#attributes=" do
89
+ subject { described_class.new(attrs) }
90
+
91
+ context "when an ISO code is provided" do
92
+ let(:attrs) { { country_code: "US" } }
93
+
94
+ it "uses the ISO code provided" do
95
+ expect(subject.country_code).to eq "US"
96
+ end
97
+ end
98
+
99
+ context "when the ISO code is blank" do
100
+ context "with a valid country name provided" do
101
+ before do
102
+ create :country, name: "canada", iso: "CA"
103
+ end
104
+
105
+ let(:attrs) { { country_name: "Canada" } }
106
+
107
+ it "looks up the ISO code by the country name" do
108
+ expect(subject.country_code).to eq "CA"
109
+ end
110
+ end
111
+
112
+ context "without valid country name" do
113
+ let(:attrs) { { country_name: "Neverland" } }
114
+
115
+ it "leaves the country code blank" do
116
+ expect(subject.country_code).to be_nil
117
+ end
118
+ end
119
+ end
120
+ end
121
+
122
+ describe '#spree_country' do
123
+ subject { described_class.new(country_code: country_code).spree_country }
124
+
125
+ before do
126
+ create :country, name: 'United States', iso: 'US'
127
+ end
128
+
129
+ ['us', 'US'].each do |code|
130
+ let(:country_code) { code }
131
+
132
+ it 'looks up by iso' do
133
+ expect(subject.name).to eq 'United States'
134
+ end
135
+ end
136
+
137
+ context 'when country does not exist' do
138
+ let(:country_code) { 'NA' }
139
+
140
+ it { is_expected.to be_nil }
141
+ end
142
+ end
143
+
144
+ describe '#spree_state' do
145
+ subject { described_class.new(country_code: 'US', state_code: state_code).spree_state }
146
+
147
+ let(:state_code) { 'newy' }
148
+
149
+ it { is_expected.to be_nil }
150
+
151
+ context 'when state exists' do
152
+ before do
153
+ us = create :country, iso: 'US'
154
+ create :state, abbr: 'NY', name: 'New York', country: us
155
+ end
156
+
157
+ ['ny', ' ny', 'ny ', 'New York', 'new york', 'NY'].each do |code|
158
+ let(:state_code) { code }
159
+
160
+ it 'looks up the right state' do
161
+ expect(subject.abbr).to eq "NY"
162
+ end
163
+ end
164
+
165
+ context 'with no matching state' do
166
+ let(:state_code) { 'AL' }
167
+
168
+ it { is_expected.to be_nil }
169
+ end
170
+ end
171
+ end
172
+
173
+ describe '#should_match_state_model' do
174
+ subject { described_class.new(country_code: 'US').should_match_state_model? }
175
+
176
+ it { is_expected.to be_falsey }
177
+
178
+ context 'when country does not require states' do
179
+ before { create :country, iso: 'US', states_required: false }
180
+
181
+ it { is_expected.to be false }
182
+ end
183
+
184
+ context 'when country requires states' do
185
+ before { create :country, iso: 'US', states_required: true }
186
+
187
+ it { is_expected.to be true }
188
+ end
189
+ end
190
+
191
+ describe '#to_spree_address' do
192
+ subject { described_class.new(address_params).to_spree_address }
193
+
194
+ let(:address_params) do
195
+ {
196
+ country_code: 'US',
197
+ state_code: 'NY',
198
+ name: "Alfred"
199
+ }
200
+ end
201
+ let!(:us) { create :country, iso: 'US' }
202
+
203
+ it { is_expected.to be_a Spree::Address }
204
+
205
+ context 'when country exists with states' do
206
+ before do
207
+ create :state, country: us, abbr: 'NY', name: 'New York'
208
+ end
209
+
210
+ it 'uses state model' do
211
+ expect(subject.state.name).to eq 'New York'
212
+ end
213
+ end
214
+
215
+ context 'when country exist with no states' do
216
+ it 'uses state_name' do
217
+ expect(subject.state).to be_nil
218
+ expect(subject.state_text).to eq 'NY'
219
+ end
220
+ end
221
+
222
+ unless SolidusSupport.combined_first_and_last_name_in_address?
223
+ context 'when using first_name and last_name' do
224
+ let(:address_params) { super().merge({ first_name: "Bruce", last_name: "Wayne" }) }
225
+
226
+ it 'displays a deprecation warning' do
227
+ expect(Spree::Deprecation).to receive(:warn).
228
+ with("first_name and last_name are deprecated. Use name instead.", any_args)
229
+
230
+ subject
231
+ end
232
+ end
233
+ end
234
+ end
235
+ end
@@ -0,0 +1,302 @@
1
+ require 'spec_helper'
2
+
3
+ describe SolidusBraintree::TransactionImport do
4
+ let(:order) { Spree::Order.new }
5
+ let!(:country) { create :country, iso: "US" }
6
+ let(:braintree_gateway) { SolidusBraintree::Gateway.new }
7
+ let(:transaction_address) { nil }
8
+ let(:transaction) do
9
+ SolidusBraintree::Transaction.new(
10
+ nonce: 'abcd1234',
11
+ payment_type: "ApplePayCard",
12
+ address: transaction_address,
13
+ payment_method: braintree_gateway,
14
+ email: "test@example.com",
15
+ phone: "123-456-6789"
16
+ )
17
+ end
18
+ let(:transaction_import) { described_class.new(order, transaction) }
19
+
20
+ describe "#valid?" do
21
+ subject { transaction_import.valid? }
22
+
23
+ it { is_expected.to be true }
24
+
25
+ context "with invalid transaction" do
26
+ let(:transaction) { SolidusBraintree::Transaction.new }
27
+
28
+ it { is_expected.to be false }
29
+ end
30
+
31
+ context "with invalid address" do
32
+ let(:transaction_address) do
33
+ SolidusBraintree::TransactionAddress.new(
34
+ name: "Bruce Wayne",
35
+ address_line_1: "42 Spruce Lane",
36
+ city: "Gotham",
37
+ state_code: "WA",
38
+ country_code: "US"
39
+ )
40
+ end
41
+
42
+ before do
43
+ create(:state, state_code: "WA")
44
+ end
45
+
46
+ it { is_expected.to be false }
47
+
48
+ it "sets useful error messages" do
49
+ transaction_import.valid?
50
+ expect(transaction_import.errors.full_messages).
51
+ to eq ["Address is invalid", "Address Zip can't be blank"]
52
+ end
53
+ end
54
+ end
55
+
56
+ describe '#source' do
57
+ subject { described_class.new(order, transaction).source }
58
+
59
+ it { is_expected.to be_a SolidusBraintree::Source }
60
+
61
+ it 'takes the nonce from the transaction' do
62
+ expect(subject.nonce).to eq 'abcd1234'
63
+ end
64
+
65
+ it 'takes the payment type from the transaction' do
66
+ expect(subject.payment_type).to eq 'ApplePayCard'
67
+ end
68
+
69
+ it 'takes the payment method from the transaction' do
70
+ expect(subject.payment_method).to eq braintree_gateway
71
+ end
72
+
73
+ it 'takes the paypal funding source from the transaction' do
74
+ transaction.paypal_funding_source = 'paypal'
75
+
76
+ expect(subject.paypal_funding_source).to eq('paypal')
77
+ end
78
+
79
+ context 'when order has a user' do
80
+ let(:user) { Spree.user_class.new }
81
+ let(:order) { Spree::Order.new user: user }
82
+
83
+ it 'associates user to the source' do
84
+ expect(subject.user).to eq user
85
+ end
86
+ end
87
+ end
88
+
89
+ describe '#user' do
90
+ subject { described_class.new(order, transaction).user }
91
+
92
+ it { is_expected.to be_nil }
93
+
94
+ context 'when order has a user' do
95
+ let(:user) { Spree.user_class.new }
96
+ let(:order) { Spree::Order.new user: user }
97
+
98
+ it { is_expected.to eq user }
99
+ end
100
+ end
101
+
102
+ describe '#import!' do
103
+ subject { described_class.new(order, transaction).import!(end_state) }
104
+
105
+ let(:store) { create :store }
106
+ let(:variant) { create :variant }
107
+ let(:line_item) { Spree::LineItem.new(variant: variant, quantity: 1, price: 10) }
108
+ let(:address) { create :address, country: country }
109
+ let(:order) {
110
+ Spree::Order.create(
111
+ number: "R999999999",
112
+ store: store,
113
+ line_items: [line_item],
114
+ ship_address: address,
115
+ currency: 'USD',
116
+ total: 10,
117
+ email: 'test@example.com'
118
+ )
119
+ }
120
+ let(:payment_method) { create_gateway }
121
+
122
+ let(:transaction_address) { nil }
123
+ let(:end_state) { 'confirm' }
124
+
125
+ let(:transaction) do
126
+ SolidusBraintree::Transaction.new(
127
+ nonce: 'fake-valid-nonce',
128
+ payment_method: payment_method,
129
+ address: transaction_address,
130
+ payment_type: SolidusBraintree::Source::PAYPAL,
131
+ phone: '123-456-7890',
132
+ email: 'user@example.com'
133
+ )
134
+ end
135
+
136
+ before do
137
+ # create a shipping method so we can push through to the end
138
+ create :shipping_method, cost: 5
139
+
140
+ # ensure payments have the same number so VCR matches the request body
141
+ allow_any_instance_of(Spree::Payment).
142
+ to receive(:generate_identifier).
143
+ and_return("ABCD1234")
144
+ end
145
+
146
+ context "with passing validation", vcr: {
147
+ cassette_name: 'transaction/import/valid',
148
+ match_requests_on: [:braintree_uri]
149
+ } do
150
+ context "when order end state is confirm" do
151
+ it 'advances order to confirm state' do
152
+ subject
153
+ expect(order.state).to eq 'confirm'
154
+ end
155
+
156
+ it 'has a payment for the cost of line items + shipment' do
157
+ subject
158
+ expect(order.payments.first.amount).to eq 15
159
+ end
160
+
161
+ it 'is complete and capturable', aggregate_failures: true, vcr: {
162
+ cassette_name: 'transaction/import/valid/capture',
163
+ match_requests_on: [:braintree_uri]
164
+ } do
165
+ subject
166
+ order.complete
167
+
168
+ expect(order).to be_complete
169
+ expect(order.payments.first).to be_pending
170
+
171
+ order.payments.first.capture!
172
+ # need to reload, as capture will update the order
173
+ expect(order.reload).to be_paid
174
+ end
175
+ end
176
+
177
+ context "when order end state is delivery" do
178
+ let(:end_state) { 'delivery' }
179
+
180
+ it "advances the order to delivery" do
181
+ subject
182
+ expect(order.state).to eq 'delivery'
183
+ end
184
+
185
+ it "has a payment for the cost of line items" do
186
+ subject
187
+ expect(order.payments.first.amount).to eq 10
188
+ end
189
+ end
190
+
191
+ context 'when transaction has address' do
192
+ let!(:new_york) { create :state, country: country, abbr: 'NY' }
193
+
194
+ let(:transaction_address) do
195
+ SolidusBraintree::TransactionAddress.new(
196
+ country_code: 'US',
197
+ name: 'Thaddeus Venture',
198
+ city: 'New York',
199
+ state_code: 'NY',
200
+ address_line_1: '350 5th Ave',
201
+ zip: '10118'
202
+ )
203
+ end
204
+
205
+ it 'uses the new address', aggregate_failures: true do
206
+ subject
207
+ expect(order.shipping_address.address1).to eq '350 5th Ave'
208
+ expect(order.shipping_address.country).to eq country
209
+ expect(order.shipping_address.state).to eq new_york
210
+ end
211
+
212
+ context 'when transaction has paypal funding source' do
213
+ it 'saves it to the payment source' do
214
+ transaction.paypal_funding_source = 'paypal'
215
+
216
+ subject
217
+
218
+ source = SolidusBraintree::Source.last
219
+ expect(source.paypal_funding_source).to eq('paypal')
220
+ end
221
+ end
222
+
223
+ context 'with a tax category' do
224
+ before do
225
+ zone = Spree::Zone.create name: 'nyc tax'
226
+ zone.members << Spree::ZoneMember.new(zoneable: new_york)
227
+ create :tax_rate, zone: zone
228
+ end
229
+
230
+ it 'includes the tax in the payment' do
231
+ subject
232
+ expect(order.payments.first.amount).to eq 16
233
+ end
234
+ end
235
+
236
+ context 'with a less expensive tax category' do
237
+ before do
238
+ original_zone = Spree::Zone.create name: 'first address tax'
239
+ original_zone.members << Spree::ZoneMember.new(zoneable: address.state)
240
+ original_tax_rate = create :tax_rate, zone: original_zone, amount: 0.2
241
+
242
+ # new address is NY
243
+ ny_zone = Spree::Zone.create name: 'nyc tax'
244
+ ny_zone.members << Spree::ZoneMember.new(zoneable: new_york)
245
+ create :tax_rate, tax_categories: [original_tax_rate.tax_categories.first], zone: ny_zone, amount: 0.1
246
+ end
247
+
248
+ it 'includes the lower tax in the payment' do
249
+ # so shipments and shipment cost is calculated before transaction import
250
+ order.next!; order.next!
251
+ # precondition
252
+ expect(order.additional_tax_total).to eq 2
253
+ expect(order.total).to eq 17
254
+
255
+ subject
256
+ expect(order.additional_tax_total).to eq 1
257
+ expect(order.payments.first.amount).to eq 16
258
+ end
259
+ end
260
+ end
261
+ end
262
+
263
+ context "when validation fails" do
264
+ let(:transaction_address) do
265
+ SolidusBraintree::TransactionAddress.new(
266
+ country_code: 'US',
267
+ name: 'Thaddeus Venture',
268
+ city: 'New York',
269
+ state_code: 'NY',
270
+ address_line_1: '350 5th Ave'
271
+ )
272
+ end
273
+
274
+ it "raises an error with the validation messages" do
275
+ expect { subject }.to raise_error(
276
+ SolidusBraintree::TransactionImport::InvalidImportError
277
+ )
278
+ end
279
+ end
280
+
281
+ context "with checkout flow", vcr: {
282
+ cassette_name: 'transaction/import/valid',
283
+ match_requests_on: [:braintree_uri]
284
+ } do
285
+ it "is not restarted by default" do
286
+ expect(order).not_to receive(:restart_checkout_flow)
287
+ subject
288
+ end
289
+
290
+ context "with restart_checkout: true" do
291
+ subject do
292
+ described_class.new(order, transaction).import!(end_state, restart_checkout: true)
293
+ end
294
+
295
+ it "is restarted" do
296
+ expect(order).to receive(:restart_checkout_flow)
297
+ subject
298
+ end
299
+ end
300
+ end
301
+ end
302
+ end
@@ -0,0 +1,86 @@
1
+ require 'spec_helper'
2
+
3
+ describe SolidusBraintree::Transaction do
4
+ describe "#valid?" do
5
+ subject { transaction.valid? }
6
+
7
+ let(:valid_attributes) do
8
+ {
9
+ nonce: 'abcde-fghjkl-lmnop',
10
+ payment_method: SolidusBraintree::Gateway.new,
11
+ payment_type: 'ApplePayCard',
12
+ email: "test@example.com"
13
+ }
14
+ end
15
+ let(:valid_address_attributes) do
16
+ {
17
+ address_attributes: {
18
+ name: "Bruce Wayne",
19
+ address_line_1: "42 Spruce Lane",
20
+ city: "Gotham",
21
+ zip: "98201",
22
+ state_code: "WA",
23
+ country_code: "US"
24
+ }
25
+ }
26
+ end
27
+ let(:transaction) { described_class.new(valid_attributes) }
28
+
29
+ before do
30
+ create(:country, iso: "US")
31
+ create(:state, state_code: "WA")
32
+ end
33
+
34
+ it { is_expected.to be true }
35
+
36
+ context 'without nonce' do
37
+ let(:valid_attributes) { super().except(:nonce) }
38
+
39
+ it { is_expected.to be false }
40
+ end
41
+
42
+ context 'without gateway' do
43
+ let(:valid_attributes) { super().except(:payment_method) }
44
+
45
+ it { is_expected.to be false }
46
+ end
47
+
48
+ context 'with bad gateway' do
49
+ let(:valid_attributes) { super().merge(payment_method: Spree::PaymentMethod.new) }
50
+
51
+ it { is_expected.to be false }
52
+ end
53
+
54
+ context 'without payment_type' do
55
+ let(:valid_attributes) { super().except(:payment_type) }
56
+
57
+ it { is_expected.to be false }
58
+ end
59
+
60
+ context 'without email' do
61
+ let(:valid_attributes) { super().except(:email) }
62
+
63
+ it { is_expected.to be false }
64
+ end
65
+
66
+ context "with valid address" do
67
+ let(:valid_attributes) { super().merge(valid_address_attributes) }
68
+
69
+ it { is_expected.to be true }
70
+ end
71
+
72
+ context "with invalid address" do
73
+ let(:valid_attributes) { super().merge(valid_address_attributes) }
74
+
75
+ before { valid_address_attributes[:address_attributes][:zip] = nil }
76
+
77
+ it { is_expected.to be false }
78
+
79
+ it "sets useful error messages" do
80
+ transaction.valid?
81
+ expect(transaction.errors.full_messages).
82
+ to eq ["Address Zip can't be blank"]
83
+ end
84
+ end
85
+ end
86
+ end
@@ -0,0 +1,14 @@
1
+ require 'spec_helper'
2
+
3
+ describe Spree::Store do
4
+ describe 'before_create :build_default_configuration' do
5
+ context 'when a braintree_configuration record already exists' do
6
+ it 'does not overwrite it' do
7
+ store = build(:store)
8
+ custom_braintree_configuration = store.build_braintree_configuration
9
+ store.save!
10
+ expect(store.braintree_configuration).to be custom_braintree_configuration
11
+ end
12
+ end
13
+ end
14
+ end
@@ -0,0 +1,36 @@
1
+ require 'spec_helper'
2
+
3
+ describe Spree::Api::OrdersController, type: :request do
4
+ stub_authorization!
5
+
6
+ describe 'get show' do
7
+ let(:gateway) { create_gateway }
8
+ let(:order) { create(:order_with_line_items) }
9
+ let(:source) do
10
+ SolidusBraintree::Source.new(
11
+ nonce: 'fake-valid-nonce',
12
+ user: order.user,
13
+ payment_type: SolidusBraintree::Source::PAYPAL,
14
+ payment_method: gateway
15
+ )
16
+ end
17
+
18
+ context 'when using braintree as the payment' do
19
+ before do
20
+ allow_any_instance_of(Spree::Payment).to receive(:create_payment_profile).and_return(true)
21
+
22
+ order.payments.create!(
23
+ payment_method: gateway,
24
+ source: source,
25
+ amount: 55
26
+ )
27
+ end
28
+
29
+ it "can be rendered correctly" do
30
+ get "/api/orders/#{order.number}"
31
+
32
+ expect(response).to have_http_status :ok
33
+ end
34
+ end
35
+ end
36
+ end
@@ -0,0 +1,32 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Configure Rails Environment
4
+ ENV['RAILS_ENV'] = 'test'
5
+
6
+ # Run Coverage report
7
+ require 'solidus_dev_support/rspec/coverage'
8
+ require 'rails-controller-testing'
9
+
10
+ # Create the dummy app if it's still missing.
11
+ dummy_env = "#{__dir__}/dummy/config/environment.rb"
12
+ system 'bin/rake extension:test_app' unless File.exist? dummy_env
13
+ require dummy_env
14
+
15
+ # Requires factories and other useful helpers defined in spree_core.
16
+ require 'solidus_dev_support/rspec/feature_helper'
17
+
18
+ # Requires supporting ruby files with custom matchers and macros, etc,
19
+ # in spec/support/ and its subdirectories.
20
+ Dir["#{__dir__}/support/**/*.rb"].sort.each { |f| require f }
21
+
22
+ # Requires factories defined in lib/solidus_braintree/testing_support/factories.rb
23
+ SolidusDevSupport::TestingSupport::Factories.load_for(SolidusBraintree::Engine)
24
+
25
+ RSpec.configure do |config|
26
+ config.infer_spec_type_from_file_location!
27
+ config.use_transactional_fixtures = false
28
+
29
+ if Spree.solidus_gem_version < Gem::Version.new('2.11')
30
+ config.extend Spree::TestingSupport::AuthorizationHelpers::Request, type: :system
31
+ end
32
+ end