WooCommerce Stripe Payment Gateway - Version 4.3.2

Version Description

2020-02-17 = * Fix - Add compatibility to payment request buttons with some of the WooCommerce Product Add-ons on the product page * Fix - Improved compatibility for free orders with other extensions * Add - Support for multisite when sites use different Stripe accounts * Fix - Display a localized error message when a customer tries to save a card during checkout, but there's an error * Add - Send level 3 credit card data for purchases when possible

Download this release

Release Info

Developer woothemes
Plugin Icon 128x128 WooCommerce Stripe Payment Gateway
Version 4.3.2
Comparing to
See all releases

Code changes from version 4.3.1 to 4.3.2

assets/js/stripe-payment-request.js CHANGED
@@ -58,7 +58,7 @@ jQuery( function( $ ) {
58
  'count' : count,
59
  'chosenCount': chosen,
60
  'data' : data
61
- };
62
  },
63
 
64
  processSource: function( source, paymentRequestType ) {
@@ -269,6 +269,23 @@ jQuery( function( $ ) {
269
  attributes: $( '.variations_form' ).length ? wc_stripe_payment_request.getAttributes().data : []
270
  };
271
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
272
  return $.ajax( {
273
  type: 'POST',
274
  data: data,
@@ -372,7 +389,7 @@ jQuery( function( $ ) {
372
  }
373
  } );
374
 
375
- $( document.body ).on( 'woocommerce_variation_has_changed', function() {
376
  $( '#wc-stripe-payment-request-button' ).block( { message: null } );
377
 
378
  $.when( wc_stripe_payment_request.getSelectedProductData() ).then( function( response ) {
@@ -428,7 +445,7 @@ jQuery( function( $ ) {
428
  if ( 'fail' === response.result ) {
429
  evt.updateWith( { status: 'fail' } );
430
  }
431
- } );
432
  } );
433
 
434
  paymentRequest.on( 'source', function( evt ) {
@@ -455,11 +472,15 @@ jQuery( function( $ ) {
455
  product_id = $( '.single_variation_wrap' ).find( 'input[name="product_id"]' ).val();
456
  }
457
 
 
 
 
458
  var data = {
459
  security: wc_stripe_payment_request_params.nonce.get_selected_product_data,
460
  product_id: product_id,
461
  qty: $( '.quantity .qty' ).val(),
462
- attributes: $( '.variations_form' ).length ? wc_stripe_payment_request.getAttributes().data : []
 
463
  };
464
 
465
  return $.ajax( {
58
  'count' : count,
59
  'chosenCount': chosen,
60
  'data' : data
61
+ };
62
  },
63
 
64
  processSource: function( source, paymentRequestType ) {
269
  attributes: $( '.variations_form' ).length ? wc_stripe_payment_request.getAttributes().data : []
270
  };
271
 
272
+ // add addons data to the POST body
273
+ var formData = $( 'form.cart' ).serializeArray();
274
+ $.each( formData, function( i, field ) {
275
+ if ( /^addon-/.test( field.name ) ) {
276
+ if ( /\[\]$/.test( field.name ) ) {
277
+ var fieldName = field.name.substring( 0, field.name.length - 2);
278
+ if ( data[ fieldName ] ) {
279
+ data[ fieldName ].push( field.value );
280
+ } else {
281
+ data[ fieldName ] = [ field.value ];
282
+ }
283
+ } else {
284
+ data[ field.name ] = field.value;
285
+ }
286
+ }
287
+ } );
288
+
289
  return $.ajax( {
290
  type: 'POST',
291
  data: data,
389
  }
390
  } );
391
 
392
+ $( document.body ).on( 'woocommerce_variation_has_changed updated_addons', function() {
393
  $( '#wc-stripe-payment-request-button' ).block( { message: null } );
394
 
395
  $.when( wc_stripe_payment_request.getSelectedProductData() ).then( function( response ) {
445
  if ( 'fail' === response.result ) {
446
  evt.updateWith( { status: 'fail' } );
447
  }
448
+ } );
449
  } );
450
 
451
  paymentRequest.on( 'source', function( evt ) {
472
  product_id = $( '.single_variation_wrap' ).find( 'input[name="product_id"]' ).val();
473
  }
474
 
475
+ var addons = $( '#product-addons-total' ).data('price_data') || [];
476
+ var addon_value = addons.reduce( function ( sum, addon ) { return sum + addon.cost; }, 0 );
477
+
478
  var data = {
479
  security: wc_stripe_payment_request_params.nonce.get_selected_product_data,
480
  product_id: product_id,
481
  qty: $( '.quantity .qty' ).val(),
482
+ attributes: $( '.variations_form' ).length ? wc_stripe_payment_request.getAttributes().data : [],
483
+ addon_value: addon_value,
484
  };
485
 
486
  return $.ajax( {
assets/js/stripe-payment-request.min.js CHANGED
@@ -1 +1 @@
1
- jQuery(function(i){"use strict";var s,p=Stripe(wc_stripe_payment_request_params.stripe.key),o={getAjaxURL:function(t){return wc_stripe_payment_request_params.ajax_url.toString().replace("%%endpoint%%","wc_stripe_"+t)},getCartDetails:function(){var t={security:wc_stripe_payment_request_params.nonce.payment};i.ajax({type:"POST",data:t,url:o.getAjaxURL("get_cart_details"),success:function(t){o.startPaymentRequest(t)}})},getAttributes:function(){var t=i(".variations_form").find(".variations select"),a={},n=0,r=0;return t.each(function(){var t=i(this).data("attribute_name")||i(this).attr("name"),e=i(this).val()||"";0<e.length&&r++,n++,a[t]=e}),{count:n,chosenCount:r,data:a}},processSource:function(t,e){var a=o.getOrderData(t,e);return i.ajax({type:"POST",data:a,dataType:"json",url:o.getAjaxURL("create_order")})},getOrderData:function(t,e){var a=t.source,n=a.owner.email,r=a.owner.phone,i=a.owner.address,s=a.owner.name,p=t.shippingAddress,o={_wpnonce:wc_stripe_payment_request_params.nonce.checkout,billing_first_name:null!==s?s.split(" ").slice(0,1).join(" "):"",billing_last_name:null!==s?s.split(" ").slice(1).join(" "):"",billing_company:"",billing_email:null!==n?n:t.payerEmail,billing_phone:null!==r?r:t.payerPhone.replace("/[() -]/g",""),billing_country:null!==i?i.country:"",billing_address_1:null!==i?i.line1:"",billing_address_2:null!==i?i.line2:"",billing_city:null!==i?i.city:"",billing_state:null!==i?i.state:"",billing_postcode:null!==i?i.postal_code:"",shipping_first_name:"",shipping_last_name:"",shipping_company:"",shipping_country:"",shipping_address_1:"",shipping_address_2:"",shipping_city:"",shipping_state:"",shipping_postcode:"",shipping_method:[null===t.shippingOption?null:t.shippingOption.id],order_comments:"",payment_method:"stripe",ship_to_different_address:1,terms:1,stripe_source:a.id,payment_request_type:e};return p&&(o.shipping_first_name=p.recipient.split(" ").slice(0,1).join(" "),o.shipping_last_name=p.recipient.split(" ").slice(1).join(" "),o.shipping_company=p.organization,o.shipping_country=p.country,o.shipping_address_1=void 0===p.addressLine[0]?"":p.addressLine[0],o.shipping_address_2=void 0===p.addressLine[1]?"":p.addressLine[1],o.shipping_city=p.city,o.shipping_state=p.region,o.shipping_postcode=p.postalCode),o},getErrorMessageHTML:function(t){return i('<div class="woocommerce-error" />').text(t)},abortPayment:function(t,e){if(t.complete("fail"),i(".woocommerce-error").remove(),wc_stripe_payment_request_params.is_product_page){var a=i(".product");a.before(e),i("html, body").animate({scrollTop:a.prev(".woocommerce-error").offset().top},600)}else{var n=i(".shop_table.cart").closest("form");n.before(e),i("html, body").animate({scrollTop:n.prev(".woocommerce-error").offset().top},600)}},completePayment:function(t,e){o.block(),t.complete("success"),window.location=e},block:function(){i.blockUI({message:null,overlayCSS:{background:"#fff",opacity:.6}})},updateShippingOptions:function(t,e){var a={security:wc_stripe_payment_request_params.nonce.shipping,country:e.country,state:e.region,postcode:e.postalCode,city:e.city,address:void 0===e.addressLine[0]?"":e.addressLine[0],address_2:void 0===e.addressLine[1]?"":e.addressLine[1],payment_request_type:s};return i.ajax({type:"POST",data:a,url:o.getAjaxURL("get_shipping_options")})},updateShippingDetails:function(t,e){var a={security:wc_stripe_payment_request_params.nonce.update_shipping,shipping_method:[e.id],payment_request_type:s};return i.ajax({type:"POST",data:a,url:o.getAjaxURL("update_shipping_method")})},addToCart:function(){var t=i(".single_add_to_cart_button").val();i(".single_variation_wrap").length&&(t=i(".single_variation_wrap").find('input[name="product_id"]').val());var e={security:wc_stripe_payment_request_params.nonce.add_to_cart,product_id:t,qty:i(".quantity .qty").val(),attributes:i(".variations_form").length?o.getAttributes().data:[]};return i.ajax({type:"POST",data:e,url:o.getAjaxURL("add_to_cart")})},clearCart:function(){var t={security:wc_stripe_payment_request_params.nonce.clear_cart};return i.ajax({type:"POST",data:t,url:o.getAjaxURL("clear_cart"),success:function(t){}})},getRequestOptionsFromLocal:function(){return{total:wc_stripe_payment_request_params.product.total,currency:wc_stripe_payment_request_params.checkout.currency_code,country:wc_stripe_payment_request_params.checkout.country_code,requestPayerName:!0,requestPayerEmail:!0,requestPayerPhone:!0,requestShipping:wc_stripe_payment_request_params.product.requestShipping,displayItems:wc_stripe_payment_request_params.product.displayItems}},startPaymentRequest:function(t){var a,e;a=wc_stripe_payment_request_params.is_product_page?e=o.getRequestOptionsFromLocal():(e={total:t.order_data.total,currency:t.order_data.currency,country:t.order_data.country_code,requestPayerName:!0,requestPayerEmail:!0,requestPayerPhone:!0,requestShipping:!!t.shipping_required,displayItems:t.order_data.displayItems},t.order_data);var n=p.paymentRequest(e),r=p.elements({locale:wc_stripe_payment_request_params.button.locale}).create("paymentRequestButton",{paymentRequest:n,style:{paymentRequestButton:{type:wc_stripe_payment_request_params.button.type,theme:wc_stripe_payment_request_params.button.theme,height:wc_stripe_payment_request_params.button.height+"px"}}});n.canMakePayment().then(function(t){var e=[];if(t){if(s=t.applePay?"apple_pay":"payment_request_api",wc_stripe_payment_request_params.is_product_page){var a=i(".single_add_to_cart_button");r.on("click",function(t){a.is(".disabled")?(t.preventDefault(),a.is(".wc-variation-is-unavailable")?window.alert(wc_add_to_cart_variation_params.i18n_unavailable_text):a.is(".wc-variation-selection-needed")&&window.alert(wc_add_to_cart_variation_params.i18n_make_a_selection_text)):0<e.length?(t.preventDefault(),window.alert(e)):o.addToCart()}),i(document.body).on("woocommerce_variation_has_changed",function(){i("#wc-stripe-payment-request-button").block({message:null}),i.when(o.getSelectedProductData()).then(function(t){i.when(n.update({total:t.total,displayItems:t.displayItems})).then(function(){i("#wc-stripe-payment-request-button").unblock()})})}),i(".quantity").on("keyup",".qty",function(){i("#wc-stripe-payment-request-button").block({message:null}),e=[],i.when(o.getSelectedProductData()).then(function(t){t.error?(e=[t.error],i("#wc-stripe-payment-request-button").unblock()):i.when(n.update({total:t.total,displayItems:t.displayItems})).then(function(){i("#wc-stripe-payment-request-button").unblock()})})})}i("#wc-stripe-payment-request-button").length&&(i("#wc-stripe-payment-request-wrapper, #wc-stripe-payment-request-button-separator").show(),r.mount("#wc-stripe-payment-request-button"))}}),n.on("shippingaddresschange",function(e){i.when(o.updateShippingOptions(a,e.shippingAddress)).then(function(t){e.updateWith({status:t.result,shippingOptions:t.shipping_options,total:t.total,displayItems:t.displayItems})})}),n.on("shippingoptionchange",function(e){i.when(o.updateShippingDetails(a,e.shippingOption)).then(function(t){"success"===t.result&&e.updateWith({status:"success",total:t.total,displayItems:t.displayItems}),"fail"===t.result&&e.updateWith({status:"fail"})})}),n.on("source",function(e){"no"===wc_stripe_payment_request_params.stripe.allow_prepaid_card&&"prepaid"===e.source.card.funding?o.abortPayment(e,o.getErrorMessageHTML(wc_stripe_payment_request_params.i18n.no_prepaid_card)):i.when(o.processSource(e,s)).then(function(t){"success"===t.result?o.completePayment(e,t.redirect):o.abortPayment(e,t.messages)})})},getSelectedProductData:function(){var t=i(".single_add_to_cart_button").val();i(".single_variation_wrap").length&&(t=i(".single_variation_wrap").find('input[name="product_id"]').val());var e={security:wc_stripe_payment_request_params.nonce.get_selected_product_data,product_id:t,qty:i(".quantity .qty").val(),attributes:i(".variations_form").length?o.getAttributes().data:[]};return i.ajax({type:"POST",data:e,url:o.getAjaxURL("get_selected_product_data")})},init:function(){wc_stripe_payment_request_params.is_product_page?o.startPaymentRequest(""):o.getCartDetails()}};o.init(),i(document.body).on("updated_cart_totals",function(){o.init()}),i(document.body).on("updated_checkout",function(){o.init()})});
1
+ jQuery(function(i){"use strict";var s,p=Stripe(wc_stripe_payment_request_params.stripe.key),o={getAjaxURL:function(t){return wc_stripe_payment_request_params.ajax_url.toString().replace("%%endpoint%%","wc_stripe_"+t)},getCartDetails:function(){var t={security:wc_stripe_payment_request_params.nonce.payment};i.ajax({type:"POST",data:t,url:o.getAjaxURL("get_cart_details"),success:function(t){o.startPaymentRequest(t)}})},getAttributes:function(){var t=i(".variations_form").find(".variations select"),a={},n=0,r=0;return t.each(function(){var t=i(this).data("attribute_name")||i(this).attr("name"),e=i(this).val()||"";0<e.length&&r++,n++,a[t]=e}),{count:n,chosenCount:r,data:a}},processSource:function(t,e){var a=o.getOrderData(t,e);return i.ajax({type:"POST",data:a,dataType:"json",url:o.getAjaxURL("create_order")})},getOrderData:function(t,e){var a=t.source,n=a.owner.email,r=a.owner.phone,i=a.owner.address,s=a.owner.name,p=t.shippingAddress,o={_wpnonce:wc_stripe_payment_request_params.nonce.checkout,billing_first_name:null!==s?s.split(" ").slice(0,1).join(" "):"",billing_last_name:null!==s?s.split(" ").slice(1).join(" "):"",billing_company:"",billing_email:null!==n?n:t.payerEmail,billing_phone:null!==r?r:t.payerPhone.replace("/[() -]/g",""),billing_country:null!==i?i.country:"",billing_address_1:null!==i?i.line1:"",billing_address_2:null!==i?i.line2:"",billing_city:null!==i?i.city:"",billing_state:null!==i?i.state:"",billing_postcode:null!==i?i.postal_code:"",shipping_first_name:"",shipping_last_name:"",shipping_company:"",shipping_country:"",shipping_address_1:"",shipping_address_2:"",shipping_city:"",shipping_state:"",shipping_postcode:"",shipping_method:[null===t.shippingOption?null:t.shippingOption.id],order_comments:"",payment_method:"stripe",ship_to_different_address:1,terms:1,stripe_source:a.id,payment_request_type:e};return p&&(o.shipping_first_name=p.recipient.split(" ").slice(0,1).join(" "),o.shipping_last_name=p.recipient.split(" ").slice(1).join(" "),o.shipping_company=p.organization,o.shipping_country=p.country,o.shipping_address_1=void 0===p.addressLine[0]?"":p.addressLine[0],o.shipping_address_2=void 0===p.addressLine[1]?"":p.addressLine[1],o.shipping_city=p.city,o.shipping_state=p.region,o.shipping_postcode=p.postalCode),o},getErrorMessageHTML:function(t){return i('<div class="woocommerce-error" />').text(t)},abortPayment:function(t,e){if(t.complete("fail"),i(".woocommerce-error").remove(),wc_stripe_payment_request_params.is_product_page){var a=i(".product");a.before(e),i("html, body").animate({scrollTop:a.prev(".woocommerce-error").offset().top},600)}else{var n=i(".shop_table.cart").closest("form");n.before(e),i("html, body").animate({scrollTop:n.prev(".woocommerce-error").offset().top},600)}},completePayment:function(t,e){o.block(),t.complete("success"),window.location=e},block:function(){i.blockUI({message:null,overlayCSS:{background:"#fff",opacity:.6}})},updateShippingOptions:function(t,e){var a={security:wc_stripe_payment_request_params.nonce.shipping,country:e.country,state:e.region,postcode:e.postalCode,city:e.city,address:void 0===e.addressLine[0]?"":e.addressLine[0],address_2:void 0===e.addressLine[1]?"":e.addressLine[1],payment_request_type:s};return i.ajax({type:"POST",data:a,url:o.getAjaxURL("get_shipping_options")})},updateShippingDetails:function(t,e){var a={security:wc_stripe_payment_request_params.nonce.update_shipping,shipping_method:[e.id],payment_request_type:s};return i.ajax({type:"POST",data:a,url:o.getAjaxURL("update_shipping_method")})},addToCart:function(){var t=i(".single_add_to_cart_button").val();i(".single_variation_wrap").length&&(t=i(".single_variation_wrap").find('input[name="product_id"]').val());var n={security:wc_stripe_payment_request_params.nonce.add_to_cart,product_id:t,qty:i(".quantity .qty").val(),attributes:i(".variations_form").length?o.getAttributes().data:[]},e=i("form.cart").serializeArray();return i.each(e,function(t,e){if(/^addon-/.test(e.name))if(/\[\]$/.test(e.name)){var a=e.name.substring(0,e.name.length-2);n[a]?n[a].push(e.value):n[a]=[e.value]}else n[e.name]=e.value}),i.ajax({type:"POST",data:n,url:o.getAjaxURL("add_to_cart")})},clearCart:function(){var t={security:wc_stripe_payment_request_params.nonce.clear_cart};return i.ajax({type:"POST",data:t,url:o.getAjaxURL("clear_cart"),success:function(t){}})},getRequestOptionsFromLocal:function(){return{total:wc_stripe_payment_request_params.product.total,currency:wc_stripe_payment_request_params.checkout.currency_code,country:wc_stripe_payment_request_params.checkout.country_code,requestPayerName:!0,requestPayerEmail:!0,requestPayerPhone:!0,requestShipping:wc_stripe_payment_request_params.product.requestShipping,displayItems:wc_stripe_payment_request_params.product.displayItems}},startPaymentRequest:function(t){var a,e;a=wc_stripe_payment_request_params.is_product_page?e=o.getRequestOptionsFromLocal():(e={total:t.order_data.total,currency:t.order_data.currency,country:t.order_data.country_code,requestPayerName:!0,requestPayerEmail:!0,requestPayerPhone:!0,requestShipping:!!t.shipping_required,displayItems:t.order_data.displayItems},t.order_data);var n=p.paymentRequest(e),r=p.elements({locale:wc_stripe_payment_request_params.button.locale}).create("paymentRequestButton",{paymentRequest:n,style:{paymentRequestButton:{type:wc_stripe_payment_request_params.button.type,theme:wc_stripe_payment_request_params.button.theme,height:wc_stripe_payment_request_params.button.height+"px"}}});n.canMakePayment().then(function(t){var e=[];if(t){if(s=t.applePay?"apple_pay":"payment_request_api",wc_stripe_payment_request_params.is_product_page){var a=i(".single_add_to_cart_button");r.on("click",function(t){a.is(".disabled")?(t.preventDefault(),a.is(".wc-variation-is-unavailable")?window.alert(wc_add_to_cart_variation_params.i18n_unavailable_text):a.is(".wc-variation-selection-needed")&&window.alert(wc_add_to_cart_variation_params.i18n_make_a_selection_text)):0<e.length?(t.preventDefault(),window.alert(e)):o.addToCart()}),i(document.body).on("woocommerce_variation_has_changed updated_addons",function(){i("#wc-stripe-payment-request-button").block({message:null}),i.when(o.getSelectedProductData()).then(function(t){i.when(n.update({total:t.total,displayItems:t.displayItems})).then(function(){i("#wc-stripe-payment-request-button").unblock()})})}),i(".quantity").on("keyup",".qty",function(){i("#wc-stripe-payment-request-button").block({message:null}),e=[],i.when(o.getSelectedProductData()).then(function(t){t.error?(e=[t.error],i("#wc-stripe-payment-request-button").unblock()):i.when(n.update({total:t.total,displayItems:t.displayItems})).then(function(){i("#wc-stripe-payment-request-button").unblock()})})})}i("#wc-stripe-payment-request-button").length&&(i("#wc-stripe-payment-request-wrapper, #wc-stripe-payment-request-button-separator").show(),r.mount("#wc-stripe-payment-request-button"))}}),n.on("shippingaddresschange",function(e){i.when(o.updateShippingOptions(a,e.shippingAddress)).then(function(t){e.updateWith({status:t.result,shippingOptions:t.shipping_options,total:t.total,displayItems:t.displayItems})})}),n.on("shippingoptionchange",function(e){i.when(o.updateShippingDetails(a,e.shippingOption)).then(function(t){"success"===t.result&&e.updateWith({status:"success",total:t.total,displayItems:t.displayItems}),"fail"===t.result&&e.updateWith({status:"fail"})})}),n.on("source",function(e){"no"===wc_stripe_payment_request_params.stripe.allow_prepaid_card&&"prepaid"===e.source.card.funding?o.abortPayment(e,o.getErrorMessageHTML(wc_stripe_payment_request_params.i18n.no_prepaid_card)):i.when(o.processSource(e,s)).then(function(t){"success"===t.result?o.completePayment(e,t.redirect):o.abortPayment(e,t.messages)})})},getSelectedProductData:function(){var t=i(".single_add_to_cart_button").val();i(".single_variation_wrap").length&&(t=i(".single_variation_wrap").find('input[name="product_id"]').val());var e=(i("#product-addons-total").data("price_data")||[]).reduce(function(t,e){return t+e.cost},0),a={security:wc_stripe_payment_request_params.nonce.get_selected_product_data,product_id:t,qty:i(".quantity .qty").val(),attributes:i(".variations_form").length?o.getAttributes().data:[],addon_value:e};return i.ajax({type:"POST",data:a,url:o.getAjaxURL("get_selected_product_data")})},init:function(){wc_stripe_payment_request_params.is_product_page?o.startPaymentRequest(""):o.getCartDetails()}};o.init(),i(document.body).on("updated_cart_totals",function(){o.init()}),i(document.body).on("updated_checkout",function(){o.init()})});
assets/js/stripe.js CHANGED
@@ -249,6 +249,9 @@ jQuery( function( $ ) {
249
  this.onSepaError
250
  );
251
 
 
 
 
252
  wc_stripe_form.createElements();
253
 
254
  // Listen for hash changes in order to handle payment intents
@@ -788,7 +791,33 @@ jQuery( function( $ ) {
788
  // Report back to the server.
789
  $.get( redirectURL + '&is_ajax' );
790
  } );
791
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
792
  };
793
 
794
  wc_stripe_form.init();
249
  this.onSepaError
250
  );
251
 
252
+ // Subscription early renewals modal.
253
+ $( '#early_renewal_modal_submit' ).on( 'click', this.onEarlyRenewalSubmit );
254
+
255
  wc_stripe_form.createElements();
256
 
257
  // Listen for hash changes in order to handle payment intents
791
  // Report back to the server.
792
  $.get( redirectURL + '&is_ajax' );
793
  } );
794
+ },
795
+
796
+ /**
797
+ * Prevents the standard behavior of the "Renew Now" button in the
798
+ * early renewals modal by using AJAX instead of a simple redirect.
799
+ *
800
+ * @param {Event} e The event that occured.
801
+ */
802
+ onEarlyRenewalSubmit: function( e ) {
803
+ e.preventDefault();
804
+
805
+ $.ajax( {
806
+ url: $( '#early_renewal_modal_submit' ).attr( 'href' ),
807
+ method: 'get',
808
+ success: function( html ) {
809
+ var response = $.parseJSON( html );
810
+
811
+ if ( response.stripe_sca_required ) {
812
+ wc_stripe_form.openIntentModal( response.intent_secret, response.redirect_url, true, false );
813
+ } else {
814
+ window.location = response.redirect_url;
815
+ }
816
+ },
817
+ } );
818
+
819
+ return false;
820
+ },
821
  };
822
 
823
  wc_stripe_form.init();
assets/js/stripe.min.js CHANGED
@@ -1 +1 @@
1
- jQuery(function(c){"use strict";try{var o=Stripe(wc_stripe_params.key)}catch(e){return void console.log(e)}var t,n,i,e=Object.keys(wc_stripe_params.elements_options).length?wc_stripe_params.elements_options:{},r=Object.keys(wc_stripe_params.sepa_elements_options).length?wc_stripe_params.sepa_elements_options:{},s=o.elements(e),a=s.create("iban",r),m={getAjaxURL:function(e){return wc_stripe_params.ajaxurl.toString().replace("%%endpoint%%","wc_stripe_"+e)},unmountElements:function(){"yes"===wc_stripe_params.inline_cc_form?t.unmount("#stripe-card-element"):(t.unmount("#stripe-card-element"),n.unmount("#stripe-exp-element"),i.unmount("#stripe-cvc-element"))},mountElements:function(){if(c("#stripe-card-element").length){if("yes"===wc_stripe_params.inline_cc_form)return t.mount("#stripe-card-element");t.mount("#stripe-card-element"),n.mount("#stripe-exp-element"),i.mount("#stripe-cvc-element")}},createElements:function(){var e={base:{iconColor:"#666EE8",color:"#31325F",fontSize:"15px","::placeholder":{color:"#CFD7E0"}}},r={focus:"focused",empty:"empty",invalid:"invalid"};e=wc_stripe_params.elements_styling?wc_stripe_params.elements_styling:e,r=wc_stripe_params.elements_classes?wc_stripe_params.elements_classes:r,"yes"===wc_stripe_params.inline_cc_form?(t=s.create("card",{style:e,hidePostalCode:!0})).addEventListener("change",function(e){m.onCCFormChange(),e.error&&c(document.body).trigger("stripeError",e)}):(t=s.create("cardNumber",{style:e,classes:r}),n=s.create("cardExpiry",{style:e,classes:r}),i=s.create("cardCvc",{style:e,classes:r}),t.addEventListener("change",function(e){m.onCCFormChange(),m.updateCardBrand(e.brand),e.error&&c(document.body).trigger("stripeError",e)}),n.addEventListener("change",function(e){m.onCCFormChange(),e.error&&c(document.body).trigger("stripeError",e)}),i.addEventListener("change",function(e){m.onCCFormChange(),e.error&&c(document.body).trigger("stripeError",e)})),"yes"===wc_stripe_params.is_checkout?c(document.body).on("updated_checkout",function(){c("#stripe-card-element").children().length||(t&&m.unmountElements(),m.mountElements(),c("#stripe-iban-element").length&&a.mount("#stripe-iban-element"))}):(c("form#add_payment_method").length||c("form#order_review").length)&&(m.mountElements(),c("#stripe-iban-element").length&&a.mount("#stripe-iban-element"))},updateCardBrand:function(e){var r={visa:"stripe-visa-brand",mastercard:"stripe-mastercard-brand",amex:"stripe-amex-brand",discover:"stripe-discover-brand",diners:"stripe-diners-brand",jcb:"stripe-jcb-brand",unknown:"stripe-credit-card-brand"},t=c(".stripe-card-brand"),n="stripe-credit-card-brand";e in r&&(n=r[e]),c.each(r,function(e,r){t.removeClass(r)}),t.addClass(n)},init:function(){"yes"!==wc_stripe_params.is_change_payment_page&&"yes"!==wc_stripe_params.is_pay_for_order_page||c(document.body).trigger("wc-credit-card-form-init"),c("form.woocommerce-checkout").length&&(this.form=c("form.woocommerce-checkout")),c("form.woocommerce-checkout").on("checkout_place_order_stripe checkout_place_order_stripe_bancontact checkout_place_order_stripe_sofort checkout_place_order_stripe_giropay checkout_place_order_stripe_ideal checkout_place_order_stripe_alipay checkout_place_order_stripe_sepa",this.onSubmit),c("form#order_review").length&&(this.form=c("form#order_review")),c("form#order_review, form#add_payment_method").on("submit",this.onSubmit),c("form#add_payment_method").length&&(this.form=c("form#add_payment_method")),c("form.woocommerce-checkout").on("change",this.reset),c(document).on("stripeError",this.onError).on("checkout_error",this.reset),a.on("change",this.onSepaError),m.createElements(),window.addEventListener("hashchange",m.onHashChange),m.maybeConfirmIntent()},isStripeChosen:function(){return c("#payment_method_stripe, #payment_method_stripe_bancontact, #payment_method_stripe_sofort, #payment_method_stripe_giropay, #payment_method_stripe_ideal, #payment_method_stripe_alipay, #payment_method_stripe_sepa, #payment_method_stripe_eps, #payment_method_stripe_multibanco").is(":checked")||c("#payment_method_stripe").is(":checked")&&"new"===c('input[name="wc-stripe-payment-token"]:checked').val()||c("#payment_method_stripe_sepa").is(":checked")&&"new"===c('input[name="wc-stripe-payment-token"]:checked').val()},isStripeSaveCardChosen:function(){return c("#payment_method_stripe").is(":checked")&&c('input[name="wc-stripe-payment-token"]').is(":checked")&&"new"!==c('input[name="wc-stripe-payment-token"]:checked').val()||c("#payment_method_stripe_sepa").is(":checked")&&c('input[name="wc-stripe_sepa-payment-token"]').is(":checked")&&"new"!==c('input[name="wc-stripe_sepa-payment-token"]:checked').val()},isStripeCardChosen:function(){return c("#payment_method_stripe").is(":checked")},isBancontactChosen:function(){return c("#payment_method_stripe_bancontact").is(":checked")},isGiropayChosen:function(){return c("#payment_method_stripe_giropay").is(":checked")},isIdealChosen:function(){return c("#payment_method_stripe_ideal").is(":checked")},isSofortChosen:function(){return c("#payment_method_stripe_sofort").is(":checked")},isAlipayChosen:function(){return c("#payment_method_stripe_alipay").is(":checked")},isSepaChosen:function(){return c("#payment_method_stripe_sepa").is(":checked")},isP24Chosen:function(){return c("#payment_method_stripe_p24").is(":checked")},isEpsChosen:function(){return c("#payment_method_stripe_eps").is(":checked")},isMultibancoChosen:function(){return c("#payment_method_stripe_multibanco").is(":checked")},hasSource:function(){return 0<c("input.stripe-source").length},isMobile:function(){return!!/Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(navigator.userAgent)},block:function(){m.isMobile()||m.form.block({message:null,overlayCSS:{background:"#fff",opacity:.6}})},unblock:function(){m.form&&m.form.unblock()},getSelectedPaymentElement:function(){return c('.payment_methods input[name="payment_method"]:checked')},getOwnerDetails:function(){var e=c("#billing_first_name").length?c("#billing_first_name").val():wc_stripe_params.billing_first_name,r=c("#billing_last_name").length?c("#billing_last_name").val():wc_stripe_params.billing_last_name,t={name:"",address:{},email:"",phone:""};return t.name=e,t.name=e&&r?e+" "+r:c("#stripe-payment-data").data("full-name"),t.email=c("#billing_email").val(),t.phone=c("#billing_phone").val(),(void 0===t.phone||t.phone.length<=0)&&delete t.phone,(void 0===t.email||t.email.length<=0)&&(c("#stripe-payment-data").data("email").length?t.email=c("#stripe-payment-data").data("email"):delete t.email),(void 0===t.name||t.name.length<=0)&&delete t.name,t.address.line1=c("#billing_address_1").val()||wc_stripe_params.billing_address_1,t.address.line2=c("#billing_address_2").val()||wc_stripe_params.billing_address_2,t.address.state=c("#billing_state").val()||wc_stripe_params.billing_state,t.address.city=c("#billing_city").val()||wc_stripe_params.billing_city,t.address.postal_code=c("#billing_postcode").val()||wc_stripe_params.billing_postcode,t.address.country=c("#billing_country").val()||wc_stripe_params.billing_country,{owner:t}},createSource:function(){var e=m.getOwnerDetails();return m.isSepaChosen()?(e.currency=c("#stripe-sepa_debit-payment-data").data("currency"),e.mandate={notification_method:wc_stripe_params.sepa_mandate_notification},e.type="sepa_debit",o.createSource(a,e).then(m.sourceResponse)):o.createSource(t,e).then(m.sourceResponse)},sourceResponse:function(e){if(e.error)return c(document.body).trigger("stripeError",e);m.reset(),m.form.append(c('<input type="hidden" />').addClass("stripe-source").attr("name","stripe_source").val(e.source.id)),c("form#add_payment_method").length&&c(m.form).off("submit",m.form.onSubmit),m.form.submit()},onSubmit:function(){return!m.isStripeChosen()||(!(!m.isStripeSaveCardChosen()&&!m.hasSource())||(!!(m.isBancontactChosen()||m.isGiropayChosen()||m.isIdealChosen()||m.isAlipayChosen()||m.isSofortChosen()||m.isP24Chosen()||m.isEpsChosen()||m.isMultibancoChosen())||(m.block(),m.createSource(),!1)))},onCCFormChange:function(){m.reset()},reset:function(){c(".wc-stripe-error, .stripe-source").remove()},onSepaError:function(e){var r=m.getSelectedPaymentElement().parents("li").eq(0).find(".stripe-source-errors");if(!e.error)return c(r).html("");console.log(e.error.message),c(r).html('<ul class="woocommerce_error woocommerce-error wc-stripe-error"><li /></ul>'),c(r).find("li").text(e.error.message)},onError:function(e,r){var t,n=r.error.message,o=m.getSelectedPaymentElement().closest("li"),i=o.find(".woocommerce-SavedPaymentMethods-tokenInput");if(i.length){var s=i.filter(":checked");t=s.closest(".woocommerce-SavedPaymentMethods-new").length?c("#wc-stripe-cc-form .stripe-source-errors"):s.closest("li").find(".stripe-source-errors")}else t=o.find(".stripe-source-errors");if(m.isSepaChosen()&&"invalid_owner_name"===r.error.code&&wc_stripe_params.hasOwnProperty(r.error.code)){var a='<ul class="woocommerce-error"><li /></ul>';return a.find("li").text(wc_stripe_params[r.error.code]),m.submitError(a)}"email_invalid"===r.error.code?n=wc_stripe_params.email_invalid:"invalid_request_error"!==r.error.type&&"api_connection_error"!==r.error.type&&"api_error"!==r.error.type&&"authentication_error"!==r.error.type&&"rate_limit_error"!==r.error.type||(n=wc_stripe_params.invalid_request_error),"card_error"===r.error.type&&wc_stripe_params.hasOwnProperty(r.error.code)&&(n=wc_stripe_params[r.error.code]),"validation_error"===r.error.type&&wc_stripe_params.hasOwnProperty(r.error.code)&&(n=wc_stripe_params[r.error.code]),m.reset(),c(".woocommerce-NoticeGroup-checkout").remove(),console.log(r.error.message),c(t).html('<ul class="woocommerce_error woocommerce-error wc-stripe-error"><li /></ul>'),c(t).find("li").text(n),c(".wc-stripe-error").length&&c("html, body").animate({scrollTop:c(".wc-stripe-error").offset().top-200},200),m.unblock(),c.unblockUI()},submitError:function(e){c(".woocommerce-NoticeGroup-checkout, .woocommerce-error, .woocommerce-message").remove(),m.form.prepend('<div class="woocommerce-NoticeGroup woocommerce-NoticeGroup-checkout">'+e+"</div>"),m.form.removeClass("processing").unblock(),m.form.find(".input-text, select, input:checkbox").blur();var r="";c("#add_payment_method").length&&(r=c("#add_payment_method")),c("#order_review").length&&(r=c("#order_review")),c("form.checkout").length&&(r=c("form.checkout")),r.length&&c("html, body").animate({scrollTop:r.offset().top-100},500),c(document.body).trigger("checkout_error"),m.unblock()},onHashChange:function(){var e=window.location.hash.match(/^#?confirm-(pi|si)-([^:]+):(.+)$/);if(e&&!(e.length<4)){var r=e[1],t=e[2],n=decodeURIComponent(e[3]);window.location.hash="",m.openIntentModal(t,n,!1,"si"===r)}},maybeConfirmIntent:function(){if(c("#stripe-intent-id").length&&c("#stripe-intent-return").length){var e=c("#stripe-intent-id").val(),r=c("#stripe-intent-return").val();m.openIntentModal(e,r,!0,!1)}},openIntentModal:function(e,t,r,n){o[n?"handleCardSetup":"handleCardPayment"](e).then(function(e){if(e.error)throw e.error;var r=e[n?"setupIntent":"paymentIntent"];"requires_capture"!==r.status&&"succeeded"!==r.status||(window.location=t)}).catch(function(e){if(r)return window.location=t;c(document.body).trigger("stripeError",{error:e}),m.form&&m.form.removeClass("processing"),c.get(t+"&is_ajax")})}};m.init()});
1
+ jQuery(function(c){"use strict";try{var o=Stripe(wc_stripe_params.key)}catch(e){return void console.log(e)}var t,n,i,e=Object.keys(wc_stripe_params.elements_options).length?wc_stripe_params.elements_options:{},r=Object.keys(wc_stripe_params.sepa_elements_options).length?wc_stripe_params.sepa_elements_options:{},a=o.elements(e),s=a.create("iban",r),m={getAjaxURL:function(e){return wc_stripe_params.ajaxurl.toString().replace("%%endpoint%%","wc_stripe_"+e)},unmountElements:function(){"yes"===wc_stripe_params.inline_cc_form?t.unmount("#stripe-card-element"):(t.unmount("#stripe-card-element"),n.unmount("#stripe-exp-element"),i.unmount("#stripe-cvc-element"))},mountElements:function(){if(c("#stripe-card-element").length){if("yes"===wc_stripe_params.inline_cc_form)return t.mount("#stripe-card-element");t.mount("#stripe-card-element"),n.mount("#stripe-exp-element"),i.mount("#stripe-cvc-element")}},createElements:function(){var e={base:{iconColor:"#666EE8",color:"#31325F",fontSize:"15px","::placeholder":{color:"#CFD7E0"}}},r={focus:"focused",empty:"empty",invalid:"invalid"};e=wc_stripe_params.elements_styling?wc_stripe_params.elements_styling:e,r=wc_stripe_params.elements_classes?wc_stripe_params.elements_classes:r,"yes"===wc_stripe_params.inline_cc_form?(t=a.create("card",{style:e,hidePostalCode:!0})).addEventListener("change",function(e){m.onCCFormChange(),e.error&&c(document.body).trigger("stripeError",e)}):(t=a.create("cardNumber",{style:e,classes:r}),n=a.create("cardExpiry",{style:e,classes:r}),i=a.create("cardCvc",{style:e,classes:r}),t.addEventListener("change",function(e){m.onCCFormChange(),m.updateCardBrand(e.brand),e.error&&c(document.body).trigger("stripeError",e)}),n.addEventListener("change",function(e){m.onCCFormChange(),e.error&&c(document.body).trigger("stripeError",e)}),i.addEventListener("change",function(e){m.onCCFormChange(),e.error&&c(document.body).trigger("stripeError",e)})),"yes"===wc_stripe_params.is_checkout?c(document.body).on("updated_checkout",function(){c("#stripe-card-element").children().length||(t&&m.unmountElements(),m.mountElements(),c("#stripe-iban-element").length&&s.mount("#stripe-iban-element"))}):(c("form#add_payment_method").length||c("form#order_review").length)&&(m.mountElements(),c("#stripe-iban-element").length&&s.mount("#stripe-iban-element"))},updateCardBrand:function(e){var r={visa:"stripe-visa-brand",mastercard:"stripe-mastercard-brand",amex:"stripe-amex-brand",discover:"stripe-discover-brand",diners:"stripe-diners-brand",jcb:"stripe-jcb-brand",unknown:"stripe-credit-card-brand"},t=c(".stripe-card-brand"),n="stripe-credit-card-brand";e in r&&(n=r[e]),c.each(r,function(e,r){t.removeClass(r)}),t.addClass(n)},init:function(){"yes"!==wc_stripe_params.is_change_payment_page&&"yes"!==wc_stripe_params.is_pay_for_order_page||c(document.body).trigger("wc-credit-card-form-init"),c("form.woocommerce-checkout").length&&(this.form=c("form.woocommerce-checkout")),c("form.woocommerce-checkout").on("checkout_place_order_stripe checkout_place_order_stripe_bancontact checkout_place_order_stripe_sofort checkout_place_order_stripe_giropay checkout_place_order_stripe_ideal checkout_place_order_stripe_alipay checkout_place_order_stripe_sepa",this.onSubmit),c("form#order_review").length&&(this.form=c("form#order_review")),c("form#order_review, form#add_payment_method").on("submit",this.onSubmit),c("form#add_payment_method").length&&(this.form=c("form#add_payment_method")),c("form.woocommerce-checkout").on("change",this.reset),c(document).on("stripeError",this.onError).on("checkout_error",this.reset),s.on("change",this.onSepaError),c("#early_renewal_modal_submit").on("click",this.onEarlyRenewalSubmit),m.createElements(),window.addEventListener("hashchange",m.onHashChange),m.maybeConfirmIntent()},isStripeChosen:function(){return c("#payment_method_stripe, #payment_method_stripe_bancontact, #payment_method_stripe_sofort, #payment_method_stripe_giropay, #payment_method_stripe_ideal, #payment_method_stripe_alipay, #payment_method_stripe_sepa, #payment_method_stripe_eps, #payment_method_stripe_multibanco").is(":checked")||c("#payment_method_stripe").is(":checked")&&"new"===c('input[name="wc-stripe-payment-token"]:checked').val()||c("#payment_method_stripe_sepa").is(":checked")&&"new"===c('input[name="wc-stripe-payment-token"]:checked').val()},isStripeSaveCardChosen:function(){return c("#payment_method_stripe").is(":checked")&&c('input[name="wc-stripe-payment-token"]').is(":checked")&&"new"!==c('input[name="wc-stripe-payment-token"]:checked').val()||c("#payment_method_stripe_sepa").is(":checked")&&c('input[name="wc-stripe_sepa-payment-token"]').is(":checked")&&"new"!==c('input[name="wc-stripe_sepa-payment-token"]:checked').val()},isStripeCardChosen:function(){return c("#payment_method_stripe").is(":checked")},isBancontactChosen:function(){return c("#payment_method_stripe_bancontact").is(":checked")},isGiropayChosen:function(){return c("#payment_method_stripe_giropay").is(":checked")},isIdealChosen:function(){return c("#payment_method_stripe_ideal").is(":checked")},isSofortChosen:function(){return c("#payment_method_stripe_sofort").is(":checked")},isAlipayChosen:function(){return c("#payment_method_stripe_alipay").is(":checked")},isSepaChosen:function(){return c("#payment_method_stripe_sepa").is(":checked")},isP24Chosen:function(){return c("#payment_method_stripe_p24").is(":checked")},isEpsChosen:function(){return c("#payment_method_stripe_eps").is(":checked")},isMultibancoChosen:function(){return c("#payment_method_stripe_multibanco").is(":checked")},hasSource:function(){return 0<c("input.stripe-source").length},isMobile:function(){return!!/Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(navigator.userAgent)},block:function(){m.isMobile()||m.form.block({message:null,overlayCSS:{background:"#fff",opacity:.6}})},unblock:function(){m.form&&m.form.unblock()},getSelectedPaymentElement:function(){return c('.payment_methods input[name="payment_method"]:checked')},getOwnerDetails:function(){var e=c("#billing_first_name").length?c("#billing_first_name").val():wc_stripe_params.billing_first_name,r=c("#billing_last_name").length?c("#billing_last_name").val():wc_stripe_params.billing_last_name,t={name:"",address:{},email:"",phone:""};return t.name=e,t.name=e&&r?e+" "+r:c("#stripe-payment-data").data("full-name"),t.email=c("#billing_email").val(),t.phone=c("#billing_phone").val(),(void 0===t.phone||t.phone.length<=0)&&delete t.phone,(void 0===t.email||t.email.length<=0)&&(c("#stripe-payment-data").data("email").length?t.email=c("#stripe-payment-data").data("email"):delete t.email),(void 0===t.name||t.name.length<=0)&&delete t.name,t.address.line1=c("#billing_address_1").val()||wc_stripe_params.billing_address_1,t.address.line2=c("#billing_address_2").val()||wc_stripe_params.billing_address_2,t.address.state=c("#billing_state").val()||wc_stripe_params.billing_state,t.address.city=c("#billing_city").val()||wc_stripe_params.billing_city,t.address.postal_code=c("#billing_postcode").val()||wc_stripe_params.billing_postcode,t.address.country=c("#billing_country").val()||wc_stripe_params.billing_country,{owner:t}},createSource:function(){var e=m.getOwnerDetails();return m.isSepaChosen()?(e.currency=c("#stripe-sepa_debit-payment-data").data("currency"),e.mandate={notification_method:wc_stripe_params.sepa_mandate_notification},e.type="sepa_debit",o.createSource(s,e).then(m.sourceResponse)):o.createSource(t,e).then(m.sourceResponse)},sourceResponse:function(e){if(e.error)return c(document.body).trigger("stripeError",e);m.reset(),m.form.append(c('<input type="hidden" />').addClass("stripe-source").attr("name","stripe_source").val(e.source.id)),c("form#add_payment_method").length&&c(m.form).off("submit",m.form.onSubmit),m.form.submit()},onSubmit:function(){return!m.isStripeChosen()||(!(!m.isStripeSaveCardChosen()&&!m.hasSource())||(!!(m.isBancontactChosen()||m.isGiropayChosen()||m.isIdealChosen()||m.isAlipayChosen()||m.isSofortChosen()||m.isP24Chosen()||m.isEpsChosen()||m.isMultibancoChosen())||(m.block(),m.createSource(),!1)))},onCCFormChange:function(){m.reset()},reset:function(){c(".wc-stripe-error, .stripe-source").remove()},onSepaError:function(e){var r=m.getSelectedPaymentElement().parents("li").eq(0).find(".stripe-source-errors");if(!e.error)return c(r).html("");console.log(e.error.message),c(r).html('<ul class="woocommerce_error woocommerce-error wc-stripe-error"><li /></ul>'),c(r).find("li").text(e.error.message)},onError:function(e,r){var t,n=r.error.message,o=m.getSelectedPaymentElement().closest("li"),i=o.find(".woocommerce-SavedPaymentMethods-tokenInput");if(i.length){var a=i.filter(":checked");t=a.closest(".woocommerce-SavedPaymentMethods-new").length?c("#wc-stripe-cc-form .stripe-source-errors"):a.closest("li").find(".stripe-source-errors")}else t=o.find(".stripe-source-errors");if(m.isSepaChosen()&&"invalid_owner_name"===r.error.code&&wc_stripe_params.hasOwnProperty(r.error.code)){var s='<ul class="woocommerce-error"><li /></ul>';return s.find("li").text(wc_stripe_params[r.error.code]),m.submitError(s)}"email_invalid"===r.error.code?n=wc_stripe_params.email_invalid:"invalid_request_error"!==r.error.type&&"api_connection_error"!==r.error.type&&"api_error"!==r.error.type&&"authentication_error"!==r.error.type&&"rate_limit_error"!==r.error.type||(n=wc_stripe_params.invalid_request_error),"card_error"===r.error.type&&wc_stripe_params.hasOwnProperty(r.error.code)&&(n=wc_stripe_params[r.error.code]),"validation_error"===r.error.type&&wc_stripe_params.hasOwnProperty(r.error.code)&&(n=wc_stripe_params[r.error.code]),m.reset(),c(".woocommerce-NoticeGroup-checkout").remove(),console.log(r.error.message),c(t).html('<ul class="woocommerce_error woocommerce-error wc-stripe-error"><li /></ul>'),c(t).find("li").text(n),c(".wc-stripe-error").length&&c("html, body").animate({scrollTop:c(".wc-stripe-error").offset().top-200},200),m.unblock(),c.unblockUI()},submitError:function(e){c(".woocommerce-NoticeGroup-checkout, .woocommerce-error, .woocommerce-message").remove(),m.form.prepend('<div class="woocommerce-NoticeGroup woocommerce-NoticeGroup-checkout">'+e+"</div>"),m.form.removeClass("processing").unblock(),m.form.find(".input-text, select, input:checkbox").blur();var r="";c("#add_payment_method").length&&(r=c("#add_payment_method")),c("#order_review").length&&(r=c("#order_review")),c("form.checkout").length&&(r=c("form.checkout")),r.length&&c("html, body").animate({scrollTop:r.offset().top-100},500),c(document.body).trigger("checkout_error"),m.unblock()},onHashChange:function(){var e=window.location.hash.match(/^#?confirm-(pi|si)-([^:]+):(.+)$/);if(e&&!(e.length<4)){var r=e[1],t=e[2],n=decodeURIComponent(e[3]);window.location.hash="",m.openIntentModal(t,n,!1,"si"===r)}},maybeConfirmIntent:function(){if(c("#stripe-intent-id").length&&c("#stripe-intent-return").length){var e=c("#stripe-intent-id").val(),r=c("#stripe-intent-return").val();m.openIntentModal(e,r,!0,!1)}},openIntentModal:function(e,t,r,n){o[n?"handleCardSetup":"handleCardPayment"](e).then(function(e){if(e.error)throw e.error;var r=e[n?"setupIntent":"paymentIntent"];"requires_capture"!==r.status&&"succeeded"!==r.status||(window.location=t)}).catch(function(e){if(r)return window.location=t;c(document.body).trigger("stripeError",{error:e}),m.form&&m.form.removeClass("processing"),c.get(t+"&is_ajax")})},onEarlyRenewalSubmit:function(e){return e.preventDefault(),c.ajax({url:c("#early_renewal_modal_submit").attr("href"),method:"get",success:function(e){var r=c.parseJSON(e);r.stripe_sca_required?m.openIntentModal(r.intent_secret,r.redirect_url,!0,!1):window.location=r.redirect_url}}),!1}};m.init()});
changelog.txt CHANGED
@@ -1,5 +1,12 @@
1
  *** Changelog ***
2
 
 
 
 
 
 
 
 
3
  = 4.3.1 2019-11-12 =
4
  * Fix - Overwrite the previous Apple Pay verification file if it has changed.
5
  * Fix - Avoid re-mounting card elements if they are already mounted in the DOM.
1
  *** Changelog ***
2
 
3
+ = 4.3.2 2020-02-17 =
4
+ * Fix - Add compatibility to payment request buttons with some of the WooCommerce Product Add-ons on the product page
5
+ * Fix - Improved compatibility for free orders with other extensions
6
+ * Add - Support for multisite when sites use different Stripe accounts
7
+ * Fix - Display a localized error message when a customer tries to save a card during checkout, but there's an error
8
+ * Add - Send level 3 credit card data for purchases when possible
9
+
10
  = 4.3.1 2019-11-12 =
11
  * Fix - Overwrite the previous Apple Pay verification file if it has changed.
12
  * Fix - Avoid re-mounting card elements if they are already mounted in the DOM.
includes/abstracts/abstract-wc-stripe-payment-gateway.php CHANGED
@@ -254,7 +254,7 @@ abstract class WC_Stripe_Payment_Gateway extends WC_Payment_Gateway_CC {
254
  * @version 4.0.0
255
  */
256
  public function get_stripe_customer_id( $order ) {
257
- $customer = get_user_meta( WC_Stripe_Helper::is_wc_lt( '3.0' ) ? $order->customer_user : $order->get_customer_id(), '_stripe_customer_id', true );
258
 
259
  if ( empty( $customer ) ) {
260
  // Try to get it via the order.
@@ -291,10 +291,10 @@ abstract class WC_Stripe_Payment_Gateway extends WC_Payment_Gateway_CC {
291
  'order_id' => $order_id,
292
  );
293
 
294
- return esc_url_raw( add_query_arg( $args, $this->get_return_url( $order ) ) );
295
  }
296
 
297
- return esc_url_raw( add_query_arg( array( 'utm_nooverride' => '1' ), $this->get_return_url() ) );
298
  }
299
 
300
  /**
@@ -606,7 +606,7 @@ abstract class WC_Stripe_Payment_Gateway extends WC_Payment_Gateway_CC {
606
  $response = $customer->add_source( $source_object->id );
607
 
608
  if ( ! empty( $response->error ) ) {
609
- throw new WC_Stripe_Exception( print_r( $response, true ), $response->error->message );
610
  }
611
  }
612
  } elseif ( $this->is_using_saved_payment_method() ) {
@@ -1055,6 +1055,66 @@ abstract class WC_Stripe_Payment_Gateway extends WC_Payment_Gateway_CC {
1055
  return apply_filters( 'wc_stripe_generate_create_intent_request', $request, $order, $prepared_source );
1056
  }
1057
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1058
  /**
1059
  * Create a new PaymentIntent.
1060
  *
@@ -1108,7 +1168,13 @@ abstract class WC_Stripe_Payment_Gateway extends WC_Payment_Gateway_CC {
1108
  return $intent;
1109
  }
1110
 
1111
- return WC_Stripe_API::request( $request, "payment_intents/$intent->id" );
 
 
 
 
 
 
1112
  }
1113
 
1114
  /**
@@ -1130,7 +1196,13 @@ abstract class WC_Stripe_Payment_Gateway extends WC_Payment_Gateway_CC {
1130
  'source' => $prepared_source->source,
1131
  );
1132
 
1133
- $confirmed_intent = WC_Stripe_API::request( $confirm_request, "payment_intents/$intent->id/confirm" );
 
 
 
 
 
 
1134
 
1135
  if ( ! empty( $confirmed_intent->error ) ) {
1136
  return $confirmed_intent;
@@ -1315,7 +1387,13 @@ abstract class WC_Stripe_Payment_Gateway extends WC_Payment_Gateway_CC {
1315
  $request['source'] = $full_request['source'];
1316
  }
1317
 
1318
- $intent = WC_Stripe_API::request( $request, 'payment_intents' );
 
 
 
 
 
 
1319
  $is_authentication_required = $this->is_authentication_required_for_payment( $intent );
1320
 
1321
  if ( ! empty( $intent->error ) && ! $is_authentication_required ) {
@@ -1338,4 +1416,14 @@ abstract class WC_Stripe_Payment_Gateway extends WC_Payment_Gateway_CC {
1338
 
1339
  return $intent;
1340
  }
 
 
 
 
 
 
 
 
 
 
1341
  }
254
  * @version 4.0.0
255
  */
256
  public function get_stripe_customer_id( $order ) {
257
+ $customer = get_user_option( '_stripe_customer_id', WC_Stripe_Helper::is_wc_lt( '3.0' ) ? $order->customer_user : $order->get_customer_id() );
258
 
259
  if ( empty( $customer ) ) {
260
  // Try to get it via the order.
291
  'order_id' => $order_id,
292
  );
293
 
294
+ return wp_sanitize_redirect( esc_url_raw( add_query_arg( $args, $this->get_return_url( $order ) ) ) );
295
  }
296
 
297
+ return wp_sanitize_redirect( esc_url_raw( add_query_arg( array( 'utm_nooverride' => '1' ), $this->get_return_url() ) ) );
298
  }
299
 
300
  /**
606
  $response = $customer->add_source( $source_object->id );
607
 
608
  if ( ! empty( $response->error ) ) {
609
+ throw new WC_Stripe_Exception( print_r( $response, true ), $this->get_localized_error_message_from_response( $response ) );
610
  }
611
  }
612
  } elseif ( $this->is_using_saved_payment_method() ) {
1055
  return apply_filters( 'wc_stripe_generate_create_intent_request', $request, $order, $prepared_source );
1056
  }
1057
 
1058
+ /**
1059
+ * Create the level 3 data array to send to Stripe when making a purchase.
1060
+ *
1061
+ * @param WC_Order $order The order that is being paid for.
1062
+ * @return array The level 3 data to send to Stripe.
1063
+ */
1064
+ public function get_level3_data_from_order( $order ) {
1065
+ // WC Versions before 3.0 don't support postcodes and are
1066
+ // incompatible with level3 data.
1067
+ if ( WC_Stripe_Helper::is_wc_lt( '3.0' ) ) {
1068
+ return array();
1069
+ }
1070
+
1071
+ // Get the order items. Don't need their keys, only their values.
1072
+ // Order item IDs are used as keys in the original order items array.
1073
+ $order_items = array_values( $order->get_items() );
1074
+ $currency = $order->get_currency();
1075
+
1076
+ $stripe_line_items = array_map(function( $item ) use ( $currency ) {
1077
+ $product_id = $item->get_variation_id()
1078
+ ? $item->get_variation_id()
1079
+ : $item->get_product_id();
1080
+ $product_description = substr( $item->get_name(), 0, 26 );
1081
+ $quantity = $item->get_quantity();
1082
+ $unit_cost = WC_Stripe_Helper::get_stripe_amount( ( $item->get_subtotal() / $quantity ), $currency );
1083
+ $tax_amount = WC_Stripe_Helper::get_stripe_amount( $item->get_total_tax(), $currency );
1084
+ $discount_amount = WC_Stripe_Helper::get_stripe_amount( $item->get_subtotal() - $item->get_total(), $currency );
1085
+
1086
+ return (object) array(
1087
+ 'product_code' => (string) $product_id, // Up to 12 characters that uniquely identify the product.
1088
+ 'product_description' => $product_description, // Up to 26 characters long describing the product.
1089
+ 'unit_cost' => $unit_cost, // Cost of the product, in cents, as a non-negative integer.
1090
+ 'quantity' => $quantity, // The number of items of this type sold, as a non-negative integer.
1091
+ 'tax_amount' => $tax_amount, // The amount of tax this item had added to it, in cents, as a non-negative integer.
1092
+ 'discount_amount' => $discount_amount, // The amount an item was discounted—if there was a sale,for example, as a non-negative integer.
1093
+ );
1094
+ }, $order_items);
1095
+
1096
+ $level3_data = array(
1097
+ 'merchant_reference' => $order->get_id(), // An alphanumeric string of up to characters in length. This unique value is assigned by the merchant to identify the order. Also known as an “Order ID”.
1098
+
1099
+ 'shipping_amount' => WC_Stripe_Helper::get_stripe_amount( $order->get_shipping_total() + $order->get_shipping_tax(), $currency), // The shipping cost, in cents, as a non-negative integer.
1100
+ 'line_items' => $stripe_line_items,
1101
+ );
1102
+
1103
+ // The customer’s U.S. shipping ZIP code.
1104
+ $shipping_address_zip = $order->get_shipping_postcode();
1105
+ if ( $this->is_valid_us_zip_code( $shipping_address_zip ) ) {
1106
+ $level3_data['shipping_address_zip'] = $shipping_address_zip;
1107
+ }
1108
+
1109
+ // The merchant’s U.S. shipping ZIP code.
1110
+ $store_postcode = get_option( 'woocommerce_store_postcode' );
1111
+ if ( $this->is_valid_us_zip_code( $store_postcode ) ) {
1112
+ $level3_data['shipping_from_zip'] = $store_postcode;
1113
+ }
1114
+
1115
+ return $level3_data;
1116
+ }
1117
+
1118
  /**
1119
  * Create a new PaymentIntent.
1120
  *
1168
  return $intent;
1169
  }
1170
 
1171
+ $level3_data = $this->get_level3_data_from_order( $order );
1172
+ return WC_Stripe_API::request_with_level3_data(
1173
+ $request,
1174
+ "payment_intents/$intent->id",
1175
+ $level3_data,
1176
+ $order
1177
+ );
1178
  }
1179
 
1180
  /**
1196
  'source' => $prepared_source->source,
1197
  );
1198
 
1199
+ $level3_data = $this->get_level3_data_from_order( $order );
1200
+ $confirmed_intent = WC_Stripe_API::request_with_level3_data(
1201
+ $confirm_request,
1202
+ "payment_intents/$intent->id/confirm",
1203
+ $level3_data,
1204
+ $order
1205
+ );
1206
 
1207
  if ( ! empty( $confirmed_intent->error ) ) {
1208
  return $confirmed_intent;
1387
  $request['source'] = $full_request['source'];
1388
  }
1389
 
1390
+ $level3_data = $this->get_level3_data_from_order( $order );
1391
+ $intent = WC_Stripe_API::request_with_level3_data(
1392
+ $request,
1393
+ 'payment_intents',
1394
+ $level3_data,
1395
+ $order
1396
+ );
1397
  $is_authentication_required = $this->is_authentication_required_for_payment( $intent );
1398
 
1399
  if ( ! empty( $intent->error ) && ! $is_authentication_required ) {
1416
 
1417
  return $intent;
1418
  }
1419
+
1420
+ /**
1421
+ * Verifies whether a certain ZIP code is valid for the US, incl. 4-digit extensions.
1422
+ *
1423
+ * @param string $zip The ZIP code to verify.
1424
+ * @return boolean
1425
+ */
1426
+ public function is_valid_us_zip_code( $zip ) {
1427
+ return ! empty( $zip ) && preg_match( '/^\d{5,5}(-\d{4,4})?$/', $zip );
1428
+ }
1429
  }
includes/admin/class-wc-stripe-admin-notices.php CHANGED
@@ -100,21 +100,22 @@ class WC_Stripe_Admin_Notices {
100
  * @version 4.0.0
101
  */
102
  public function stripe_check_environment() {
103
- $show_style_notice = get_option( 'wc_stripe_show_style_notice' );
104
- $show_ssl_notice = get_option( 'wc_stripe_show_ssl_notice' );
105
- $show_keys_notice = get_option( 'wc_stripe_show_keys_notice' );
106
- $show_3ds_notice = get_option( 'wc_stripe_show_3ds_notice' );
107
- $show_phpver_notice = get_option( 'wc_stripe_show_phpver_notice' );
108
- $show_wcver_notice = get_option( 'wc_stripe_show_wcver_notice' );
109
- $show_curl_notice = get_option( 'wc_stripe_show_curl_notice' );
110
- $show_sca_notice = get_option( 'wc_stripe_show_sca_notice' );
111
- $options = get_option( 'woocommerce_stripe_settings' );
112
- $testmode = ( isset( $options['testmode'] ) && 'yes' === $options['testmode'] ) ? true : false;
113
- $test_pub_key = isset( $options['test_publishable_key'] ) ? $options['test_publishable_key'] : '';
114
- $test_secret_key = isset( $options['test_secret_key'] ) ? $options['test_secret_key'] : '';
115
- $live_pub_key = isset( $options['publishable_key'] ) ? $options['publishable_key'] : '';
116
- $live_secret_key = isset( $options['secret_key'] ) ? $options['secret_key'] : '';
117
- $three_d_secure = isset( $options['three_d_secure'] ) && 'yes' === $options['three_d_secure'];
 
118
 
119
  if ( isset( $options['enabled'] ) && 'yes' === $options['enabled'] ) {
120
  if ( empty( $show_3ds_notice ) && $three_d_secure ) {
@@ -205,6 +206,11 @@ class WC_Stripe_Admin_Notices {
205
  if ( empty( $show_sca_notice ) ) {
206
  $this->add_admin_notice( 'sca', 'notice notice-success', sprintf( __( 'Stripe is now ready for Strong Customer Authentication (SCA) and 3D Secure 2! <a href="%1$s" target="_blank">Read about SCA</a>', 'woocommerce-gateway-stripe' ), 'https://woocommerce.com/posts/introducing-strong-customer-authentication-sca/' ), true );
207
  }
 
 
 
 
 
208
  }
209
  }
210
 
@@ -301,6 +307,8 @@ class WC_Stripe_Admin_Notices {
301
  case 'sca':
302
  update_option( 'wc_stripe_show_sca_notice', 'no' );
303
  break;
 
 
304
  }
305
  }
306
  }
100
  * @version 4.0.0
101
  */
102
  public function stripe_check_environment() {
103
+ $show_style_notice = get_option( 'wc_stripe_show_style_notice' );
104
+ $show_ssl_notice = get_option( 'wc_stripe_show_ssl_notice' );
105
+ $show_keys_notice = get_option( 'wc_stripe_show_keys_notice' );
106
+ $show_3ds_notice = get_option( 'wc_stripe_show_3ds_notice' );
107
+ $show_phpver_notice = get_option( 'wc_stripe_show_phpver_notice' );
108
+ $show_wcver_notice = get_option( 'wc_stripe_show_wcver_notice' );
109
+ $show_curl_notice = get_option( 'wc_stripe_show_curl_notice' );
110
+ $show_sca_notice = get_option( 'wc_stripe_show_sca_notice' );
111
+ $changed_keys_notice = get_option( 'wc_stripe_show_changed_keys_notice' );
112
+ $options = get_option( 'woocommerce_stripe_settings' );
113
+ $testmode = ( isset( $options['testmode'] ) && 'yes' === $options['testmode'] ) ? true : false;
114
+ $test_pub_key = isset( $options['test_publishable_key'] ) ? $options['test_publishable_key'] : '';
115
+ $test_secret_key = isset( $options['test_secret_key'] ) ? $options['test_secret_key'] : '';
116
+ $live_pub_key = isset( $options['publishable_key'] ) ? $options['publishable_key'] : '';
117
+ $live_secret_key = isset( $options['secret_key'] ) ? $options['secret_key'] : '';
118
+ $three_d_secure = isset( $options['three_d_secure'] ) && 'yes' === $options['three_d_secure'];
119
 
120
  if ( isset( $options['enabled'] ) && 'yes' === $options['enabled'] ) {
121
  if ( empty( $show_3ds_notice ) && $three_d_secure ) {
206
  if ( empty( $show_sca_notice ) ) {
207
  $this->add_admin_notice( 'sca', 'notice notice-success', sprintf( __( 'Stripe is now ready for Strong Customer Authentication (SCA) and 3D Secure 2! <a href="%1$s" target="_blank">Read about SCA</a>', 'woocommerce-gateway-stripe' ), 'https://woocommerce.com/posts/introducing-strong-customer-authentication-sca/' ), true );
208
  }
209
+
210
+ if ( 'yes' === $changed_keys_notice ) {
211
+ // translators: %s is a the URL for the link.
212
+ $this->add_admin_notice( 'changed_keys', 'notice notice-warning', sprintf( __( 'The public and/or secret keys for the Stripe gateway have been changed. This might cause errors for existing customers and saved payment methods. <a href="%s" target="_blank">Click here to learn more</a>.', 'woocommerce-gateway-stripe' ), 'https://docs.woocommerce.com/document/stripe-fixing-customer-errors/' ), true );
213
+ }
214
  }
215
  }
216
 
307
  case 'sca':
308
  update_option( 'wc_stripe_show_sca_notice', 'no' );
309
  break;
310
+ case 'changed_keys':
311
+ update_option( 'wc_stripe_show_changed_keys_notice', 'no' );
312
  }
313
  }
314
  }
includes/admin/class-wc-stripe-privacy.php CHANGED
@@ -225,7 +225,7 @@ class WC_Stripe_Privacy extends WC_Abstract_Privacy {
225
  'data' => array(
226
  array(
227
  'name' => __( 'Stripe payment id', 'woocommerce-gateway-stripe' ),
228
- 'value' => get_user_meta( $user->ID, '_stripe_source_id', true ),
229
  ),
230
  array(
231
  'name' => __( 'Stripe customer id', 'woocommerce-gateway-stripe' ),
@@ -255,8 +255,8 @@ class WC_Stripe_Privacy extends WC_Abstract_Privacy {
255
  $stripe_source_id = '';
256
 
257
  if ( $user instanceof WP_User ) {
258
- $stripe_customer_id = get_user_meta( $user->ID, '_stripe_customer_id', true );
259
- $stripe_source_id = get_user_meta( $user->ID, '_stripe_source_id', true );
260
  }
261
 
262
  $items_removed = false;
@@ -264,8 +264,8 @@ class WC_Stripe_Privacy extends WC_Abstract_Privacy {
264
 
265
  if ( ! empty( $stripe_customer_id ) || ! empty( $stripe_source_id ) ) {
266
  $items_removed = true;
267
- delete_user_meta( $user->ID, '_stripe_customer_id' );
268
- delete_user_meta( $user->ID, '_stripe_source_id' );
269
  $messages[] = __( 'Stripe User Data Erased.', 'woocommerce-gateway-stripe' );
270
  }
271
 
225
  'data' => array(
226
  array(
227
  'name' => __( 'Stripe payment id', 'woocommerce-gateway-stripe' ),
228
+ 'value' => get_user_option( '_stripe_source_id', $user->ID ),
229
  ),
230
  array(
231
  'name' => __( 'Stripe customer id', 'woocommerce-gateway-stripe' ),
255
  $stripe_source_id = '';
256
 
257
  if ( $user instanceof WP_User ) {
258
+ $stripe_customer_id = get_user_option( '_stripe_customer_id', $user->ID );
259
+ $stripe_source_id = get_user_option( '_stripe_source_id', $user->ID );
260
  }
261
 
262
  $items_removed = false;
264
 
265
  if ( ! empty( $stripe_customer_id ) || ! empty( $stripe_source_id ) ) {
266
  $items_removed = true;
267
+ delete_user_option( $user->ID, '_stripe_customer_id' );
268
+ delete_user_option( $user->ID, '_stripe_source_id' );
269
  $messages[] = __( 'Stripe User Data Erased.', 'woocommerce-gateway-stripe' );
270
  }
271
 
includes/admin/stripe-eps-settings.php CHANGED
@@ -36,7 +36,7 @@ return apply_filters(
36
  'desc_tip' => true,
37
  ),
38
  'webhook' => array(
39
- 'title' => __( 'Webhook Enpoints', 'woocommerce-gateway-stripe' ),
40
  'type' => 'title',
41
  /* translators: webhook URL */
42
  'description' => $this->display_admin_settings_webhook_description(),
36
  'desc_tip' => true,
37
  ),
38
  'webhook' => array(
39
+ 'title' => __( 'Webhook Endpoints', 'woocommerce-gateway-stripe' ),
40
  'type' => 'title',
41
  /* translators: webhook URL */
42
  'description' => $this->display_admin_settings_webhook_description(),
includes/class-wc-gateway-stripe.php CHANGED
@@ -372,7 +372,16 @@ class WC_Gateway_Stripe extends WC_Stripe_Payment_Gateway {
372
  * @version 4.0.0
373
  */
374
  public function payment_scripts() {
375
- if ( ! is_product() && ! is_cart() && ! is_checkout() && ! isset( $_GET['pay_for_order'] ) && ! is_add_payment_method_page() && ! isset( $_GET['change_payment_method'] ) || ( is_order_received_page() ) ) { // wpcs: csrf ok.
 
 
 
 
 
 
 
 
 
376
  return;
377
  }
378
 
@@ -511,10 +520,10 @@ class WC_Gateway_Stripe extends WC_Stripe_Payment_Gateway {
511
  }
512
 
513
  if ( WC_Stripe_Helper::is_wc_lt( '3.0' ) ) {
514
- delete_user_meta( $order->customer_user, '_stripe_customer_id' );
515
  delete_post_meta( $order->get_id(), '_stripe_customer_id' );
516
  } else {
517
- delete_user_meta( $order->get_customer_id(), '_stripe_customer_id' );
518
  $order->delete_meta_data( '_stripe_customer_id' );
519
  $order->save();
520
  }
@@ -532,17 +541,16 @@ class WC_Gateway_Stripe extends WC_Stripe_Payment_Gateway {
532
  * @return array Redirection data for `process_payment`.
533
  */
534
  public function complete_free_order( $order, $prepared_source, $force_save_source ) {
535
- $response = array(
536
- 'result' => 'success',
537
- 'redirect' => $this->get_return_url( $order ),
538
- );
539
-
540
  if ( $force_save_source ) {
541
  $intent_secret = $this->setup_intent( $order, $prepared_source );
542
 
543
  if ( ! empty( $intent_secret ) ) {
544
- $response['setup_intent_secret'] = $intent_secret;
545
- return $response;
 
 
 
 
546
  }
547
  }
548
 
@@ -552,7 +560,10 @@ class WC_Gateway_Stripe extends WC_Stripe_Payment_Gateway {
552
  $order->payment_complete();
553
 
554
  // Return thank you page redirect.
555
- return $response;
 
 
 
556
  }
557
 
558
  /**
@@ -564,11 +575,12 @@ class WC_Gateway_Stripe extends WC_Stripe_Payment_Gateway {
564
  * @param bool $retry Should we retry on fail.
565
  * @param bool $force_save_source Force save the payment source.
566
  * @param mix $previous_error Any error message from previous request.
 
567
  *
568
  * @throws Exception If payment will not be accepted.
569
  * @return array|void
570
  */
571
- public function process_payment( $order_id, $retry = true, $force_save_source = false, $previous_error = false ) {
572
  try {
573
  $order = wc_get_order( $order_id );
574
 
@@ -589,7 +601,12 @@ class WC_Gateway_Stripe extends WC_Stripe_Payment_Gateway {
589
  $stripe_customer_id = $intent->customer;
590
  }
591
 
592
- $prepared_source = $this->prepare_source( get_current_user_id(), $force_save_source, $stripe_customer_id );
 
 
 
 
 
593
 
594
  $this->maybe_disallow_prepaid_card( $prepared_source );
595
  $this->check_source( $prepared_source );
@@ -621,7 +638,7 @@ class WC_Gateway_Stripe extends WC_Stripe_Payment_Gateway {
621
 
622
  // We want to retry.
623
  if ( $this->is_retryable_error( $intent->error ) ) {
624
- return $this->retry_after_error( $intent, $order, $retry, $force_save_source, $previous_error );
625
  }
626
 
627
  $this->unlock_order_payment( $order );
@@ -767,14 +784,15 @@ class WC_Gateway_Stripe extends WC_Stripe_Payment_Gateway {
767
  }
768
 
769
  /**
770
- * Generates a localized message for an error, adds it as a note and throws it.
771
  *
772
- * @since 4.2.0
773
- * @param stdClass $response The response from the Stripe API.
774
- * @param WC_Order $order The order to add a note to.
775
- * @throws WC_Stripe_Exception An exception with the right message.
 
776
  */
777
- public function throw_localized_message( $response, $order ) {
778
  $localized_messages = WC_Stripe_Helper::get_localized_messages();
779
 
780
  if ( 'card_error' === $response->error->type ) {
@@ -783,6 +801,20 @@ class WC_Gateway_Stripe extends WC_Stripe_Payment_Gateway {
783
  $localized_message = isset( $localized_messages[ $response->error->type ] ) ? $localized_messages[ $response->error->type ] : $response->error->message;
784
  }
785
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
786
  $order->add_order_note( $localized_message );
787
 
788
  throw new WC_Stripe_Exception( print_r( $response, true ), $localized_message );
@@ -796,11 +828,12 @@ class WC_Gateway_Stripe extends WC_Stripe_Payment_Gateway {
796
  * @param WC_Order $order An order that is being paid for.
797
  * @param bool $retry A flag that indicates whether another retry should be attempted.
798
  * @param bool $force_save_source Force save the payment source.
799
- * @param mixed $previous_error Any error message from previous request.
 
800
  * @throws WC_Stripe_Exception If the payment is not accepted.
801
  * @return array|void
802
  */
803
- public function retry_after_error( $response, $order, $retry, $force_save_source, $previous_error ) {
804
  if ( ! $retry ) {
805
  $localized_message = __( 'Sorry, we are unable to process your payment at this time. Please retry later.', 'woocommerce-gateway-stripe' );
806
  $order->add_order_note( $localized_message );
@@ -815,7 +848,7 @@ class WC_Gateway_Stripe extends WC_Stripe_Payment_Gateway {
815
  sleep( $this->retry_interval );
816
  $this->retry_interval++;
817
 
818
- return $this->process_payment( $order->get_id(), true, $force_save_source, $response->error, $previous_error );
819
  }
820
 
821
  /**
@@ -878,9 +911,16 @@ class WC_Gateway_Stripe extends WC_Stripe_Payment_Gateway {
878
 
879
  if ( 'requires_payment_method' === $intent->status && isset( $intent->last_payment_error )
880
  && 'authentication_required' === $intent->last_payment_error->code ) {
881
- $intent = WC_Stripe_API::request( array(
882
- 'payment_method' => $intent->last_payment_error->source->id,
883
- ), 'payment_intents/' . $intent->id . '/confirm' );
 
 
 
 
 
 
 
884
  if ( isset( $intent->error ) ) {
885
  throw new WC_Stripe_Exception( print_r( $intent, true ), $intent->error->message );
886
  }
@@ -1042,15 +1082,37 @@ class WC_Gateway_Stripe extends WC_Stripe_Payment_Gateway {
1042
  }
1043
  } else if ( 'succeeded' === $intent->status || 'requires_capture' === $intent->status ) {
1044
  // Proceed with the payment completion.
1045
- $this->process_response( end( $intent->charges->data ), $order );
1046
  } else if ( 'requires_payment_method' === $intent->status ) {
1047
  // `requires_payment_method` means that SCA got denied for the current payment method.
1048
- $this->failed_sca_auth( $order, $intent );
1049
  }
1050
 
1051
  $this->unlock_order_payment( $order );
1052
  }
1053
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1054
  /**
1055
  * Checks if the payment intent associated with an order failed and records the event.
1056
  *
@@ -1087,4 +1149,38 @@ class WC_Gateway_Stripe extends WC_Stripe_Payment_Gateway {
1087
  }
1088
  return $pay_url;
1089
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1090
  }
372
  * @version 4.0.0
373
  */
374
  public function payment_scripts() {
375
+ if (
376
+ ! is_product()
377
+ && ! is_cart()
378
+ && ! is_checkout()
379
+ && ! isset( $_GET['pay_for_order'] ) // wpcs: csrf ok.
380
+ && ! is_add_payment_method_page()
381
+ && ! isset( $_GET['change_payment_method'] ) // wpcs: csrf ok.
382
+ && ! ( ! empty( get_query_var( 'view-subscription' ) ) && class_exists( 'WCS_Early_Renewal_Manager' ) && WCS_Early_Renewal_Manager::is_early_renewal_via_modal_enabled() )
383
+ || ( is_order_received_page() )
384
+ ) {
385
  return;
386
  }
387
 
520
  }
521
 
522
  if ( WC_Stripe_Helper::is_wc_lt( '3.0' ) ) {
523
+ delete_user_option( $order->customer_user, '_stripe_customer_id' );
524
  delete_post_meta( $order->get_id(), '_stripe_customer_id' );
525
  } else {
526
+ delete_user_option( $order->get_customer_id(), '_stripe_customer_id' );
527
  $order->delete_meta_data( '_stripe_customer_id' );
528
  $order->save();
529
  }
541
  * @return array Redirection data for `process_payment`.
542
  */
543
  public function complete_free_order( $order, $prepared_source, $force_save_source ) {
 
 
 
 
 
544
  if ( $force_save_source ) {
545
  $intent_secret = $this->setup_intent( $order, $prepared_source );
546
 
547
  if ( ! empty( $intent_secret ) ) {
548
+ // `get_return_url()` must be called immediately before returning a value.
549
+ return array(
550
+ 'result' => 'success',
551
+ 'redirect' => $this->get_return_url( $order ),
552
+ 'setup_intent_secret' => $intent_secret,
553
+ );
554
  }
555
  }
556
 
560
  $order->payment_complete();
561
 
562
  // Return thank you page redirect.
563
+ return array(
564
+ 'result' => 'success',
565
+ 'redirect' => $this->get_return_url( $order ),
566
+ );
567
  }
568
 
569
  /**
575
  * @param bool $retry Should we retry on fail.
576
  * @param bool $force_save_source Force save the payment source.
577
  * @param mix $previous_error Any error message from previous request.
578
+ * @param bool $use_order_source Whether to use the source, which should already be attached to the order.
579
  *
580
  * @throws Exception If payment will not be accepted.
581
  * @return array|void
582
  */
583
+ public function process_payment( $order_id, $retry = true, $force_save_source = false, $previous_error = false, $use_order_source = false ) {
584
  try {
585
  $order = wc_get_order( $order_id );
586
 
601
  $stripe_customer_id = $intent->customer;
602
  }
603
 
604
+ // For some payments the source should already be present in the order.
605
+ if ( $use_order_source ) {
606
+ $prepared_source = $this->prepare_order_source( $order );
607
+ } else {
608
+ $prepared_source = $this->prepare_source( get_current_user_id(), $force_save_source, $stripe_customer_id );
609
+ }
610
 
611
  $this->maybe_disallow_prepaid_card( $prepared_source );
612
  $this->check_source( $prepared_source );
638
 
639
  // We want to retry.
640
  if ( $this->is_retryable_error( $intent->error ) ) {
641
+ return $this->retry_after_error( $intent, $order, $retry, $force_save_source, $previous_error, $use_order_source );
642
  }
643
 
644
  $this->unlock_order_payment( $order );
784
  }
785
 
786
  /**
787
+ * Generates a localized message for an error from a response.
788
  *
789
+ * @since 4.3.2
790
+ *
791
+ * @param stdClass $response The response from the Stripe API.
792
+ *
793
+ * @return string The localized error message.
794
  */
795
+ public function get_localized_error_message_from_response( $response ) {
796
  $localized_messages = WC_Stripe_Helper::get_localized_messages();
797
 
798
  if ( 'card_error' === $response->error->type ) {
801
  $localized_message = isset( $localized_messages[ $response->error->type ] ) ? $localized_messages[ $response->error->type ] : $response->error->message;
802
  }
803
 
804
+ return $localized_message;
805
+ }
806
+
807
+ /**
808
+ * Gets a localized message for an error from a response, adds it as a note to the order, and throws it.
809
+ *
810
+ * @since 4.2.0
811
+ * @param stdClass $response The response from the Stripe API.
812
+ * @param WC_Order $order The order to add a note to.
813
+ * @throws WC_Stripe_Exception An exception with the right message.
814
+ */
815
+ public function throw_localized_message( $response, $order ) {
816
+ $localized_message = $this->get_localized_error_message_from_response( $response );
817
+
818
  $order->add_order_note( $localized_message );
819
 
820
  throw new WC_Stripe_Exception( print_r( $response, true ), $localized_message );
828
  * @param WC_Order $order An order that is being paid for.
829
  * @param bool $retry A flag that indicates whether another retry should be attempted.
830
  * @param bool $force_save_source Force save the payment source.
831
+ * @param mixed $previous_error Any error message from previous request.
832
+ * @param bool $use_order_source Whether to use the source, which should already be attached to the order.
833
  * @throws WC_Stripe_Exception If the payment is not accepted.
834
  * @return array|void
835
  */
836
+ public function retry_after_error( $response, $order, $retry, $force_save_source, $previous_error, $use_order_source ) {
837
  if ( ! $retry ) {
838
  $localized_message = __( 'Sorry, we are unable to process your payment at this time. Please retry later.', 'woocommerce-gateway-stripe' );
839
  $order->add_order_note( $localized_message );
848
  sleep( $this->retry_interval );
849
  $this->retry_interval++;
850
 
851
+ return $this->process_payment( $order->get_id(), true, $force_save_source, $response->error, $previous_error, $use_order_source );
852
  }
853
 
854
  /**
911
 
912
  if ( 'requires_payment_method' === $intent->status && isset( $intent->last_payment_error )
913
  && 'authentication_required' === $intent->last_payment_error->code ) {
914
+ $level3_data = $this->get_level3_data_from_order( $order );
915
+ $intent = WC_Stripe_API::request_with_level3_data(
916
+ array(
917
+ 'payment_method' => $intent->last_payment_error->source->id,
918
+ ),
919
+ 'payment_intents/' . $intent->id . '/confirm',
920
+ $level3_data,
921
+ $order
922
+ );
923
+
924
  if ( isset( $intent->error ) ) {
925
  throw new WC_Stripe_Exception( print_r( $intent, true ), $intent->error->message );
926
  }
1082
  }
1083
  } else if ( 'succeeded' === $intent->status || 'requires_capture' === $intent->status ) {
1084
  // Proceed with the payment completion.
1085
+ $this->handle_intent_verification_success( $order, $intent );
1086
  } else if ( 'requires_payment_method' === $intent->status ) {
1087
  // `requires_payment_method` means that SCA got denied for the current payment method.
1088
+ $this->handle_intent_verification_failure( $order, $intent );
1089
  }
1090
 
1091
  $this->unlock_order_payment( $order );
1092
  }
1093
 
1094
+ /**
1095
+ * Called after an intent verification succeeds, this allows
1096
+ * specific APNs or children of this class to modify its behavior.
1097
+ *
1098
+ * @param WC_Order $order The order whose verification succeeded.
1099
+ * @param stdClass $intent The Payment Intent object.
1100
+ */
1101
+ protected function handle_intent_verification_success( $order, $intent ) {
1102
+ $this->process_response( end( $intent->charges->data ), $order );
1103
+ }
1104
+
1105
+ /**
1106
+ * Called after an intent verification fails, this allows
1107
+ * specific APNs or children of this class to modify its behavior.
1108
+ *
1109
+ * @param WC_Order $order The order whose verification failed.
1110
+ * @param stdClass $intent The Payment Intent object.
1111
+ */
1112
+ protected function handle_intent_verification_failure( $order, $intent ) {
1113
+ $this->failed_sca_auth( $order, $intent );
1114
+ }
1115
+
1116
  /**
1117
  * Checks if the payment intent associated with an order failed and records the event.
1118
  *
1149
  }
1150
  return $pay_url;
1151
  }
1152
+
1153
+ /**
1154
+ * Checks whether new keys are being entered when saving options.
1155
+ */
1156
+ public function process_admin_options() {
1157
+ // Load all old values before the new settings get saved.
1158
+ $old_publishable_key = $this->get_option( 'publishable_key' );
1159
+ $old_secret_key = $this->get_option( 'secret_key' );
1160
+ $old_test_publishable_key = $this->get_option( 'test_publishable_key' );
1161
+ $old_test_secret_key = $this->get_option( 'test_secret_key' );
1162
+
1163
+ parent::process_admin_options();
1164
+
1165
+ // Load all old values after the new settings have been saved.
1166
+ $new_publishable_key = $this->get_option( 'publishable_key' );
1167
+ $new_secret_key = $this->get_option( 'secret_key' );
1168
+ $new_test_publishable_key = $this->get_option( 'test_publishable_key' );
1169
+ $new_test_secret_key = $this->get_option( 'test_secret_key' );
1170
+
1171
+ // Checks whether a value has transitioned from a non-empty value to a new one.
1172
+ $has_changed = function( $old_value, $new_value ) {
1173
+ return ! empty( $old_value ) && ( $old_value !== $new_value );
1174
+ };
1175
+
1176
+ // Look for updates.
1177
+ if (
1178
+ $has_changed( $old_publishable_key, $new_publishable_key )
1179
+ || $has_changed( $old_secret_key, $new_secret_key )
1180
+ || $has_changed( $old_test_publishable_key, $new_test_publishable_key )
1181
+ || $has_changed( $old_test_secret_key, $new_test_secret_key )
1182
+ ) {
1183
+ update_option( 'wc_stripe_show_changed_keys_notice', 'yes' );
1184
+ }
1185
+ }
1186
  }
includes/class-wc-stripe-api.php CHANGED
@@ -176,4 +176,90 @@ class WC_Stripe_API {
176
 
177
  return json_decode( $response['body'] );
178
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
179
  }
176
 
177
  return json_decode( $response['body'] );
178
  }
179
+
180
+ /**
181
+ * Send the request to Stripe's API with level 3 data generated
182
+ * from the order. If the request fails due to an error related
183
+ * to level3 data, make the request again without it to allow
184
+ * the payment to go through.
185
+ *
186
+ * @since 4.3.2
187
+ * @version 4.3.2
188
+ *
189
+ * @param array $request Array with request parameters.
190
+ * @param string $api The API path for the request.
191
+ * @param array $level3_data The level 3 data for this request.
192
+ * @param WC_Order $order The order associated with the payment.
193
+ *
194
+ * @return stdClass|array The response
195
+ */
196
+ public static function request_with_level3_data( $request, $api, $level3_data, $order ) {
197
+ // Do not add level3 data it's the array is empty.
198
+ if ( empty( $level3_data ) ) {
199
+ return self::request(
200
+ $request,
201
+ $api
202
+ );
203
+ }
204
+
205
+ // If there's a transient indicating that level3 data was not accepted by
206
+ // Stripe in the past for this account, do not try to add level3 data.
207
+ if ( get_transient( 'wc_stripe_level3_not_allowed' ) ) {
208
+ return self::request(
209
+ $request,
210
+ $api
211
+ );
212
+ }
213
+
214
+ // Add level 3 data to the request.
215
+ $request['level3'] = $level3_data;
216
+
217
+ $result = self::request(
218
+ $request,
219
+ $api
220
+ );
221
+
222
+ $is_level3_param_not_allowed = (
223
+ isset( $result->error )
224
+ && isset( $result->error->code )
225
+ && 'parameter_unknown' === $result->error->code
226
+ && isset( $result->error->param )
227
+ && 'level3' === $result->error->param
228
+ );
229
+
230
+ $is_level_3data_incorrect = (
231
+ isset( $result->error )
232
+ && isset( $result->error->type )
233
+ && 'invalid_request_error' === $result->error->type
234
+ );
235
+
236
+ if ( $is_level3_param_not_allowed ) {
237
+ // Set a transient so that future requests do not add level 3 data.
238
+ // Transient is set to expire in 3 months, can be manually removed if needed.
239
+ set_transient( 'wc_stripe_level3_not_allowed', true, 3 * MONTH_IN_SECONDS );
240
+ } else if ( $is_level_3data_incorrect ) {
241
+ // Log the issue so we could debug it.
242
+ WC_Stripe_Logger::log(
243
+ 'Level3 data sum incorrect: ' . PHP_EOL
244
+ . print_r( $result->error->message, true ) . PHP_EOL
245
+ . print_r( 'Order line items: ', true ) . PHP_EOL
246
+ . print_r( $order->get_items(), true ) . PHP_EOL
247
+ . print_r( 'Order shipping amount: ', true ) . PHP_EOL
248
+ . print_r( $order->get_shipping_total(), true ) . PHP_EOL
249
+ . print_r( 'Order currency: ', true ) . PHP_EOL
250
+ . print_r( $order->get_currency(), true )
251
+ );
252
+ }
253
+
254
+ // Make the request again without level 3 data.
255
+ if ( $is_level3_param_not_allowed || $is_level_3data_incorrect ) {
256
+ unset( $request['level3'] );
257
+ return WC_Stripe_API::request(
258
+ $request,
259
+ $api
260
+ );
261
+ }
262
+
263
+ return $result;
264
+ }
265
  }
includes/class-wc-stripe-customer.php CHANGED
@@ -35,7 +35,7 @@ class WC_Stripe_Customer {
35
  public function __construct( $user_id = 0 ) {
36
  if ( $user_id ) {
37
  $this->set_user_id( $user_id );
38
- $this->set_id( get_user_meta( $user_id, '_stripe_customer_id', true ) );
39
  }
40
  }
41
 
@@ -56,7 +56,7 @@ class WC_Stripe_Customer {
56
  if ( is_array( $id ) && isset( $id['customer_id'] ) ) {
57
  $id = $id['customer_id'];
58
 
59
- update_user_meta( $this->get_user_id(), '_stripe_customer_id', $id );
60
  }
61
 
62
  $this->id = wc_clean( $id );
@@ -161,7 +161,7 @@ class WC_Stripe_Customer {
161
  $this->set_customer_data( $response );
162
 
163
  if ( $this->get_user_id() ) {
164
- update_user_meta( $this->get_user_id(), '_stripe_customer_id', $response->id );
165
  }
166
 
167
  do_action( 'woocommerce_stripe_add_customer', $args, $response );
@@ -175,15 +175,35 @@ class WC_Stripe_Customer {
175
  * @param array $args Additional arguments for the request (optional).
176
  */
177
  public function update_customer( $args = array() ) {
178
- if ( empty( $this->id ) ) {
179
  throw new WC_Stripe_Exception( 'id_required_to_update_user', __( 'Attempting to update a Stripe customer without a customer ID.', 'woocommerce-gateway-stripe' ) );
180
  }
181
 
182
  $args = $this->generate_customer_request( $args );
183
  $args = apply_filters( 'wc_stripe_update_customer_args', $args );
184
- $response = WC_Stripe_API::request( $args, 'customers/' . $this->id );
185
 
186
  if ( ! empty( $response->error ) ) {
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
187
  throw new WC_Stripe_Exception( print_r( $response, true ), $response->error->message );
188
  }
189
 
@@ -232,7 +252,7 @@ class WC_Stripe_Customer {
232
  // but no longer exists. Instead of failing, lets try to create a
233
  // new customer.
234
  if ( $this->is_no_such_customer_error( $response->error ) ) {
235
- delete_user_meta( $this->get_user_id(), '_stripe_customer_id' );
236
  $this->create_customer();
237
  return $this->add_source( $source_id );
238
  } else {
@@ -374,4 +394,30 @@ class WC_Stripe_Customer {
374
  delete_transient( 'stripe_customer_' . $this->get_id() );
375
  $this->customer_data = array();
376
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
377
  }
35
  public function __construct( $user_id = 0 ) {
36
  if ( $user_id ) {
37
  $this->set_user_id( $user_id );
38
+ $this->set_id( $this->get_id_from_meta( $user_id ) );
39
  }
40
  }
41
 
56
  if ( is_array( $id ) && isset( $id['customer_id'] ) ) {
57
  $id = $id['customer_id'];
58
 
59
+ $this->update_id_in_meta( $id );
60
  }
61
 
62
  $this->id = wc_clean( $id );
161
  $this->set_customer_data( $response );
162
 
163
  if ( $this->get_user_id() ) {
164
+ $this->update_id_in_meta( $response->id );
165
  }
166
 
167
  do_action( 'woocommerce_stripe_add_customer', $args, $response );
175
  * @param array $args Additional arguments for the request (optional).
176
  */
177
  public function update_customer( $args = array() ) {
178
+ if ( empty( $this->get_id() ) ) {
179
  throw new WC_Stripe_Exception( 'id_required_to_update_user', __( 'Attempting to update a Stripe customer without a customer ID.', 'woocommerce-gateway-stripe' ) );
180
  }
181
 
182
  $args = $this->generate_customer_request( $args );
183
  $args = apply_filters( 'wc_stripe_update_customer_args', $args );
184
+ $response = WC_Stripe_API::request( $args, 'customers/' . $this->get_id() );
185
 
186
  if ( ! empty( $response->error ) ) {
187
+ if ( $this->is_no_such_customer_error( $response->error ) ) {
188
+ $message = $response->error->message;
189
+
190
+ if ( ! preg_match( '/similar object exists/i', $message ) ) {
191
+ $options = get_option( 'woocommerce_stripe_settings' );
192
+ $testmode = isset( $options['testmode'] ) && 'yes' === $options['testmode'];
193
+
194
+ $message = sprintf(
195
+ ( $testmode
196
+ // Translators: %s is a message, which states that no such customer exists, without a full stop at the end.
197
+ ? __( '%s. Was the customer created in live mode? ', 'woocommerce-gateway-stripe' )
198
+ // Translators: %s is a message, which states that no such customer exists, without a full stop at the end.
199
+ : __( '%s. Was the customer created in test mode? ', 'woocommerce-gateway-stripe' ) ),
200
+ $message
201
+ );
202
+ }
203
+
204
+ throw new WC_Stripe_Exception( print_r( $response, true ), $message );
205
+ }
206
+
207
  throw new WC_Stripe_Exception( print_r( $response, true ), $response->error->message );
208
  }
209
 
252
  // but no longer exists. Instead of failing, lets try to create a
253
  // new customer.
254
  if ( $this->is_no_such_customer_error( $response->error ) ) {
255
+ $this->delete_id_from_meta();
256
  $this->create_customer();
257
  return $this->add_source( $source_id );
258
  } else {
394
  delete_transient( 'stripe_customer_' . $this->get_id() );
395
  $this->customer_data = array();
396
  }
397
+
398
+ /**
399
+ * Retrieves the Stripe Customer ID from the user meta.
400
+ *
401
+ * @param int $user_id The ID of the WordPress user.
402
+ * @return string|bool Either the Stripe ID or false.
403
+ */
404
+ public function get_id_from_meta( $user_id ) {
405
+ return get_user_option( '_stripe_customer_id', $user_id );
406
+ }
407
+
408
+ /**
409
+ * Updates the current user with the right Stripe ID in the meta table.
410
+ *
411
+ * @param string $id The Stripe customer ID.
412
+ */
413
+ public function update_id_in_meta( $id ) {
414
+ update_user_option( $this->get_user_id(), '_stripe_customer_id', $id, false );
415
+ }
416
+
417
+ /**
418
+ * Deletes the user ID from the meta table with the right key.
419
+ */
420
+ public function delete_id_from_meta() {
421
+ delete_user_option( $this->get_user_id(), '_stripe_customer_id', false );
422
+ }
423
  }
includes/class-wc-stripe-order-handler.php CHANGED
@@ -128,10 +128,10 @@ class WC_Stripe_Order_Handler extends WC_Stripe_Payment_Gateway {
128
  // Customer param wrong? The user may have been deleted on stripe's end. Remove customer_id. Can be retried without.
129
  if ( $this->is_no_such_customer_error( $response->error ) ) {
130
  if ( WC_Stripe_Helper::is_wc_lt( '3.0' ) ) {
131
- delete_user_meta( $order->customer_user, '_stripe_customer_id' );
132
  delete_post_meta( $order_id, '_stripe_customer_id' );
133
  } else {
134
- delete_user_meta( $order->get_customer_id(), '_stripe_customer_id' );
135
  $order->delete_meta_data( '_stripe_customer_id' );
136
  $order->save();
137
  }
@@ -244,12 +244,15 @@ class WC_Stripe_Order_Handler extends WC_Stripe_Payment_Gateway {
244
  /* translators: error message */
245
  $order->add_order_note( sprintf( __( 'Unable to capture charge! %s', 'woocommerce-gateway-stripe' ), $intent->error->message ) );
246
  } elseif ( 'requires_capture' === $intent->status ) {
247
- $result = WC_Stripe_API::request(
 
248
  array(
249
  'amount' => WC_Stripe_Helper::get_stripe_amount( $order_total ),
250
  'expand[]' => 'charges.data.balance_transaction',
251
  ),
252
- 'payment_intents/' . $intent->id . '/capture'
 
 
253
  );
254
 
255
  if ( ! empty( $result->error ) ) {
@@ -272,12 +275,15 @@ class WC_Stripe_Order_Handler extends WC_Stripe_Payment_Gateway {
272
  /* translators: error message */
273
  $order->add_order_note( sprintf( __( 'Unable to capture charge! %s', 'woocommerce-gateway-stripe' ), $result->error->message ) );
274
  } elseif ( false === $result->captured ) {
275
- $result = WC_Stripe_API::request(
 
276
  array(
277
  'amount' => WC_Stripe_Helper::get_stripe_amount( $order_total ),
278
  'expand[]' => 'balance_transaction',
279
  ),
280
- 'charges/' . $charge . '/capture'
 
 
281
  );
282
 
283
  if ( ! empty( $result->error ) ) {
128
  // Customer param wrong? The user may have been deleted on stripe's end. Remove customer_id. Can be retried without.
129
  if ( $this->is_no_such_customer_error( $response->error ) ) {
130
  if ( WC_Stripe_Helper::is_wc_lt( '3.0' ) ) {
131
+ delete_user_option( $order->customer_user, '_stripe_customer_id' );
132
  delete_post_meta( $order_id, '_stripe_customer_id' );
133
  } else {
134
+ delete_user_option( $order->get_customer_id(), '_stripe_customer_id' );
135
  $order->delete_meta_data( '_stripe_customer_id' );
136
  $order->save();
137
  }
244
  /* translators: error message */
245
  $order->add_order_note( sprintf( __( 'Unable to capture charge! %s', 'woocommerce-gateway-stripe' ), $intent->error->message ) );
246
  } elseif ( 'requires_capture' === $intent->status ) {
247
+ $level3_data = $this->get_level3_data_from_order( $order );
248
+ $result = WC_Stripe_API::request_with_level3_data(
249
  array(
250
  'amount' => WC_Stripe_Helper::get_stripe_amount( $order_total ),
251
  'expand[]' => 'charges.data.balance_transaction',
252
  ),
253
+ 'payment_intents/' . $intent->id . '/capture',
254
+ $level3_data,
255
+ $order
256
  );
257
 
258
  if ( ! empty( $result->error ) ) {
275
  /* translators: error message */
276
  $order->add_order_note( sprintf( __( 'Unable to capture charge! %s', 'woocommerce-gateway-stripe' ), $result->error->message ) );
277
  } elseif ( false === $result->captured ) {
278
+ $level3_data = $this->get_level3_data_from_order( $order );
279
+ $result = WC_Stripe_API::request_with_level3_data(
280
  array(
281
  'amount' => WC_Stripe_Helper::get_stripe_amount( $order_total ),
282
  'expand[]' => 'balance_transaction',
283
  ),
284
+ 'charges/' . $charge . '/capture',
285
+ $level3_data,
286
+ $order
287
  );
288
 
289
  if ( ! empty( $result->error ) ) {
includes/class-wc-stripe-webhook-handler.php CHANGED
@@ -203,10 +203,10 @@ class WC_Stripe_Webhook_Handler extends WC_Stripe_Payment_Gateway {
203
  // Customer param wrong? The user may have been deleted on stripe's end. Remove customer_id. Can be retried without.
204
  if ( $this->is_no_such_customer_error( $response->error ) ) {
205
  if ( WC_Stripe_Helper::is_wc_lt( '3.0' ) ) {
206
- delete_user_meta( $order->customer_user, '_stripe_customer_id' );
207
  delete_post_meta( $order_id, '_stripe_customer_id' );
208
  } else {
209
- delete_user_meta( $order->get_customer_id(), '_stripe_customer_id' );
210
  $order->delete_meta_data( '_stripe_customer_id' );
211
  $order->save();
212
  }
203
  // Customer param wrong? The user may have been deleted on stripe's end. Remove customer_id. Can be retried without.
204
  if ( $this->is_no_such_customer_error( $response->error ) ) {
205
  if ( WC_Stripe_Helper::is_wc_lt( '3.0' ) ) {
206
+ delete_user_option( $order->customer_user, '_stripe_customer_id' );
207
  delete_post_meta( $order_id, '_stripe_customer_id' );
208
  } else {
209
+ delete_user_option( $order->get_customer_id(), '_stripe_customer_id' );
210
  $order->delete_meta_data( '_stripe_customer_id' );
211
  $order->save();
212
  }
includes/compat/class-wc-stripe-sepa-subs-compat.php CHANGED
@@ -102,13 +102,15 @@ class WC_Stripe_Sepa_Subs_Compat extends WC_Gateway_Stripe_Sepa {
102
  */
103
  public function handle_add_payment_method_success( $source_id, $source_object ) {
104
  if ( isset( $_POST[ 'wc-' . $this->id . '-update-subs-payment-method-card' ] ) ) {
105
- $all_subs = wcs_get_users_subscriptions();
106
- $subs_statuses = apply_filters( 'wc_stripe_update_subs_payment_method_card_statuses', array( 'active' ) );
 
107
 
108
  if ( ! empty( $all_subs ) ) {
109
  foreach ( $all_subs as $sub ) {
110
  if ( $sub->has_status( $subs_statuses ) ) {
111
  update_post_meta( $sub->get_id(), '_stripe_source_id', $source_id );
 
112
  update_post_meta( $sub->get_id(), '_payment_method', $this->id );
113
  update_post_meta( $sub->get_id(), '_payment_method_title', $this->method_title );
114
  }
@@ -435,15 +437,15 @@ class WC_Stripe_Sepa_Subs_Compat extends WC_Gateway_Stripe_Sepa {
435
  // If we couldn't find a Stripe customer linked to the subscription, fallback to the user meta data.
436
  if ( ! $stripe_customer_id || ! is_string( $stripe_customer_id ) ) {
437
  $user_id = $customer_user;
438
- $stripe_customer_id = get_user_meta( $user_id, '_stripe_customer_id', true );
439
- $stripe_source_id = get_user_meta( $user_id, '_stripe_source_id', true );
440
 
441
  // For BW compat will remove in future.
442
  if ( empty( $stripe_source_id ) ) {
443
- $stripe_source_id = get_user_meta( $user_id, '_stripe_card_id', true );
444
 
445
  // Take this opportunity to update the key name.
446
- update_user_meta( $user_id, '_stripe_source_id', $stripe_source_id );
447
  }
448
  }
449
 
102
  */
103
  public function handle_add_payment_method_success( $source_id, $source_object ) {
104
  if ( isset( $_POST[ 'wc-' . $this->id . '-update-subs-payment-method-card' ] ) ) {
105
+ $all_subs = wcs_get_users_subscriptions();
106
+ $subs_statuses = apply_filters( 'wc_stripe_update_subs_payment_method_card_statuses', array( 'active' ) );
107
+ $stripe_customer = new WC_Stripe_Customer( get_current_user_id() );
108
 
109
  if ( ! empty( $all_subs ) ) {
110
  foreach ( $all_subs as $sub ) {
111
  if ( $sub->has_status( $subs_statuses ) ) {
112
  update_post_meta( $sub->get_id(), '_stripe_source_id', $source_id );
113
+ update_post_meta( $sub->get_id(), '_stripe_customer_id', $stripe_customer->get_id() );
114
  update_post_meta( $sub->get_id(), '_payment_method', $this->id );
115
  update_post_meta( $sub->get_id(), '_payment_method_title', $this->method_title );
116
  }
437
  // If we couldn't find a Stripe customer linked to the subscription, fallback to the user meta data.
438
  if ( ! $stripe_customer_id || ! is_string( $stripe_customer_id ) ) {
439
  $user_id = $customer_user;
440
+ $stripe_customer_id = get_user_option( '_stripe_customer_id', $user_id );
441
+ $stripe_source_id = get_user_option( '_stripe_source_id', $user_id );
442
 
443
  // For BW compat will remove in future.
444
  if ( empty( $stripe_source_id ) ) {
445
+ $stripe_source_id = get_user_option( '_stripe_card_id', $user_id );
446
 
447
  // Take this opportunity to update the key name.
448
+ update_user_option( $user_id, '_stripe_source_id', $stripe_source_id, false );
449
  }
450
  }
451
 
includes/compat/class-wc-stripe-subs-compat.php CHANGED
@@ -111,13 +111,15 @@ class WC_Stripe_Subs_Compat extends WC_Gateway_Stripe {
111
  */
112
  public function handle_add_payment_method_success( $source_id, $source_object ) {
113
  if ( isset( $_POST[ 'wc-' . $this->id . '-update-subs-payment-method-card' ] ) ) {
114
- $all_subs = wcs_get_users_subscriptions();
115
- $subs_statuses = apply_filters( 'wc_stripe_update_subs_payment_method_card_statuses', array( 'active' ) );
 
116
 
117
  if ( ! empty( $all_subs ) ) {
118
  foreach ( $all_subs as $sub ) {
119
  if ( $sub->has_status( $subs_statuses ) ) {
120
  update_post_meta( $sub->get_id(), '_stripe_source_id', $source_id );
 
121
  update_post_meta( $sub->get_id(), '_payment_method', $this->id );
122
  update_post_meta( $sub->get_id(), '_payment_method_title', $this->method_title );
123
  }
@@ -159,16 +161,16 @@ class WC_Stripe_Subs_Compat extends WC_Gateway_Stripe {
159
  * @param int $order_id
160
  * @return array
161
  */
162
- public function process_payment( $order_id, $retry = true, $force_save_source = false, $previous_error = false ) {
163
  if ( $this->has_subscription( $order_id ) ) {
164
  if ( $this->is_subs_change_payment() ) {
165
  return $this->change_subs_payment_method( $order_id );
166
  }
167
 
168
  // Regular payment with force customer enabled
169
- return parent::process_payment( $order_id, $retry, true, $previous_error );
170
  } else {
171
- return parent::process_payment( $order_id, $retry, $force_save_source, $previous_error );
172
  }
173
  }
174
 
@@ -224,6 +226,37 @@ class WC_Stripe_Subs_Compat extends WC_Gateway_Stripe {
224
 
225
  $order_id = WC_Stripe_Helper::is_wc_lt( '3.0' ) ? $renewal_order->id : $renewal_order->get_id();
226
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
227
  // Check for an existing intent, which is associated with the order.
228
  if ( $this->has_authentication_already_failed( $renewal_order ) ) {
229
  return;
@@ -502,15 +535,15 @@ class WC_Stripe_Subs_Compat extends WC_Gateway_Stripe {
502
  // If we couldn't find a Stripe customer linked to the subscription, fallback to the user meta data.
503
  if ( ! $stripe_customer_id || ! is_string( $stripe_customer_id ) ) {
504
  $user_id = $customer_user;
505
- $stripe_customer_id = get_user_meta( $user_id, '_stripe_customer_id', true );
506
- $stripe_source_id = get_user_meta( $user_id, '_stripe_source_id', true );
507
 
508
  // For BW compat will remove in future.
509
  if ( empty( $stripe_source_id ) ) {
510
- $stripe_source_id = get_user_meta( $user_id, '_stripe_card_id', true );
511
 
512
  // Take this opportunity to update the key name.
513
- update_user_meta( $user_id, '_stripe_source_id', $stripe_source_id );
514
  }
515
  }
516
 
@@ -614,4 +647,51 @@ class WC_Stripe_Subs_Compat extends WC_Gateway_Stripe {
614
 
615
  return true;
616
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
617
  }
111
  */
112
  public function handle_add_payment_method_success( $source_id, $source_object ) {
113
  if ( isset( $_POST[ 'wc-' . $this->id . '-update-subs-payment-method-card' ] ) ) {
114
+ $all_subs = wcs_get_users_subscriptions();
115
+ $subs_statuses = apply_filters( 'wc_stripe_update_subs_payment_method_card_statuses', array( 'active' ) );
116
+ $stripe_customer = new WC_Stripe_Customer( get_current_user_id() );
117
 
118
  if ( ! empty( $all_subs ) ) {
119
  foreach ( $all_subs as $sub ) {
120
  if ( $sub->has_status( $subs_statuses ) ) {
121
  update_post_meta( $sub->get_id(), '_stripe_source_id', $source_id );
122
+ update_post_meta( $sub->get_id(), '_stripe_customer_id', $stripe_customer->get_id() );
123
  update_post_meta( $sub->get_id(), '_payment_method', $this->id );
124
  update_post_meta( $sub->get_id(), '_payment_method_title', $this->method_title );
125
  }
161
  * @param int $order_id
162
  * @return array
163
  */
164
+ public function process_payment( $order_id, $retry = true, $force_save_source = false, $previous_error = false, $use_order_source = false ) {
165
  if ( $this->has_subscription( $order_id ) ) {
166
  if ( $this->is_subs_change_payment() ) {
167
  return $this->change_subs_payment_method( $order_id );
168
  }
169
 
170
  // Regular payment with force customer enabled
171
+ return parent::process_payment( $order_id, $retry, true, $previous_error, $use_order_source );
172
  } else {
173
+ return parent::process_payment( $order_id, $retry, $force_save_source, $previous_error, $use_order_source );
174
  }
175
  }
176
 
226
 
227
  $order_id = WC_Stripe_Helper::is_wc_lt( '3.0' ) ? $renewal_order->id : $renewal_order->get_id();
228
 
229
+
230
+ // Unlike regular off-session subscription payments, early renewals are treated as on-session payments, involving the customer.
231
+ if ( isset( $_REQUEST['process_early_renewal'] ) ) { // wpcs: csrf ok.
232
+ $response = parent::process_payment( $order_id, true, false, $previous_error, true );
233
+
234
+ if( 'success' === $response['result'] && isset( $response['payment_intent_secret'] ) ) {
235
+ $verification_url = add_query_arg(
236
+ array(
237
+ 'order' => $order_id,
238
+ 'nonce' => wp_create_nonce( 'wc_stripe_confirm_pi' ),
239
+ 'redirect_to' => remove_query_arg( array( 'process_early_renewal', 'subscription_id', 'wcs_nonce' ) ),
240
+ 'early_renewal' => true,
241
+ ),
242
+ WC_AJAX::get_endpoint( 'wc_stripe_verify_intent' )
243
+ );
244
+
245
+ echo wp_json_encode( array(
246
+ 'stripe_sca_required' => true,
247
+ 'intent_secret' => $response['payment_intent_secret'],
248
+ 'redirect_url' => $verification_url,
249
+ ) );
250
+
251
+ exit;
252
+ }
253
+
254
+ // Hijack all other redirects in order to do the redirection in JavaScript.
255
+ add_action( 'wp_redirect', array( $this, 'redirect_after_early_renewal' ), 100 );
256
+
257
+ return;
258
+ }
259
+
260
  // Check for an existing intent, which is associated with the order.
261
  if ( $this->has_authentication_already_failed( $renewal_order ) ) {
262
  return;
535
  // If we couldn't find a Stripe customer linked to the subscription, fallback to the user meta data.
536
  if ( ! $stripe_customer_id || ! is_string( $stripe_customer_id ) ) {
537
  $user_id = $customer_user;
538
+ $stripe_customer_id = get_user_option( '_stripe_customer_id', $user_id );
539
+ $stripe_source_id = get_user_option( '_stripe_source_id', $user_id );
540
 
541
  // For BW compat will remove in future.
542
  if ( empty( $stripe_source_id ) ) {
543
+ $stripe_source_id = get_user_option( '_stripe_card_id', $user_id );
544
 
545
  // Take this opportunity to update the key name.
546
+ update_user_option( $user_id, '_stripe_source_id', $stripe_source_id, false );
547
  }
548
  }
549
 
647
 
648
  return true;
649
  }
650
+
651
+ /**
652
+ * Hijacks `wp_redirect` in order to generate a JS-friendly object with the URL.
653
+ *
654
+ * @param string $url The URL that Subscriptions attempts a redirect to.
655
+ * @return void
656
+ */
657
+ public function redirect_after_early_renewal( $url ) {
658
+ echo wp_json_encode(
659
+ array(
660
+ 'stripe_sca_required' => false,
661
+ 'redirect_url' => $url,
662
+ )
663
+ );
664
+
665
+ exit;
666
+ }
667
+
668
+ /**
669
+ * Once an intent has been verified, perform some final actions for early renewals.
670
+ *
671
+ * @param WC_Order $order The renewal order.
672
+ * @param stdClass $intent The Payment Intent object.
673
+ */
674
+ protected function handle_intent_verification_success( $order, $intent ) {
675
+ parent::handle_intent_verification_success( $order, $intent );
676
+
677
+ if ( isset( $_GET['early_renewal'] ) ) { // wpcs: csrf ok.
678
+ wcs_update_dates_after_early_renewal( wcs_get_subscription( $order->get_meta( '_subscription_renewal' ) ), $order );
679
+ wc_add_notice( __( 'Your early renewal order was successful.', 'woocommerce-gateway-stripe' ), 'success' );
680
+ }
681
+ }
682
+
683
+ /**
684
+ * During early renewals, instead of failing the renewal order, delete it and let Subs redirect to the checkout.
685
+ *
686
+ * @param WC_Order $order The renewal order.
687
+ * @param stdClass $intent The Payment Intent object (unused).
688
+ */
689
+ protected function handle_intent_verification_failure( $order, $intent ) {
690
+ if ( isset( $_GET['early_renewal'] ) ) {
691
+ $order->delete( true );
692
+ wc_add_notice( __( 'Payment authorization for the renewal order was unsuccessful, please try again.', 'woocommerce-gateway-stripe' ), 'error' );
693
+ $renewal_url = wcs_get_early_renewal_url( wcs_get_subscription( $order->get_meta( '_subscription_renewal' ) ) );
694
+ wp_redirect( $renewal_url ); exit;
695
+ }
696
+ }
697
  }
includes/payment-methods/class-wc-gateway-stripe-sepa.php CHANGED
@@ -337,10 +337,10 @@ class WC_Gateway_Stripe_Sepa extends WC_Stripe_Payment_Gateway {
337
  // Customer param wrong? The user may have been deleted on stripe's end. Remove customer_id. Can be retried without.
338
  if ( $this->is_no_such_customer_error( $response->error ) ) {
339
  if ( WC_Stripe_Helper::is_wc_lt( '3.0' ) ) {
340
- delete_user_meta( $order->customer_user, '_stripe_customer_id' );
341
  delete_post_meta( $order_id, '_stripe_customer_id' );
342
  } else {
343
- delete_user_meta( $order->get_customer_id(), '_stripe_customer_id' );
344
  $order->delete_meta_data( '_stripe_customer_id' );
345
  $order->save();
346
  }
337
  // Customer param wrong? The user may have been deleted on stripe's end. Remove customer_id. Can be retried without.
338
  if ( $this->is_no_such_customer_error( $response->error ) ) {
339
  if ( WC_Stripe_Helper::is_wc_lt( '3.0' ) ) {
340
+ delete_user_option( $order->customer_user, '_stripe_customer_id' );
341
  delete_post_meta( $order_id, '_stripe_customer_id' );
342
  } else {
343
+ delete_user_option( $order->get_customer_id(), '_stripe_customer_id' );
344
  $order->delete_meta_data( '_stripe_customer_id' );
345
  $order->save();
346
  }
includes/payment-methods/class-wc-stripe-payment-request.php CHANGED
@@ -147,14 +147,7 @@ class WC_Stripe_Payment_Request {
147
  return;
148
  }
149
 
150
- $session_class = apply_filters( 'woocommerce_session_handler', 'WC_Session_Handler' );
151
- $wc_session = new $session_class();
152
-
153
- if ( version_compare( WC_VERSION, '3.3', '>=' ) ) {
154
- $wc_session->init();
155
- }
156
-
157
- $wc_session->set_customer_session_cookie( true );
158
  }
159
 
160
  /**
@@ -467,18 +460,8 @@ class WC_Stripe_Payment_Request {
467
  return;
468
  }
469
 
470
- if ( is_product() ) {
471
- global $post;
472
-
473
- $product = wc_get_product( $post->ID );
474
-
475
- if ( ! is_object( $product ) || ! in_array( ( WC_Stripe_Helper::is_wc_lt( '3.0' ) ? $product->product_type : $product->get_type() ), $this->supported_product_types() ) ) {
476
- return;
477
- }
478
-
479
- if ( apply_filters( 'wc_stripe_hide_payment_request_on_product_page', false, $post ) ) {
480
- return;
481
- }
482
  }
483
 
484
  $suffix = defined( 'SCRIPT_DEBUG' ) && SCRIPT_DEBUG ? '' : '.min';
@@ -552,31 +535,12 @@ class WC_Stripe_Payment_Request {
552
  return;
553
  }
554
 
555
- if ( is_product() && apply_filters( 'wc_stripe_hide_payment_request_on_product_page', false, $post ) ) {
556
- return;
557
- }
558
-
559
  if ( is_checkout() && ! apply_filters( 'wc_stripe_show_payment_request_on_checkout', false, $post ) ) {
560
  return;
561
  }
562
 
563
- if ( is_product() ) {
564
- $product = wc_get_product( $post->ID );
565
-
566
- if ( ! is_object( $product ) || ! in_array( ( WC_Stripe_Helper::is_wc_lt( '3.0' ) ? $product->product_type : $product->get_type() ), $this->supported_product_types() ) ) {
567
- return;
568
- }
569
-
570
- // Trial subscriptions with shipping are not supported
571
- if ( class_exists( 'WC_Subscriptions_Order' ) && $product->needs_shipping() && WC_Subscriptions_Product::get_trial_length( $product ) > 0 ) {
572
- return;
573
- }
574
-
575
- // Pre Orders charge upon release not supported.
576
- if ( class_exists( 'WC_Pre_Orders_Order' ) && WC_Pre_Orders_Product::product_is_charged_upon_release( $product ) ) {
577
- WC_Stripe_Logger::log( 'Pre Order charge upon release is not supported. ( Payment Request button disabled )' );
578
- return;
579
- }
580
  } else {
581
  if ( ! $this->allowed_items_in_cart() ) {
582
  WC_Stripe_Logger::log( 'Items in the cart has unsupported product type ( Payment Request button disabled )' );
@@ -611,31 +575,12 @@ class WC_Stripe_Payment_Request {
611
  return;
612
  }
613
 
614
- if ( is_product() && apply_filters( 'wc_stripe_hide_payment_request_on_product_page', false, $post ) ) {
615
- return;
616
- }
617
-
618
  if ( is_checkout() && ! apply_filters( 'wc_stripe_show_payment_request_on_checkout', false, $post ) ) {
619
  return;
620
  }
621
 
622
- if ( is_product() ) {
623
- $product = wc_get_product( $post->ID );
624
-
625
- if ( ! is_object( $product ) || ! in_array( ( WC_Stripe_Helper::is_wc_lt( '3.0' ) ? $product->product_type : $product->get_type() ), $this->supported_product_types() ) ) {
626
- return;
627
- }
628
-
629
- // Trial subscriptions with shipping are not supported
630
- if ( class_exists( 'WC_Subscriptions_Order' ) && $product->needs_shipping() && WC_Subscriptions_Product::get_trial_length( $product ) > 0 ) {
631
- return;
632
- }
633
-
634
- // Pre Orders charge upon release not supported.
635
- if ( class_exists( 'WC_Pre_Orders_Order' ) && WC_Pre_Orders_Product::product_is_charged_upon_release( $product ) ) {
636
- WC_Stripe_Logger::log( 'Pre Order charge upon release is not supported. ( Payment Request button disabled )' );
637
- return;
638
- }
639
  } else {
640
  if ( ! $this->allowed_items_in_cart() ) {
641
  WC_Stripe_Logger::log( 'Items in the cart has unsupported product type ( Payment Request button disabled )' );
@@ -647,6 +592,52 @@ class WC_Stripe_Payment_Request {
647
  <?php
648
  }
649
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
650
  /**
651
  * Log errors coming from Payment Request
652
  *
@@ -815,6 +806,7 @@ class WC_Stripe_Payment_Request {
815
  try {
816
  $product_id = absint( $_POST['product_id'] );
817
  $qty = ! isset( $_POST['qty'] ) ? 1 : apply_filters( 'woocommerce_add_to_cart_quantity', absint( $_POST['qty'] ), $product_id );
 
818
  $product = wc_get_product( $product_id );
819
  $variation_id = null;
820
 
@@ -849,7 +841,7 @@ class WC_Stripe_Payment_Request {
849
  throw new Exception( sprintf( __( 'You cannot add that amount of "%1$s"; to the cart because there is not enough stock (%2$s remaining).', 'woocommerce-gateway-stripe' ), $product->get_name(), wc_format_stock_quantity_for_display( $product->get_stock_quantity(), $product ) ) );
850
  }
851
 
852
- $total = $qty * ( WC_Stripe_Helper::is_wc_lt( '3.0' ) ? $product->price : $product->get_price() );
853
 
854
  $quantity_label = 1 < $qty ? ' (x' . $qty . ')' : '';
855
 
147
  return;
148
  }
149
 
150
+ WC()->session->set_customer_session_cookie( true );
 
 
 
 
 
 
 
151
  }
152
 
153
  /**
460
  return;
461
  }
462
 
463
+ if ( is_product() && ! $this->should_show_payment_button_on_product_page() ) {
464
+ return;
 
 
 
 
 
 
 
 
 
 
465
  }
466
 
467
  $suffix = defined( 'SCRIPT_DEBUG' ) && SCRIPT_DEBUG ? '' : '.min';
535
  return;
536
  }
537
 
 
 
 
 
538
  if ( is_checkout() && ! apply_filters( 'wc_stripe_show_payment_request_on_checkout', false, $post ) ) {
539
  return;
540
  }
541
 
542
+ if ( is_product() && ! $this->should_show_payment_button_on_product_page() ) {
543
+ return;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
544
  } else {
545
  if ( ! $this->allowed_items_in_cart() ) {
546
  WC_Stripe_Logger::log( 'Items in the cart has unsupported product type ( Payment Request button disabled )' );
575
  return;
576
  }
577
 
 
 
 
 
578
  if ( is_checkout() && ! apply_filters( 'wc_stripe_show_payment_request_on_checkout', false, $post ) ) {
579
  return;
580
  }
581
 
582
+ if ( is_product() && ! $this->should_show_payment_button_on_product_page() ) {
583
+ return;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
584
  } else {
585
  if ( ! $this->allowed_items_in_cart() ) {
586
  WC_Stripe_Logger::log( 'Items in the cart has unsupported product type ( Payment Request button disabled )' );
592
  <?php
593
  }
594
 
595
+ /**
596
+ * Whether payment button html should be rendered
597
+ *
598
+ * @since 4.3.2
599
+ *
600
+ * @param object $post
601
+ *
602
+ * @return bool
603
+ */
604
+ private function should_show_payment_button_on_product_page() {
605
+ global $post;
606
+
607
+ $product = wc_get_product( $post->ID );
608
+
609
+ if ( apply_filters( 'wc_stripe_hide_payment_request_on_product_page', false, $post ) ) {
610
+ return false;
611
+ }
612
+
613
+ if ( ! is_object( $product ) || ! in_array( ( WC_Stripe_Helper::is_wc_lt( '3.0' ) ? $product->product_type : $product->get_type() ), $this->supported_product_types() ) ) {
614
+ return false;
615
+ }
616
+
617
+ // Trial subscriptions with shipping are not supported
618
+ if ( class_exists( 'WC_Subscriptions_Order' ) && $product->needs_shipping() && WC_Subscriptions_Product::get_trial_length( $product ) > 0 ) {
619
+ return false;
620
+ }
621
+
622
+ // Pre Orders charge upon release not supported.
623
+ if ( class_exists( 'WC_Pre_Orders_Order' ) && WC_Pre_Orders_Product::product_is_charged_upon_release( $product ) ) {
624
+ WC_Stripe_Logger::log( 'Pre Order charge upon release is not supported. ( Payment Request button disabled )' );
625
+ return false;
626
+ }
627
+
628
+ // File upload addon not supported
629
+ if ( class_exists( 'WC_Product_Addons_Helper' ) ) {
630
+ $product_addons = WC_Product_Addons_Helper::get_product_addons( $product->get_id() );
631
+ foreach ( $product_addons as $addon ) {
632
+ if ( 'file_upload' === $addon['type'] ) {
633
+ return false;
634
+ }
635
+ }
636
+ }
637
+
638
+ return true;
639
+ }
640
+
641
  /**
642
  * Log errors coming from Payment Request
643
  *
806
  try {
807
  $product_id = absint( $_POST['product_id'] );
808
  $qty = ! isset( $_POST['qty'] ) ? 1 : apply_filters( 'woocommerce_add_to_cart_quantity', absint( $_POST['qty'] ), $product_id );
809
+ $addon_value = isset( $_POST['addon_value'] ) ? max( floatval( $_POST['addon_value'] ), 0 ) : 0;
810
  $product = wc_get_product( $product_id );
811
  $variation_id = null;
812
 
841
  throw new Exception( sprintf( __( 'You cannot add that amount of "%1$s"; to the cart because there is not enough stock (%2$s remaining).', 'woocommerce-gateway-stripe' ), $product->get_name(), wc_format_stock_quantity_for_display( $product->get_stock_quantity(), $product ) ) );
842
  }
843
 
844
+ $total = $qty * ( WC_Stripe_Helper::is_wc_lt( '3.0' ) ? $product->price : $product->get_price() ) + $addon_value;
845
 
846
  $quantity_label = 1 < $qty ? ' (x' . $qty . ')' : '';
847
 
languages/woocommerce-gateway-stripe.pot CHANGED
<
@@ -1,15 +1,15 @@
1
- # Copyright (C) 2019 WooCommerce
2
  # This file is distributed under the same license as the WooCommerce Stripe Gateway package.
3
  msgid ""
4
  msgstr ""
5
- "Project-Id-Version: WooCommerce Stripe Gateway 4.3.0\n"
6
  "Report-Msgid-Bugs-To: "
7
  "https://wordpress.org/support/plugin/woocommerce-gateway-stripe\n"
8
- "POT-Creation-Date: 2019-11-12 11:30:47+00:00\n"
9
  "MIME-Version: 1.0\n"
10
  "Content-Type: text/plain; charset=utf-8\n"
11
  "Content-Transfer-Encoding: 8bit\n"
12
- "PO-Revision-Date: 2019-MO-DA HO:MI+ZONE\n"
13
  "Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
14
  "Language-Team: LANGUAGE <LL@li.org>\n"
15
  "X-Generator: node-wp-i18n 1.2.1\n"
@@ -29,8 +29,8 @@ msgid "Save payment information to my account for future purchases."
29
  msgstr ""
30
 
31
  #: includes/abstracts/abstract-wc-stripe-payment-gateway.php:230
32
- #: includes/compat/class-wc-stripe-sepa-subs-compat.php:216
33
- #: includes/compat/class-wc-stripe-subs-compat.php:218
34
  #. translators: 1) dollar amount
35
  #. translators: minimum amount
36
  msgid "Sorry, the minimum allowed order total is %1$s to use this payment method."
@@ -55,7 +55,7 @@ msgid "Stripe charge awaiting payment: %s."
55
  msgstr ""
56
 
57
  #: includes/abstracts/abstract-wc-stripe-payment-gateway.php:424
58
- #: includes/class-wc-stripe-order-handler.php:296
59
  #: includes/class-wc-stripe-webhook-handler.php:347
60
  #: includes/class-wc-stripe-webhook-handler.php:399
61
  #. translators: transaction id
@@ -63,8 +63,8 @@ msgid "Stripe charge complete (Charge ID: %s)"
63
  msgstr ""
64
 
65
  #: includes/abstracts/abstract-wc-stripe-payment-gateway.php:429
66
- #: includes/class-wc-gateway-stripe.php:495
67
- #: includes/compat/class-wc-stripe-sepa-subs-compat.php:173
68
  msgid "Payment processing failed. Please retry."
69
  msgstr ""
70
 
@@ -92,7 +92,7 @@ msgstr ""
92
  msgid "There was a problem adding the payment method."
93
  msgstr ""
94
 
95
- #: includes/admin/class-wc-stripe-admin-notices.php:124
96
  #. translators: 1) A URL that explains Stripe Radar.
97
  msgid ""
98
  "WooCommerce Stripe - We see that you had the \"Require 3D secure when "
@@ -101,7 +101,7 @@ msgid ""
101
  "href=\"%s\" target=\"_blank\">here</a>."
102
  msgstr ""
103
 
104
- #: includes/admin/class-wc-stripe-admin-notices.php:131
105
  #. translators: 1) int version 2) int version
106
  msgid ""
107
  "WooCommerce Stripe - We recently made changes to Stripe that may impact the "
@@ -111,32 +111,32 @@ msgid ""
111
  "target=\"_blank\">instructions</a> to fix."
112
  msgstr ""
113
 
114
- #: includes/admin/class-wc-stripe-admin-notices.php:141
115
  #. translators: 1) int version 2) int version
116
  msgid ""
117
  "WooCommerce Stripe - The minimum PHP version required for this plugin is "
118
  "%1$s. You are running %2$s."
119
  msgstr ""
120
 
121
- #: includes/admin/class-wc-stripe-admin-notices.php:152
122
  #. translators: 1) int version 2) int version
123
  msgid ""
124
  "WooCommerce Stripe - The minimum WooCommerce version required for this "
125
  "plugin is %1$s. You are running %2$s."
126
  msgstr ""
127
 
128
- #: includes/admin/class-wc-stripe-admin-notices.php:162
129
  msgid "WooCommerce Stripe - cURL is not installed."
130
  msgstr ""
131
 
132
- #: includes/admin/class-wc-stripe-admin-notices.php:172
133
  #. translators: 1) link
134
  msgid ""
135
  "Stripe is almost ready. To get started, <a href=\"%s\">set your Stripe "
136
  "account keys</a>."
137
  msgstr ""
138
 
139
- #: includes/admin/class-wc-stripe-admin-notices.php:183
140
  #. translators: 1) link
141
  msgid ""
142
  "Stripe is in test mode however your test keys may not be valid. Test keys "
@@ -144,7 +144,7 @@ msgid ""
144
  "<a href=\"%s\">set your Stripe account keys</a>."
145
  msgstr ""
146
 
147
- #: includes/admin/class-wc-stripe-admin-notices.php:192
148
  #. translators: 1) link
149
  msgid ""
150
  "Stripe is in live mode however your test keys may not be valid. Live keys "
@@ -152,7 +152,7 @@ msgid ""
152
  "<a href=\"%s\">set your Stripe account keys</a>."
153
  msgstr ""
154
 
155
- #: includes/admin/class-wc-stripe-admin-notices.php:201
156
  #. translators: 1) link
157
  msgid ""
158
  "Stripe is enabled, but a SSL certificate is not detected. Your checkout may "
@@ -160,22 +160,30 @@ msgid ""
160
  "target=\"_blank\">SSL certificate</a>"
161
  msgstr ""
162
 
163
- #: includes/admin/class-wc-stripe-admin-notices.php:206
164
  msgid ""
165
  "Stripe is now ready for Strong Customer Authentication (SCA) and 3D Secure "
166
  "2! <a href=\"%1$s\" target=\"_blank\">Read about SCA</a>"
167
  msgstr ""
168
 
169
- #: includes/admin/class-wc-stripe-admin-notices.php:229
 
 
 
 
 
 
 
 
170
  #. translators: %1$s Payment method, %2$s List of supported currencies
171
  msgid "%1$s is enabled - it requires store currency to be set to %2$s"
172
  msgstr ""
173
 
174
- #: includes/admin/class-wc-stripe-admin-notices.php:243
175
  msgid "Action failed. Please refresh the page and retry."
176
  msgstr ""
177
 
178
- #: includes/admin/class-wc-stripe-admin-notices.php:247
179
  msgid "Cheatin&#8217; huh?"
180
  msgstr ""
181
 
@@ -210,9 +218,9 @@ msgid "Retains any Stripe data such as Stripe customer ID, source ID."
210
  msgstr ""
211
 
212
  #: includes/admin/class-wc-stripe-privacy.php:41
213
- #: includes/compat/class-wc-stripe-sepa-subs-compat.php:463
214
- #: includes/compat/class-wc-stripe-subs-compat.php:530
215
- #: includes/compat/class-wc-stripe-subs-compat.php:545
216
  msgid "N/A"
217
  msgstr ""
218
 
@@ -380,6 +388,7 @@ msgstr ""
380
 
381
  #: includes/admin/stripe-alipay-settings.php:43
382
  #: includes/admin/stripe-bancontact-settings.php:43
 
383
  #: includes/admin/stripe-giropay-settings.php:43
384
  #: includes/admin/stripe-ideal-settings.php:43
385
  #: includes/admin/stripe-multibanco-settings.php:39
@@ -428,10 +437,6 @@ msgstr ""
428
  msgid "You will be redirected to EPS."
429
  msgstr ""
430
 
431
- #: includes/admin/stripe-eps-settings.php:39
432
- msgid "Webhook Enpoints"
433
- msgstr ""
434
-
435
  #: includes/admin/stripe-giropay-settings.php:10
436
  msgid "Relevant Payer Geography: Germany"
437
  msgstr ""
@@ -798,68 +803,68 @@ msgstr ""
798
  msgid "Card Code (CVC)"
799
  msgstr ""
800
 
801
- #: includes/class-wc-gateway-stripe.php:408
802
  msgid "Please accept the terms and conditions first"
803
  msgstr ""
804
 
805
- #: includes/class-wc-gateway-stripe.php:409
806
  msgid "Please fill in required checkout fields first"
807
  msgstr ""
808
 
809
- #: includes/class-wc-gateway-stripe.php:438
810
- #: includes/class-wc-gateway-stripe.php:482
811
  msgid ""
812
  "Sorry, we're not accepting prepaid cards at this time. Your credit card has "
813
  "not been charged. Please try with alternative payment method."
814
  msgstr ""
815
 
816
- #: includes/class-wc-gateway-stripe.php:439
817
  msgid "Please enter your IBAN account name."
818
  msgstr ""
819
 
820
- #: includes/class-wc-gateway-stripe.php:440
821
  msgid "Please enter your IBAN account number."
822
  msgstr ""
823
 
824
- #: includes/class-wc-gateway-stripe.php:441
825
  msgid "We couldn't initiate the payment. Please try again."
826
  msgstr ""
827
 
828
- #: includes/class-wc-gateway-stripe.php:452
829
  msgid "Billing First Name and Last Name are required."
830
  msgstr ""
831
 
832
- #: includes/class-wc-gateway-stripe.php:720
833
  #. translators: error message
834
  msgid "This represents the fee Stripe collects for the transaction."
835
  msgstr ""
836
 
837
- #: includes/class-wc-gateway-stripe.php:721
838
  msgid "Stripe Fee:"
839
  msgstr ""
840
 
841
- #: includes/class-wc-gateway-stripe.php:757
842
  msgid ""
843
  "This represents the net total that will be credited to your Stripe bank "
844
  "account. This may be in the currency that is set in your Stripe account."
845
  msgstr ""
846
 
847
- #: includes/class-wc-gateway-stripe.php:758
848
  msgid "Stripe Payout:"
849
  msgstr ""
850
 
851
- #: includes/class-wc-gateway-stripe.php:805
852
  #: includes/class-wc-stripe-order-handler.php:162
853
  #: includes/class-wc-stripe-webhook-handler.php:238
854
- #: includes/compat/class-wc-stripe-sepa-subs-compat.php:263
855
- #: includes/compat/class-wc-stripe-subs-compat.php:272
856
  #: includes/payment-methods/class-wc-gateway-stripe-sepa.php:373
857
  msgid ""
858
  "Sorry, we are unable to process your payment at this time. Please retry "
859
  "later."
860
  msgstr ""
861
 
862
- #: includes/class-wc-gateway-stripe.php:858
863
  msgid ""
864
  "Almost there!\n"
865
  "\n"
@@ -867,14 +872,14 @@ msgid ""
867
  "done is for you to authorize the payment with your bank."
868
  msgstr ""
869
 
870
- #: includes/class-wc-gateway-stripe.php:1070
871
  #: includes/class-wc-stripe-webhook-handler.php:685
872
  #: includes/class-wc-stripe-webhook-handler.php:724
873
  #. translators: 1) The error message that was received from Stripe.
874
  msgid "Stripe SCA authentication failed. Reason: %s"
875
  msgstr ""
876
 
877
- #: includes/class-wc-gateway-stripe.php:1071
878
  msgid "Stripe SCA authentication failed."
879
  msgstr ""
880
 
@@ -921,7 +926,19 @@ msgstr ""
921
  msgid "Attempting to update a Stripe customer without a customer ID."
922
  msgstr ""
923
 
924
- #: includes/class-wc-stripe-customer.php:242
 
 
 
 
 
 
 
 
 
 
 
 
925
  msgid "Unable to add payment source."
926
  msgstr ""
927
 
@@ -1023,9 +1040,9 @@ msgid "Stripe payment failed: %s"
1023
  msgstr ""
1024
 
1025
  #: includes/class-wc-stripe-order-handler.php:245
1026
- #: includes/class-wc-stripe-order-handler.php:257
1027
- #: includes/class-wc-stripe-order-handler.php:273
1028
- #: includes/class-wc-stripe-order-handler.php:285
1029
  #. translators: error message
1030
  msgid "Unable to capture charge! %s"
1031
  msgstr ""
@@ -1155,8 +1172,8 @@ msgid "Unable to store payment details. Please try again."
1155
  msgstr ""
1156
 
1157
  #: includes/compat/class-wc-stripe-pre-orders-compat.php:121
1158
- #: includes/compat/class-wc-stripe-subs-compat.php:304
1159
- #: includes/compat/class-wc-stripe-subs-compat.php:609
1160
  msgid "Stripe charge awaiting authentication by user: %s."
1161
  msgstr ""
1162
 
@@ -1165,52 +1182,60 @@ msgstr ""
1165
  msgid "Stripe Transaction Failed (%s)"
1166
  msgstr ""
1167
 
1168
- #: includes/compat/class-wc-stripe-sepa-subs-compat.php:88
1169
- #: includes/compat/class-wc-stripe-subs-compat.php:97
1170
- msgid ""
1171
- "Update the Payment Method used for all of my active subscriptions "
1172
- "(optional)."
1173
  msgstr ""
1174
 
1175
- #: includes/compat/class-wc-stripe-sepa-subs-compat.php:226
1176
- #: includes/compat/class-wc-stripe-subs-compat.php:233
1177
  msgid "Customer not found"
1178
  msgstr ""
1179
 
1180
- #: includes/compat/class-wc-stripe-sepa-subs-compat.php:386
1181
- #: includes/compat/class-wc-stripe-subs-compat.php:453
1182
  #. translators: error message
1183
  msgid "A \"Stripe Customer ID\" value is required."
1184
  msgstr ""
1185
 
1186
- #: includes/compat/class-wc-stripe-sepa-subs-compat.php:388
1187
- #: includes/compat/class-wc-stripe-subs-compat.php:455
1188
  msgid ""
1189
  "Invalid customer ID. A valid \"Stripe Customer ID\" must begin with "
1190
  "\"cus_\"."
1191
  msgstr ""
1192
 
1193
- #: includes/compat/class-wc-stripe-sepa-subs-compat.php:397
1194
- #: includes/compat/class-wc-stripe-subs-compat.php:464
1195
  msgid ""
1196
  "Invalid source ID. A valid source \"Stripe Source ID\" must begin with "