solidus_paypal_braintree 0.1.0 → 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,58 @@
1
+ SolidusPaypalBraintree = {
2
+ APPLE_PAY_API_VERSION: 1,
3
+
4
+ config: {
5
+ paths: {
6
+ clientTokens: Spree.pathFor('solidus_paypal_braintree/client_token'),
7
+ transactions: Spree.pathFor('solidus_paypal_braintree/transactions')
8
+ },
9
+
10
+ // Override to provide your own error messages.
11
+ braintreeErrorHandle: function(braintreeError) {
12
+ var $contentContainer = $("#content");
13
+ var $flash = $("<div class='flash error'>" + braintreeError.name + ": " + braintreeError.message + "</div>");
14
+ $contentContainer.prepend($flash);
15
+
16
+ $flash.show().delay(5000).fadeOut(500);
17
+ },
18
+
19
+ classes: {
20
+ hostedForm: function() {
21
+ return SolidusPaypalBraintree.HostedForm;
22
+ },
23
+
24
+ client: function() {
25
+ return SolidusPaypalBraintree.Client;
26
+ },
27
+
28
+ paypalButton: function() {
29
+ return SolidusPaypalBraintree.PaypalButton;
30
+ },
31
+
32
+ applepayButton: function() {
33
+ return SolidusPaypalBraintree.ApplepayButton;
34
+ }
35
+ }
36
+ },
37
+
38
+ createHostedForm: function() {
39
+ return SolidusPaypalBraintree._factory(SolidusPaypalBraintree.config.classes.hostedForm(), arguments);
40
+ },
41
+
42
+ createClient: function() {
43
+ return SolidusPaypalBraintree._factory(SolidusPaypalBraintree.config.classes.client(), arguments);
44
+ },
45
+
46
+ createPaypalButton: function() {
47
+ return SolidusPaypalBraintree._factory(SolidusPaypalBraintree.config.classes.paypalButton(), arguments);
48
+ },
49
+
50
+ createApplePayButton: function() {
51
+ return SolidusPaypalBraintree._factory(SolidusPaypalBraintree.config.classes.applepayButton(), arguments);
52
+ },
53
+
54
+ _factory: function(klass, args) {
55
+ var normalizedArgs = Array.prototype.slice.call(args);
56
+ return new (Function.prototype.bind.apply(klass, [null].concat(normalizedArgs)));
57
+ }
58
+ };
@@ -0,0 +1,12 @@
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_paypal_braintree/constants
8
+ //= require solidus_paypal_braintree/promise
9
+ //= require solidus_paypal_braintree/client
10
+ //= require solidus_paypal_braintree/hosted_form
11
+ //= require solidus_paypal_braintree/paypal_button
12
+ //= require solidus_paypal_braintree/apple_pay_button
@@ -0,0 +1,36 @@
1
+ SolidusPaypalBraintree.HostedForm = function(paymentMethodId) {
2
+ this.paymentMethodId = paymentMethodId;
3
+ this.client = null;
4
+ };
5
+
6
+ SolidusPaypalBraintree.HostedForm.prototype.initialize = function() {
7
+ this.client = SolidusPaypalBraintree.createClient({paymentMethodId: this.paymentMethodId});
8
+ return this.client.initialize().
9
+ then(this._createHostedFields.bind(this));
10
+ };
11
+
12
+ SolidusPaypalBraintree.HostedForm.prototype._createHostedFields = function () {
13
+ if (!this.client) {
14
+ throw new Error("Client not initialized, please call initialize first!");
15
+ }
16
+
17
+ var opts = {
18
+ client: this.client.getBraintreeInstance(),
19
+
20
+ fields: {
21
+ number: {
22
+ selector: "#card_number" + this.paymentMethodId
23
+ },
24
+
25
+ cvv: {
26
+ selector: "#card_code" + this.paymentMethodId
27
+ },
28
+
29
+ expirationDate: {
30
+ selector: "#card_expiry" + this.paymentMethodId
31
+ }
32
+ }
33
+ };
34
+
35
+ return SolidusPaypalBraintree.PromiseShim.convertBraintreePromise(braintree.hostedFields.create, [opts]);
36
+ };
@@ -0,0 +1,114 @@
1
+ //= require solidus_paypal_braintree/constants
2
+ /**
3
+ * Constructor for PayPal button object
4
+ * @constructor
5
+ * @param {object} element - The DOM element of your PayPal button
6
+ */
7
+ SolidusPaypalBraintree.PaypalButton = function(element, paypalOptions) {
8
+ this._element = element;
9
+ this._paypalOptions = paypalOptions || {};
10
+ this._client = null;
11
+
12
+ if(!this._element) {
13
+ throw new Error("Element for the paypal button must be present on the page");
14
+ }
15
+ }
16
+
17
+ /**
18
+ * Creates the PayPal session using the provided options and enables the button
19
+ *
20
+ * @param {object} options - The options passed to tokenize when constructing
21
+ * the PayPal instance
22
+ *
23
+ * See {@link https://braintree.github.io/braintree-web/3.9.0/PayPal.html#tokenize}
24
+ */
25
+ SolidusPaypalBraintree.PaypalButton.prototype.initialize = function() {
26
+ this._client = new SolidusPaypalBraintree.createClient({useDataCollector: true, usePaypal: true});
27
+
28
+ return this._client.initialize().then(this.initializeCallback.bind(this));
29
+ };
30
+
31
+ SolidusPaypalBraintree.PaypalButton.prototype.initializeCallback = function() {
32
+ this._paymentMethodId = this._client.paymentMethodId;
33
+
34
+ this._element.removeAttribute('disabled');
35
+ this._element.addEventListener('click', function(event) {
36
+ this._client.getPaypalInstance().tokenize(this._paypalOptions, this._tokenizeCallback.bind(this));
37
+ }.bind(this), false);
38
+ };
39
+
40
+ /**
41
+ * Default callback function for when tokenization completes
42
+ *
43
+ * @param {object|null} tokenizeErr - The error returned by Braintree on failure
44
+ * @param {object} payload - The payload returned by Braintree on success
45
+ */
46
+ SolidusPaypalBraintree.PaypalButton.prototype._tokenizeCallback = function(tokenizeErr, payload) {
47
+ if (tokenizeErr) {
48
+ SolidusPaypalBraintree.config.braintreeErrorHandle(tokenizeErr);
49
+ return;
50
+ }
51
+
52
+ var params = this._transactionParams(payload);
53
+
54
+ return Spree.ajax({
55
+ url: SolidusPaypalBraintree.config.paths.transactions,
56
+ type: 'POST',
57
+ dataType: 'json',
58
+ data: params,
59
+ success: function(response) {
60
+ window.location.href = response.redirectUrl;
61
+ },
62
+ error: function(xhr) {
63
+ console.error("Error submitting transaction")
64
+ },
65
+ });
66
+ };
67
+
68
+ /**
69
+ * Builds the transaction parameters to submit to Solidus for the given
70
+ * payload returned by Braintree
71
+ *
72
+ * @param {object} payload - The payload returned by Braintree after tokenization
73
+ */
74
+ SolidusPaypalBraintree.PaypalButton.prototype._transactionParams = function(payload) {
75
+ return {
76
+ "payment_method_id" : this._paymentMethodId,
77
+ "transaction" : {
78
+ "email" : payload.details.email,
79
+ "phone" : payload.details.phone,
80
+ "nonce" : payload.nonce,
81
+ "payment_type" : payload.type,
82
+ "address_attributes" : this._addressParams(payload)
83
+ }
84
+ }
85
+ };
86
+
87
+ /**
88
+ * Builds the address parameters to submit to Solidus using the payload
89
+ * returned by Braintree
90
+ *
91
+ * @param {object} payload - The payload returned by Braintree after tokenization
92
+ */
93
+ SolidusPaypalBraintree.PaypalButton.prototype._addressParams = function(payload) {
94
+ if (payload.details.shippingAddress.recipientName) {
95
+ var first_name = payload.details.shippingAddress.recipientName.split(" ")[0];
96
+ var last_name = payload.details.shippingAddress.recipientName.split(" ")[1];
97
+ }
98
+ if (first_name == null || last_name == null) {
99
+ var first_name = payload.details.firstName;
100
+ var last_name = payload.details.lastName;
101
+ }
102
+
103
+ return {
104
+ "first_name" : first_name,
105
+ "last_name" : last_name,
106
+ "address_line_1" : payload.details.shippingAddress.line1,
107
+ "address_line_2" : payload.details.shippingAddress.line2,
108
+ "city" : payload.details.shippingAddress.city,
109
+ "state_code" : payload.details.shippingAddress.state,
110
+ "zip" : payload.details.shippingAddress.postalCode,
111
+ "country_code" : payload.details.shippingAddress.countryCode
112
+ }
113
+ };
114
+
@@ -0,0 +1,20 @@
1
+ SolidusPaypalBraintree.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
+ }
@@ -1,4 +1,7 @@
1
- //= require spree/braintree_hosted_form.js
1
+ //= require solidus_paypal_braintree/constants
2
+ //= require solidus_paypal_braintree/client
3
+ //= require solidus_paypal_braintree/promise
4
+ //= require solidus_paypal_braintree/hosted_form
2
5
 
