WooCommerce Stripe Payment Gateway - Version 3.1.0

Version Description

  • New - Apple Pay Support.
  • New - Add Google Payment Request API.
Download this release

Release Info

Developer royho
Plugin Icon 128x128 WooCommerce Stripe Payment Gateway
Version 3.1.0
Comparing to
See all releases

Code changes from version 3.0.7 to 3.1.0

assets/css/stripe-apple-pay.css ADDED
@@ -0,0 +1 @@
1
+ .apple-pay-button,.apple-pay-button-checkout-separator,.apple-pay-button-wrapper{display:none}@supports (-webkit-appearance:-apple-pay-button){.apple-pay-button-wrapper{display:block;margin-bottom:20px}.apple-pay-button{background-size:100% 100%;background-origin:content-box;background-repeat:no-repeat;width:100%;height:44px;padding:10px 0;border-radius:10px}.apple-pay-button-checkout-separator{text-transform:uppercase;text-align:center;font-size:1.2rem}.woocommerce-checkout .apple-pay-button-wrapper{text-align:center}.woocommerce-checkout .apple-pay-button{height:50px;margin:0 auto}.woocommerce-checkout .apple-pay-button-checkout-separator{border-bottom:1px solid #EBEBEB;padding-bottom:20px}.single-product div.product form.cart .apple-pay-button,.single-product div.product form.cart .quantity,.single-product div.product form.cart .quantity~.button{margin-bottom:10px}.single-product div.product form.cart .quantity{width:100%;margin-right:0}.single-product div.product form.cart .quantity input,.single-product div.product form.cart .quantity~.button{width:100%}.single-product div.product form.cart .apple-pay-button-wrapper{display:inline;margin-bottom:0}@media (min-width:768px){.woocommerce-checkout .apple-pay-button{width:30%}.single-product div.product form.cart .apple-pay-button,.single-product div.product form.cart .quantity,.single-product div.product form.cart .quantity~.button{margin-bottom:0}.single-product div.product form.cart .quantity{width:auto;margin-right:10px}.single-product div.product form.cart .quantity input{width:70px}.single-product div.product form.cart .quantity~.button{float:none;width:auto}.single-product div.product form.cart .apple-pay-button{float:left;max-width:20%;margin-right:10px}}}
assets/css/stripe-apple-pay.less ADDED
@@ -0,0 +1,114 @@
1
+ .apple-pay-button-wrapper,
2
+ .apple-pay-button,
3
+ .apple-pay-button-checkout-separator {
4
+ display: none;
5
+ }
6
+
7
+ @supports (-webkit-appearance: -apple-pay-button) {
8
+ .apple-pay-button-wrapper {
9
+ display: block;
10
+ margin-bottom: 20px;
11
+ }
12
+
13
+ .apple-pay-button {
14
+ background-size: 100% 100%;
15
+ background-origin: content-box;
16
+ background-repeat: no-repeat;
17
+ width: 100%;
18
+ height: 44px;
19
+ padding: 10px 0;
20
+ border-radius: 10px;
21
+ }
22
+
23
+ .apple-pay-button-checkout-separator {
24
+ text-transform: uppercase;
25
+ text-align: center;
26
+ font-size: 1.2rem;
27
+ }
28
+
29
+ .woocommerce-checkout {
30
+ .apple-pay-button-wrapper {
31
+ text-align: center;
32
+ }
33
+
34
+ .apple-pay-button {
35
+ height: 50px;
36
+ margin: 0 auto;
37
+ }
38
+
39
+ .apple-pay-button-checkout-separator {
40
+ border-bottom: 1px solid #EBEBEB;
41
+ padding-bottom: 20px;
42
+ }
43
+ }
44
+
45
+ .single-product {
46
+ div.product {
47
+ form.cart {
48
+ .quantity,
49
+ .quantity ~ .button,
50
+ .apple-pay-button {
51
+ margin-bottom: 10px;
52
+ }
53
+
54
+ .quantity {
55
+ width: 100%;
56
+ margin-right: 0;
57
+
58
+ input {
59
+ width: 100%;
60
+ }
61
+ }
62
+
63
+ .quantity ~ .button {
64
+ width: 100%;
65
+ }
66
+
67
+ .apple-pay-button-wrapper {
68
+ display: inline;
69
+ margin-bottom: 0;
70
+ }
71
+ }
72
+ }
73
+ }
74
+
75
+ @media ( min-width: 768px ) {
76
+ .woocommerce-checkout {
77
+ .apple-pay-button {
78
+ width: 30%;
79
+ }
80
+ }
81
+
82
+ .single-product {
83
+ div.product {
84
+ form.cart {
85
+ .quantity,
86
+ .quantity ~ .button,
87
+ .apple-pay-button {
88
+ margin-bottom: 0;
89
+ }
90
+
91
+ .quantity {
92
+ width: auto;
93
+ margin-right: 10px;
94
+
95
+ input {
96
+ width: 70px;
97
+ }
98
+ }
99
+
100
+ .quantity ~ .button {
101
+ float: none;
102
+ width: auto;
103
+ }
104
+
105
+ .apple-pay-button {
106
+ float: left;
107
+ max-width: 20%;
108
+ margin-right: 10px;
109
+ }
110
+ }
111
+ }
112
+ }
113
+ }
114
+ }
assets/js/payment-request.js ADDED
@@ -0,0 +1,387 @@
1
+ /*global jQuery, wcStripePaymentRequestParams, PaymentRequest, Stripe, Promise */
2
+ /*jshint es3: false */
3
+ /*jshint devel: true */
4
+ (function( $ ) {
5
+
6
+ /**
7
+ * WooCommerce Stripe PaymentRequest class.
8
+ *
9
+ * @type {Object}
10
+ */
11
+ var wcStripePaymentRequest = {
12
+
13
+ /**
14
+ * Initialize class events.
15
+ */
16
+ init: function() {
17
+ var self = this;
18
+
19
+ if ( self.hasPaymentRequestSupport() ) {
20
+ $( document.body )
21
+ .on( 'click', '.cart_totals a.checkout-button', self.initPaymentRequest );
22
+ }
23
+ },
24
+
25
+ /**
26
+ * Check if browser support PaymentRequest class and if is under HTTPS.
27
+ *
28
+ * @return {Bool}
29
+ */
30
+ hasPaymentRequestSupport: function() {
31
+ return window.PaymentRequest && 'https:' === window.location.protocol;
32
+ },
33
+
34
+ /**
35
+ * Get Stripe supported methods.
36
+ *
37
+ * @return {Array}
38
+ */
39
+ getSupportedMethods: function() {
40
+ return [
41
+ 'amex',
42
+ 'diners',
43
+ 'discover',
44
+ 'jcb',
45
+ 'mastercard',
46
+ 'visa'
47
+ ];
48
+ },
49
+
50
+ /**
51
+ * Get WC AJAX endpoint URL.
52
+ *
53
+ * @param {String} endpoint Endpoint.
54
+ * @return {String}
55
+ */
56
+ getAjaxURL: function( endpoint ) {
57
+ return wcStripePaymentRequestParams.ajax_url
58
+ .toString()
59
+ .replace( '%%endpoint%%', 'wc_stripe_' + endpoint );
60
+ },
61
+
62
+ /**
63
+ * Initialize the PaymentRequest.
64
+ *
65
+ * @param {Object} evt DOM events.
66
+ */
67
+ initPaymentRequest: function( evt ) {
68
+ evt.preventDefault();
69
+ var self = wcStripePaymentRequest;
70
+ var data = {
71
+ security: wcStripePaymentRequestParams.nonce.payment
72
+ };
73
+
74
+ $.ajax({
75
+ type: 'POST',
76
+ data: data,
77
+ url: self.getAjaxURL( 'get_cart_details' ),
78
+ success: function( response ) {
79
+ self.openPaymentRequest( response );
80
+ }
81
+ });
82
+ },
83
+
84
+ /**
85
+ * Open Payment Request modal.
86
+ *
87
+ * @param {Object} details Payment request details.
88
+ */
89
+ openPaymentRequest: function( details ) {
90
+ var self = this;
91
+
92
+ // PaymentRequest options.
93
+ var supportedInstruments = [{
94
+ supportedMethods: self.getSupportedMethods()
95
+ }];
96
+ var options = {
97
+ requestPayerPhone: true,
98
+ requestPayerEmail: true
99
+ };
100
+ if ( details.shipping_required ) {
101
+ options.requestShipping = true;
102
+ }
103
+ var paymentDetails = details.order_data;
104
+
105
+ // Init PaymentRequest.
106
+ var request = new PaymentRequest( supportedInstruments, paymentDetails, options );
107
+
108
+ // Set up shipping.
109
+ request.addEventListener( 'shippingaddresschange', function( evt ) {
110
+ evt.updateWith( new Promise( function( resolve, reject ) {
111
+ self.updateShippingOptions( paymentDetails, request.shippingAddress, resolve, reject );
112
+ }));
113
+ });
114
+ request.addEventListener( 'shippingoptionchange', function( evt ) {
115
+ evt.updateWith( new Promise( function( resolve, reject ) {
116
+ self.updateShippingDetails( paymentDetails, request.shippingOption, resolve, reject );
117
+ }));
118
+ });
119
+
120
+ // Open Payment Request UI.
121
+ request.show().then( function( payment ) {
122
+ self.processPayment( payment );
123
+ })
124
+ .catch( function( err ) {
125
+ console.error( err );
126
+ });
127
+ },
128
+
129
+ /**
130
+ * Update shipping options.
131
+ *
132
+ * @param {Object} details Payment details.
133
+ * @param {PaymentAddress} address Shipping address.
134
+ * @param {Function} resolve The callback to invoke with updated line items and shipping options.
135
+ * @param {Function} reject The callback to invoke in case of failure.
136
+ */
137
+ updateShippingOptions: function( details, address, resolve, reject ) {
138
+ var self = this;
139
+ var data = {
140
+ security: wcStripePaymentRequestParams.nonce.shipping,
141
+ country: address.country,
142
+ state: address.region,
143
+ postcode: address.postalCode,
144
+ city: address.city,
145
+ address: typeof address.addressLine[0] === 'undefined' ? '' : address.addressLine[0],
146
+ address_2: typeof address.addressLine[1] === 'undefined' ? '' : address.addressLine[1]
147
+ };
148
+
149
+ $.ajax({
150
+ type: 'POST',
151
+ data: data,
152
+ url: self.getAjaxURL( 'get_shipping_options' ),
153
+ success: function( response ) {
154
+ details.shippingOptions = response;
155
+ if ( details.shippingOptions.length == 1 ) {
156
+ // The sole shipping option was auto-selected. Update the details
157
+ // (including the total).
158
+ self.updateShippingDetails(
159
+ details, details.shippingOptions[0].id, resolve, reject );
160
+ } else {
161
+ resolve( details );
162
+ }
163
+ }
164
+ });
165
+ },
166
+
167
+ /**
168
+ * Updates the shipping price and the total based on the shipping option.
169
+ *
170
+ * @param {Object} details The line items and shipping options.
171
+ * @param {String} shippingOption User's preferred shipping option to use for shipping price calculations.
172
+ * @param {Function} resolve The callback to invoke with updated line items and shipping options.
173
+ * @param {Function} reject The callback to invoke in case of failure.
174
+ */
175
+ updateShippingDetails: function( details, shippingOption, resolve, reject ) {
176
+ var self = this;
177
+ var selected = null;
178
+ var data = {
179
+ security: wcStripePaymentRequestParams.nonce.update_shipping,
180
+ shipping_method: [
181
+ shippingOption
182
+ ]
183
+ };
184
+
185
+ $.ajax({
186
+ type: 'POST',
187
+ data: data,
188
+ url: self.getAjaxURL( 'update_shipping_method' ),
189
+ success: function( response ) {
190
+ details.shippingOptions.forEach( function( value, index ) {
191
+ if ( value.id === shippingOption ) {
192
+ selected = index;
193
+ value.selected = true;
194
+ details.total.amount.value = parseFloat( response.total );
195
+
196
+ if ( response.items ) {
197
+ details.displayItems = response.items;
198
+ }
199
+ } else {
200
+ value.selected = false;
201
+ }
202
+ });
203
+
204
+ if ( null === selected ) {
205
+ reject( wcStripePaymentRequestParams.i18n.unknown_shipping.toString().replace( '[option]', shippingOption ) );
206
+ }
207
+
208
+ resolve( details );
209
+ }
210
+ });
211
+ },
212
+
213
+ /**
214
+ * Get order data.
215
+ *
216
+ * @param {PaymentResponse} payment Payment Response instance.
217
+ *
218
+ * @return {Object}
219
+ */
220
+ getOrderData: function( payment ) {
221
+ var billing = payment.details.billingAddress;
222
+ var shipping = payment.shippingAddress;
223
+ var data = {
224
+ _wpnonce: wcStripePaymentRequestParams.nonce.checkout,
225
+ billing_first_name: billing.recipient.split( ' ' ).slice( 0, 1 ).join( ' ' ),
226
+ billing_last_name: billing.recipient.split( ' ' ).slice( 1 ).join( ' ' ),
227
+ billing_company: billing.organization,
228
+ billing_email: payment.payerEmail,
229
+ billing_phone: payment.payerPhone,
230
+ billing_country: billing.country,
231
+ billing_address_1: typeof billing.addressLine[0] === 'undefined' ? '' : billing.addressLine[0],
232
+ billing_address_2: typeof billing.addressLine[1] === 'undefined' ? '' : billing.addressLine[1],
233
+ billing_city: billing.city,
234
+ billing_state: billing.region,
235
+ billing_postcode: billing.postalCode,
236
+ shipping_first_name: '',
237
+ shipping_last_name: '',
238
+ shipping_company: '',
239
+ shipping_country: '',
240
+ shipping_address_1: '',
241
+ shipping_address_2: '',
242
+ shipping_city: '',
243
+ shipping_state: '',
244
+ shipping_postcode: '',
245
+ shipping_method: [ payment.shippingOption ],
246
+ order_comments: '',
247
+ payment_method: 'stripe',
248
+ // 'wc-stripe-payment-token': 'new',
249
+ stripe_token: '',
250
+ };
251
+
252
+ if ( shipping ) {
253
+ data.shipping_first_name = shipping.recipient.split( ' ' ).slice( 0, 1 ).join( ' ' );
254
+ data.shipping_last_name = shipping.recipient.split( ' ' ).slice( 1 ).join( ' ' );
255
+ data.shipping_company = shipping.organization;
256
+ data.shipping_country = shipping.country;
257
+ data.shipping_address_1 = typeof shipping.addressLine[0] === 'undefined' ? '' : shipping.addressLine[0];
258
+ data.shipping_address_2 = typeof shipping.addressLine[1] === 'undefined' ? '' : shipping.addressLine[1];
259
+ data.shipping_city = shipping.city;
260
+ data.shipping_state = shipping.region;
261
+ data.shipping_postcode = shipping.postalCode;
262
+ }
263
+
264
+ return data;
265
+ },
266
+
267
+ /**
268
+ * Get credit card data.
269
+ *
270
+ * @param {PaymentResponse} payment Payment Response instance.
271
+ *
272
+ * @return {Object}
273
+ */
274
+ getCardData: function( payment ) {
275
+ var billing = payment.details.billingAddress;
276
+ var data = {
277
+ number: payment.details.cardNumber,
278
+ cvc: payment.details.cardSecurityCode,
279
+ exp_month: parseInt( payment.details.expiryMonth, 10 ) || 0,
280
+ exp_year: parseInt( payment.details.expiryYear, 10 ) || 0,
281
+ name: billing.recipient,
282
+ address_line1: typeof billing.addressLine[0] === 'undefined' ? '' : billing.addressLine[0],
283
+ address_line2: typeof billing.addressLine[1] === 'undefined' ? '' : billing.addressLine[1],
284
+ address_state: billing.region,
285
+ address_city: billing.city,
286
+ address_zip: billing.postalCode,
287
+ address_country: billing.country
288
+ };
289
+
290
+ return data;
291
+ },
292
+
293
+ /**
294
+ * Generate error message HTML.
295
+ *
296
+ * @param {String} message Error message.
297
+ * @return {Object}
298
+ */
299
+ getErrorMessageHTML: function( message ) {
300
+ return $( '<div class="woocommerce-error" />' ).text( message );
301
+ },
302
+
303
+ /**
304
+ * Abort payment and display error messages.
305
+ *
306
+ * @param {PaymentResponse} payment Payment response instance.
307
+ * @param {String} message Error message to display.
308
+ */
309
+ abortPayment: function( payment, message ) {
310
+ payment.complete( 'fail' ).then( function() {
311
+ var $form = $( '.shop_table.cart' ).closest( 'form' );
312
+ $( '.woocommerce-error' ).remove();
313
+ $form.before( message );
314
+ $( 'html, body' ).animate({
315
+ scrollTop: $form.prev( '.woocommerce-error' ).offset().top
316
+ }, 600 );
317
+ })
318
+ .catch( function( err ) {
319
+ console.error( err );
320
+ });
321
+ },
322
+
323
+ /**
324
+ * Complete payment.
325
+ *
326
+ * @param {PaymentResponse} payment Payment response instance.
327
+ * @param {String} url Order thank you page URL.
328
+ */
329
+ completePayment: function( payment, url ) {
330
+ payment.complete( 'success' ).then( function() {
331
+ // Success, then redirect to the Thank You page.
332
+ window.location = url;
333
+ })
334
+ .catch( function( err ) {
335
+ console.error( err );
336
+ });
337
+ },
338
+
339
+ /**
340
+ * Process payment.
341
+ *
342
+ * @param {PaymentResponse} payment Payment response instance.
343
+ */
344
+ processPayment: function( payment ) {
345
+ var self = this;
346
+ var orderData = self.getOrderData( payment );
347
+ var cardData = self.getCardData( payment );
348
+
349
+ Stripe.setPublishableKey( wcStripePaymentRequestParams.stripe.key );
350
+ Stripe.createToken( cardData, function( status, response ) {
351
+ if ( response.error ) {
352
+ self.abortPayment( payment, self.getErrorMessageHTML( response.error.message ) );
353
+ } else {
354
+ // Check if we allow prepaid cards.
355
+ if ( 'no' === wcStripePaymentRequestParams.stripe.allow_prepaid_card && 'prepaid' === response.card.funding ) {
356
+ self.abortPayment( payment, self.getErrorMessageHTML( wcStripePaymentRequestParams.i18n.no_prepaid_card ) );
357
+ } else {
358
+ // Token contains id, last4, and card type.
359
+ orderData.stripe_token = response.id;
360
+
361
+ $.ajax({
362
+ type: 'POST',
363
+ data: orderData,
364
+ dataType: 'json',
365
+ url: self.getAjaxURL( 'create_order' ),
366
+ success: function( response ) {
367
+ if ( 'success' === response.result ) {
368
+ self.completePayment( payment, response.redirect );
369
+ } else {
370
+ self.abortPayment( payment, response.messages );
371
+ }
372
+ },
373
+ complete: function( jqXHR, textStatus ) {
374
+ if ( 'success' !== textStatus ) {
375
+ console.error( jqXHR );
376
+ }
377
+ }
378
+ });
379
+ }
380
+ }
381
+ });
382
+ }
383
+ };
384
+
385
+ wcStripePaymentRequest.init();
386
+
387
+ })( jQuery );
assets/js/payment-request.min.js ADDED
@@ -0,0 +1 @@
1
+ !function(a){var b={init:function(){var b=this;b.hasPaymentRequestSupport()&&a(document.body).on("click",".cart_totals a.checkout-button",b.initPaymentRequest)},hasPaymentRequestSupport:function(){return window.PaymentRequest&&"https:"===window.location.protocol},getSupportedMethods:function(){return["amex","diners","discover","jcb","mastercard","visa"]},getAjaxURL:function(a){return wcStripePaymentRequestParams.ajax_url.toString().replace("%%endpoint%%","wc_stripe_"+a)},initPaymentRequest:function(c){c.preventDefault();var d=b,e={security:wcStripePaymentRequestParams.nonce.payment};a.ajax({type:"POST",data:e,url:d.getAjaxURL("get_cart_details"),success:function(a){d.openPaymentRequest(a)}})},openPaymentRequest:function(a){var b=this,c=[{supportedMethods:b.getSupportedMethods()}],d={requestPayerPhone:!0,requestPayerEmail:!0};a.shipping_required&&(d.requestShipping=!0);var e=a.order_data,f=new PaymentRequest(c,e,d);f.addEventListener("shippingaddresschange",function(a){a.updateWith(new Promise(function(a,c){b.updateShippingOptions(e,f.shippingAddress,a,c)}))}),f.addEventListener("shippingoptionchange",function(a){a.updateWith(new Promise(function(a,c){b.updateShippingDetails(e,f.shippingOption,a,c)}))}),f.show().then(function(a){b.processPayment(a)})["catch"](function(a){console.error(a)})},updateShippingOptions:function(b,c,d,e){var f=this,g={security:wcStripePaymentRequestParams.nonce.shipping,country:c.country,state:c.region,postcode:c.postalCode,city:c.city,address:"undefined"==typeof c.addressLine[0]?"":c.addressLine[0],address_2:"undefined"==typeof c.addressLine[1]?"":c.addressLine[1]};a.ajax({type:"POST",data:g,url:f.getAjaxURL("get_shipping_options"),success:function(a){b.shippingOptions=a,1==b.shippingOptions.length?f.updateShippingDetails(b,b.shippingOptions[0].id,d,e):d(b)}})},updateShippingDetails:function(b,c,d,e){var f=this,g=null,h={security:wcStripePaymentRequestParams.nonce.update_shipping,shipping_method:[c]};a.ajax({type:"POST",data:h,url:f.getAjaxURL("update_shipping_method"),success:function(a){b.shippingOptions.forEach(function(d,e){d.id===c?(g=e,d.selected=!0,b.total.amount.value=parseFloat(a.total),a.items&&(b.displayItems=a.items)):d.selected=!1}),null===g&&e(wcStripePaymentRequestParams.i18n.unknown_shipping.toString().replace("[option]",c)),d(b)}})},getOrderData:function(a){var b=a.details.billingAddress,c=a.shippingAddress,d={_wpnonce:wcStripePaymentRequestParams.nonce.checkout,billing_first_name:b.recipient.split(" ").slice(0,1).join(" "),billing_last_name:b.recipient.split(" ").slice(1).join(" "),billing_company:b.organization,billing_email:a.payerEmail,billing_phone:a.payerPhone,billing_country:b.country,billing_address_1:"undefined"==typeof b.addressLine[0]?"":b.addressLine[0],billing_address_2:"undefined"==typeof b.addressLine[1]?"":b.addressLine[1],billing_city:b.city,billing_state:b.region,billing_postcode:b.postalCode,shipping_first_name:"",shipping_last_name:"",shipping_company:"",shipping_country:"",shipping_address_1:"",shipping_address_2:"",shipping_city:"",shipping_state:"",shipping_postcode:"",shipping_method:[a.shippingOption],order_comments:"",payment_method:"stripe",stripe_token:""};return c&&(d.shipping_first_name=c.recipient.split(" ").slice(0,1).join(" "),d.shipping_last_name=c.recipient.split(" ").slice(1).join(" "),d.shipping_company=c.organization,d.shipping_country=c.country,d.shipping_address_1="undefined"==typeof c.addressLine[0]?"":c.addressLine[0],d.shipping_address_2="undefined"==typeof c.addressLine[1]?"":c.addressLine[1],d.shipping_city=c.city,d.shipping_state=c.region,d.shipping_postcode=c.postalCode),d},getCardData:function(a){var b=a.details.billingAddress,c={number:a.details.cardNumber,cvc:a.details.cardSecurityCode,exp_month:parseInt(a.details.expiryMonth,10)||0,exp_year:parseInt(a.details.expiryYear,10)||0,name:b.recipient,address_line1:"undefined"==typeof b.addressLine[0]?"":b.addressLine[0],address_line2:"undefined"==typeof b.addressLine[1]?"":b.addressLine[1],address_state:b.region,address_city:b.city,address_zip:b.postalCode,address_country:b.country};return c},getErrorMessageHTML:function(b){return a('<div class="woocommerce-error" />').text(b)},abortPayment:function(b,c){b.complete("fail").then(function(){var b=a(".shop_table.cart").closest("form");a(".woocommerce-error").remove(),b.before(c),a("html, body").animate({scrollTop:b.prev(".woocommerce-error").offset().top},600)})["catch"](function(a){console.error(a)})},completePayment:function(a,b){a.complete("success").then(function(){window.location=b})["catch"](function(a){console.error(a)})},processPayment:function(b){var c=this,d=c.getOrderData(b),e=c.getCardData(b);Stripe.setPublishableKey(wcStripePaymentRequestParams.stripe.key),Stripe.createToken(e,function(e,f){f.error?c.abortPayment(b,c.getErrorMessageHTML(f.error.message)):"no"===wcStripePaymentRequestParams.stripe.allow_prepaid_card&&"prepaid"===f.card.funding?c.abortPayment(b,c.getErrorMessageHTML(wcStripePaymentRequestParams.i18n.no_prepaid_card)):(d.stripe_token=f.id,a.ajax({type:"POST",data:d,dataType:"json",url:c.getAjaxURL("create_order"),success:function(a){"success"===a.result?c.completePayment(b,a.redirect):c.abortPayment(b,a.messages)},complete:function(a,b){"success"!==b&&console.error(a)}}))})}};b.init()}(jQuery);
assets/js/stripe-admin.js ADDED
@@ -0,0 +1,92 @@
1
+ jQuery( function( $ ) {
2
+ 'use strict';
3
+
4
+ /**
5
+ * Object to handle Stripe admin functions.
6
+ */
7
+ var wc_stripe_admin = {
8
+ isTestMode: function() {
9
+ return $( '#woocommerce_stripe_testmode' ).is( ':checked' );
10
+ },
11
+
12
+ getSecretKey: function() {
13
+ if ( wc_stripe_admin.isTestMode() ) {
14
+ return $( '#woocommerce_stripe_test_secret_key' ).val();
15
+ } else {
16
+ return $( '#woocommerce_stripe_secret_key' ).val();
17
+ }
18
+ },
19
+
20
+ /**
21
+ * Initialize.
22
+ */
23
+ init: function() {
24
+ $( document.body ).on( 'change', '#woocommerce_stripe_testmode', function() {
25
+ var test_secret_key = $( '#woocommerce_stripe_test_secret_key' ).parents( 'tr' ).eq( 0 ),
26
+ test_publishable_key = $( '#woocommerce_stripe_test_publishable_key' ).parents( 'tr' ).eq( 0 ),
27
+ live_secret_key = $( '#woocommerce_stripe_secret_key' ).parents( 'tr' ).eq( 0 ),
28
+ live_publishable_key = $( '#woocommerce_stripe_publishable_key' ).parents( 'tr' ).eq( 0 );
29
+
30
+ if ( $( this ).is( ':checked' ) ) {
31
+ test_secret_key.show();
32
+ test_publishable_key.show();
33
+ live_secret_key.hide();
34
+ live_publishable_key.hide();
35
+ } else {
36
+ test_secret_key.hide();
37
+ test_publishable_key.hide();
38
+ live_secret_key.show();
39
+ live_publishable_key.show();
40
+ }
41
+ } );
42
+
43
+ $( '#woocommerce_stripe_testmode' ).change();
44
+
45
+ // Toggle Stripe Checkout settings.
46
+ $( '#woocommerce_stripe_stripe_checkout' ).change( function() {
47
+ if ( $( this ).is( ':checked' ) ) {
48
+ $( '#woocommerce_stripe_stripe_checkout_locale, #woocommerce_stripe_stripe_bitcoin, #woocommerce_stripe_stripe_checkout_image, #woocommerce_stripe_allow_remember_me' ).closest( 'tr' ).show();
49
+ $( '#woocommerce_stripe_request_payment_api' ).closest( 'tr' ).hide();
50
+ } else {
51
+ $( '#woocommerce_stripe_stripe_checkout_locale, #woocommerce_stripe_stripe_bitcoin, #woocommerce_stripe_stripe_checkout_image, #woocommerce_stripe_allow_remember_me' ).closest( 'tr' ).hide();
52
+ $( '#woocommerce_stripe_request_payment_api' ).closest( 'tr' ).show();
53
+ }
54
+ }).change();
55
+
56
+ // Toggle Apple Pay settings.
57
+ $( '#woocommerce_stripe_apple_pay' ).change( function() {
58
+ if ( $( this ).is( ':checked' ) ) {
59
+ $( '#woocommerce_stripe_apple_pay_button, #woocommerce_stripe_apple_pay_button_lang' ).closest( 'tr' ).show();
60
+ } else {
61
+ $( '#woocommerce_stripe_apple_pay_button, #woocommerce_stripe_apple_pay_button_lang' ).closest( 'tr' ).hide();
62
+ }
63
+ }).change();
64
+
65
+ // Validate the keys to make sure it is matching test with test field.
66
+ $( '#woocommerce_stripe_secret_key, #woocommerce_stripe_publishable_key' ).on( 'input', function() {
67
+ var value = $( this ).val();
68
+
69
+ if ( value.indexOf( '_test_' ) >= 0 ) {
70
+ $( this ).css( 'border-color', 'red' ).after( '<span class="description stripe-error-description" style="color:red; display:block;">' + wc_stripe_admin_params.localized_messages.not_valid_live_key_msg + '</span>' );
71
+ } else {
72
+ $( this ).css( 'border-color', '' );
73
+ $( '.stripe-error-description', $( this ).parent() ).remove();
74
+ }
75
+ }).trigger( 'input' );
76
+
77
+ // Validate the keys to make sure it is matching live with live field.
78
+ $( '#woocommerce_stripe_test_secret_key, #woocommerce_stripe_test_publishable_key' ).on( 'input', function() {
79
+ var value = $( this ).val();
80
+
81
+ if ( value.indexOf( '_live_' ) >= 0 ) {
82
+ $( this ).css( 'border-color', 'red' ).after( '<span class="description stripe-error-description" style="color:red; display:block;">' + wc_stripe_admin_params.localized_messages.not_valid_test_key_msg + '</span>' );
83
+ } else {
84
+ $( this ).css( 'border-color', '' );
85
+ $( '.stripe-error-description', $( this ).parent() ).remove();
86
+ }
87
+ }).trigger( 'input' );
88
+ }
89
+ };
90
+
91
+ wc_stripe_admin.init();
92
+ });
assets/js/stripe-admin.min.js ADDED
@@ -0,0 +1 @@
1
+ jQuery(function(a){"use strict";var b={isTestMode:function(){return a("#woocommerce_stripe_testmode").is(":checked")},getSecretKey:function(){return b.isTestMode()?a("#woocommerce_stripe_test_secret_key").val():a("#woocommerce_stripe_secret_key").val()},init:function(){a(document.body).on("change","#woocommerce_stripe_testmode",function(){var b=a("#woocommerce_stripe_test_secret_key").parents("tr").eq(0),c=a("#woocommerce_stripe_test_publishable_key").parents("tr").eq(0),d=a("#woocommerce_stripe_secret_key").parents("tr").eq(0),e=a("#woocommerce_stripe_publishable_key").parents("tr").eq(0);a(this).is(":checked")?(b.show(),c.show(),d.hide(),e.hide()):(b.hide(),c.hide(),d.show(),e.show())}),a("#woocommerce_stripe_testmode").change(),a("#woocommerce_stripe_stripe_checkout").change(function(){a(this).is(":checked")?(a("#woocommerce_stripe_stripe_checkout_locale, #woocommerce_stripe_stripe_bitcoin, #woocommerce_stripe_stripe_checkout_image, #woocommerce_stripe_allow_remember_me").closest("tr").show(),a("#woocommerce_stripe_request_payment_api").closest("tr").hide()):(a("#woocommerce_stripe_stripe_checkout_locale, #woocommerce_stripe_stripe_bitcoin, #woocommerce_stripe_stripe_checkout_image, #woocommerce_stripe_allow_remember_me").closest("tr").hide(),a("#woocommerce_stripe_request_payment_api").closest("tr").show())}).change(),a("#woocommerce_stripe_apple_pay").change(function(){a(this).is(":checked")?a("#woocommerce_stripe_apple_pay_button, #woocommerce_stripe_apple_pay_button_lang").closest("tr").show():a("#woocommerce_stripe_apple_pay_button, #woocommerce_stripe_apple_pay_button_lang").closest("tr").hide()}).change(),a("#woocommerce_stripe_secret_key, #woocommerce_stripe_publishable_key").on("input",function(){var b=a(this).val();b.indexOf("_test_")>=0?a(this).css("border-color","red").after('<span class="description stripe-error-description" style="color:red; display:block;">'+wc_stripe_admin_params.localized_messages.not_valid_live_key_msg+"</span>"):(a(this).css("border-color",""),a(".stripe-error-description",a(this).parent()).remove())}).trigger("input"),a("#woocommerce_stripe_test_secret_key, #woocommerce_stripe_test_publishable_key").on("input",function(){var b=a(this).val();b.indexOf("_live_")>=0?a(this).css("border-color","red").after('<span class="description stripe-error-description" style="color:red; display:block;">'+wc_stripe_admin_params.localized_messages.not_valid_test_key_msg+"</span>"):(a(this).css("border-color",""),a(".stripe-error-description",a(this).parent()).remove())}).trigger("input")}};b.init()});
assets/js/stripe-apple-pay-single.js ADDED
@@ -0,0 +1,207 @@
1
+ /* global wc_stripe_apple_pay_single_params, Stripe */
2
+ Stripe.setPublishableKey( wc_stripe_apple_pay_single_params.key );
3
+
4
+ jQuery( function( $ ) {
5
+ 'use strict';
6
+
7
+ /**
8
+ * Object to handle Stripe payment forms.
9
+ */
10
+ var wc_stripe_apple_pay_single = {
11
+ /**
12
+ * Get WC AJAX endpoint URL.
13
+ *
14
+ * @param {String} endpoint Endpoint.
15
+ * @return {String}
16
+ */
17
+ getAjaxURL: function( endpoint ) {
18
+ return wc_stripe_apple_pay_single_params.ajaxurl
19
+ .toString()
20
+ .replace( '%%endpoint%%', 'wc_stripe_' + endpoint );
21
+ },
22
+
23
+ /**
24
+ * Initialize event handlers and UI state.
25
+ */
26
+ init: function() {
27
+ Stripe.applePay.checkAvailability( function( available ) {
28
+ if ( available ) {
29
+ $( document.body ).on( 'woocommerce_variation_has_changed', function() {
30
+ wc_stripe_apple_pay_single.generate_cart();
31
+ })
32
+
33
+ .on( 'change', '.quantity .qty', function() {
34
+ wc_stripe_apple_pay_single.generate_cart();
35
+ });
36
+
37
+ wc_stripe_apple_pay_single.generate_cart();
38
+
39
+ $( '.apple-pay-button' ).show();
40
+ }
41
+ });
42
+
43
+ $( document.body ).on( 'click', '.apple-pay-button', function( e ) {
44
+ e.preventDefault();
45
+
46
+ var addToCartButton = $( '.single_add_to_cart_button' );
47
+
48
+ // First check if product can be added to cart.
49
+ if ( addToCartButton.is( '.disabled' ) ) {
50
+ if ( addToCartButton.is( '.wc-variation-is-unavailable' ) ) {
51
+ window.alert( wc_add_to_cart_variation_params.i18n_unavailable_text );
52
+ } else if ( addToCartButton.is( '.wc-variation-selection-needed' ) ) {
53
+ window.alert( wc_add_to_cart_variation_params.i18n_make_a_selection_text );
54
+ }
55
+
56
+ return;
57
+ }
58
+
59
+ var paymentRequest = {
60
+ countryCode: wc_stripe_apple_pay_single_params.country_code,
61
+ currencyCode: wc_stripe_apple_pay_single_params.currency_code,
62
+ total: {
63
+ label: wc_stripe_apple_pay_single_params.label,
64
+ amount: wc_stripe_apple_pay_single_params.total
65
+ },
66
+ lineItems: wc_stripe_apple_pay_single_params.line_items,
67
+ requiredBillingContactFields: ['postalAddress'],
68
+ requiredShippingContactFields: 'yes' === wc_stripe_apple_pay_single_params.needs_shipping ? ['postalAddress', 'phone', 'email', 'name'] : ['phone', 'email', 'name']
69
+ };
70
+
71
+ var applePaySession = Stripe.applePay.buildSession( paymentRequest, function( result, completion ) {
72
+ var data = {
73
+ 'nonce': wc_stripe_apple_pay_single_params.stripe_apple_pay_nonce,
74
+ 'result': result
75
+ };
76
+
77
+ $.ajax({
78
+ type: 'POST',
79
+ data: data,
80
+ url: wc_stripe_apple_pay_single.getAjaxURL( 'apple_pay' ),
81
+ success: function( response ) {
82
+ if ( 'true' === response.success ) {
83
+ completion( ApplePaySession.STATUS_SUCCESS );
84
+ window.location.href = response.redirect;
85
+ }
86
+
87
+ if ( 'false' === response.success ) {
88
+ completion( ApplePaySession.STATUS_FAILURE );
89
+
90
+ $( '.apple-pay-button' ).before( '<p class="woocommerce-error wc-stripe-apple-pay-error">' + response.msg + '</p>' );
91
+
92
+ // Scroll to error so user can see it.
93
+ $( document.body ).animate({ scrollTop: $( '.wc-stripe-apple-pay-error' ).offset().top }, 500 );
94
+ }
95
+ }
96
+ });
97
+ });
98
+
99
+ // If shipping is needed -- get shipping methods.
100
+ if ( 'yes' === wc_stripe_apple_pay_single_params.needs_shipping ) {
101
+ // After the shipping contact/address has been selected
102
+ applePaySession.onshippingcontactselected = function( shipping ) {
103
+ var data = {
104
+ 'nonce': wc_stripe_apple_pay_single_params.stripe_apple_pay_get_shipping_methods_nonce,
105
+ 'address': shipping.shippingContact
106
+ };
107
+
108
+ $.ajax({
109
+ type: 'POST',
110
+ data: data,
111
+ url: wc_stripe_apple_pay_single.getAjaxURL( 'apple_pay_get_shipping_methods' ),
112
+ success: function( response ) {
113
+ var total = {
114
+ 'label': wc_stripe_apple_pay_single_params.label,
115
+ 'amount': response.total
116
+ };
117
+
118
+ if ( 'true' === response.success ) {
119
+ applePaySession.completeShippingContactSelection( ApplePaySession.STATUS_SUCCESS, response.shipping_methods, total, response.line_items );
120
+ }
121
+
122
+ if ( 'false' === response.success ) {
123
+ applePaySession.completeShippingContactSelection( ApplePaySession.STATUS_INVALID_SHIPPING_POSTAL_ADDRESS, response.shipping_methods, total, response.line_items );
124
+ }
125
+ }
126
+ });
127
+ };
128
+
129
+ // After the shipping method has been selected
130
+ applePaySession.onshippingmethodselected = function( event ) {
131
+ var data = {
132
+ 'nonce': wc_stripe_apple_pay_single_params.stripe_apple_pay_update_shipping_method_nonce,
133
+ 'selected_shipping_method': event.shippingMethod
134
+ };
135
+
136
+ $.ajax({
137
+ type: 'POST',
138
+ data: data,
139
+ url: wc_stripe_apple_pay_single.getAjaxURL( 'apple_pay_update_shipping_method' ),
140
+ success: function( response ) {
141
+ var newTotal = {
142
+ 'label': wc_stripe_apple_pay_single_params.label,
143
+ 'amount': parseFloat( response.total ).toFixed(2)
144
+ };
145
+
146
+ if ( 'true' === response.success ) {
147
+ applePaySession.completeShippingMethodSelection( ApplePaySession.STATUS_SUCCESS, newTotal, response.line_items );
148
+ }
149
+
150
+ if ( 'false' === response.success ) {
151
+ applePaySession.completeShippingMethodSelection( ApplePaySession.STATUS_INVALID_SHIPPING_POSTAL_ADDRESS, newTotal, response.line_items );
152
+ }
153
+ }
154
+ });
155
+ };
156
+ }
157
+
158
+ applePaySession.begin();
159
+ });
160
+ },
161
+
162
+ get_attributes: function() {
163
+ var select = $( '.variations_form' ).find( '.variations select' ),
164
+ data = {},
165
+ count = 0,
166
+ chosen = 0;
167
+
168
+ select.each( function() {
169
+ var attribute_name = $( this ).data( 'attribute_name' ) || $( this ).attr( 'name' );
170
+ var value = $( this ).val() || '';
171
+
172
+ if ( value.length > 0 ) {
173
+ chosen ++;
174
+ }
175
+
176
+ count ++;
177
+ data[ attribute_name ] = value;
178
+ });
179
+
180
+ return {
181
+ 'count' : count,
182
+ 'chosenCount': chosen,
183
+ 'data' : data
184
+ };
185
+ },
186
+
187
+ generate_cart: function() {
188
+ var data = {
189
+ 'nonce': wc_stripe_apple_pay_single_params.stripe_apple_pay_cart_nonce,
190
+ 'qty': $( '.quantity .qty' ).val(),
191
+ 'attributes': $( '.variations_form' ).length ? wc_stripe_apple_pay_single.get_attributes().data : []
192
+ };
193
+
194
+ return $.ajax({
195
+ type: 'POST',
196
+ data: data,
197
+ url: wc_stripe_apple_pay_single.getAjaxURL( 'generate_apple_pay_single' ),
198
+ success: function( response ) {
199
+ wc_stripe_apple_pay_single_params.total = response.total;
200
+ wc_stripe_apple_pay_single_params.line_items = response.line_items;
201
+ }
202
+ });
203
+ }
204
+ };
205
+
206
+ wc_stripe_apple_pay_single.init();
207
+ });
assets/js/stripe-apple-pay-single.min.js ADDED
@@ -0,0 +1 @@
1
+ Stripe.setPublishableKey(wc_stripe_apple_pay_single_params.key),jQuery(function(a){"use strict";var b={getAjaxURL:function(a){return wc_stripe_apple_pay_single_params.ajaxurl.toString().replace("%%endpoint%%","wc_stripe_"+a)},init:function(){Stripe.applePay.checkAvailability(function(c){c&&(a(document.body).on("woocommerce_variation_has_changed",function(){b.generate_cart()}).on("change",".quantity .qty",function(){b.generate_cart()}),b.generate_cart(),a(".apple-pay-button").show())}),a(document.body).on("click",".apple-pay-button",function(c){c.preventDefault();var d=a(".single_add_to_cart_button");if(d.is(".disabled"))return void(d.is(".wc-variation-is-unavailable")?window.alert(wc_add_to_cart_variation_params.i18n_unavailable_text):d.is(".wc-variation-selection-needed")&&window.alert(wc_add_to_cart_variation_params.i18n_make_a_selection_text));var e={countryCode:wc_stripe_apple_pay_single_params.country_code,currencyCode:wc_stripe_apple_pay_single_params.currency_code,total:{label:wc_stripe_apple_pay_single_params.label,amount:wc_stripe_apple_pay_single_params.total},lineItems:wc_stripe_apple_pay_single_params.line_items,requiredBillingContactFields:["postalAddress"],requiredShippingContactFields:"yes"===wc_stripe_apple_pay_single_params.needs_shipping?["postalAddress","phone","email","name"]:["phone","email","name"]},f=Stripe.applePay.buildSession(e,function(c,d){var e={nonce:wc_stripe_apple_pay_single_params.stripe_apple_pay_nonce,result:c};a.ajax({type:"POST",data:e,url:b.getAjaxURL("apple_pay"),success:function(b){"true"===b.success&&(d(ApplePaySession.STATUS_SUCCESS),window.location.href=b.redirect),"false"===b.success&&(d(ApplePaySession.STATUS_FAILURE),a(".apple-pay-button").before('<p class="woocommerce-error wc-stripe-apple-pay-error">'+b.msg+"</p>"),a(document.body).animate({scrollTop:a(".wc-stripe-apple-pay-error").offset().top},500))}})});"yes"===wc_stripe_apple_pay_single_params.needs_shipping&&(f.onshippingcontactselected=function(c){var d={nonce:wc_stripe_apple_pay_single_params.stripe_apple_pay_get_shipping_methods_nonce,address:c.shippingContact};a.ajax({type:"POST",data:d,url:b.getAjaxURL("apple_pay_get_shipping_methods"),success:function(a){var b={label:wc_stripe_apple_pay_single_params.label,amount:a.total};"true"===a.success&&f.completeShippingContactSelection(ApplePaySession.STATUS_SUCCESS,a.shipping_methods,b,a.line_items),"false"===a.success&&f.completeShippingContactSelection(ApplePaySession.STATUS_INVALID_SHIPPING_POSTAL_ADDRESS,a.shipping_methods,b,a.line_items)}})},f.onshippingmethodselected=function(c){var d={nonce:wc_stripe_apple_pay_single_params.stripe_apple_pay_update_shipping_method_nonce,selected_shipping_method:c.shippingMethod};a.ajax({type:"POST",data:d,url:b.getAjaxURL("apple_pay_update_shipping_method"),success:function(a){var b={label:wc_stripe_apple_pay_single_params.label,amount:parseFloat(a.total).toFixed(2)};"true"===a.success&&f.completeShippingMethodSelection(ApplePaySession.STATUS_SUCCESS,b,a.line_items),"false"===a.success&&f.completeShippingMethodSelection(ApplePaySession.STATUS_INVALID_SHIPPING_POSTAL_ADDRESS,b,a.line_items)}})}),f.begin()})},get_attributes:function(){var b=a(".variations_form").find(".variations select"),c={},d=0,e=0;return b.each(function(){var b=a(this).data("attribute_name")||a(this).attr("name"),f=a(this).val()||"";f.length>0&&e++,d++,c[b]=f}),{count:d,chosenCount:e,data:c}},generate_cart:function(){var c={nonce:wc_stripe_apple_pay_single_params.stripe_apple_pay_cart_nonce,qty:a(".quantity .qty").val(),attributes:a(".variations_form").length?b.get_attributes().data:[]};return a.ajax({type:"POST",data:c,url:b.getAjaxURL("generate_apple_pay_single"),success:function(a){wc_stripe_apple_pay_single_params.total=a.total,wc_stripe_apple_pay_single_params.line_items=a.line_items}})}};b.init()});
assets/js/stripe-apple-pay.js ADDED
@@ -0,0 +1,172 @@
1
+ /* global wc_stripe_apple_pay_params, Stripe */
2
+ Stripe.setPublishableKey( wc_stripe_apple_pay_params.key );
3
+
4
+ jQuery( function( $ ) {
5
+ 'use strict';
6
+
7
+ /**
8
+ * Object to handle Stripe payment forms.
9
+ */
10
+ var wc_stripe_apple_pay = {
11
+ /**
12
+ * Get WC AJAX endpoint URL.
13
+ *
14
+ * @param {String} endpoint Endpoint.
15
+ * @return {String}
16
+ */
17
+ getAjaxURL: function( endpoint ) {
18
+ return wc_stripe_apple_pay_params.ajaxurl
19
+ .toString()
20
+ .replace( '%%endpoint%%', 'wc_stripe_' + endpoint );
21
+ },
22
+
23
+ /**
24
+ * Initialize event handlers and UI state.
25
+ */
26
+ init: function() {
27
+ Stripe.applePay.checkAvailability( function( available ) {
28
+ if ( available ) {
29
+ $( '.apple-pay-button' ).show();
30
+ // This is so it is centered on the checkout page.
31
+ $( '.woocommerce-checkout .apple-pay-button' ).css( 'visibility', 'visible' );
32
+ $( '.apple-pay-button-checkout-separator' ).show();
33
+
34
+ wc_stripe_apple_pay.generate_cart();
35
+ }
36
+ });
37
+
38
+ $( document.body ).on( 'click', '.apple-pay-button', function( e ) {
39
+ e.preventDefault();
40
+
41
+ var paymentRequest = {
42
+ countryCode: wc_stripe_apple_pay_params.country_code,
43
+ currencyCode: wc_stripe_apple_pay_params.currency_code,
44
+ total: {
45
+ label: wc_stripe_apple_pay_params.label,
46
+ amount: wc_stripe_apple_pay_params.total
47
+ },
48
+ lineItems: wc_stripe_apple_pay_params.line_items,
49
+ requiredBillingContactFields: ['postalAddress'],
50
+ requiredShippingContactFields: 'yes' === wc_stripe_apple_pay_params.needs_shipping ? ['postalAddress', 'phone', 'email', 'name'] : ['phone', 'email', 'name']
51
+ };
52
+
53
+ var applePaySession = Stripe.applePay.buildSession( paymentRequest, function( result, completion ) {
54
+ var data = {
55
+ 'nonce': wc_stripe_apple_pay_params.stripe_apple_pay_nonce,
56
+ 'result': result
57
+ };
58
+
59
+ $.ajax({
60
+ type: 'POST',
61
+ data: data,
62
+ url: wc_stripe_apple_pay.getAjaxURL( 'apple_pay' ),
63
+ success: function( response ) {
64
+ if ( 'true' === response.success ) {
65
+ completion( ApplePaySession.STATUS_SUCCESS );
66
+ window.location.href = response.redirect;
67
+ }
68
+
69
+ if ( 'false' === response.success ) {
70
+ completion( ApplePaySession.STATUS_FAILURE );
71
+
72
+ $( '.apple-pay-button' ).before( '<p class="woocommerce-error wc-stripe-apple-pay-error">' + response.msg + '</p>' );
73
+
74
+ // Scroll to error so user can see it.
75
+ $( document.body ).animate({ scrollTop: $( '.wc-stripe-apple-pay-error' ).offset().top }, 500 );
76
+ }
77
+ }
78
+ });
79
+ });
80
+
81
+ // If shipping is needed -- get shipping methods.
82
+ if ( 'yes' === wc_stripe_apple_pay_params.needs_shipping ) {
83
+ // After the shipping contact/address has been selected
84
+ applePaySession.onshippingcontactselected = function( shipping ) {
85
+ var data = {
86
+ 'nonce': wc_stripe_apple_pay_params.stripe_apple_pay_get_shipping_methods_nonce,
87
+ 'address': shipping.shippingContact
88
+ };
89
+
90
+ $.ajax({
91
+ type: 'POST',
92
+ data: data,
93
+ url: wc_stripe_apple_pay.getAjaxURL( 'apple_pay_get_shipping_methods' ),
94
+ success: function( response ) {
95
+ var total = {
96
+ 'label': wc_stripe_apple_pay_params.label,
97
+ 'amount': response.total
98
+ };
99
+
100
+ if ( 'true' === response.success ) {
101
+ applePaySession.completeShippingContactSelection( ApplePaySession.STATUS_SUCCESS, response.shipping_methods, total, response.line_items );
102
+ }
103
+
104
+ if ( 'false' === response.success ) {
105
+ applePaySession.completeShippingContactSelection( ApplePaySession.STATUS_INVALID_SHIPPING_POSTAL_ADDRESS, response.shipping_methods, total, response.line_items );
106
+ }
107
+ }
108
+ });
109
+ };
110
+
111
+ // After the shipping method has been selected
112
+ applePaySession.onshippingmethodselected = function( event ) {
113
+ var data = {
114
+ 'nonce': wc_stripe_apple_pay_params.stripe_apple_pay_update_shipping_method_nonce,
115
+ 'selected_shipping_method': event.shippingMethod
116
+ };
117
+
118
+ $.ajax({
119
+ type: 'POST',
120
+ data: data,
121
+ url: wc_stripe_apple_pay.getAjaxURL( 'apple_pay_update_shipping_method' ),
122
+ success: function( response ) {
123
+ var newTotal = {
124
+ 'label': wc_stripe_apple_pay_params.label,
125
+ 'amount': parseFloat( response.total ).toFixed(2)
126
+ };
127
+
128
+ if ( 'true' === response.success ) {
129
+ applePaySession.completeShippingMethodSelection( ApplePaySession.STATUS_SUCCESS, newTotal, response.line_items );
130
+ }
131
+
132
+ if ( 'false' === response.success ) {
133
+ applePaySession.completeShippingMethodSelection( ApplePaySession.STATUS_INVALID_SHIPPING_POSTAL_ADDRESS, newTotal, response.line_items );
134
+ }
135
+ }
136
+ });
137
+ };
138
+ }
139
+
140
+ applePaySession.begin();
141
+ });
142
+ },
143
+
144
+ generate_cart: function() {
145
+ var data = {
146
+ 'nonce': wc_stripe_apple_pay_params.stripe_apple_pay_cart_nonce
147
+ };
148
+
149
+ $.ajax({
150
+ type: 'POST',
151
+ data: data,
152
+ url: wc_stripe_apple_pay.getAjaxURL( 'generate_apple_pay_cart' ),
153
+ success: function( response ) {
154
+ wc_stripe_apple_pay_params.total = response.total;
155
+ wc_stripe_apple_pay_params.line_items = response.line_items;
156
+ }
157
+ });
158
+ }
159
+ };
160
+
161
+ wc_stripe_apple_pay.init();
162
+
163
+ // We need to refresh Apple Pay data when total is updated.
164
+ $( document.body ).on( 'updated_cart_totals', function() {
165
+ wc_stripe_apple_pay.init();
166
+ });
167
+
168
+ // We need to refresh Apple Pay data when total is updated.
169
+ $( document.body ).on( 'updated_checkout', function() {
170
+ wc_stripe_apple_pay.init();
171
+ });
172
+ });
assets/js/stripe-apple-pay.min.js ADDED
@@ -0,0 +1 @@
1
+ Stripe.setPublishableKey(wc_stripe_apple_pay_params.key),jQuery(function(a){"use strict";var b={getAjaxURL:function(a){return wc_stripe_apple_pay_params.ajaxurl.toString().replace("%%endpoint%%","wc_stripe_"+a)},init:function(){Stripe.applePay.checkAvailability(function(c){c&&(a(".apple-pay-button").show(),a(".woocommerce-checkout .apple-pay-button").css("visibility","visible"),a(".apple-pay-button-checkout-separator").show(),b.generate_cart())}),a(document.body).on("click",".apple-pay-button",function(c){c.preventDefault();var d={countryCode:wc_stripe_apple_pay_params.country_code,currencyCode:wc_stripe_apple_pay_params.currency_code,total:{label:wc_stripe_apple_pay_params.label,amount:wc_stripe_apple_pay_params.total},lineItems:wc_stripe_apple_pay_params.line_items,requiredBillingContactFields:["postalAddress"],requiredShippingContactFields:"yes"===wc_stripe_apple_pay_params.needs_shipping?["postalAddress","phone","email","name"]:["phone","email","name"]},e=Stripe.applePay.buildSession(d,function(c,d){var e={nonce:wc_stripe_apple_pay_params.stripe_apple_pay_nonce,result:c};a.ajax({type:"POST",data:e,url:b.getAjaxURL("apple_pay"),success:function(b){"true"===b.success&&(d(ApplePaySession.STATUS_SUCCESS),window.location.href=b.redirect),"false"===b.success&&(d(ApplePaySession.STATUS_FAILURE),a(".apple-pay-button").before('<p class="woocommerce-error wc-stripe-apple-pay-error">'+b.msg+"</p>"),a(document.body).animate({scrollTop:a(".wc-stripe-apple-pay-error").offset().top},500))}})});"yes"===wc_stripe_apple_pay_params.needs_shipping&&(e.onshippingcontactselected=function(c){var d={nonce:wc_stripe_apple_pay_params.stripe_apple_pay_get_shipping_methods_nonce,address:c.shippingContact};a.ajax({type:"POST",data:d,url:b.getAjaxURL("apple_pay_get_shipping_methods"),success:function(a){var b={label:wc_stripe_apple_pay_params.label,amount:a.total};"true"===a.success&&e.completeShippingContactSelection(ApplePaySession.STATUS_SUCCESS,a.shipping_methods,b,a.line_items),"false"===a.success&&e.completeShippingContactSelection(ApplePaySession.STATUS_INVALID_SHIPPING_POSTAL_ADDRESS,a.shipping_methods,b,a.line_items)}})},e.onshippingmethodselected=function(c){var d={nonce:wc_stripe_apple_pay_params.stripe_apple_pay_update_shipping_method_nonce,selected_shipping_method:c.shippingMethod};a.ajax({type:"POST",data:d,url:b.getAjaxURL("apple_pay_update_shipping_method"),success:function(a){var b={label:wc_stripe_apple_pay_params.label,amount:parseFloat(a.total).toFixed(2)};"true"===a.success&&e.completeShippingMethodSelection(ApplePaySession.STATUS_SUCCESS,b,a.line_items),"false"===a.success&&e.completeShippingMethodSelection(ApplePaySession.STATUS_INVALID_SHIPPING_POSTAL_ADDRESS,b,a.line_items)}})}),e.begin()})},generate_cart:function(){var c={nonce:wc_stripe_apple_pay_params.stripe_apple_pay_cart_nonce};a.ajax({type:"POST",data:c,url:b.getAjaxURL("generate_apple_pay_cart"),success:function(a){wc_stripe_apple_pay_params.total=a.total,wc_stripe_apple_pay_params.line_items=a.line_items}})}};b.init(),a(document.body).on("updated_cart_totals",function(){b.init()}),a(document.body).on("updated_checkout",function(){b.init()})});
assets/js/{stripe_checkout.js → stripe-checkout.js} RENAMED
File without changes
assets/js/{stripe_checkout.min.js → stripe-checkout.min.js} RENAMED
File without changes
assets/js/stripe.js CHANGED
@@ -3,7 +3,7 @@ Stripe.setPublishableKey( wc_stripe_params.key );
3
4
jQuery( function( $ ) {
5
'use strict';
6
-
7
/* Open and close for legacy class */
8
$( 'form.checkout, form#order_review' ).on( 'change', 'input[name="wc-stripe-payment-token"]', function() {
9
if ( 'new' === $( '.stripe-legacy-payment-fields input[name="wc-stripe-payment-token"]:checked' ).val() ) {
@@ -112,8 +112,8 @@ jQuery( function( $ ) {
112
message = wc_stripe_params[ responseObject.response.error.code ];
113
}
114
115
- $( '.woocommerce-error, .stripe_token' ).remove();
116
- $( '#stripe-card-number' ).closest( 'p' ).before( '<ul class="woocommerce_error woocommerce-error"><li>' + message + '</li></ul>' );
117
wc_stripe_form.unblock();
118
},
119
@@ -162,7 +162,7 @@ jQuery( function( $ ) {
162
},
163
164
onCCFormChange: function() {
165
- $( '.woocommerce-error, .stripe_token' ).remove();
166
},
167
168
onStripeResponse: function( status, response ) {
3
4
jQuery( function( $ ) {
5
'use strict';
6
+
7
/* Open and close for legacy class */
8
$( 'form.checkout, form#order_review' ).on( 'change', 'input[name="wc-stripe-payment-token"]', function() {
9
if ( 'new' === $( '.stripe-legacy-payment-fields input[name="wc-stripe-payment-token"]:checked' ).val() ) {
112
message = wc_stripe_params[ responseObject.response.error.code ];
113
}
114
115
+ $( '.wc-stripe-error, .stripe_token' ).remove();
116
+ $( '#stripe-card-number' ).closest( 'p' ).before( '<ul class="woocommerce_error woocommerce-error wc-stripe-error"><li>' + message + '</li></ul>' );
117
wc_stripe_form.unblock();
118
},
119
162
},
163
164
onCCFormChange: function() {
165
+ $( '.wc-stripe-error, .stripe_token' ).remove();
166
},
167
168
onStripeResponse: function( status, response ) {
assets/js/stripe.min.js CHANGED
@@ -1 +1 @@
1
- Stripe.setPublishableKey(wc_stripe_params.key),jQuery(function(a){"use strict";a("form.checkout, form#order_review").on("change",'input[name="wc-stripe-payment-token"]',function(){"new"===a('.stripe-legacy-payment-fields input[name="wc-stripe-payment-token"]:checked').val()?a(".stripe-legacy-payment-fields #stripe-payment-data").slideDown(200):a(".stripe-legacy-payment-fields #stripe-payment-data").slideUp(200)});var b={init:function(){a("form.woocommerce-checkout").length&&(this.form=a("form.woocommerce-checkout")),a("form.woocommerce-checkout").on("checkout_place_order_stripe",this.onSubmit),a("form#order_review").length&&(this.form=a("form#order_review")),a("form#order_review").on("submit",this.onSubmit),a("form#add_payment_method").length&&(this.form=a("form#add_payment_method")),a("form#add_payment_method").on("submit",this.onSubmit),a(document).on("change","#wc-stripe-cc-form :input",this.onCCFormChange).on("stripeError",this.onError).on("checkout_error",this.clearToken)},isStripeChosen:function(){return a("#payment_method_stripe").is(":checked")&&(!a('input[name="wc-stripe-payment-token"]:checked').length||"new"===a('input[name="wc-stripe-payment-token"]:checked').val())},hasToken:function(){return 0<a("input.stripe_token").length},block:function(){b.form.block({message:null,overlayCSS:{background:"#fff",opacity:.6}})},unblock:function(){b.form.unblock()},onError:function(c,d){var e=d.response.error.message;("invalid_request_error"===d.response.error.type||"api_connection_error"===d.response.error.type||"api_error"===d.response.error.type||"authentication_error"===d.response.error.type||"rate_limit_error"===d.response.error.type)&&(e=wc_stripe_params.invalid_request_error),"card_error"===d.response.error.type&&wc_stripe_params.hasOwnProperty(d.response.error.code)&&(e=wc_stripe_params[d.response.error.code]),a(".woocommerce-error, .stripe_token").remove(),a("#stripe-card-number").closest("p").before('<ul class="woocommerce_error woocommerce-error"><li>'+e+"</li></ul>"),b.unblock()},onSubmit:function(c){if(b.isStripeChosen()&&!b.hasToken()){c.preventDefault(),b.block();var d=a("#stripe-card-number").val(),e=a("#stripe-card-cvc").val(),f=a("#stripe-card-expiry").payment("cardExpiryVal"),g=a("#billing_first_name").length?a("#billing_first_name").val():wc_stripe_params.billing_first_name,h=a("#billing_last_name").length?a("#billing_last_name").val():wc_stripe_params.billing_last_name,i={number:d,cvc:e,exp_month:parseInt(f.month,10)||0,exp_year:parseInt(f.year,10)||0};return g&&h&&(i.name=g+" "+h),a("#billing_address_1").length>0?(i.address_line1=a("#billing_address_1").val(),i.address_line2=a("#billing_address_2").val(),i.address_state=a("#billing_state").val(),i.address_city=a("#billing_city").val(),i.address_zip=a("#billing_postcode").val(),i.address_country=a("#billing_country").val()):wc_stripe_params.billing_address_1&&(i.address_line1=wc_stripe_params.billing_address_1,i.address_line2=wc_stripe_params.billing_address_2,i.address_state=wc_stripe_params.billing_state,i.address_city=wc_stripe_params.billing_city,i.address_zip=wc_stripe_params.billing_postcode,i.address_country=wc_stripe_params.billing_country),Stripe.createToken(i,b.onStripeResponse),!1}},onCCFormChange:function(){a(".woocommerce-error, .stripe_token").remove()},onStripeResponse:function(c,d){if(d.error)a(document).trigger("stripeError",{response:d});else{if("no"===wc_stripe_params.allow_prepaid_card&&"prepaid"===d.card.funding)return d.error={message:wc_stripe_params.no_prepaid_card_msg},a(document).trigger("stripeError",{response:d}),!1;var e=d.id;b.form.append("<input type='hidden' class='stripe_token' name='stripe_token' value='"+e+"'/>"),b.form.submit()}},clearToken:function(){a(".stripe_token").remove()}};b.init()});
1
+ Stripe.setPublishableKey(wc_stripe_params.key),jQuery(function(a){"use strict";a("form.checkout, form#order_review").on("change",'input[name="wc-stripe-payment-token"]',function(){"new"===a('.stripe-legacy-payment-fields input[name="wc-stripe-payment-token"]:checked').val()?a(".stripe-legacy-payment-fields #stripe-payment-data").slideDown(200):a(".stripe-legacy-payment-fields #stripe-payment-data").slideUp(200)});var b={init:function(){a("form.woocommerce-checkout").length&&(this.form=a("form.woocommerce-checkout")),a("form.woocommerce-checkout").on("checkout_place_order_stripe",this.onSubmit),a("form#order_review").length&&(this.form=a("form#order_review")),a("form#order_review").on("submit",this.onSubmit),a("form#add_payment_method").length&&(this.form=a("form#add_payment_method")),a("form#add_payment_method").on("submit",this.onSubmit),a(document).on("change","#wc-stripe-cc-form :input",this.onCCFormChange).on("stripeError",this.onError).on("checkout_error",this.clearToken)},isStripeChosen:function(){return a("#payment_method_stripe").is(":checked")&&(!a('input[name="wc-stripe-payment-token"]:checked').length||"new"===a('input[name="wc-stripe-payment-token"]:checked').val())},hasToken:function(){return 0<a("input.stripe_token").length},block:function(){b.form.block({message:null,overlayCSS:{background:"#fff",opacity:.6}})},unblock:function(){b.form.unblock()},onError:function(c,d){var e=d.response.error.message;("invalid_request_error"===d.response.error.type||"api_connection_error"===d.response.error.type||"api_error"===d.response.error.type||"authentication_error"===d.response.error.type||"rate_limit_error"===d.response.error.type)&&(e=wc_stripe_params.invalid_request_error),"card_error"===d.response.error.type&&wc_stripe_params.hasOwnProperty(d.response.error.code)&&(e=wc_stripe_params[d.response.error.code]),a(".wc-stripe-error, .stripe_token").remove(),a("#stripe-card-number").closest("p").before('<ul class="woocommerce_error woocommerce-error wc-stripe-error"><li>'+e+"</li></ul>"),b.unblock()},onSubmit:function(c){if(b.isStripeChosen()&&!b.hasToken()){c.preventDefault(),b.block();var d=a("#stripe-card-number").val(),e=a("#stripe-card-cvc").val(),f=a("#stripe-card-expiry").payment("cardExpiryVal"),g=a("#billing_first_name").length?a("#billing_first_name").val():wc_stripe_params.billing_first_name,h=a("#billing_last_name").length?a("#billing_last_name").val():wc_stripe_params.billing_last_name,i={number:d,cvc:e,exp_month:parseInt(f.month,10)||0,exp_year:parseInt(f.year,10)||0};return g&&h&&(i.name=g+" "+h),a("#billing_address_1").length>0?(i.address_line1=a("#billing_address_1").val(),i.address_line2=a("#billing_address_2").val(),i.address_state=a("#billing_state").val(),i.address_city=a("#billing_city").val(),i.address_zip=a("#billing_postcode").val(),i.address_country=a("#billing_country").val()):wc_stripe_params.billing_address_1&&(i.address_line1=wc_stripe_params.billing_address_1,i.address_line2=wc_stripe_params.billing_address_2,i.address_state=wc_stripe_params.billing_state,i.address_city=wc_stripe_params.billing_city,i.address_zip=wc_stripe_params.billing_postcode,i.address_country=wc_stripe_params.billing_country),Stripe.createToken(i,b.onStripeResponse),!1}},onCCFormChange:function(){a(".wc-stripe-error, .stripe_token").remove()},onStripeResponse:function(c,d){if(d.error)a(document).trigger("stripeError",{response:d});else{if("no"===wc_stripe_params.allow_prepaid_card&&"prepaid"===d.card.funding)return d.error={message:wc_stripe_params.no_prepaid_card_msg},a(document).trigger("stripeError",{response:d}),!1;var e=d.id;b.form.append("<input type='hidden' class='stripe_token' name='stripe_token' value='"+e+"'/>"),b.form.submit()}},clearToken:function(){a(".stripe_token").remove()}};b.init()});
includes/class-wc-gateway-stripe-addons.php CHANGED
@@ -77,16 +77,18 @@ class WC_Gateway_Stripe_Addons extends WC_Gateway_Stripe {
77
protected function save_source( $order, $source ) {
78
parent::save_source( $order, $source );
79
80
// Also store it on the subscriptions being purchased or paid for in the order
81
- if ( function_exists( 'wcs_order_contains_subscription' ) && wcs_order_contains_subscription( $order->id ) ) {
82
- $subscriptions = wcs_get_subscriptions_for_order( $order->id );
83
- } elseif ( function_exists( 'wcs_order_contains_renewal' ) && wcs_order_contains_renewal( $order->id ) ) {
84
- $subscriptions = wcs_get_subscriptions_for_renewal_order( $order->id );
85
} else {
86
$subscriptions = array();
87
}
88
89
- foreach( $subscriptions as $subscription ) {
90
update_post_meta( $subscription->id, '_stripe_customer_id', $source->customer );
91
update_post_meta( $subscription->id, '_stripe_card_id', $source->source );
92
}
@@ -99,7 +101,7 @@ class WC_Gateway_Stripe_Addons extends WC_Gateway_Stripe {
99
* @param string $stripe_token (default: '')
100
* @param bool initial_payment
101
*/
102
- public function process_subscription_payment( $order = '', $amount = 0 ) {
103
if ( $amount * 100 < WC_Stripe::get_minimum_amount() ) {
104
return new WP_Error( 'stripe_error', sprintf( __( 'Sorry, the minimum allowed order total is %1$s to use this payment method.', 'woocommerce-gateway-stripe' ), wc_price( WC_Stripe::get_minimum_amount() / 100 ) ) );
105
}
@@ -117,14 +119,15 @@ class WC_Gateway_Stripe_Addons extends WC_Gateway_Stripe {
117
return new WP_Error( 'stripe_error', __( 'Customer not found', 'woocommerce-gateway-stripe' ) );
118
}
119
120
- WC_Stripe::log( "Info: Begin processing subscription payment for order {$order->id} for the amount of {$amount}" );
121
122
// Make the request
123
$request = $this->generate_payment_request( $order, $source );
124
$request['capture'] = 'true';
125
$request['amount'] = $this->get_stripe_amount( $amount, $request['currency'] );
126
$request['metadata'] = array(
127
- 'payment_type' => 'recurring'
128
);
129
$response = WC_Stripe_API::request( $request );
130
@@ -169,7 +172,7 @@ class WC_Gateway_Stripe_Addons extends WC_Gateway_Stripe {
169
// Return thank you page redirect
170
return array(
171
'result' => 'success',
172
- 'redirect' => $this->get_return_url( $order )
173
);
174
} catch ( Exception $e ) {
175
wc_add_notice( $e->getMessage(), 'error' );
@@ -210,7 +213,6 @@ class WC_Gateway_Stripe_Addons extends WC_Gateway_Stripe {
210
break;
211
}
212
}
213
-
214
} catch ( Exception $e ) {
215
$order_note = sprintf( __( 'Stripe Transaction Failed (%s)', 'woocommerce-gateway-stripe' ), $e->getMessage() );
216
@@ -264,7 +266,8 @@ class WC_Gateway_Stripe_Addons extends WC_Gateway_Stripe {
264
* @param object $order
265
*/
266
public function remove_order_source_before_retry( $order ) {
267
- delete_post_meta( $order->id, '_stripe_card_id' );
268
}
269
270
/**
@@ -272,7 +275,8 @@ class WC_Gateway_Stripe_Addons extends WC_Gateway_Stripe {
272
* @param object $order
273
*/
274
public function remove_order_customer_before_retry( $order ) {
275
- delete_post_meta( $order->id, '_stripe_customer_id' );
276
}
277
278
/**
@@ -377,15 +381,31 @@ class WC_Gateway_Stripe_Addons extends WC_Gateway_Stripe {
377
foreach ( $cards as $card ) {
378
if ( $card->id === $stripe_card_id ) {
379
$found_card = true;
380
- $payment_method_to_display = sprintf( __( 'Via %s card ending in %s', 'woocommerce-gateway-stripe' ), ( isset( $card->type ) ? $card->type : $card->brand ), $card->last4 );
381
break;
382
}
383
}
384
if ( ! $found_card ) {
385
- $payment_method_to_display = sprintf( __( 'Via %s card ending in %s', 'woocommerce-gateway-stripe' ), ( isset( $cards[0]->type ) ? $cards[0]->type : $cards[0]->brand ), $cards[0]->last4 );
386
}
387
}
388
389
return $payment_method_to_display;
390
}
391
}
77
protected function save_source( $order, $source ) {
78
parent::save_source( $order, $source );
79
80
+ $order_id = version_compare( WC_VERSION, '3.0.0', '<' ) ? $order->id : $order->get_id();
81
+
82
// Also store it on the subscriptions being purchased or paid for in the order
83
+ if ( function_exists( 'wcs_order_contains_subscription' ) && wcs_order_contains_subscription( $order_id ) ) {
84
+ $subscriptions = wcs_get_subscriptions_for_order( $order_id );
85
+ } elseif ( function_exists( 'wcs_order_contains_renewal' ) && wcs_order_contains_renewal( $order_id ) ) {
86
+ $subscriptions = wcs_get_subscriptions_for_renewal_order( $order_id );
87
} else {
88
$subscriptions = array();
89
}
90
91
+ foreach ( $subscriptions as $subscription ) {
92
update_post_meta( $subscription->id, '_stripe_customer_id', $source->customer );
93
update_post_meta( $subscription->id, '_stripe_card_id', $source->source );
94
}
101
* @param string $stripe_token (default: '')
102
* @param bool initial_payment
103
*/
104
+ public function process_subscription_payment( $order = '', $amount = 0 ) {
105
if ( $amount * 100 < WC_Stripe::get_minimum_amount() ) {
106
return new WP_Error( 'stripe_error', sprintf( __( 'Sorry, the minimum allowed order total is %1$s to use this payment method.', 'woocommerce-gateway-stripe' ), wc_price( WC_Stripe::get_minimum_amount() / 100 ) ) );
107
}
119
return new WP_Error( 'stripe_error', __( 'Customer not found', 'woocommerce-gateway-stripe' ) );
120
}
121
122
+ $order_id = version_compare( WC_VERSION, '3.0.0', '<' ) ? $order->id : $order->get_id();
123
+ $this->log( "Info: Begin processing subscription payment for order {$order_id} for the amount of {$amount}" );
124
125
// Make the request
126
$request = $this->generate_payment_request( $order, $source );
127
$request['capture'] = 'true';
128
$request['amount'] = $this->get_stripe_amount( $amount, $request['currency'] );
129
$request['metadata'] = array(
130
+ 'payment_type' => 'recurring',
131
);
132
$response = WC_Stripe_API::request( $request );
133
172
// Return thank you page redirect
173
return array(
174
'result' => 'success',
175
+ 'redirect' => $this->get_return_url( $order ),
176
);
177
} catch ( Exception $e ) {
178
wc_add_notice( $e->getMessage(), 'error' );
213
break;
214
}
215
}
216
} catch ( Exception $e ) {
217
$order_note = sprintf( __( 'Stripe Transaction Failed (%s)', 'woocommerce-gateway-stripe' ), $e->getMessage() );
218
266
* @param object $order
267
*/
268
public function remove_order_source_before_retry( $order ) {
269
+ $order_id = version_compare( WC_VERSION, '3.0.0', '<' ) ? $order->id : $order->get_id();
270
+ delete_post_meta( $order_id, '_stripe_card_id' );
271
}
272
273
/**
275
* @param object $order
276
*/
277
public function remove_order_customer_before_retry( $order ) {
278
+ $order_id = version_compare( WC_VERSION, '3.0.0', '<' ) ? $order->id : $order->get_id();
279
+ delete_post_meta( $order_id, '_stripe_customer_id' );
280
}
281
282
/**
381
foreach ( $cards as $card ) {
382
if ( $card->id === $stripe_card_id ) {
383
$found_card = true;
384
+ $payment_method_to_display = sprintf( __( 'Via %1$s card ending in %2$s', 'woocommerce-gateway-stripe' ), ( isset( $card->type ) ? $card->type : $card->brand ), $card->last4 );
385
break;
386
}
387
}
388
if ( ! $found_card ) {
389
+ $payment_method_to_display = sprintf( __( 'Via %1$s card ending in %2$s', 'woocommerce-gateway-stripe' ), ( isset( $cards[0]->type ) ? $cards[0]->type : $cards[0]->brand ), $cards[0]->last4 );
390
}
391
}
392
393
return $payment_method_to_display;
394
}
395
+
396
+ /**
397
+ * Logs
398
+ *
399
+ * @since 3.1.0
400
+ * @version 3.1.0
401
+ *
402
+ * @param string $message
403
+ */
404
+ public function log( $message ) {
405
+ $options = get_option( 'woocommerce_stripe_settings' );
406
+
407
+ if ( 'yes' === $options['logging'] ) {
408
+ WC_Stripe::log( $message );
409
+ }
410
+ }
411
}
includes/class-wc-gateway-stripe.php CHANGED
@@ -17,6 +17,13 @@ class WC_Gateway_Stripe extends WC_Payment_Gateway_CC {
17
*/
18
public $capture;
19
20
/**
21
* Checkout enabled
22
*
@@ -73,6 +80,27 @@ class WC_Gateway_Stripe extends WC_Payment_Gateway_CC {
73
*/
74
public $allow_remember_me;
75
76
/**
77
* Is test mode active?
78
*
@@ -111,7 +139,7 @@ class WC_Gateway_Stripe extends WC_Payment_Gateway_CC {
111
'multiple_subscriptions',
112
'pre-orders',
113
'tokenization',
114
- 'add_payment_method'
115
);
116
117
// Load the form fields.
@@ -126,6 +154,7 @@ class WC_Gateway_Stripe extends WC_Payment_Gateway_CC {
126
$this->enabled = $this->get_option( 'enabled' );
127
$this->testmode = 'yes' === $this->get_option( 'testmode' );
128
$this->capture = 'yes' === $this->get_option( 'capture', 'yes' );
129
$this->stripe_checkout = 'yes' === $this->get_option( 'stripe_checkout' );
130
$this->stripe_checkout_locale = $this->get_option( 'stripe_checkout_locale' );
131
$this->stripe_checkout_image = $this->get_option( 'stripe_checkout_image', '' );
@@ -133,6 +162,9 @@ class WC_Gateway_Stripe extends WC_Payment_Gateway_CC {
133
$this->secret_key = $this->testmode ? $this->get_option( 'test_secret_key' ) : $this->get_option( 'secret_key' );
134
$this->publishable_key = $this->testmode ? $this->get_option( 'test_publishable_key' ) : $this->get_option( 'publishable_key' );
135
$this->bitcoin = 'USD' === strtoupper( get_woocommerce_currency() ) && 'yes' === $this->get_option( 'stripe_bitcoin' );
136
$this->logging = 'yes' === $this->get_option( 'logging' );
137
$this->allow_remember_me = 'yes' === $this->get_option( 'allow_remember_me', 'no' );
138
@@ -147,8 +179,11 @@ class WC_Gateway_Stripe extends WC_Payment_Gateway_CC {
147
148
WC_Stripe_API::set_secret_key( $this->secret_key );
149
150
// Hooks.
151
add_action( 'wp_enqueue_scripts', array( $this, 'payment_scripts' ) );
152
add_action( 'admin_notices', array( $this, 'admin_notices' ) );
153
add_action( 'woocommerce_update_options_payment_gateways_' . $this->id, array( $this, 'process_admin_options' ) );
154
}
@@ -218,6 +253,108 @@ class WC_Gateway_Stripe extends WC_Payment_Gateway_CC {
218
return $total;
219
}
220
221
/**
222
* Check if SSL is enabled and notify the user
223
*/
@@ -226,6 +363,15 @@ class WC_Gateway_Stripe extends WC_Payment_Gateway_CC {
226
return;
227
}
228
229
// Show message if enabled and FORCE SSL is disabled and WordpressHTTPS plugin is not detected.
230
if ( ( function_exists( 'wc_site_is_https' ) && ! wc_site_is_https() ) && ( 'no' === get_option( 'woocommerce_force_ssl_checkout' ) && ! class_exists( 'WordPressHTTPS' ) ) ) {
231
echo '<div class="error stripe-ssl-message"><p>' . sprintf( __( 'Stripe is enabled, but the <a href="%s">force SSL option</a> is disabled; your checkout may not be secure! Please enable SSL and ensure your server has a valid SSL certificate - Stripe will only work in test mode.', 'woocommerce-gateway-stripe' ), admin_url( 'admin.php?page=wc-settings&tab=checkout' ) ) . '</p></div>';
@@ -253,61 +399,6 @@ class WC_Gateway_Stripe extends WC_Payment_Gateway_CC {
253
*/
254
public function init_form_fields() {
255
$this->form_fields = include( 'settings-stripe.php' );
256
-
257
- wc_enqueue_js( "
258
- jQuery( function( $ ) {
259
- $( document.body ).on( 'change', '#woocommerce_stripe_testmode', function() {
260
- var test_secret_key = $( '#woocommerce_stripe_test_secret_key' ).parents( 'tr' ).eq( 0 ),
261
- test_publishable_key = $( '#woocommerce_stripe_test_publishable_key' ).parents( 'tr' ).eq( 0 ),
262
- live_secret_key = $( '#woocommerce_stripe_secret_key' ).parents( 'tr' ).eq( 0 ),
263
- live_publishable_key = $( '#woocommerce_stripe_publishable_key' ).parents( 'tr' ).eq( 0 );
264
-
265
- if ( $( this ).is( ':checked' ) ) {
266
- test_secret_key.show();
267
- test_publishable_key.show();
268
- live_secret_key.hide();
269
- live_publishable_key.hide();
270
- } else {
271
- test_secret_key.hide();
272
- test_publishable_key.hide();
273
- live_secret_key.show();
274
- live_publishable_key.show();
275
- }
276
- } );
277
-
278
- $( '#woocommerce_stripe_testmode' ).change();
279
-
280
- $( '#woocommerce_stripe_stripe_checkout' ).change( function() {
281
- if ( $( this ).is( ':checked' ) ) {
282
- $( '#woocommerce_stripe_stripe_checkout_locale, #woocommerce_stripe_stripe_bitcoin, #woocommerce_stripe_stripe_checkout_image, #woocommerce_stripe_allow_remember_me' ).closest( 'tr' ).show();
283
- } else {
284
- $( '#woocommerce_stripe_stripe_checkout_locale, #woocommerce_stripe_stripe_bitcoin, #woocommerce_stripe_stripe_checkout_image, #woocommerce_stripe_allow_remember_me' ).closest( 'tr' ).hide();
285
- }
286
- }).change();
287
-
288
- $( '#woocommerce_stripe_secret_key, #woocommerce_stripe_publishable_key' ).change(function(){
289
- var value = $( this ).val();
290
-
291
- if ( value.indexOf( '_test_' ) >= 0 ) {
292
- $( this ).css( 'border-color', 'red' ).after( '<span class=\"description stripe-error-description\" style=\"color:red; display:block;\">" . __( 'This is not a valid live key. Live keys start with "sk_live_" and "pk_live_".', 'woocommerce-gateway-stripe' ) . "</span>' );
293
- } else {
294
- $( this ).css( 'border-color', '' );
295
- $( '.stripe-error-description', $( this ).parent() ).remove();
296
- }
297
- }).change();
298
-
299
- $( '#woocommerce_stripe_test_secret_key, #woocommerce_stripe_test_publishable_key' ).change(function(){
300
- var value = $( this ).val();
301
-
302
- if ( value.indexOf( '_live_' ) >= 0 ) {
303
- $( this ).css( 'border-color', 'red' ).after( '<span class=\"description stripe-error-description\" style=\"color:red; display:block;\">" . __( 'This is not a valid test key. Test keys start with "sk_test_" and "pk_test_".', 'woocommerce-gateway-stripe' ) . "</span>' );
304
- } else {
305
- $( this ).css( 'border-color', '' );
306
- $( '.stripe-error-description', $( this ).parent() ).remove();
307
- }
308
- }).change();
309
- });
310
- " );
311
}
312
313
/**
@@ -343,7 +434,7 @@ class WC_Gateway_Stripe extends WC_Payment_Gateway_CC {
343
data-description=""
344
data-email="' . esc_attr( $user_email ) . '"
345
data-amount="' . esc_attr( $this->get_stripe_amount( $total ) ) . '"
346
- data-name="' . esc_attr( get_bloginfo( 'name', 'display' ) ) . '"
347
data-currency="' . esc_attr( strtolower( get_woocommerce_currency() ) ) . '"
348
data-image="' . esc_attr( $this->stripe_checkout_image ) . '"
349
data-bitcoin="' . esc_attr( $this->bitcoin ? 'true' : 'false' ) . '"
@@ -361,7 +452,7 @@ class WC_Gateway_Stripe extends WC_Payment_Gateway_CC {
361
362
if ( ! $this->stripe_checkout ) {
363
$this->form();
364
-
365
if ( $display_tokenization ) {
366
$this->save_payment_method_checkbox();
367
}
@@ -391,7 +482,38 @@ class WC_Gateway_Stripe extends WC_Payment_Gateway_CC {
391
'missing' => __( 'There is no card on a customer that is being charged.', 'woocommerce-gateway-stripe' ),
392
'processing_error' => __( 'An error occurred while processing the card.', 'woocommerce-gateway-stripe' ),
393
'invalid_request_error' => __( 'Could not find payment information.', 'woocommerce-gateway-stripe' ),
394
- ) );
395
}
396
397
/**
@@ -402,11 +524,15 @@ class WC_Gateway_Stripe extends WC_Payment_Gateway_CC {
402
* @access public
403
*/
404
public function payment_scripts() {
405
$suffix = defined( 'SCRIPT_DEBUG' ) && SCRIPT_DEBUG ? '' : '.min';
406
-
407
if ( $this->stripe_checkout ) {
408
- wp_enqueue_script( 'stripe', 'https://checkout.stripe.com/v2/checkout.js', '', '2.0', true );
409
- wp_enqueue_script( 'woocommerce_stripe', plugins_url( 'assets/js/stripe_checkout' . $suffix . '.js', WC_STRIPE_MAIN_FILE ), array( 'stripe' ), WC_STRIPE_VERSION, true );
410
} else {
411
wp_enqueue_script( 'stripe', 'https://js.stripe.com/v2/', '', '1.0', true );
412
wp_enqueue_script( 'woocommerce_stripe', plugins_url( 'assets/js/stripe' . $suffix . '.js', WC_STRIPE_MAIN_FILE ), array( 'jquery-payment', 'stripe' ), WC_STRIPE_VERSION, true );
@@ -423,14 +549,14 @@ class WC_Gateway_Stripe extends WC_Payment_Gateway_CC {
423
$order_id = wc_get_order_id_by_order_key( urldecode( $_GET['key'] ) );
424
$order = wc_get_order( $order_id );
425
426
- $stripe_params['billing_first_name'] = $order->billing_first_name;
427
- $stripe_params['billing_last_name'] = $order->billing_last_name;
428
- $stripe_params['billing_address_1'] = $order->billing_address_1;
429
- $stripe_params['billing_address_2'] = $order->billing_address_2;
430
- $stripe_params['billing_state'] = $order->billing_state;
431
- $stripe_params['billing_city'] = $order->billing_city;
432
- $stripe_params['billing_postcode'] = $order->billing_postcode;
433
- $stripe_params['billing_country'] = $order->billing_country;
434
}
435
436
$stripe_params['no_prepaid_card_msg'] = __( 'Sorry, we\'re not accepting prepaid cards at this time.', 'woocommerce-gateway-stripe' );
@@ -451,17 +577,28 @@ class WC_Gateway_Stripe extends WC_Payment_Gateway_CC {
451
*/
452
protected function generate_payment_request( $order, $source ) {
453
$post_data = array();
454
- $post_data['currency'] = strtolower( $order->get_order_currency() ? $order->get_order_currency() : get_woocommerce_currency() );
455
$post_data['amount'] = $this->get_stripe_amount( $order->get_total(), $post_data['currency'] );
456
- $post_data['description'] = sprintf( __( '%s - Order %s', 'woocommerce-gateway-stripe' ), wp_specialchars_decode( get_bloginfo( 'name' ), ENT_QUOTES ), $order->get_order_number() );
457
$post_data['capture'] = $this->capture ? 'true' : 'false';
458
459
- if ( ! empty( $order->billing_email ) && apply_filters( 'wc_stripe_send_stripe_receipt', false ) ) {
460
- $post_data['receipt_email'] = $order->billing_email;
461
}
462
463
$post_data['expand[]'] = 'balance_transaction';
464
465
if ( $source->customer ) {
466
$post_data['customer'] = $source->customer;
467
}
@@ -469,7 +606,7 @@ class WC_Gateway_Stripe extends WC_Payment_Gateway_CC {
469
if ( $source->source ) {
470
$post_data['source'] = $source->source;
471
}
472
-
473
/**
474
* Filter the return value of the WC_Payment_Gateway_CC::generate_payment_request.
475
*
@@ -507,16 +644,14 @@ class WC_Gateway_Stripe extends WC_Payment_Gateway_CC {
507
if ( is_wp_error( $stripe_source ) ) {
508
throw new Exception( $stripe_source->get_error_message() );
509
}
510
-
511
} else {
512
// Not saving token, so don't define customer either.
513
$stripe_source = $stripe_token;
514
$stripe_customer = false;
515
}
516
- }
517
518
- // Use an existing token, and then process the payment
519
- elseif ( isset( $_POST['wc-stripe-payment-token'] ) && 'new' !== $_POST['wc-stripe-payment-token'] ) {
520
$token_id = wc_clean( $_POST['wc-stripe-payment-token'] );
521
$token = WC_Payment_Tokens::get( $token_id );
522
@@ -552,10 +687,13 @@ class WC_Gateway_Stripe extends WC_Payment_Gateway_CC {
552
$token_id = false;
553
554
if ( $order ) {
555
- if ( $meta_value = get_post_meta( $order->id, '_stripe_customer_id', true ) ) {
556
$stripe_customer->set_id( $meta_value );
557
}
558
- if ( $meta_value = get_post_meta( $order->id, '_stripe_card_id', true ) ) {
559
$stripe_source = $meta_value;
560
}
561
}
@@ -594,11 +732,12 @@ class WC_Gateway_Stripe extends WC_Payment_Gateway_CC {
594
595
// Handle payment.
596
if ( $order->get_total() > 0 ) {
597
if ( $order->get_total() * 100 < WC_Stripe::get_minimum_amount() ) {
598
throw new Exception( sprintf( __( 'Sorry, the minimum allowed order total is %1$s to use this payment method.', 'woocommerce-gateway-stripe' ), wc_price( WC_Stripe::get_minimum_amount() / 100 ) ) );
599
}
600
601
- WC_Stripe::log( "Info: Begin processing payment for order $order_id for the amount of {$order->get_total()}" );
602
603
// Make the request.
604
$response = WC_Stripe_API::request( $this->generate_payment_request( $order, $source ) );
@@ -612,11 +751,18 @@ class WC_Gateway_Stripe extends WC_Payment_Gateway_CC {
612
} elseif ( 'source' === $response->get_error_code() && $source->token_id ) {
613
$token = WC_Payment_Tokens::get( $source->token_id );
614
$token->delete();
615
- throw new Exception( __( 'This card is no longer available and has been removed.', 'woocommerce-gateway-stripe' ) );
616
}
617
$localized_messages = $this->get_localized_messages();
618
619
- throw new Exception( ( isset( $localized_messages[ $response->get_error_code() ] ) ? $localized_messages[ $response->get_error_code() ] : $response->get_error_message() ) );
620
}
621
622
// Process valid response.
@@ -633,12 +779,12 @@ class WC_Gateway_Stripe extends WC_Payment_Gateway_CC {
633
// Return thank you page redirect.
634
return array(
635
'result' => 'success',
636
- 'redirect' => $this->get_return_url( $order )
637
);
638
639
} catch ( Exception $e ) {
640
wc_add_notice( $e->getMessage(), 'error' );
641
- WC_Stripe::log( sprintf( __( 'Error: %s', 'woocommerce-gateway-stripe' ), $e->getMessage() ) );
642
643
if ( $order->has_status( array( 'pending', 'failed' ) ) ) {
644
$this->send_failed_order_email( $order_id );
@@ -648,7 +794,7 @@ class WC_Gateway_Stripe extends WC_Payment_Gateway_CC {
648
649
return array(
650
'result' => 'fail',
651
- 'redirect' => ''
652
);
653
}
654
}
@@ -660,12 +806,14 @@ class WC_Gateway_Stripe extends WC_Payment_Gateway_CC {
660
* @param stdClass $source Source information.
661
*/
662
protected function save_source( $order, $source ) {
663
// Store source in the order.
664
if ( $source->customer ) {
665
- update_post_meta( $order->id, '_stripe_customer_id', $source->customer );
666
}
667
if ( $source->source ) {
668
- update_post_meta( $order->id, '_stripe_card_id', $source->source );
669
}
670
}
671
@@ -673,20 +821,22 @@ class WC_Gateway_Stripe extends WC_Payment_Gateway_CC {
673
* Store extra meta data for an order from a Stripe Response.
674
*/
675
public function process_response( $response, $order ) {
676
- WC_Stripe::log( "Processing response: " . print_r( $response, true ) );
677
678
// Store charge data
679
- update_post_meta( $order->id, '_stripe_charge_id', $response->id );
680
- update_post_meta( $order->id, '_stripe_charge_captured', $response->captured ? 'yes' : 'no' );
681
682
// Store other data such as fees
683
if ( isset( $response->balance_transaction ) && isset( $response->balance_transaction->fee ) ) {
684
// Fees and Net needs to both come from Stripe to be accurate as the returned
685
// values are in the local currency of the Stripe account, not from WC.
686
- $fee = ! empty( $response->balance_transaction->fee ) ? number_format( $response->balance_transaction->fee / 100, 2, '.', '' ) : 0;
687
- $net = ! empty( $response->balance_transaction->net ) ? number_format( $response->balance_transaction->net / 100, 2, '.', '' ) : 0;
688
- update_post_meta( $order->id, 'Stripe Fee', $fee );
689
- update_post_meta( $order->id, 'Net Revenue From Stripe', $net );
690
}
691
692
if ( $response->captured ) {
@@ -694,17 +844,17 @@ class WC_Gateway_Stripe extends WC_Payment_Gateway_CC {
694
695
$message = sprintf( __( 'Stripe charge complete (Charge ID: %s)', 'woocommerce-gateway-stripe' ), $response->id );
696
$order->add_order_note( $message );
697
- WC_Stripe::log( 'Success: ' . $message );
698
699
} else {
700
- add_post_meta( $order->id, '_transaction_id', $response->id, true );
701
702
if ( $order->has_status( array( 'pending', 'failed' ) ) ) {
703
- $order->reduce_order_stock();
704
}
705
706
$order->update_status( 'on-hold', sprintf( __( 'Stripe charge authorized (Charge ID: %s). Process order to take payment, or cancel to remove the pre-authorization.', 'woocommerce-gateway-stripe' ), $response->id ) );
707
- WC_Stripe::log( "Successful auth: $response->id" );
708
}
709
710
return $response;
@@ -770,17 +920,17 @@ class WC_Gateway_Stripe extends WC_Payment_Gateway_CC {
770
);
771
}
772
773
- WC_Stripe::log( "Info: Beginning refund for order $order_id for the amount of {$amount}" );
774
775
$response = WC_Stripe_API::request( $body, 'charges/' . $order->get_transaction_id() . '/refunds' );
776
777
if ( is_wp_error( $response ) ) {
778
- WC_Stripe::log( "Error: " . $response->get_error_message() );
779
return $response;
780
} elseif ( ! empty( $response->id ) ) {
781
- $refund_message = sprintf( __( 'Refunded %s - Refund ID: %s - Reason: %s', 'woocommerce-gateway-stripe' ), wc_price( $response->amount / 100 ), $response->id, $reason );
782
$order->add_order_note( $refund_message );
783
- WC_Stripe::log( "Success: " . html_entity_decode( strip_tags( $refund_message ) ) );
784
return true;
785
}
786
}
@@ -799,4 +949,18 @@ class WC_Gateway_Stripe extends WC_Payment_Gateway_CC {
799
$emails['WC_Email_Failed_Order']->trigger( $order_id );
800
}
801
}
802
}
17
*/
18
public $capture;
19
20
+ /**
21
+ * Alternate credit card statement name
22
+ *
23
+ * @var bool
24
+ */
25
+ public $statement_descriptor;
26
+
27
/**
28
* Checkout enabled
29
*
80
*/
81
public $allow_remember_me;
82
83
+ /**
84
+ * Do we accept Apple Pay?
85
+ *
86
+ * @var bool
87
+ */
88
+ public $apple_pay;
89
+
90
+ /**
91
+ * Apple Pay Domain Set.
92
+ *
93
+ * @var bool
94
+ */
95
+ public $apple_pay_domain_set;
96
+
97
+ /**
98
+ * Apple Pay button style.
99
+ *
100
+ * @var bool
101
+ */
102
+ public $apple_pay_button;
103
+
104
/**
105
* Is test mode active?
106
*
139
'multiple_subscriptions',
140
'pre-orders',
141
'tokenization',
142
+ 'add_payment_method',
143
);
144
145
// Load the form fields.
154
$this->enabled = $this->get_option( 'enabled' );
155
$this->testmode = 'yes' === $this->get_option( 'testmode' );
156
$this->capture = 'yes' === $this->get_option( 'capture', 'yes' );
157
+ $this->statement_descriptor = $this->get_option( 'statement_descriptor', wp_specialchars_decode( get_bloginfo( 'name' ), ENT_QUOTES ) );
158
$this->stripe_checkout = 'yes' === $this->get_option( 'stripe_checkout' );
159
$this->stripe_checkout_locale = $this->get_option( 'stripe_checkout_locale' );
160
$this->stripe_checkout_image = $this->get_option( 'stripe_checkout_image', '' );
162
$this->secret_key = $this->testmode ? $this->get_option( 'test_secret_key' ) : $this->get_option( 'secret_key' );
163
$this->publishable_key = $this->testmode ? $this->get_option( 'test_publishable_key' ) : $this->get_option( 'publishable_key' );
164
$this->bitcoin = 'USD' === strtoupper( get_woocommerce_currency() ) && 'yes' === $this->get_option( 'stripe_bitcoin' );
165
+ $this->apple_pay = 'yes' === $this->get_option( 'apple_pay', 'yes' );
166
+ $this->apple_pay_domain_set = 'yes' === $this->get_option( 'apple_pay_domain_set', 'no' );
167
+ $this->apple_pay_button = $this->get_option( 'apple_pay_button', 'black' );
168
$this->logging = 'yes' === $this->get_option( 'logging' );
169
$this->allow_remember_me = 'yes' === $this->get_option( 'allow_remember_me', 'no' );
170
179
180
WC_Stripe_API::set_secret_key( $this->secret_key );
181
182
+ $this->init_apple_pay();
183
+
184
// Hooks.
185
add_action( 'wp_enqueue_scripts', array( $this, 'payment_scripts' ) );
186
+ add_action( 'admin_enqueue_scripts', array( $this, 'admin_scripts' ) );
187
add_action( 'admin_notices', array( $this, 'admin_notices' ) );
188
add_action( 'woocommerce_update_options_payment_gateways_' . $this->id, array( $this, 'process_admin_options' ) );
189
}
253
return $total;
254
}
255
256
+ /**
257
+ * Initializes Apple Pay process on settings page.
258
+ *
259
+ * @since 3.1.0
260
+ * @version 3.1.0
261
+ */
262
+ public function init_apple_pay() {
263
+ if (
264
+ is_admin() &&
265
+ isset( $_GET['page'] ) && 'wc-settings' === $_GET['page'] &&
266
+ isset( $_GET['tab'] ) && 'checkout' === $_GET['tab'] &&
267
+ isset( $_GET['section'] ) && 'stripe' === $_GET['section']
268
+ ) {
269
+ $this->process_apple_pay_verification();
270
+ }
271
+ }
272
+
273
+ /**
274
+ * Registers the domain with Stripe/Apple Pay
275
+ *
276
+ * @since 3.1.0
277
+ * @version 3.1.0
278
+ * @param string $secret_key
279
+ */
280
+ private function _register_apple_pay_domain( $secret_key = '' ) {
281
+ if ( empty( $secret_key ) ) {
282
+ throw new Exception( __( 'Unable to verify domain - missing secret key.', 'woocommerce-gateway-stripe' ) );
283
+ }
284
+
285
+ $endpoint = 'https://api.stripe.com/v1/apple_pay/domains';
286
+
287
+ $data = array(
288
+ 'domain_name' => $_SERVER['HTTP_HOST'],
289
+ );
290
+
291
+ $headers = array(
292
+ 'User-Agent' => 'WooCommerce Stripe Apple Pay',
293
+ 'Authorization' => 'Bearer ' . $secret_key,
294
+ );
295
+
296
+ $response = wp_remote_post( $endpoint, array(
297
+ 'headers' => $headers,
298
+ 'body' => http_build_query( $data ),
299
+ ) );
300
+
301
+ if ( 200 !== $response['response']['code'] ) {
302
+ throw new Exception( sprintf( __( 'Unable to verify domain - %s', 'woocommerce-gateway-stripe' ), $response['response']['message'] ) );
303
+ }
304
+ }
305
+
306
+ /**
307
+ * Processes the Apple Pay domain verification.
308
+ *
309
+ * @since 3.1.0
310
+ * @version 3.1.0
311
+ */
312
+ public function process_apple_pay_verification() {
313
+ $gateway_settings = get_option( 'woocommerce_stripe_settings', '' );
314
+
315
+ try {
316
+ $path = untrailingslashit( preg_replace( "!${_SERVER['SCRIPT_NAME']}$!", '', $_SERVER['SCRIPT_FILENAME'] ) );
317
+ $dir = '.well-known';
318
+ $file = 'apple-developer-merchantid-domain-association';
319
+ $fullpath = $path . '/' . $dir . '/' . $file;
320
+
321
+ if ( 'yes' === $gateway_settings['apple_pay_domain_set'] && file_exists( $fullpath ) ) {
322
+ return;
323
+ }
324
+
325
+ if ( ! file_exists( $path . '/' . $dir ) || ! file_exists( $fullpath ) ) {
326
+ if ( ! mkdir( $path . '/' . $dir, 0755 ) ) {
327
+ throw new Exception( __( 'Unable to create domain association folder to domain root.', 'woocommerce-gateway-stripe' ) );
328
+ }
329
+
330
+ if ( ! file_exists( $path . '/' . $dir . '/' . 'apple-developer-merchantid-domain-association' ) ) {
331
+ if ( ! copy( WC_STRIPE_PLUGIN_PATH . '/' . $file, $fullpath ) ) {
332
+ throw new Exception( __( 'Unable to copy domain association file to domain root.', 'woocommerce-gateway-stripe' ) );
333
+ }
334
+ }
335
+ }
336
+
337
+ // At this point then the domain association folder and file should be available.
338
+ // Proceed to verify/and or verify again.
339
+ $this->_register_apple_pay_domain( $this->secret_key );
340
+
341
+ // No errors to this point, verification success!
342
+ $gateway_settings['apple_pay_domain_set'] = 'yes';
343
+ $this->apple_pay_domain_set = true;
344
+
345
+ update_option( 'woocommerce_stripe_settings', $gateway_settings );
346
+
347
+ $this->log( __( 'Your domain has been verified with Apple Pay!', 'woocommerce-gateway-stripe' ) );
348
+
349
+ } catch ( Exception $e ) {
350
+ $gateway_settings['apple_pay_domain_set'] = 'no';
351
+
352
+ update_option( 'woocommerce_stripe_settings', $gateway_settings );
353
+
354
+ $this->log( sprintf( __( 'Error: %s', 'woocommerce-gateway-stripe' ), $e->getMessage() ) );
355
+ }
356
+ }
357
+
358
/**
359
* Check if SSL is enabled and notify the user
360
*/
363
return;
364
}
365
366
+ /**
367
+ * Apple pay is enabled by default and domain verification initializes
368
+ * when setting screen is displayed. So if domain verification is not set,
369
+ * something went wrong so lets notify user.
370
+ */
371
+ if ( ! empty( $this->secret_key ) && $this->apple_pay && ! $this->apple_pay_domain_set ) {
372
+ echo '<div class="error stripe-apple-pay-message"><p>' . sprintf( __( 'Apple Pay domain verification failed. Please check the %1$slog%2$s to see the issue.', 'woocommerce-gateway-stripe' ), '<a href="' . admin_url( 'page=wc-status&tab=logs' ) . '">', '</a>' ) . '</p></div>';
373
+ }
374
+
375
// Show message if enabled and FORCE SSL is disabled and WordpressHTTPS plugin is not detected.
376
if ( ( function_exists( 'wc_site_is_https' ) && ! wc_site_is_https() ) && ( 'no' === get_option( 'woocommerce_force_ssl_checkout' ) && ! class_exists( 'WordPressHTTPS' ) ) ) {
377
echo '<div class="error stripe-ssl-message"><p>' . sprintf( __( 'Stripe is enabled, but the <a href="%s">force SSL option</a> is disabled; your checkout may not be secure! Please enable SSL and ensure your server has a valid SSL certificate - Stripe will only work in test mode.', 'woocommerce-gateway-stripe' ), admin_url( 'admin.php?page=wc-settings&tab=checkout' ) ) . '</p></div>';
399
*/
400
public function init_form_fields() {
401
$this->form_fields = include( 'settings-stripe.php' );
402
}
403
404
/**
434
data-description=""
435
data-email="' . esc_attr( $user_email ) . '"
436
data-amount="' . esc_attr( $this->get_stripe_amount( $total ) ) . '"
437
+ data-name="' . esc_attr( $this->statement_descriptor ) . '"
438
data-currency="' . esc_attr( strtolower( get_woocommerce_currency() ) ) . '"
439
data-image="' . esc_attr( $this->stripe_checkout_image ) . '"
440
data-bitcoin="' . esc_attr( $this->bitcoin ? 'true' : 'false' ) . '"
452
453
if ( ! $this->stripe_checkout ) {
454
$this->form();
455
+
456
if ( $display_tokenization ) {
457
$this->save_payment_method_checkbox();
458
}
482
'missing' => __( 'There is no card on a customer that is being charged.', 'woocommerce-gateway-stripe' ),
483
'processing_error' => __( 'An error occurred while processing the card.', 'woocommerce-gateway-stripe' ),
484
'invalid_request_error' => __( 'Could not find payment information.', 'woocommerce-gateway-stripe' ),
485
+ ) );
486
+ }
487
+
488
+ /**
489
+ * Load admin scripts.
490
+ *
491
+ * @since 3.1.0
492
+ * @version 3.1.0
493
+ */
494
+ public function admin_scripts() {
495
+ if ( 'woocommerce_page_wc-settings' !== get_current_screen()->id ) {
496
+ return;
497
+ }
498
+
499
+ $suffix = defined( 'SCRIPT_DEBUG' ) && SCRIPT_DEBUG ? '' : '.min';
500
+
501
+ wp_enqueue_script( 'woocommerce_stripe_admin', plugins_url( 'assets/js/stripe-admin' . $suffix . '.js', WC_STRIPE_MAIN_FILE ), array(), WC_STRIPE_VERSION, true );
502
+
503
+ $stripe_admin_params = array(
504
+ 'localized_messages' => array(
505
+ 'not_valid_live_key_msg' => __( 'This is not a valid live key. Live keys start with "sk_live_" and "pk_live_".', 'woocommerce-gateway-stripe' ),
506
+ 'not_valid_test_key_msg' => __( 'This is not a valid test key. Test keys start with "sk_test_" and "pk_test_".', 'woocommerce-gateway-stripe' ),
507
+ 're_verify_button_text' => __( 'Re-verify Domain', 'woocommerce-gateway-stripe' ),
508
+ 'missing_secret_key' => __( 'Missing Secret Key. Please set the secret key field above and re-try.', 'woocommerce-gateway-stripe' ),
509
+ ),
510
+ 'ajaxurl' => admin_url( 'admin-ajax.php' ),
511
+ 'nonce' => array(
512
+ 'apple_pay_domain_nonce' => wp_create_nonce( '_wc_stripe_apple_pay_domain_nonce' ),
513
+ ),
514
+ );
515
+
516
+ wp_localize_script( 'woocommerce_stripe_admin', 'wc_stripe_admin_params', apply_filters( 'wc_stripe_admin_params', $stripe_admin_params ) );
517
}
518
519
/**
524
* @access public
525
*/
526
public function payment_scripts() {
527
+ if ( ! is_cart() && ! is_checkout() && ! isset( $_GET['pay_for_order'] ) ) {
528
+ return;
529
+ }
530
+
531
$suffix = defined( 'SCRIPT_DEBUG' ) && SCRIPT_DEBUG ? '' : '.min';
532
+
533
if ( $this->stripe_checkout ) {
534
+ wp_enqueue_script( 'stripe_checkout', 'https://checkout.stripe.com/v2/checkout.js', '', '2.0', true );
535
+ wp_enqueue_script( 'woocommerce_stripe', plugins_url( 'assets/js/stripe-checkout' . $suffix . '.js', WC_STRIPE_MAIN_FILE ), array( 'stripe' ), WC_STRIPE_VERSION, true );
536
} else {
537
wp_enqueue_script( 'stripe', 'https://js.stripe.com/v2/', '', '1.0', true );
538
wp_enqueue_script( 'woocommerce_stripe', plugins_url( 'assets/js/stripe' . $suffix . '.js', WC_STRIPE_MAIN_FILE ), array( 'jquery-payment', 'stripe' ), WC_STRIPE_VERSION, true );
549
$order_id = wc_get_order_id_by_order_key( urldecode( $_GET['key'] ) );
550
$order = wc_get_order( $order_id );
551
552
+ $stripe_params['billing_first_name'] = version_compare( WC_VERSION, '3.0.0', '<' ) ? $order->billing_first_name : $order->get_billing_first_name();
553
+ $stripe_params['billing_last_name'] = version_compare( WC_VERSION, '3.0.0', '<' ) ? $order->billing_last_name : $order->get_billing_last_name();
554
+ $stripe_params['billing_address_1'] = version_compare( WC_VERSION, '3.0.0', '<' ) ? $order->billing_address_1 : $order->get_billing_address_1();
555
+ $stripe_params['billing_address_2'] = version_compare( WC_VERSION, '3.0.0', '<' ) ? $order->billing_address_2 : $order->get_billing_address_2();
556
+ $stripe_params['billing_state'] = version_compare( WC_VERSION, '3.0.0', '<' ) ? $order->billing_state : $order->get_billing_state();
557
+ $stripe_params['billing_city'] = version_compare( WC_VERSION, '3.0.0', '<' ) ? $order->billing_city : $order->get_billing_city();
558
+ $stripe_params['billing_postcode'] = version_compare( WC_VERSION, '3.0.0', '<' ) ? $order->billing_postcode : $order->get_billing_postcode();
559
+ $stripe_params['billing_country'] = version_compare( WC_VERSION, '3.0.0', '<' ) ? $order->billing_country : $order->get_billing_country();
560
}
561
562
$stripe_params['no_prepaid_card_msg'] = __( 'Sorry, we\'re not accepting prepaid cards at this time.', 'woocommerce-gateway-stripe' );
577
*/
578
protected function generate_payment_request( $order, $source ) {
579
$post_data = array();
580
+ $post_data['currency'] = strtolower( version_compare( WC_VERSION, '3.0.0', '<' ) ? $order->get_order_currency() : $order->get_currency() );
581
$post_data['amount'] = $this->get_stripe_amount( $order->get_total(), $post_data['currency'] );
582
+ $post_data['description'] = sprintf( __( '%1$s - Order %2$s', 'woocommerce-gateway-stripe' ), $this->statement_descriptor, $order->get_order_number() );
583
$post_data['capture'] = $this->capture ? 'true' : 'false';
584
585
+ $billing_email = version_compare( WC_VERSION, '3.0.0', '<' ) ? $order->billing_email : $order->get_billing_email();
586
+ $billing_first_name = version_compare( WC_VERSION, '3.0.0', '<' ) ? $order->billing_first_name : $order->get_billing_first_name();
587
+ $billing_last_name = version_compare( WC_VERSION, '3.0.0', '<' ) ? $order->billing_last_name : $order->get_billing_last_name();
588
+
589
+ if ( ! empty( $billing_email ) && apply_filters( 'wc_stripe_send_stripe_receipt', false ) ) {
590
+ $post_data['receipt_email'] = $billing_email;
591
}
592
593
$post_data['expand[]'] = 'balance_transaction';
594
595
+ $metadata = array(
596
+ __( 'Customer Name', 'woocommerce-gateway-stripe' ) => sanitize_text_field( $billing_first_name ) . ' ' . sanitize_text_field( $billing_last_name ),
597
+ __( 'Customer Email', 'woocommerce-gateway-stripe' ) => sanitize_email( $billing_email ),
598
+ );
599
+
600
+ $post_data['metadata'] = apply_filters( 'wc_stripe_payment_metadata', $metadata, $order, $source );
601
+
602
if ( $source->customer ) {
603
$post_data['customer'] = $source->customer;
604
}
606
if ( $source->source ) {
607
$post_data['source'] = $source->source;
608
}
609
+
610
/**
611
* Filter the return value of the WC_Payment_Gateway_CC::generate_payment_request.
612
*
644
if ( is_wp_error( $stripe_source ) ) {
645
throw new Exception( $stripe_source->get_error_message() );
646
}
647
} else {
648
// Not saving token, so don't define customer either.
649
$stripe_source = $stripe_token;
650
$stripe_customer = false;
651
}
652
+ } elseif ( isset( $_POST['wc-stripe-payment-token'] ) && 'new' !== $_POST['wc-stripe-payment-token'] ) {
653
+ // Use an existing token, and then process the payment
654
655
$token_id = wc_clean( $_POST['wc-stripe-payment-token'] );
656
$token = WC_Payment_Tokens::get( $token_id );
657
687
$token_id = false;
688
689
if ( $order ) {
690
+ $order_id = version_compare( WC_VERSION, '3.0.0', '<' ) ? $order->id : $order->get_id();
691
+
692
+ if ( $meta_value = get_post_meta( $order_id, '_stripe_customer_id', true ) ) {
693
$stripe_customer->set_id( $meta_value );
694
}
695
+
696
+ if ( $meta_value = get_post_meta( $order_id, '_stripe_card_id', true ) ) {
697
$stripe_source = $meta_value;
698
}
699
}
732
733
// Handle payment.
734
if ( $order->get_total() > 0 ) {
735
+
736
if ( $order->get_total() * 100 < WC_Stripe::get_minimum_amount() ) {
737
throw new Exception( sprintf( __( 'Sorry, the minimum allowed order total is %1$s to use this payment method.', 'woocommerce-gateway-stripe' ), wc_price( WC_Stripe::get_minimum_amount() / 100 ) ) );
738
}
739
740
+ $this->log( "Info: Begin processing payment for order $order_id for the amount of {$order->get_total()}" );
741
742
// Make the request.
743
$response = WC_Stripe_API::request( $this->generate_payment_request( $order, $source ) );
751
} elseif ( 'source' === $response->get_error_code() && $source->token_id ) {
752
$token = WC_Payment_Tokens::get( $source->token_id );
753
$token->delete();
754
+ $message = __( 'This card is no longer available and has been removed.', 'woocommerce-gateway-stripe' );
755
+ $order->add_order_note( $message );
756
+ throw new Exception( $message );
757
}
758
+
759
$localized_messages = $this->get_localized_messages();
760
761
+ $message = isset( $localized_messages[ $response->get_error_code() ] ) ? $localized_messages[ $response->get_error_code() ] : $response->get_error_message();
762
+
763
+ $order->add_order_note( $message );
764
+
765
+ throw new Exception( $message );
766
}
767
768
// Process valid response.
779
// Return thank you page redirect.
780
return array(
781
'result' => 'success',
782
+ 'redirect' => $this->get_return_url( $order ),
783
);
784
785
} catch ( Exception $e ) {
786
wc_add_notice( $e->getMessage(), 'error' );
787
+ $this->log( sprintf( __( 'Error: %s', 'woocommerce-gateway-stripe' ), $e->getMessage() ) );
788
789
if ( $order->has_status( array( 'pending', 'failed' ) ) ) {
790
$this->send_failed_order_email( $order_id );
794
795
return array(
796
'result' => 'fail',
797
+ 'redirect' => '',
798
);
799
}
800
}
806
* @param stdClass $source Source information.
807
*/
808
protected function save_source( $order, $source ) {
809
+ $order_id = version_compare( WC_VERSION, '3.0.0', '<' ) ? $order->id : $order->get_id();
810
+
811
// Store source in the order.
812
if ( $source->customer ) {
813
+ update_post_meta( $order_id, '_stripe_customer_id', $source->customer );
814
}
815
if ( $source->source ) {
816
+ update_post_meta( $order_id, '_stripe_card_id', $source->source );
817
}
818
}
819
821
* Store extra meta data for an order from a Stripe Response.
822
*/
823
public function process_response( $response, $order ) {
824
+ $this->log( 'Processing response: ' . print_r( $response, true ) );
825
+
826
+ $order_id = version_compare( WC_VERSION, '3.0.0', '<' ) ? $order->id : $order->get_id();
827
828
// Store charge data
829
+ update_post_meta( $order_id, '_stripe_charge_id', $response->id );
830
+ update_post_meta( $order_id, '_stripe_charge_captured', $response->captured ? 'yes' : 'no' );
831
832
// Store other data such as fees
833
if ( isset( $response->balance_transaction ) && isset( $response->balance_transaction->fee ) ) {
834
// Fees and Net needs to both come from Stripe to be accurate as the returned
835
// values are in the local currency of the Stripe account, not from WC.
836
+ $fee = ! empty( $response->balance_transaction->fee ) ? WC_Stripe::format_number( $response->balance_transaction, 'fee' ) : 0;
837
+ $net = ! empty( $response->balance_transaction->net ) ? WC_Stripe::format_number( $response->balance_transaction, 'net' ) : 0;
838
+ update_post_meta( $order_id, 'Stripe Fee', $fee );
839
+ update_post_meta( $order_id, 'Net Revenue From Stripe', $net );
840
}
841
842
if ( $response->captured ) {
844
845
$message = sprintf( __( 'Stripe charge complete (Charge ID: %s)', 'woocommerce-gateway-stripe' ), $response->id );
846
$order->add_order_note( $message );
847
+ $this->log( 'Success: ' . $message );
848
849
} else {
850
+ add_post_meta( $order_id, '_transaction_id', $response->id, true );
851
852
if ( $order->has_status( array( 'pending', 'failed' ) ) ) {
853
+ version_compare( WC_VERSION, '3.0.0', '<' ) ? $order->reduce_order_stock() : wc_reduce_stock_levels( $order_id );
854
}
855
856
$order->update_status( 'on-hold', sprintf( __( 'Stripe charge authorized (Charge ID: %s). Process order to take payment, or cancel to remove the pre-authorization.', 'woocommerce-gateway-stripe' ), $response->id ) );
857
+ $this->log( "Successful auth: $response->id" );
858
}
859
860
return $response;
920
);
921
}
922
923
+ $this->log( "Info: Beginning refund for order $order_id for the amount of {$amount}" );
924
925
$response = WC_Stripe_API::request( $body, 'charges/' . $order->get_transaction_id() . '/refunds' );
926
927
if ( is_wp_error( $response ) ) {
928
+ $this->log( 'Error: ' . $response->get_error_message() );
929
return $response;
930
} elseif ( ! empty( $response->id ) ) {
931
+ $refund_message = sprintf( __( 'Refunded %1$s - Refund ID: %2$s - Reason: %3$s', 'woocommerce-gateway-stripe' ), wc_price( $response->amount / 100 ), $response->id, $reason );
932
$order->add_order_note( $refund_message );
933
+ $this->log( 'Success: ' . html_entity_decode( strip_tags( $refund_message ) ) );
934
return true;
935
}
936
}
949
$emails['WC_Email_Failed_Order']->trigger( $order_id );
950
}
951
}
952
+
953
+ /**
954
+ * Logs
955
+ *
956
+ * @since 3.1.0
957
+ * @version 3.1.0
958
+ *
959
+ * @param string $message
960
+ */
961
+ public function log( $message ) {
962
+ if ( $this->logging ) {
963
+ WC_Stripe::log( $message );
964
+ }
965
+ }
966
}
includes/class-wc-stripe-api.php CHANGED
@@ -52,24 +52,24 @@ class WC_Stripe_API {
52
* @return array|WP_Error
53
*/
54
public static function request( $request, $api = 'charges', $method = 'POST' ) {
55
- WC_Stripe::log( "{$api} request: " . print_r( $request, true ) );
56
57
$response = wp_safe_remote_post(
58
self::ENDPOINT . $api,
59
array(
60
'method' => $method,
61
'headers' => array(
62
- 'Authorization' => 'Basic ' . base64_encode( self::get_secret_key(). ':' ),
63
- 'Stripe-Version' => '2016-03-07'
64
),
65
'body' => apply_filters( 'woocommerce_stripe_request_body', $request, $api ),
66
'timeout' => 70,
67
- 'user-agent' => 'WooCommerce ' . WC()->version
68
)
69
);
70
71
if ( is_wp_error( $response ) || empty( $response['body'] ) ) {
72
- WC_Stripe::log( "Error Response: " . print_r( $response, true ) );
73
return new WP_Error( 'stripe_error', __( 'There was a problem connecting to the payment gateway.', 'woocommerce-gateway-stripe' ) );
74
}
75
@@ -88,4 +88,20 @@ class WC_Stripe_API {
88
return $parsed_response;
89
}
90
}
91
}
52
* @return array|WP_Error
53
*/
54
public static function request( $request, $api = 'charges', $method = 'POST' ) {
55
+ self::log( "{$api} request: " . print_r( $request, true ) );
56
57
$response = wp_safe_remote_post(
58
self::ENDPOINT . $api,
59
array(
60
'method' => $method,
61
'headers' => array(
62
+ 'Authorization' => 'Basic ' . base64_encode( self::get_secret_key() . ':' ),
63
+ 'Stripe-Version' => '2016-03-07',
64
),
65
'body' => apply_filters( 'woocommerce_stripe_request_body', $request, $api ),
66
'timeout' => 70,
67
+ 'user-agent' => 'WooCommerce ' . WC()->version,
68
)
69
);
70
71
if ( is_wp_error( $response ) || empty( $response['body'] ) ) {
72
+ self::log( 'Error Response: ' . print_r( $response, true ) );
73
return new WP_Error( 'stripe_error', __( 'There was a problem connecting to the payment gateway.', 'woocommerce-gateway-stripe' ) );
74
}
75
88
return $parsed_response;
89
}
90
}
91
+
92
+ /**
93
+ * Logs
94
+ *
95
+ * @since 3.1.0
96
+ * @version 3.1.0
97
+ *
98
+ * @param string $message
99
+ */
100
+ public static function log( $message ) {
101
+ $options = get_option( 'woocommerce_stripe_settings' );
102
+
103
+ if ( 'yes' === $options['logging'] ) {
104
+ WC_Stripe::log( $message );
105
+ }
106
+ }
107
}
includes/class-wc-stripe-apple-pay.php ADDED
@@ -0,0 +1,884 @@