solidus_paypal_braintree 1.0.0 → 1.1.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.rubocop.yml +9 -1
- data/Gemfile +1 -3
- data/README.md +96 -5
- data/app/assets/config/solidus_paypal_braintree_manifest.js +1 -0
- data/app/assets/images/solidus_paypal_braintree/venmo/venmo_active_blue_button_280x48.svg +19 -0
- data/app/assets/images/solidus_paypal_braintree/venmo/venmo_active_blue_button_320x48.svg +19 -0
- data/app/assets/images/solidus_paypal_braintree/venmo/venmo_active_blue_button_375x48.svg +19 -0
- data/app/assets/images/solidus_paypal_braintree/venmo/venmo_active_white_button_280x48.svg +19 -0
- data/app/assets/images/solidus_paypal_braintree/venmo/venmo_active_white_button_320x48.svg +19 -0
- data/app/assets/images/solidus_paypal_braintree/venmo/venmo_active_white_button_375x48.svg +19 -0
- data/app/assets/images/solidus_paypal_braintree/venmo/venmo_blue_acceptance_mark.svg +15 -0
- data/app/assets/images/solidus_paypal_braintree/venmo/venmo_blue_button_280x48.svg +19 -0
- data/app/assets/images/solidus_paypal_braintree/venmo/venmo_blue_button_320x48.svg +19 -0
- data/app/assets/images/solidus_paypal_braintree/venmo/venmo_blue_button_375x48.svg +19 -0
- data/app/assets/images/solidus_paypal_braintree/venmo/venmo_blue_logo.svg +18 -0
- data/app/assets/images/solidus_paypal_braintree/venmo/venmo_white_acceptance_mark.svg +20 -0
- data/app/assets/images/solidus_paypal_braintree/venmo/venmo_white_button_280x48.svg +19 -0
- data/app/assets/images/solidus_paypal_braintree/venmo/venmo_white_button_320x48.svg +19 -0
- data/app/assets/images/solidus_paypal_braintree/venmo/venmo_white_button_375x48.svg +19 -0
- data/app/assets/images/solidus_paypal_braintree/venmo/venmo_white_logo.svg +18 -0
- data/app/assets/javascripts/solidus_paypal_braintree/client.js +34 -0
- data/app/assets/javascripts/solidus_paypal_braintree/constants.js +8 -0
- data/app/assets/javascripts/solidus_paypal_braintree/frontend.js +1 -0
- data/app/assets/javascripts/solidus_paypal_braintree/paypal_button.js +26 -3
- data/app/assets/javascripts/solidus_paypal_braintree/venmo_button.js +86 -0
- data/app/assets/javascripts/spree/backend/solidus_paypal_braintree.js +2 -2
- data/app/assets/javascripts/spree/frontend/paypal_button.js +3 -3
- data/app/assets/stylesheets/spree/frontend/solidus_paypal_braintree.css +12 -0
- data/app/decorators/controllers/solidus_paypal_braintree/checkout_controller_decorator.rb +1 -1
- data/app/decorators/controllers/solidus_paypal_braintree/orders_controller_decorator.rb +1 -1
- data/app/helpers/solidus_paypal_braintree/braintree_checkout_helper.rb +19 -5
- data/app/models/solidus_paypal_braintree/address.rb +43 -9
- data/app/models/solidus_paypal_braintree/avs_result.rb +3 -0
- data/app/models/solidus_paypal_braintree/configuration.rb +15 -2
- data/app/models/solidus_paypal_braintree/gateway.rb +27 -2
- data/app/models/solidus_paypal_braintree/source.rb +31 -2
- data/app/models/solidus_paypal_braintree/transaction.rb +1 -1
- data/app/models/solidus_paypal_braintree/transaction_address.rb +17 -13
- data/app/models/solidus_paypal_braintree/transaction_import.rb +2 -1
- data/app/overrides/spree/payments/payment/add_paypal_funding_source_to_payment.rb +9 -0
- data/app/views/spree/shared/_braintree_errors.html.erb +3 -0
- data/app/views/spree/shared/_paypal_braintree_head_scripts.html.erb +10 -6
- data/app/views/spree/shared/_paypal_cart_button.html.erb +2 -0
- data/app/views/spree/shared/_venmo_button.html.erb +33 -0
- data/config/locales/en.yml +34 -0
- data/config/locales/it.yml +2 -0
- data/db/migrate/20211222170950_add_paypal_funding_source_to_solidus_paypal_braintree_sources.rb +5 -0
- data/db/migrate/20220104150301_add_venmo_to_braintree_configuration.rb +5 -0
- data/lib/controllers/backend/solidus_paypal_braintree/configurations_controller.rb +4 -1
- data/lib/controllers/frontend/solidus_paypal_braintree/transactions_controller.rb +1 -0
- data/lib/solidus_paypal_braintree/engine.rb +4 -2
- data/lib/solidus_paypal_braintree/factories.rb +32 -1
- data/lib/solidus_paypal_braintree/version.rb +1 -1
- data/lib/views/backend/solidus_paypal_braintree/configurations/list.html.erb +8 -0
- data/lib/views/backend/spree/admin/payments/source_views/_paypal_braintree.html.erb +5 -0
- data/lib/views/backend/spree/admin/shared/preference_fields/_preference_select.html.erb +13 -0
- data/lib/views/frontend/solidus_paypal_braintree/payments/_payment.html.erb +12 -0
- data/lib/views/frontend/spree/checkout/payment/_paypal_braintree.html.erb +4 -0
- data/lib/views/frontend/spree/shared/_paypal_checkout_button.html.erb +2 -0
- data/solidus_paypal_braintree.gemspec +6 -5
- data/spec/controllers/solidus_paypal_braintree/transactions_controller_spec.rb +1 -1
- data/spec/features/frontend/braintree_credit_card_checkout_spec.rb +5 -1
- data/spec/features/frontend/venmo_checkout_spec.rb +189 -0
- data/spec/fixtures/cassettes/checkout/valid_venmo_transaction.yml +599 -0
- data/spec/helpers/solidus_paypal_braintree/braintree_checkout_helper_spec.rb +70 -0
- data/spec/models/solidus_paypal_braintree/address_spec.rb +20 -0
- data/spec/models/solidus_paypal_braintree/gateway_spec.rb +1 -1
- data/spec/models/solidus_paypal_braintree/source_spec.rb +139 -0
- data/spec/models/solidus_paypal_braintree/transaction_address_spec.rb +8 -26
- data/spec/models/solidus_paypal_braintree/transaction_import_spec.rb +17 -0
- data/spec/spec_helper.rb +3 -0
- metadata +52 -15
@@ -0,0 +1,19 @@
|
|
1
|
+
<?xml version="1.0" encoding="UTF-8"?>
|
2
|
+
<svg width="375px" height="48px" viewBox="0 0 375 48" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
|
3
|
+
<!-- Generator: Sketch 46.1 (44463) - http://www.bohemiancoding.com/sketch -->
|
4
|
+
<title>svg/white_venmo_button_375x48</title>
|
5
|
+
<desc>Created with Sketch.</desc>
|
6
|
+
<defs></defs>
|
7
|
+
<g id="Page-1" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
|
8
|
+
<g id="white_venmo_button_375x48">
|
9
|
+
<rect id="Rectangle" fill="#FFFFFF" x="0" y="0" width="375" height="48" rx="4"></rect>
|
10
|
+
<g id="Group" transform="translate(146.000000, 16.000000)" fill="#3D95CE">
|
11
|
+
<path d="M14.1355722,0.0643062201 C14.6997229,0.996022242 14.9540614,1.95569119 14.9540614,3.16795034 C14.9540614,7.03443424 11.6533091,12.0572714 8.97435371,15.5842648 L2.85545503,15.5842648 L0.401435711,0.910859951 L5.75920168,0.402203543 L7.05667586,10.8432743 C8.26898429,8.86832019 9.76503373,5.76467606 9.76503373,3.64865382 C9.76503373,2.49041769 9.56660332,1.70150782 9.25650148,1.0519281 L14.1355722,0.0643062201 L14.1355722,0.0643062201 Z" id="Shape"></path>
|
12
|
+
<path d="M21.0794779,6.525633 C22.0654018,6.525633 24.5475201,6.07462046 24.5475201,4.66393896 C24.5475201,3.98655114 24.0685351,3.64865382 23.5040948,3.64865382 C22.5165776,3.64865382 21.2206966,4.83281521 21.0794779,6.525633 L21.0794779,6.525633 Z M20.9665029,9.31947756 C20.9665029,11.0419863 21.924328,11.7177809 23.1941378,11.7177809 C24.5769225,11.7177809 25.9009024,11.3798836 27.6217431,10.505377 L26.9735853,14.9065874 C25.7611321,15.4989577 23.8715531,15.8942092 22.0374478,15.8942092 C17.3850512,15.8942092 15.7199738,13.0728462 15.7199738,9.545708 C15.7199738,4.97417302 18.4284766,0.120067244 24.0124822,0.120067244 C27.08685,0.120067244 28.8059526,1.84243114 28.8059526,4.24073451 C28.8062423,8.10707358 23.8437439,9.29152463 20.9665029,9.31947756 L20.9665029,9.31947756 Z" id="Shape"></path>
|
13
|
+
<path d="M44.2677372,3.50758567 C44.2677372,4.07185827 44.1821369,4.89031424 44.0969712,5.42518557 L42.4892503,15.58412 L37.2722686,15.58412 L38.7387707,6.27159447 C38.7665799,6.01900427 38.8520354,5.51049269 38.8520354,5.22835639 C38.8520354,4.55096858 38.4288137,4.3819475 37.9199918,4.3819475 C37.2441697,4.3819475 36.5667543,4.69203673 36.1155786,4.918412 L34.4522393,15.5842648 L29.2058551,15.5842648 L31.6026627,0.374540282 L36.1433878,0.374540282 L36.2008892,1.58853744 C37.2721237,0.88319669 38.6827177,0.120356912 40.6841129,0.120356912 C43.3356936,0.120067244 44.2677372,1.47498771 44.2677372,3.50758567 L44.2677372,3.50758567 Z" id="Shape"></path>
|
14
|
+
<path d="M59.7554481,1.78507694 C61.2496147,0.713885943 62.6604983,0.120067244 64.6058406,0.120067244 C67.2846511,0.120067244 68.216405,1.47498771 68.216405,3.50758567 C68.216405,4.07185827 68.1310944,4.89031424 68.0459287,5.42518557 L66.4400908,15.58412 L61.2216606,15.58412 L62.7161168,6.07476529 C62.7436363,5.82058192 62.8014274,5.51049269 62.8014274,5.31380835 C62.8014274,4.55111341 62.3780609,4.3819475 61.8693838,4.3819475 C61.2213709,4.3819475 60.5736477,4.6640838 60.0927798,4.918412 L58.4297302,15.5842648 L53.2126036,15.5842648 L54.7070598,6.07491013 C54.7345794,5.82072676 54.7906323,5.51063753 54.7906323,5.31395319 C54.7906323,4.55125824 54.367121,4.38209233 53.860182,4.38209233 C53.1829115,4.38209233 52.5069445,4.69218156 52.0557688,4.91855683 L50.3911259,15.5844097 L45.1464798,15.5844097 L47.5429977,0.374685116 L52.0282492,0.374685116 L52.1691783,1.64444329 C53.2126036,0.883486357 54.6220389,0.12064658 56.511473,0.12064658 C58.1474376,0.120067244 59.2185273,0.825552826 59.7554481,1.78507694 L59.7554481,1.78507694 Z" id="Shape"></path>
|
15
|
+
<path d="M78.5990953,6.21583344 C78.5990953,4.97417302 78.288559,4.12761929 77.358688,4.12761929 C75.2997914,4.12761929 74.8770043,7.76743825 74.8770043,9.62942196 C74.8770043,11.0419863 75.2722719,11.9162033 76.2018532,11.9162033 C78.1479196,11.9162033 78.5990953,8.07767231 78.5990953,6.21583344 L78.5990953,6.21583344 Z M69.5751464,9.40463986 C69.5751464,4.60817794 72.1127383,0.120067244 77.9512273,0.120067244 C82.3505888,0.120067244 83.9587442,2.71679297 83.9587442,6.30099573 C83.9587442,11.0418415 81.4485271,15.9514186 75.4692539,15.9514186 C71.0415037,15.9514186 69.5751464,13.0446036 69.5751464,9.40463986 L69.5751464,9.40463986 Z" id="Shape"></path>
|
16
|
+
</g>
|
17
|
+
</g>
|
18
|
+
</g>
|
19
|
+
</svg>
|
@@ -0,0 +1,18 @@
|
|
1
|
+
<?xml version="1.0" encoding="UTF-8"?>
|
2
|
+
<svg width="126px" height="24px" viewBox="0 0 126 24" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
|
3
|
+
<!-- Generator: Sketch 46.1 (44463) - http://www.bohemiancoding.com/sketch -->
|
4
|
+
<title>white_logosvg/</title>
|
5
|
+
<desc>Created with Sketch.</desc>
|
6
|
+
<defs></defs>
|
7
|
+
<g id="Page-1" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
|
8
|
+
<g id="white_logo" fill="#FFFFFF">
|
9
|
+
<g id="Group">
|
10
|
+
<path d="M21.2033583,0.0964593301 C22.0495843,1.49403336 22.4310921,2.93353679 22.4310921,4.75192551 C22.4310921,10.5516514 17.4799637,18.0859072 13.4615306,23.3763973 L4.28318255,23.3763973 L0.602153567,1.36628993 L8.63880252,0.603305315 L10.5850138,16.2649114 C12.4034764,13.3024803 14.6475506,8.6470141 14.6475506,5.47298073 C14.6475506,3.73562654 14.349905,2.55226174 13.8847522,1.57789215 L21.2033583,0.0964593301 L21.2033583,0.0964593301 Z" id="Shape"></path>
|
11
|
+
<path d="M31.6192168,9.7884495 C33.0981028,9.7884495 36.8212801,9.11193069 36.8212801,6.99590844 C36.8212801,5.97982672 36.1028027,5.47298073 35.2561421,5.47298073 C33.7748663,5.47298073 31.8310449,7.24922281 31.6192168,9.7884495 L31.6192168,9.7884495 Z M31.4497544,13.9792163 C31.4497544,16.5629794 32.8864919,17.5766714 34.7912066,17.5766714 C36.8653838,17.5766714 38.8513536,17.0698254 41.4326146,15.7580654 L40.460378,22.359881 C38.6416981,23.2484366 35.8073297,23.8413138 33.0561717,23.8413138 C26.0775769,23.8413138 23.5799608,19.6092694 23.5799608,14.318562 C23.5799608,7.46125954 27.6427148,0.180100866 36.0187232,0.180100866 C40.630275,0.180100866 43.2089289,2.76364671 43.2089289,6.36110177 C43.2093634,12.1606104 35.7656158,13.937287 31.4497544,13.9792163 L31.4497544,13.9792163 Z" id="Shape"></path>
|
12
|
+
<path d="M66.4016058,5.26137851 C66.4016058,6.1077874 66.2732054,7.33547136 66.1454568,8.13777835 L63.7338755,23.37618 L55.9084028,23.37618 L58.108156,9.4073917 C58.1498699,9.0285064 58.278053,8.26573904 58.278053,7.84253459 C58.278053,6.82645286 57.6432206,6.57292125 56.8799877,6.57292125 C55.8662545,6.57292125 54.8501315,7.03805509 54.1733679,7.377618 L51.6783589,23.3763973 L43.8087826,23.3763973 L47.403994,0.561810423 L54.2150817,0.561810423 L54.3013338,2.38280616 C55.9081856,1.32479503 58.0240766,0.180535368 61.0261694,0.180535368 C65.0035404,0.180100866 66.4016058,2.21248157 66.4016058,5.26137851 L66.4016058,5.26137851 Z" id="Shape"></path>
|
13
|
+
<path d="M89.6331722,2.67761541 C91.874422,1.07082892 93.9907475,0.180100866 96.9087609,0.180100866 C100.926977,0.180100866 102.324608,2.21248157 102.324608,5.26137851 C102.324608,6.1077874 102.196642,7.33547136 102.068893,8.13777835 L99.6601361,23.37618 L91.8324909,23.37618 L94.0741752,9.11214794 C94.1154545,8.73087288 94.2021411,8.26573904 94.2021411,7.97071253 C94.2021411,6.82667012 93.5670913,6.57292125 92.8040757,6.57292125 C91.8320564,6.57292125 90.8604715,6.9961257 90.1391698,7.377618 L87.6445953,23.3763973 L79.8189054,23.3763973 L82.0605897,9.11236519 C82.101869,8.73109013 82.1859485,8.26595629 82.1859485,7.97092978 C82.1859485,6.82688737 81.5506815,6.5731385 80.790273,6.5731385 C79.7743672,6.5731385 78.7604168,7.03827234 78.0836532,7.37783525 L75.5866889,23.3766145 L67.7197197,23.3766145 L71.3144966,0.562027674 L78.0423739,0.562027674 L78.2537674,2.46666494 C79.8189054,1.32522954 81.9330583,0.180969869 84.7672095,0.180969869 C87.2211564,0.180100866 88.827791,1.23832924 89.6331722,2.67761541 L89.6331722,2.67761541 Z" id="Shape"></path>
|
14
|
+
<path d="M117.898643,9.32375016 C117.898643,7.46125954 117.432838,6.19142894 116.038032,6.19142894 C112.949687,6.19142894 112.315506,11.6511574 112.315506,14.4441329 C112.315506,16.5629794 112.908408,17.8743049 114.30278,17.8743049 C117.221879,17.8743049 117.898643,12.1165085 117.898643,9.32375016 L117.898643,9.32375016 Z M104.36272,14.1069598 C104.36272,6.91226691 108.169107,0.180100866 116.926841,0.180100866 C123.525883,0.180100866 125.938116,4.07518945 125.938116,9.4514936 C125.938116,16.5627622 122.172791,23.9271279 113.203881,23.9271279 C106.562256,23.9271279 104.36272,19.5669055 104.36272,14.1069598 L104.36272,14.1069598 Z" id="Shape"></path>
|
15
|
+
</g>
|
16
|
+
</g>
|
17
|
+
</g>
|
18
|
+
</svg>
|
@@ -57,11 +57,15 @@ SolidusPaypalBraintree.Client = function(config) {
|
|
57
57
|
this.useDataCollector = config.useDataCollector;
|
58
58
|
this.usePaypal = config.usePaypal;
|
59
59
|
this.useApplepay = config.useApplepay;
|
60
|
+
this.useVenmo = config.useVenmo;
|
61
|
+
this.flow = config.flow;
|
62
|
+
this.venmoNewTabSupported = config.newBrowserTabSupported
|
60
63
|
this.useThreeDSecure = config.useThreeDSecure;
|
61
64
|
|
62
65
|
this._braintreeInstance = null;
|
63
66
|
this._dataCollectorInstance = null;
|
64
67
|
this._paypalInstance = null;
|
68
|
+
this._venmoInstance = null;
|
65
69
|
this._threeDSecureInstance = null;
|
66
70
|
};
|
67
71
|
|
@@ -85,6 +89,10 @@ SolidusPaypalBraintree.Client.prototype.initialize = function() {
|
|
85
89
|
initializationPromise = initializationPromise.then(this._createApplepay.bind(this));
|
86
90
|
}
|
87
91
|
|
92
|
+
if (this.useVenmo) {
|
93
|
+
initializationPromise = initializationPromise.then(this._createVenmo.bind(this));
|
94
|
+
}
|
95
|
+
|
88
96
|
if (this.useThreeDSecure) {
|
89
97
|
initializationPromise = initializationPromise.then(this._createThreeDSecure.bind(this));
|
90
98
|
}
|
@@ -116,6 +124,14 @@ SolidusPaypalBraintree.Client.prototype.getApplepayInstance = function() {
|
|
116
124
|
return this._applepayInstance;
|
117
125
|
};
|
118
126
|
|
127
|
+
/**
|
128
|
+
* Returns the braintree Venmo instance
|
129
|
+
* @returns {external:"braintree.Venmo"} The Braintree Venmo that was initialized by this class
|
130
|
+
**/
|
131
|
+
SolidusPaypalBraintree.Client.prototype.getVenmoInstance = function() {
|
132
|
+
return this._venmoInstance;
|
133
|
+
};
|
134
|
+
|
119
135
|
/**
|
120
136
|
* Returns the braintree dataCollector instance
|
121
137
|
* @returns {external:"braintree.DataCollector"} The braintree dataCollector that was initialized by this class
|
@@ -193,6 +209,24 @@ SolidusPaypalBraintree.Client.prototype._createApplepay = function() {
|
|
193
209
|
}.bind(this));
|
194
210
|
};
|
195
211
|
|
212
|
+
SolidusPaypalBraintree.Client.prototype._createVenmo = function() {
|
213
|
+
return SolidusPaypalBraintree.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
|
+
|
196
230
|
SolidusPaypalBraintree.Client.prototype._createThreeDSecure = function() {
|
197
231
|
return SolidusPaypalBraintree.PromiseShim.convertBraintreePromise(braintree.threeDSecure.create, [{
|
198
232
|
client: this._braintreeInstance,
|
@@ -32,6 +32,10 @@ SolidusPaypalBraintree = {
|
|
32
32
|
|
33
33
|
applepayButton: function() {
|
34
34
|
return SolidusPaypalBraintree.ApplepayButton;
|
35
|
+
},
|
36
|
+
|
37
|
+
venmoButton: function() {
|
38
|
+
return SolidusPaypalBraintree.VenmoButton;
|
35
39
|
}
|
36
40
|
}
|
37
41
|
},
|
@@ -63,6 +67,10 @@ SolidusPaypalBraintree = {
|
|
63
67
|
return SolidusPaypalBraintree._factory(SolidusPaypalBraintree.config.classes.applepayButton(), arguments);
|
64
68
|
},
|
65
69
|
|
70
|
+
createVenmoButton: function() {
|
71
|
+
return SolidusPaypalBraintree._factory(SolidusPaypalBraintree.config.classes.venmoButton(), arguments);
|
72
|
+
},
|
73
|
+
|
66
74
|
_factory: function(klass, args) {
|
67
75
|
var normalizedArgs = Array.prototype.slice.call(args);
|
68
76
|
return new (Function.prototype.bind.apply(klass, [null].concat(normalizedArgs)));
|
@@ -18,6 +18,14 @@ SolidusPaypalBraintree.PaypalButton = function(element, paypalOptions, options)
|
|
18
18
|
this._environment = this._paypalOptions.environment || 'sandbox';
|
19
19
|
delete this._paypalOptions.environment;
|
20
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
|
+
|
21
29
|
if(!this._element) {
|
22
30
|
throw new Error("Element for the paypal button must be present on the page");
|
23
31
|
}
|
@@ -32,7 +40,10 @@ SolidusPaypalBraintree.PaypalButton = function(element, paypalOptions, options)
|
|
32
40
|
* See {@link https://braintree.github.io/braintree-web/3.9.0/PayPal.html#tokenize}
|
33
41
|
*/
|
34
42
|
SolidusPaypalBraintree.PaypalButton.prototype.initialize = function() {
|
35
|
-
this._client = new SolidusPaypalBraintree.createClient({
|
43
|
+
this._client = new SolidusPaypalBraintree.createClient({
|
44
|
+
useDataCollector: this._paypalOptions.useDataCollector,
|
45
|
+
usePaypal: true
|
46
|
+
});
|
36
47
|
|
37
48
|
return this._client.initialize().then(this.initializeCallback.bind(this));
|
38
49
|
};
|
@@ -40,17 +51,28 @@ SolidusPaypalBraintree.PaypalButton.prototype.initialize = function() {
|
|
40
51
|
SolidusPaypalBraintree.PaypalButton.prototype.initializeCallback = function() {
|
41
52
|
this._paymentMethodId = this._client.paymentMethodId;
|
42
53
|
|
43
|
-
|
54
|
+
var args = {
|
55
|
+
"client-id": this._environment === "sandbox" ? "sb" : null,
|
44
56
|
currency: this._paypalOptions.currency,
|
45
57
|
commit: true,
|
46
58
|
vault: this._paypalOptions.flow == "vault",
|
47
59
|
components: this.style['messaging'] == "true" && this._paypalOptions.flow != "vault" ? "buttons,messages" : "buttons",
|
48
60
|
intent: this._paypalOptions.flow == "vault" ? "tokenize" : "authorize"
|
49
|
-
}
|
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(() => {
|
50
71
|
var create_method = this._paypalOptions.flow == "vault" ? "createBillingAgreement" : "createOrder"
|
51
72
|
|
52
73
|
var render_config = {
|
53
74
|
style: this.style,
|
75
|
+
onClick: (data) => { SolidusPaypalBraintree.fundingSource = data.fundingSource },
|
54
76
|
[create_method]: function () {
|
55
77
|
return this._client.getPaypalInstance().createPayment(this._paypalOptions);
|
56
78
|
}.bind(this),
|
@@ -121,6 +143,7 @@ SolidusPaypalBraintree.PaypalButton.prototype._transactionParams = function(payl
|
|
121
143
|
"phone" : payload.details.phone,
|
122
144
|
"nonce" : payload.nonce,
|
123
145
|
"payment_type" : payload.type,
|
146
|
+
"paypal_funding_source": SolidusPaypalBraintree.fundingSource,
|
124
147
|
"address_attributes" : this._addressParams(payload)
|
125
148
|
}
|
126
149
|
};
|
@@ -0,0 +1,86 @@
|
|
1
|
+
//= require solidus_paypal_braintree/constants
|
2
|
+
/**
|
3
|
+
* Constructor for Venmo button object
|
4
|
+
* @constructor
|
5
|
+
* @param {object} element - The DOM element of your Venmo button
|
6
|
+
*/
|
7
|
+
SolidusPaypalBraintree.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
|
+
SolidusPaypalBraintree.VenmoButton.prototype.initialize = function() {
|
26
|
+
this._client = new SolidusPaypalBraintree.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
|
+
SolidusPaypalBraintree.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
|
+
SolidusPaypalBraintree.VenmoButton.prototype.initializeVenmoSession = function() {
|
54
|
+
this.tokenize();
|
55
|
+
};
|
56
|
+
|
57
|
+
SolidusPaypalBraintree.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
|
+
SolidusPaypalBraintree.config.braintreeErrorHandle(error);
|
86
|
+
}
|
@@ -68,8 +68,8 @@ $(function() {
|
|
68
68
|
if (!$paymentForm.length || !$hostedFields.length) { return; }
|
69
69
|
|
70
70
|
$.when(
|
71
|
-
$.getScript("https://js.braintreegateway.com/web/3.
|
72
|
-
$.getScript("https://js.braintreegateway.com/web/3.
|
71
|
+
$.getScript("https://js.braintreegateway.com/web/3.84.0/js/client.min.js"),
|
72
|
+
$.getScript("https://js.braintreegateway.com/web/3.84.0/js/hosted-fields.min.js")
|
73
73
|
).done(function() {
|
74
74
|
$hostedFields.each(function() {
|
75
75
|
var $this = $(this),
|
@@ -4,9 +4,9 @@
|
|
4
4
|
$(document).ready(function() {
|
5
5
|
if (document.getElementById("empty-cart")) {
|
6
6
|
$.when(
|
7
|
-
$.getScript("https://js.braintreegateway.com/
|
8
|
-
$.getScript("https://js.braintreegateway.com/
|
9
|
-
$.getScript("https://js.braintreegateway.com/
|
7
|
+
$.getScript("https://js.braintreegateway.com/3.84.0/js/client.min.js"),
|
8
|
+
$.getScript("https://js.braintreegateway.com/3.84.0/js/paypal-checkout.min.js"),
|
9
|
+
$.getScript("https://js.braintreegateway.com/3.84.0/js/data-collector.min.js")
|
10
10
|
).done(function() {
|
11
11
|
$("#content").append('<div id="paypal-button"/>');
|
12
12
|
$('<script/>').attr({
|
@@ -37,3 +37,15 @@ the installer will append this file to the app vendored assets here: 'vendor/ass
|
|
37
37
|
.apple-pay-button.visible {
|
38
38
|
visibility: visible;
|
39
39
|
}
|
40
|
+
|
41
|
+
.venmo-button {
|
42
|
+
visibility: hidden;
|
43
|
+
border: none;
|
44
|
+
height: 48px;
|
45
|
+
background-color: transparent;
|
46
|
+
background-repeat: no-repeat;
|
47
|
+
}
|
48
|
+
|
49
|
+
.venmo-button.visible {
|
50
|
+
visibility: visible;
|
51
|
+
}
|
@@ -3,9 +3,8 @@
|
|
3
3
|
module SolidusPaypalBraintree
|
4
4
|
module BraintreeCheckoutHelper
|
5
5
|
def braintree_3ds_options_for(order)
|
6
|
-
ship_address = order.ship_address
|
7
|
-
bill_address = order.bill_address
|
8
|
-
|
6
|
+
ship_address = SolidusPaypalBraintree::Address.new(order.ship_address)
|
7
|
+
bill_address = SolidusPaypalBraintree::Address.new(order.bill_address)
|
9
8
|
{
|
10
9
|
nonce: nil, # populated after tokenization
|
11
10
|
bin: nil, # populated after tokenization
|
@@ -19,7 +18,7 @@ module SolidusPaypalBraintree
|
|
19
18
|
streetAddress: bill_address.address1,
|
20
19
|
extendedAddress: bill_address.address2,
|
21
20
|
locality: bill_address.city,
|
22
|
-
region: bill_address.state&.
|
21
|
+
region: bill_address.state&.abbr,
|
23
22
|
postalCode: bill_address.zipcode,
|
24
23
|
countryCodeAlpha2: bill_address.country&.iso,
|
25
24
|
},
|
@@ -31,7 +30,7 @@ module SolidusPaypalBraintree
|
|
31
30
|
streedAddress: ship_address.address1,
|
32
31
|
extendedAddress: ship_address.address2,
|
33
32
|
locality: ship_address.city,
|
34
|
-
region: ship_address.state&.
|
33
|
+
region: ship_address.state&.abbr,
|
35
34
|
postalCode: ship_address.zipcode,
|
36
35
|
countryCodeAlpha2: ship_address.country&.iso,
|
37
36
|
}
|
@@ -42,5 +41,20 @@ module SolidusPaypalBraintree
|
|
42
41
|
def paypal_button_preference(key, store:)
|
43
42
|
store.braintree_configuration.preferences[key]
|
44
43
|
end
|
44
|
+
|
45
|
+
def venmo_button_style(store)
|
46
|
+
configuration = store.braintree_configuration
|
47
|
+
color = configuration.preferred_venmo_button_color
|
48
|
+
width = configuration.preferred_venmo_button_width
|
49
|
+
|
50
|
+
{ width: width, color: color }
|
51
|
+
end
|
52
|
+
|
53
|
+
def venmo_button_asset_url(style, active: false)
|
54
|
+
prefix = 'solidus_paypal_braintree/venmo/venmo_'
|
55
|
+
active_string = active ? 'active_' : ''
|
56
|
+
path = "#{prefix}#{active_string}#{style[:color]}_button_#{style[:width]}x48.svg"
|
57
|
+
asset_path(path)
|
58
|
+
end
|
45
59
|
end
|
46
60
|
end
|
@@ -2,27 +2,61 @@
|
|
2
2
|
|
3
3
|
module SolidusPaypalBraintree
|
4
4
|
class Address
|
5
|
+
delegate :address1,
|
6
|
+
:address2,
|
7
|
+
:city,
|
8
|
+
:country,
|
9
|
+
:phone,
|
10
|
+
:state,
|
11
|
+
:zipcode,
|
12
|
+
to: :spree_address
|
13
|
+
|
14
|
+
def self.split_name(name)
|
15
|
+
if defined?(Spree::Address::Name)
|
16
|
+
address_name = Spree::Address::Name.new(name)
|
17
|
+
[address_name.first_name, address_name.last_name]
|
18
|
+
else
|
19
|
+
name.strip.split(' ', 2)
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
5
23
|
def initialize(spree_address)
|
6
24
|
@spree_address = spree_address
|
7
25
|
end
|
8
26
|
|
9
27
|
def to_json(*_args)
|
10
28
|
address_hash = {
|
11
|
-
line1:
|
12
|
-
line2:
|
13
|
-
city:
|
14
|
-
postalCode:
|
15
|
-
countryCode:
|
16
|
-
phone:
|
17
|
-
recipientName:
|
29
|
+
line1: address1,
|
30
|
+
line2: address2,
|
31
|
+
city: city,
|
32
|
+
postalCode: zipcode,
|
33
|
+
countryCode: country.iso,
|
34
|
+
phone: phone,
|
35
|
+
recipientName: "#{firstname} #{lastname}"
|
18
36
|
}
|
19
37
|
|
20
|
-
if ::Spree::Config.address_requires_state &&
|
21
|
-
address_hash[:state] =
|
38
|
+
if ::Spree::Config.address_requires_state && country.states_required
|
39
|
+
address_hash[:state] = state.name
|
22
40
|
end
|
23
41
|
address_hash.to_json
|
24
42
|
end
|
25
43
|
|
44
|
+
def firstname
|
45
|
+
if SolidusSupport.combined_first_and_last_name_in_address?
|
46
|
+
self.class.split_name(spree_address.name).first
|
47
|
+
else
|
48
|
+
spree_address.firstname
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
def lastname
|
53
|
+
if SolidusSupport.combined_first_and_last_name_in_address?
|
54
|
+
self.class.split_name(spree_address.name).last
|
55
|
+
else
|
56
|
+
spree_address.lastname
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
26
60
|
private
|
27
61
|
|
28
62
|
attr_reader :spree_address
|
@@ -11,9 +11,11 @@ module SolidusPaypalBraintree
|
|
11
11
|
messaging: { availables: %w[true false], default: 'false' }
|
12
12
|
}.freeze
|
13
13
|
|
14
|
-
|
14
|
+
unless respond_to?(:preference)
|
15
|
+
include ::Spree::Preferences::Persistable
|
16
|
+
end
|
15
17
|
|
16
|
-
|
18
|
+
belongs_to :store, class_name: 'Spree::Store', optional: false
|
17
19
|
|
18
20
|
# Preferences for Paypal button
|
19
21
|
PAYPAL_BUTTON_PREFERENCES.each do |name, desc|
|
@@ -24,5 +26,16 @@ module SolidusPaypalBraintree
|
|
24
26
|
|
25
27
|
validates attribute_name, inclusion: desc[:availables]
|
26
28
|
end
|
29
|
+
|
30
|
+
preference :venmo_button_color, :preference_select, default: 'blue'
|
31
|
+
preference :venmo_button_width, :preference_select, default: '320'
|
32
|
+
|
33
|
+
def preferred_venmo_button_color_options
|
34
|
+
[["Blue", "blue"], ["White", "white"]]
|
35
|
+
end
|
36
|
+
|
37
|
+
def preferred_venmo_button_width_options
|
38
|
+
[["280", "280"], ["320", "320"], ["375", "375"]]
|
39
|
+
end
|
27
40
|
end
|
28
41
|
end
|
@@ -12,8 +12,8 @@ module SolidusPaypalBraintree
|
|
12
12
|
NON_VOIDABLE_STATUS_ERROR_REGEXP = /can only be voided if status is authorized/.freeze
|
13
13
|
|
14
14
|
TOKEN_GENERATION_DISABLED_MESSAGE = 'Token generation is disabled.' \
|
15
|
-
|
16
|
-
|
15
|
+
' To re-enable set the `token_generation_enabled` preference on the' \
|
16
|
+
' gateway to `true`.'
|
17
17
|
|
18
18
|
ALLOWED_BRAINTREE_OPTIONS = [
|
19
19
|
:device_data,
|
@@ -55,6 +55,21 @@ module SolidusPaypalBraintree
|
|
55
55
|
# Example: { number: "Enter card number", cvv: "Enter CVV", expirationDate: "mm/yy" }
|
56
56
|
preference(:placeholder_text, :hash, default: {})
|
57
57
|
|
58
|
+
# Wether to use the JS device data collector
|
59
|
+
preference(:use_data_collector, :boolean, default: true)
|
60
|
+
|
61
|
+
# Useful for testing purposes, as PayPal will show funding sources based on the buyer's country;
|
62
|
+
# usually retrieved by their ip geolocation. I.e. Venmo will show for US buyers, but not European.
|
63
|
+
preference(:force_buyer_country, :string)
|
64
|
+
|
65
|
+
preference(:enable_venmo_funding, :boolean, default: false)
|
66
|
+
|
67
|
+
# When on mobile, paying with Venmo, the user may be returned to the same store tab
|
68
|
+
# depending on if their browser supports it, otherwise a new tab will be created
|
69
|
+
# However, returning to a new tab may break the payment checkout flow for some stores, for example,
|
70
|
+
# if they are single-page applications (SPA). Set this to false if this is the case
|
71
|
+
preference(:venmo_new_tab_support, :boolean, default: true)
|
72
|
+
|
58
73
|
def partial_name
|
59
74
|
"paypal_braintree"
|
60
75
|
end
|
@@ -334,6 +349,10 @@ module SolidusPaypalBraintree
|
|
334
349
|
params[:options][:paypal] = { payee_email: paypal_email }
|
335
350
|
end
|
336
351
|
|
352
|
+
if source.venmo? && venmo_business_profile_id
|
353
|
+
params[:options][:venmo] = { profile_id: venmo_business_profile_id }
|
354
|
+
end
|
355
|
+
|
337
356
|
if merchant_account_id = merchant_account_for(source, options)
|
338
357
|
params[:merchant_account_id] = merchant_account_id
|
339
358
|
end
|
@@ -401,5 +420,11 @@ module SolidusPaypalBraintree
|
|
401
420
|
|
402
421
|
params
|
403
422
|
end
|
423
|
+
|
424
|
+
# override with the Venmo business profile that you want to use for transactions,
|
425
|
+
# or leave it to be nil if want Braintree to use your default account
|
426
|
+
def venmo_business_profile_id
|
427
|
+
nil
|
428
|
+
end
|
404
429
|
end
|
405
430
|
end
|
@@ -6,21 +6,30 @@ module SolidusPaypalBraintree
|
|
6
6
|
|
7
7
|
PAYPAL = "PayPalAccount"
|
8
8
|
APPLE_PAY = "ApplePayCard"
|
9
|
+
VENMO = "VenmoAccount"
|
9
10
|
CREDIT_CARD = "CreditCard"
|
10
11
|
|
12
|
+
enum paypal_funding_source: {
|
13
|
+
applepay: 0, bancontact: 1, blik: 2, boleto: 3, card: 4, credit: 5, eps: 6, giropay: 7, ideal: 8,
|
14
|
+
itau: 9, maxima: 10, mercadopago: 11, mybank: 12, oxxo: 13, p24: 14, paylater: 15, paypal: 16, payu: 17,
|
15
|
+
sepa: 18, sofort: 19, trustly: 20, venmo: 21, verkkopankki: 22, wechatpay: 23, zimpler: 24
|
16
|
+
}, _suffix: :funding
|
17
|
+
|
11
18
|
belongs_to :user, class_name: ::Spree::UserClassHandle.new, optional: true
|
12
19
|
belongs_to :payment_method, class_name: 'Spree::PaymentMethod'
|
13
20
|
has_many :payments, as: :source, class_name: "Spree::Payment", dependent: :destroy
|
14
21
|
|
15
22
|
belongs_to :customer, class_name: "SolidusPaypalBraintree::Customer", optional: true
|
16
23
|
|
17
|
-
validates :payment_type, inclusion: [PAYPAL, APPLE_PAY, CREDIT_CARD]
|
24
|
+
validates :payment_type, inclusion: [PAYPAL, APPLE_PAY, VENMO, CREDIT_CARD]
|
25
|
+
|
26
|
+
before_save :clear_paypal_funding_source, unless: :paypal?
|
18
27
|
|
19
28
|
scope(:with_payment_profile, -> { joins(:customer) })
|
20
29
|
scope(:credit_card, -> { where(payment_type: CREDIT_CARD) })
|
21
30
|
|
22
31
|
delegate :last_4, :card_type, :expiration_month, :expiration_year, :email,
|
23
|
-
to: :braintree_payment_method, allow_nil: true
|
32
|
+
:username, :source_description, to: :braintree_payment_method, allow_nil: true
|
24
33
|
|
25
34
|
# Aliases to match Spree::CreditCard's interface
|
26
35
|
alias_method :last_digits, :last_4
|
@@ -68,6 +77,10 @@ module SolidusPaypalBraintree
|
|
68
77
|
payment_type == PAYPAL
|
69
78
|
end
|
70
79
|
|
80
|
+
def venmo?
|
81
|
+
payment_type == VENMO
|
82
|
+
end
|
83
|
+
|
71
84
|
def reusable?
|
72
85
|
token.present?
|
73
86
|
end
|
@@ -79,11 +92,23 @@ module SolidusPaypalBraintree
|
|
79
92
|
def display_number
|
80
93
|
if paypal?
|
81
94
|
email
|
95
|
+
elsif venmo?
|
96
|
+
username
|
82
97
|
else
|
83
98
|
"XXXX-XXXX-XXXX-#{last_digits.to_s.rjust(4, 'X')}"
|
84
99
|
end
|
85
100
|
end
|
86
101
|
|
102
|
+
def display_paypal_funding_source
|
103
|
+
I18n.t(paypal_funding_source,
|
104
|
+
scope: 'solidus_paypal_braintree.paypal_funding_sources',
|
105
|
+
default: paypal_funding_source)
|
106
|
+
end
|
107
|
+
|
108
|
+
def display_payment_type
|
109
|
+
"#{I18n.t('solidus_paypal_braintree.payment_type.label')}: #{friendly_payment_type}"
|
110
|
+
end
|
111
|
+
|
87
112
|
private
|
88
113
|
|
89
114
|
def braintree_payment_method
|
@@ -100,5 +125,9 @@ module SolidusPaypalBraintree
|
|
100
125
|
def braintree_client
|
101
126
|
@braintree_client ||= payment_method.try(:braintree)
|
102
127
|
end
|
128
|
+
|
129
|
+
def clear_paypal_funding_source
|
130
|
+
self.paypal_funding_source = nil
|
131
|
+
end
|
103
132
|
end
|
104
133
|
end
|
@@ -6,7 +6,7 @@ module SolidusPaypalBraintree
|
|
6
6
|
class Transaction
|
7
7
|
include ActiveModel::Model
|
8
8
|
|
9
|
-
attr_accessor :nonce, :payment_method, :payment_type, :address, :email, :phone
|
9
|
+
attr_accessor :nonce, :payment_method, :payment_type, :paypal_funding_source, :address, :email, :phone
|
10
10
|
|
11
11
|
validates :nonce, presence: true
|
12
12
|
validates :payment_method, presence: true
|