3
6
  $(function() {
4
7
  var $paymentForm = $("#new_payment"),
@@ -18,6 +21,33 @@ $(function() {
18
21
  $("#card_form" + id).hide();
19
22
  }
20
23
 
24
+ function addFormHook(braintreeForm, errorCallback) {
25
+ var shouldSubmit = false;
26
+
27
+ function submit(payload) {
28
+ shouldSubmit = true;
29
+
30
+ $("#payment_method_nonce", braintreeForm.hostedFields).val(payload.nonce);
31
+ $paymentForm.submit();
32
+ }
33
+
34
+ return function(hostedFields) {
35
+ $paymentForm.on("submit", function(e) {
36
+ if ($hostedFields.is(":visible") && !shouldSubmit) {
37
+ e.preventDefault();
38
+
39
+ hostedFields.tokenize(function(err, payload) {
40
+ if (err) {
41
+ errorCallback(err);
42
+ } else {
43
+ submit(payload);
44
+ }
45
+ });
46
+ }
47
+ });
48
+ };
49
+ }
50
+
21
51
  function initFields($container, id) {
22
52
  function setHostedFieldsInstance(instance) {
23
53
  hostedFieldsInstance = instance;
@@ -25,10 +55,10 @@ $(function() {
25
55
  }
26
56
 
27
57
  if (hostedFieldsInstance === null) {
28
- braintreeForm = new BraintreeHostedForm($paymentForm, $container, id);
29
- braintreeForm.initializeHostedFields().
58
+ braintreeForm = new SolidusPaypalBraintree.createHostedForm(id);
59
+ braintreeForm.initialize().
30
60
  then(setHostedFieldsInstance).
31
- then(braintreeForm.addFormHook(onError)).
61
+ then(addFormHook(braintreeForm, onError)).
32
62
  fail(onError);
33
63
  }
34
64
  }
@@ -1,162 +1,11 @@
1
- /**
2
- * Constructor for PayPal button object
3
- * @constructor
4
- * @param {object} element - The DOM element of your PayPal button
5
- */
6
- function PaypalButton(element) {
7
- this.element = element;
8
- }
9
-
10
- /**
11
- * Creates the PayPal session using the provided options and enables the button
12
- *
13
- * @param {object} options - The options passed to tokenize when constructing
14
- * the PayPal instance
15
- *
16
- * See {@link https://braintree.github.io/braintree-web/3.9.0/PayPal.html#tokenize}
17
- */
18
- PaypalButton.prototype.initialize = function(options) {
19
- var self = this;
20
-
21
- /* This sets the payment method id returned by fetchToken on the PaypalButton
22
- * instance so that we can use it to build the transaction params later. */
23
- SolidusPaypalBraintree.fetchToken(function(token, paymentMethodId) {
24
- self.paymentMethodId = paymentMethodId;
25
-
26
- SolidusPaypalBraintree.initializeWithDataCollector(token, function(client) {
27
- self.createPaypalInstance(client, function(paypal) {
28
-
29
- self.initializePaypalSession({
30
- paypalInstance: paypal,
31
- paypalButton: self.element,
32
- paypalOptions: options
33
- }, self.tokenizeCallback.bind(self));
34
- });
35
-
36
- });
37
- });
38
- };
39
-
40
- PaypalButton.prototype.createPaypalInstance = function(braintreeClient, readyCallback) {
41
- braintree.paypal.create({
42
- client: braintreeClient
43
- }, function (paypalErr, paypalInstance) {
44
- if (paypalErr) {
45
- console.error("Error creating PayPal:", paypalErr);
46
- return;
47
- }
48
- readyCallback(paypalInstance);
49
- });
50
- };
51
-
52
- /* Initializes and begins the Paypal session
53
- *
54
- * @param config Configuration settings for the session
55
- * @param config.paypalInstance {object} The Paypal instance returned by Braintree
56
- * @param config.paypalButton {object} The button DOM element
57
- * @param config.paypalOptions {object} Configuration options for Paypal
58
- * @param config.error {tokenizeErrorCallback} Callback function for tokenize errors
59
- * @param {tokenizeCallback} callback Callback function for tokenization
60
- */
61
- PaypalButton.prototype.initializePaypalSession = function(config, callback) {
62
- config.paypalButton.removeAttribute('disabled');
63
- config.paypalButton.addEventListener('click', function(event) {
64
- config.paypalInstance.tokenize(config.paypalOptions, callback);
65
- }, false);
66
- },
67
-
68
- /**
69
- * Default callback function for when tokenization completes
70
- *
71
- * @param {object|null} tokenizeErr - The error returned by Braintree on failure
72
- * @param {object} payload - The payload returned by Braintree on success
73
- */
74
- PaypalButton.prototype.tokenizeCallback = function(tokenizeErr, payload) {
75
- if (tokenizeErr) {
76
- console.error('Error tokenizing:', tokenizeErr);
77
- } else {
78
- var params = this.transactionParams(payload);
79
-
80
- Spree.ajax({
81
- url: Spree.pathFor("solidus_paypal_braintree/transactions"),
82
- type: 'POST',
83
- dataType: 'json',
84
- data: params,
85
- success: function(response) {
86
- window.location.href = response.redirectUrl;
87
- },
88
- error: function(xhr) {
89
- console.error("Error submitting transaction")
90
- },
91
- });
92
- }
93
- };
94
-
95
- /**
96
- * Assigns a new callback function for when tokenization completes
97
- *
98
- * @callback callback - The callback function to assign
99
- */
100
- PaypalButton.prototype.setTokenizeCallback = function(callback) {
101
- this.tokenizeCallback = callback;
102
- };
103
-
104
- /**
105
- * Builds the transaction parameters to submit to Solidus for the given
106
- * payload returned by Braintree
107
- *
108
- * @param {object} payload - The payload returned by Braintree after tokenization
109
- */
110
- PaypalButton.prototype.transactionParams = function(payload) {
111
- return {
112
- "payment_method_id" : this.paymentMethodId,
113
- "transaction" : {
114
- "email" : payload.details.email,
115
- "phone" : payload.details.phone,
116
- "nonce" : payload.nonce,
117
- "payment_type" : payload.type,
118
- "address_attributes" : this.addressParams(payload)
119
- }
120
- }
121
- };
122
-
123
- /**
124
- * Builds the address parameters to submit to Solidus using the payload
125
- * returned by Braintree
126
- *
127
- * @param {object} payload - The payload returned by Braintree after tokenization
128
- */
129
- PaypalButton.prototype.addressParams = function(payload) {
130
- if (payload.details.shippingAddress.recipientName) {
131
- var first_name = payload.details.shippingAddress.recipientName.split(" ")[0];
132
- var last_name = payload.details.shippingAddress.recipientName.split(" ")[1];
133
- }
134
- if (first_name == null || last_name == null) {
135
- var first_name = payload.details.firstName;
136
- var last_name = payload.details.lastName;
137
- }
138
-
139
- return {
140
- "first_name" : first_name,
141
- "last_name" : last_name,
142
- "address_line_1" : payload.details.shippingAddress.line1,
143
- "address_line_2" : payload.details.shippingAddress.line2,
144
- "city" : payload.details.shippingAddress.city,
145
- "state_code" : payload.details.shippingAddress.state,
146
- "zip" : payload.details.shippingAddress.postalCode,
147
- "country_code" : payload.details.shippingAddress.countryCode
148
- }
149
- };
1
+ //= require solidus_paypal_braintree/paypal_button
150
2
 
151
3
  $(document).ready(function() {
152
4
  if (document.getElementById("empty-cart")) {
153
5
  $.when(
154
- $.getScript("https://js.braintreegateway.com/web/3.9.0/js/client.min.js"),
155
- $.getScript("https://js.braintreegateway.com/web/3.9.0/js/paypal.min.js"),
156
- $.getScript("https://js.braintreegateway.com/web/3.9.0/js/data-collector.min.js"),
157
- $.Deferred(function( deferred ){
158
- $( deferred.resolve );
159
- })
6
+ $.getScript("https://js.braintreegateway.com/web/3.14.0/js/client.min.js"),
7
+ $.getScript("https://js.braintreegateway.com/web/3.14.0/js/paypal.min.js"),
8
+ $.getScript("https://js.braintreegateway.com/web/3.14.0/js/data-collector.min.js")
160
9
  ).done(function() {
161
10
  $('<script/>').attr({
162
11
  'data-merchant' : "braintree",
@@ -169,11 +18,12 @@ $(document).ready(function() {
169
18
  'data-button_disabled' : "true"
170
19
  }).
171
20
  load(function() {
172
- var button = new PaypalButton(document.querySelector("#paypal-button"));
173
- button.initialize({
21
+ var paypalOptions = {
174
22
  flow: 'vault',
175
- enableShippingAddress: true,
176
- });
23
+ enableShippingAddress: true
24
+ }
25
+ var button = new SolidusPaypalBraintree.createPaypalButton(document.querySelector("#paypal-button"), paypalOptions);
26
+ return button.initialize();
177
27
  }).
178
28
  insertAfter("#content").
179
29
  attr('src', 'https://www.paypalobjects.com/api/button.js?')