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,239 @@
1
+ /**
2
+ * Braintree client interface
3
+ * @external "braintree.Client"
4
+ * @see {@link https://braintree.github.io/braintree-web/current/Client.html|Braintree Client Docs}
5
+ **/
6
+
7
+ /**
8
+ * Braintree paypal interface
9
+ * @external "braintree.PayPal"
10
+ * @see {@link https://braintree.github.io/braintree-web/current/PayPal.html|Braintree Paypal Docs}
11
+ **/
12
+
13
+ /**
14
+ * Braintree paypal interface
15
+ * @external "braintree.ApplePay"
16
+ * @see {@link https://braintree.github.io/braintree-web/current/ApplePay.html|Braintree Apple Pay Docs}
17
+ **/
18
+
19
+ /**
20
+ * Braintree dataCollector interface
21
+ * @external "braintree.DataCollector"
22
+ * @see {@link https://braintree.github.io/braintree-web/current/DataCollector.html|Braintree DataCollector Docs}
23
+ **/
24
+
25
+ /**
26
+ * jQuery.Deferred interface
27
+ *
28
+ * We use this for our promises because ES6 promises are non standard, and because jquery 1/2
29
+ * promises do not play nicely with them.
30
+ * @external "jQuery.Deferred"
31
+ * @see {@link https://api.jquery.com/category/deferred-object/|jQuery Deferred Documentation}
32
+ **/
33
+
34
+ /**
35
+ * Represents a wrapper around the braintree js library.
36
+ *
37
+ * This class is responsible for fetching tokens from a solidus store and using them
38
+ * to manage a braintree client. It takes a number of options as capabilities for the client
39
+ * depending on if you want to use use the data collector or paypal.
40
+ *
41
+ * We use this class mostly to hide the token operations for users.
42
+ *
43
+ * After creating the class, a call should be made to initialize before using it.
44
+ * @see initialize
45
+ *
46
+ * @constructor
47
+ * @param {Object} config Initalization options for the client
48
+ * @param {Boolean} config.useDataCollector Use data collector capabilities for the braintree client
49
+ * @param {Boolean} config.usePaypal Use Paypal capabilities for the braintree client
50
+ * @param {requestCallback} config.readyCallback A callback to be invoked when the client is ready to go.
51
+ * @param {Number} config.paymentMethodId A number indicating a specific payment method to be preferrred.
52
+ *
53
+ **/
54
+ SolidusBraintree.Client = function(config) {
55
+ this.paymentMethodId = config.paymentMethodId;
56
+ this.readyCallback = config.readyCallback;
57
+ this.useDataCollector = config.useDataCollector;
58
+ this.usePaypal = config.usePaypal;
59
+ this.useApplepay = config.useApplepay;
60
+ this.useVenmo = config.useVenmo;
61
+ this.flow = config.flow;
62
+ this.venmoNewTabSupported = config.newBrowserTabSupported
63
+ this.useThreeDSecure = config.useThreeDSecure;
64
+
65
+ this._braintreeInstance = null;
66
+ this._dataCollectorInstance = null;
67
+ this._paypalInstance = null;
68
+ this._venmoInstance = null;
69
+ this._threeDSecureInstance = null;
70
+ };
71
+
72
+ /**
73
+ * Fetches a client token from the backend and initializes the braintree client.
74
+ * @returns {external:"jQuery.Deferred"} Promise to be invoked after initialization is complete
75
+ **/
76
+ SolidusBraintree.Client.prototype.initialize = function() {
77
+ var initializationPromise = this._fetchToken().
78
+ then(this._createBraintreeInstance.bind(this));
79
+
80
+ if (this.useDataCollector) {
81
+ initializationPromise = initializationPromise.then(this._createDataCollector.bind(this));
82
+ }
83
+
84
+ if (this.usePaypal) {
85
+ initializationPromise = initializationPromise.then(this._createPaypal.bind(this));
86
+ }
87
+
88
+ if (this.useApplepay) {
89
+ initializationPromise = initializationPromise.then(this._createApplepay.bind(this));
90
+ }
91
+
92
+ if (this.useVenmo) {
93
+ initializationPromise = initializationPromise.then(this._createVenmo.bind(this));
94
+ }
95
+
96
+ if (this.useThreeDSecure) {
97
+ initializationPromise = initializationPromise.then(this._createThreeDSecure.bind(this));
98
+ }
99
+
100
+ return initializationPromise.then(this._invokeReadyCallback.bind(this));
101
+ };
102
+
103
+ /**
104
+ * Returns the braintree client instance
105
+ * @returns {external:"braintree.Client"} The braintree client that was initialized by this class
106
+ **/
107
+ SolidusBraintree.Client.prototype.getBraintreeInstance = function() {
108
+ return this._braintreeInstance;
109
+ };
110
+
111
+ /**
112
+ * Returns the braintree paypal instance
113
+ * @returns {external:"braintree.PayPal"} The braintree paypal that was initialized by this class
114
+ **/
115
+ SolidusBraintree.Client.prototype.getPaypalInstance = function() {
116
+ return this._paypalInstance;
117
+ };
118
+
119
+ /**
120
+ * Returns the braintree Apple Pay instance
121
+ * @returns {external:"braintree.ApplePay"} The Braintree Apple Pay that was initialized by this class
122
+ **/
123
+ SolidusBraintree.Client.prototype.getApplepayInstance = function() {
124
+ return this._applepayInstance;
125
+ };
126
+
127
+ /**
128
+ * Returns the braintree Venmo instance
129
+ * @returns {external:"braintree.Venmo"} The Braintree Venmo that was initialized by this class
130
+ **/
131
+ SolidusBraintree.Client.prototype.getVenmoInstance = function() {
132
+ return this._venmoInstance;
133
+ };
134
+
135
+ /**
136
+ * Returns the braintree dataCollector instance
137
+ * @returns {external:"braintree.DataCollector"} The braintree dataCollector that was initialized by this class
138
+ **/
139
+ SolidusBraintree.Client.prototype.getDataCollectorInstance = function() {
140
+ return this._dataCollectorInstance;
141
+ };
142
+
143
+
144
+ SolidusBraintree.Client.prototype._fetchToken = function() {
145
+ var payload = {
146
+ dataType: 'json',
147
+ type: 'POST',
148
+ url: SolidusBraintree.config.paths.clientTokens,
149
+ error: function(xhr) {
150
+ console.error("Error fetching braintree token");
151
+ }
152
+ };
153
+
154
+ if (this.paymentMethodId) {
155
+ payload.data = {
156
+ payment_method_id: this.paymentMethodId
157
+ };
158
+ }
159
+
160
+ return Spree.ajax(payload);
161
+ };
162
+
163
+ SolidusBraintree.Client.prototype._createBraintreeInstance = function(tokenResponse) {
164
+ this.paymentMethodId = tokenResponse.payment_method_id;
165
+
166
+ return SolidusBraintree.PromiseShim.convertBraintreePromise(braintree.client.create, [{
167
+ authorization: tokenResponse.client_token
168
+ }]).then(function (clientInstance) {
169
+ this._braintreeInstance = clientInstance;
170
+ return clientInstance;
171
+ }.bind(this));
172
+ };
173
+
174
+ SolidusBraintree.Client.prototype._invokeReadyCallback = function() {
175
+ if(this.readyCallback) {
176
+ this.readyCallback(this._braintreeInstance);
177
+ }
178
+
179
+ return this;
180
+ };
181
+
182
+ SolidusBraintree.Client.prototype._createDataCollector = function() {
183
+ return SolidusBraintree.PromiseShim.convertBraintreePromise(braintree.dataCollector.create, [{
184
+ client: this._braintreeInstance,
185
+ paypal: !!this.usePaypal
186
+ }]).then(function (dataCollectorInstance) {
187
+ this._dataCollectorInstance = dataCollectorInstance;
188
+ return dataCollectorInstance;
189
+ }.bind(this));
190
+ };
191
+
192
+ SolidusBraintree.Client.prototype._createPaypal = function() {
193
+ return SolidusBraintree.PromiseShim.convertBraintreePromise(braintree.paypalCheckout.create, [{
194
+ client: this._braintreeInstance
195
+ }]).then(function (paypalInstance) {
196
+ this._paypalInstance = paypalInstance;
197
+ return paypalInstance;
198
+ }.bind(this), function(error) {
199
+ console.error(error.name + ':', error.message);
200
+ });
201
+ };
202
+
203
+ SolidusBraintree.Client.prototype._createApplepay = function() {
204
+ return SolidusBraintree.PromiseShim.convertBraintreePromise(braintree.applePay.create, [{
205
+ client: this._braintreeInstance
206
+ }]).then(function (applePayInstance) {
207
+ this._applepayInstance = applePayInstance;
208
+ return applePayInstance;
209
+ }.bind(this));
210
+ };
211
+
212
+ SolidusBraintree.Client.prototype._createVenmo = function() {
213
+ return SolidusBraintree.PromiseShim.convertBraintreePromise(braintree.venmo.create, [{
214
+ client: this._braintreeInstance,
215
+ allowDesktop: true,
216
+ paymentMethodUsage: this.flow === 'vault' ? 'multi_use' : 'single_use',
217
+ allowNewBrowserTab: this.venmoNewTabSupported
218
+ }]).then(function (venmoInstance) {
219
+ // Verify browser support before proceeding.
220
+ if (!venmoInstance.isBrowserSupported()) {
221
+ console.log('Browser does not support Venmo');
222
+ return;
223
+ }
224
+
225
+ this._venmoInstance = venmoInstance;
226
+ return venmoInstance;
227
+ }.bind(this));
228
+ };
229
+
230
+ SolidusBraintree.Client.prototype._createThreeDSecure = function() {
231
+ return SolidusBraintree.PromiseShim.convertBraintreePromise(braintree.threeDSecure.create, [{
232
+ client: this._braintreeInstance,
233
+ version: 2
234
+ }]).then(function (threeDSecureInstance) {
235
+ this._threeDSecureInstance = threeDSecureInstance;
236
+ }.bind(this), function(error) {
237
+ console.log(error);
238
+ });
239
+ };
@@ -0,0 +1,89 @@
1
+ SolidusBraintree = {
2
+ APPLE_PAY_API_VERSION: 1,
3
+
4
+ config: {
5
+ paths: {
6
+ clientTokens: Spree.pathFor('solidus_braintree/client_token'),
7
+ transactions: Spree.pathFor('solidus_braintree/transactions')
8
+ },
9
+
10
+ // Override to provide your own error messages.
11
+ braintreeErrorHandle: function(braintreeError) {
12
+ BraintreeError.getErrorFromSlug(braintreeError.code);
13
+ SolidusBraintree.showError(error);
14
+ },
15
+
16
+ classes: {
17
+ hostedForm: function() {
18
+ return SolidusBraintree.HostedForm;
19
+ },
20
+
21
+ client: function() {
22
+ return SolidusBraintree.Client;
23
+ },
24
+
25
+ paypalButton: function() {
26
+ return SolidusBraintree.PaypalButton;
27
+ },
28
+
29
+ paypalMessaging: function() {
30
+ return SolidusBraintree.PaypalMessaging;
31
+ },
32
+
33
+ applepayButton: function() {
34
+ return SolidusBraintree.ApplepayButton;
35
+ },
36
+
37
+ venmoButton: function() {
38
+ return SolidusBraintree.VenmoButton;
39
+ }
40
+ }
41
+ },
42
+
43
+ showError: function(error) {
44
+ var $contentContainer = $("#content");
45
+ var $flash = $("<div class='flash error'>" + error + "</div>");
46
+ $contentContainer.prepend($flash);
47
+ $flash.show().delay(5000).fadeOut(500);
48
+ },
49
+
50
+ createHostedForm: function() {
51
+ return SolidusBraintree._factory(SolidusBraintree.config.classes.hostedForm(), arguments);
52
+ },
53
+
54
+ createClient: function() {
55
+ return SolidusBraintree._factory(SolidusBraintree.config.classes.client(), arguments);
56
+ },
57
+
58
+ createPaypalButton: function() {
59
+ return SolidusBraintree._factory(SolidusBraintree.config.classes.paypalButton(), arguments);
60
+ },
61
+
62
+ createPaypalMessaging: function() {
63
+ return SolidusBraintree._factory(SolidusBraintree.config.classes.paypalMessaging(), arguments);
64
+ },
65
+
66
+ createApplePayButton: function() {
67
+ return SolidusBraintree._factory(SolidusBraintree.config.classes.applepayButton(), arguments);
68
+ },
69
+
70
+ createVenmoButton: function() {
71
+ return SolidusBraintree._factory(SolidusBraintree.config.classes.venmoButton(), arguments);
72
+ },
73
+
74
+ _factory: function(klass, args) {
75
+ var normalizedArgs = Array.prototype.slice.call(args);
76
+ return new (Function.prototype.bind.apply(klass, [null].concat(normalizedArgs)));
77
+ }
78
+ };
79
+
80
+ BraintreeError = {
81
+ DEFAULT: "Something bad happened!",
82
+
83
+ getErrorFromSlug: function(slug) {
84
+ error = BraintreeError.DEFAULT
85
+ if (slug in BraintreeError)
86
+ error = BraintreeError[slug]
87
+ return error
88
+ }
89
+ }
@@ -0,0 +1,14 @@
1
+ // This is a manifest file that'll be compiled into including all the files listed below.
2
+ // Add new JavaScript/Coffee code in separate files in this directory and they'll automatically
3
+ // be included in the compiled file accessible from http://example.com/assets/application.js
4
+ // It's not advisable to add code directly here, but if you do, it'll appear at the bottom of the
5
+ // the compiled file.
6
+ //
7
+ //= require solidus_braintree/constants
8
+ //= require solidus_braintree/promise
9
+ //= require solidus_braintree/client
10
+ //= require solidus_braintree/hosted_form
11
+ //= require solidus_braintree/paypal_button
12
+ //= require solidus_braintree/paypal_messaging
13
+ //= require solidus_braintree/apple_pay_button
14
+ //= require solidus_braintree/venmo_button
@@ -0,0 +1,46 @@
1
+ SolidusBraintree.HostedForm = function(paymentMethodId) {
2
+ this.paymentMethodId = paymentMethodId;
3
+ this.client = null;
4
+ };
5
+
6
+ SolidusBraintree.HostedForm.prototype.initialize = function() {
7
+ this.client = SolidusBraintree.createClient({
8
+ paymentMethodId: this.paymentMethodId,
9
+ useThreeDSecure: (typeof(window.threeDSecureOptions) !== 'undefined'),
10
+ });
11
+
12
+ return this.client.initialize().
13
+ then(this._createHostedFields.bind(this));
14
+ };
15
+
16
+ SolidusBraintree.HostedForm.prototype._createHostedFields = function () {
17
+ if (!this.client) {
18
+ throw new Error("Client not initialized, please call initialize first!");
19
+ }
20
+
21
+ var opts = {
22
+ _solidusClient: this.client,
23
+ client: this.client.getBraintreeInstance(),
24
+
25
+ fields: {
26
+ number: {
27
+ selector: "#card_number" + this.paymentMethodId,
28
+ placeholder: placeholder_text["number"]
29
+ },
30
+
31
+ cvv: {
32
+ selector: "#card_code" + this.paymentMethodId,
33
+ placeholder: placeholder_text["cvv"]
34
+ },
35
+
36
+ expirationDate: {
37
+ selector: "#card_expiry" + this.paymentMethodId,
38
+ placeholder: placeholder_text["expirationDate"]
39
+ }
40
+ },
41
+
42
+ styles: credit_card_fields_style
43
+ };
44
+
45
+ return SolidusBraintree.PromiseShim.convertBraintreePromise(braintree.hostedFields.create, [opts]);
46
+ };
@@ -0,0 +1,178 @@
1
+ //= require solidus_braintree/constants
2
+ /**
3
+ * Constructor for PayPal button object
4
+ * @constructor
5
+ * @param {object} element - The DOM element of your PayPal button
6
+ */
7
+ SolidusBraintree.PaypalButton = function(element, paypalOptions, options) {
8
+ this._element = element;
9
+ this._paypalOptions = paypalOptions || {};
10
+
11
+ this.locale = paypalOptions['locale'] || "en_US";
12
+ this.style = paypalOptions['style'] || {};
13
+ delete paypalOptions['locale'];
14
+ delete paypalOptions['style'];
15
+
16
+ this._options = options || {};
17
+ this._client = null;
18
+ this._environment = this._paypalOptions.environment || 'sandbox';
19
+ delete this._paypalOptions.environment;
20
+
21
+ this._buyerCountry = this._paypalOptions.buyerCountry;
22
+ delete paypalOptions['buyerCountry'];
23
+
24
+ this._enabledFunding = [];
25
+
26
+ if (paypalOptions['venmoFunding']) this._enabledFunding.push('venmo');
27
+ delete paypalOptions['venmoFunding'];
28
+
29
+ if(!this._element) {
30
+ throw new Error("Element for the paypal button must be present on the page");
31
+ }
32
+ };
33
+
34
+ /**
35
+ * Creates the PayPal session using the provided options and enables the button
36
+ *
37
+ * @param {object} options - The options passed to tokenize when constructing
38
+ * the PayPal instance
39
+ *
40
+ * See {@link https://braintree.github.io/braintree-web/3.9.0/PayPal.html#tokenize}
41
+ */
42
+ SolidusBraintree.PaypalButton.prototype.initialize = function() {
43
+ this._client = new SolidusBraintree.createClient({
44
+ useDataCollector: this._paypalOptions.useDataCollector,
45
+ usePaypal: true
46
+ });
47
+
48
+ return this._client.initialize().then(this.initializeCallback.bind(this));
49
+ };
50
+
51
+ SolidusBraintree.PaypalButton.prototype.initializeCallback = function() {
52
+ this._paymentMethodId = this._client.paymentMethodId;
53
+
54
+ var args = {
55
+ "client-id": this._environment === "sandbox" ? "sb" : null,
56
+ currency: this._paypalOptions.currency,
57
+ commit: true,
58
+ vault: this._paypalOptions.flow == "vault",
59
+ components: this.style['messaging'] == "true" && this._paypalOptions.flow != "vault" ? "buttons,messages" : "buttons",
60
+ intent: this._paypalOptions.flow == "vault" ? "tokenize" : "authorize"
61
+ };
62
+
63
+ if (this._environment === "sandbox" && this._buyerCountry) {
64
+ args["buyer-country"] = this._buyerCountry
65
+ }
66
+ if (this._enabledFunding.length !== 0) {
67
+ args["enable-funding"] = this._enabledFunding.join(',');
68
+ }
69
+
70
+ this._client.getPaypalInstance().loadPayPalSDK(args).then(() => {
71
+ var create_method = this._paypalOptions.flow == "vault" ? "createBillingAgreement" : "createOrder"
72
+
73
+ var render_config = {
74
+ style: this.style,
75
+ onClick: (data) => { SolidusBraintree.fundingSource = data.fundingSource },
76
+ [create_method]: function () {
77
+ return this._client.getPaypalInstance().createPayment(this._paypalOptions);
78
+ }.bind(this),
79
+ onApprove: function (data, actions) {
80
+ return this._client.getPaypalInstance().tokenizePayment(data, this._tokenizeCallback.bind(this));
81
+ }.bind(this)
82
+ };
83
+
84
+ paypal.Buttons(render_config).render(this._element);
85
+ })
86
+ };
87
+
88
+ /**
89
+ * Default callback function for when tokenization completes
90
+ *
91
+ * @param {object|null} tokenizeErr - The error returned by Braintree on failure
92
+ * @param {object} payload - The payload returned by Braintree on success
93
+ */
94
+ SolidusBraintree.PaypalButton.prototype._tokenizeCallback = function(tokenizeErr, payload) {
95
+ if (tokenizeErr) {
96
+ SolidusBraintree.config.braintreeErrorHandle(tokenizeErr);
97
+ return;
98
+ }
99
+
100
+ var params = this._transactionParams(payload);
101
+
102
+ return Spree.ajax({
103
+ url: SolidusBraintree.config.paths.transactions,
104
+ type: 'POST',
105
+ dataType: 'json',
106
+ data: params,
107
+ success: function(response) {
108
+ window.location.href = response.redirectUrl;
109
+ },
110
+ error: function(xhr) {
111
+ var errorText = BraintreeError.DEFAULT;
112
+
113
+ if (xhr.responseJSON && xhr.responseJSON.errors) {
114
+ var errors = [];
115
+ $.each(xhr.responseJSON.errors, function(key, values) {
116
+ $.each(values, function(index, value) {
117
+ errors.push(key + " " + value)
118
+ });
119
+ });
120
+
121
+ if (errors.length > 0)
122
+ errorText = errors.join(", ");
123
+ }
124
+
125
+ console.error("Error submitting transaction: " + errorText);
126
+ SolidusBraintree.showError(errorText);
127
+ },
128
+ });
129
+ };
130
+
131
+ /**
132
+ * Builds the transaction parameters to submit to Solidus for the given
133
+ * payload returned by Braintree
134
+ *
135
+ * @param {object} payload - The payload returned by Braintree after tokenization
136
+ */
137
+ SolidusBraintree.PaypalButton.prototype._transactionParams = function(payload) {
138
+ return {
139
+ "payment_method_id" : this._paymentMethodId,
140
+ "options": this._options,
141
+ "transaction" : {
142
+ "email" : payload.details.email,
143
+ "phone" : payload.details.phone,
144
+ "nonce" : payload.nonce,
145
+ "payment_type" : payload.type,
146
+ "paypal_funding_source": SolidusBraintree.fundingSource,
147
+ "address_attributes" : this._addressParams(payload)
148
+ }
149
+ };
150
+ };
151
+
152
+ /**
153
+ * Builds the address parameters to submit to Solidus using the payload
154
+ * returned by Braintree
155
+ *
156
+ * @param {object} payload - The payload returned by Braintree after tokenization
157
+ */
158
+ SolidusBraintree.PaypalButton.prototype._addressParams = function(payload) {
159
+ var name;
160
+ var payload_address = payload.details.shippingAddress || payload.details.billingAddress;
161
+ if (!payload_address) return {};
162
+
163
+ if (payload_address.recipientName) {
164
+ name = payload_address.recipientName
165
+ } else {
166
+ name = payload.details.firstName + " " + payload.details.lastName;
167
+ }
168
+
169
+ return {
170
+ "name" : name,
171
+ "address_line_1" : payload_address.line1,
172
+ "address_line_2" : payload_address.line2,
173
+ "city" : payload_address.city,
174
+ "state_code" : payload_address.state,
175
+ "zip" : payload_address.postalCode,
176
+ "country_code" : payload_address.countryCode
177
+ };
178
+ };
@@ -0,0 +1,22 @@
1
+ //= require solidus_braintree/constants
2
+
3
+ SolidusBraintree.PaypalMessaging = function(paypalOptions) {
4
+ this._paypalOptions = paypalOptions || {};
5
+
6
+ this._client = null;
7
+ };
8
+
9
+ SolidusBraintree.PaypalMessaging.prototype.initialize = function() {
10
+ this._client = new SolidusBraintree.createClient({usePaypal: true});
11
+
12
+ return this._client.initialize().then(this.initializeCallback.bind(this));
13
+ };
14
+
15
+ SolidusBraintree.PaypalMessaging.prototype.initializeCallback = function() {
16
+ this._paymentMethodId = this._client.paymentMethodId;
17
+
18
+ this._client.getPaypalInstance().loadPayPalSDK({
19
+ currency: this._paypalOptions.currency,
20
+ components: "messages"
21
+ })
22
+ };
@@ -0,0 +1,20 @@
1
+ SolidusBraintree.PromiseShim = {
2
+ convertBraintreePromise: function(fn, args, context) {
3
+ var jqPromise = $.Deferred();
4
+
5
+ args = args || [];
6
+ context = context || this;
7
+
8
+ args = args.concat(function(error, data) {
9
+ if (error) {
10
+ jqPromise.reject(error);
11
+ } else {
12
+ jqPromise.resolve(data);
13
+ }
14
+ });
15
+
16
+ fn.apply(context, args);
17
+
18
+ return jqPromise.promise();
19
+ }
20
+ }
@@ -0,0 +1,86 @@
1
+ //= require solidus_braintree/constants
2
+ /**
3
+ * Constructor for Venmo button object
4
+ * @constructor
5
+ * @param {object} element - The DOM element of your Venmo button
6
+ */
7
+ SolidusBraintree.VenmoButton = function(element, venmoOptions) {
8
+ this._element = element;
9
+ this._client = null;
10
+ this._venmoOptions = venmoOptions || {};
11
+
12
+ if(!this._element) {
13
+ throw new Error("Element for the Venmo button must be present on the page");
14
+ }
15
+ };
16
+
17
+ /**
18
+ * Creates the Venmo session using the provided options and enables the button
19
+ *
20
+ * @param {object} options - The options passed to tokenize when constructing
21
+ * the Venmo instance
22
+ *
23
+ * See {@link https://braintree.github.io/braintree-web/3.84.0/module-braintree-web_venmo.html#.create}
24
+ */
25
+ SolidusBraintree.VenmoButton.prototype.initialize = function() {
26
+ this._client = new SolidusBraintree.createClient({
27
+ useVenmo: true,
28
+ newBrowserTabSupported: this._venmoOptions.newBrowserTabSupported,
29
+ flow: this._venmoOptions.flow
30
+ });
31
+
32
+ return this._client.initialize().then(this.initializeCallback.bind(this));
33
+ };
34
+
35
+ SolidusBraintree.VenmoButton.prototype.initializeCallback = function() {
36
+ this._venmoInstance = this._client.getVenmoInstance();
37
+
38
+ this._element.classList.add('visible');
39
+
40
+ // Check if tokenization results already exist. This occurs when your
41
+ // checkout page is relaunched in a new tab.
42
+ if (!this._venmoOptions.newBrowserTabSupported && this._venmoInstance.hasTokenizationResult()) {
43
+ this.tokenize();
44
+ }
45
+
46
+ this._element.addEventListener('click', function(event) {
47
+ event.preventDefault();
48
+ this._element.disabled = true;
49
+ this.initializeVenmoSession();
50
+ }.bind(this), false);
51
+ };
52
+
53
+ SolidusBraintree.VenmoButton.prototype.initializeVenmoSession = function() {
54
+ this.tokenize();
55
+ };
56
+
57
+ SolidusBraintree.VenmoButton.prototype.tokenize = function() {
58
+ var venmoButton = this._element;
59
+ this._venmoInstance.tokenize().then(handleVenmoSuccess).catch(handleVenmoError).then(function () {
60
+ venmoButton.removeAttribute('disabled');
61
+ });
62
+ };
63
+
64
+ function handleVenmoSuccess(payload) {
65
+ var $paymentForm = $("#checkout_form_payment");
66
+ var $nonceField = $("#venmo_payment_method_nonce", $paymentForm);
67
+
68
+ // Disable hostedFields' and enable Venmo's inputs as they use the same fields.
69
+ // Otherwise, they will clash. (Disabled inputs are not used on form submission)
70
+ $('.hosted-fields input').each(function(_index, input) {
71
+ input.disabled = true;
72
+ });
73
+ $('.venmo-fields input').each(function(_index, input) {
74
+ input.removeAttribute('disabled');
75
+ });
76
+
77
+ // remove hostedFields submit listener, otherwise empty credit card errors occur
78
+ $paymentForm.off('submit');
79
+
80
+ $nonceField.val(payload.nonce);
81
+ $paymentForm.submit();
82
+ }
83
+
84
+ function handleVenmoError(error) {
85
+ SolidusBraintree.config.braintreeErrorHandle(error);
86
+ }