WooCommerce Stripe Payment Gateway - Version 4.0.4

Version Description

  • 2018-01-30 =
  • Add - SEPA mandate notification email.
  • Add - Preferred language to SOFORT and Bancontact so it can be localized.
  • Add - Hook to change SEPA mandate notification to none "wc_stripe_sepa_mandate_notification".
  • Add - Hook to change data for product when using Payment Request Button "wc_stripe_payment_request_product_data".
  • Add - Hook to change the behavior of allowing subscriptions to charge a customer's default source "'wc_stripe_use_default_customer_source'".
  • Add - Hook to source object "wc_stripe_sofort_source", "wc_stripe_p24_source", "wc_stripe_ideal_source", "wc_stripe_giropay_source", "wc_stripe_bancontact_source", "wc_stripe_alipay_source", "wc_stripe_3ds_source".
  • Add - Hook to change payment request button total label "wc_stripe_payment_request_total_label".
  • Add - Hook to change locale of Stripe Checkout "wc_stripe_checkout_locale".
  • Add - Hook to change elements options "wc_stripe_elements_options".
  • Fix - When checkout form produces an error on mobile, sometimes the blocking mask is not release blocking new input.
  • Fix - On older subscription payments, the ending card number is not shown on the subscriptions table in my account.
  • Fix - Filter to show payment request button on checkout page not working.
  • Fix - WC session handling compatibility with WC 3.3.
  • Fix - BW compatibility with WC 2.6.x on add_order_meta to prevent errors.
  • Fix - Possible fix for duplicate charges due to webhook and redirect handler firing at the same time by adding delay to the webhook process.
  • Tweak - In a subscription billing, Stripe source ID is no longer a required field.
  • Tweak - On a subscription order renewal-- if source is empty, will now try to charge the default source.
  • Notice - Bitcoin has been soft deprecated and Stripe will no longer support it on April 23, 2018. Please plan accordingly.
  • Remove - Stripe Checkout Locale setting in favor of using store set locale.
  • Update - Stripe API version to 2018-01-23.

See changelog for all versions.

=

Download this release

Release Info

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

Code changes from version 4.0.3 to 4.0.4

assets/css/stripe-paymentfonts.css CHANGED
@@ -1,4 +1,4 @@
1
  /*!
2
  * PaymentFont 1.2.5 by @AMPoellmann - http://paymentfont.com
3
  * License - http://paymentfont.io/#license (Font: SIL OFL 1.1, CSS: MIT License)
4
- */@font-face{font-family:PaymentFont;src:url(../paymentfonts/paymentfont-webfont.eot);src:url(../paymentfonts/paymentfont-webfont.eot?#iefix) format('embedded-opentype'),url(../paymentfonts/paymentfont-webfont.woff) format('woff2'),url(../paymentfonts/paymentfont-webfont.woff) format('woff'),url(../paymentfonts/paymentfont-webfont.ttf) format('truetype'),url(../paymentfonts/paymentfont-webfont.svg#paymentfont-webfont) format('svg');font-weight:400;font-style:normal}.stripe-pf{display:inline-block;font:normal normal normal 14px/1 PaymentFont;text-rendering:auto;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale;font-size:1.2em}.stripe-pf-right{float:right}.stripe-pf-left{float:left}.stripe-pf-lg{font-size:1.33333333em;line-height:.75em;vertical-align:-15%}.stripe-pf-2x{font-size:2em}.stripe-pf-3x{font-size:3em}.stripe-pf-4x{font-size:4em}.stripe-pf-5x{font-size:5em}.stripe-pf-amazon:before{content:"\f000"}.stripe-pf-american-express:before{content:"\f001"}.stripe-pf-american-express-alt:before{content:"\f002"}.stripe-pf-atm:before{content:"\f003"}.stripe-pf-bankomat:before{content:"\f004"}.stripe-pf-bank-transfer:before{content:"\f005"}.stripe-pf-bitcoin:before{content:"\f006"}.stripe-pf-bitcoin-sign:before{content:"\f007"}.stripe-pf-braintree:before{content:"\f008"}.stripe-pf-btc:before{content:"\f009"}.stripe-pf-card:before{content:"\f00a"}.stripe-pf-carta-si:before{content:"\f00b"}.stripe-pf-cash:before{content:"\f00c"}.stripe-pf-cash-on-delivery:before{content:"\f00d"}.stripe-pf-cb:before{content:"\f00e"}.stripe-pf-cirrus:before{content:"\f00f"}.stripe-pf-cirrus-alt:before{content:"\f010"}.stripe-pf-clickandbuy:before{content:"\f011"}.stripe-pf-credit-card:before{content:"\f012"}.stripe-pf-diners:before{content:"\f013"}.stripe-pf-discover:before{content:"\f014"}.stripe-pf-ec:before{content:"\f015"}.stripe-pf-eps:before{content:"\f016"}.stripe-pf-eur:before{content:"\f017"}.stripe-pf-facture:before{content:"\f018"}.stripe-pf-fattura:before{content:"\f019"}.stripe-pf-flattr:before{content:"\f01a"}.stripe-pf-giropay:before{content:"\f01b"}.stripe-pf-google-wallet:before{content:"\f01c"}.stripe-pf-google-wallet-alt:before{content:"\f01d"}.stripe-pf-gpb:before{content:"\f01e"}.stripe-pf-gratipay:before{content:"\f01f"}.stripe-pf-ideal:before{content:"\f020"}.stripe-pf-ils:before{content:"\f021"}.stripe-pf-inr:before{content:"\f022"}.stripe-pf-invoice:before{content:"\f023"}.stripe-pf-invoice-sign:before{content:"\f024"}.stripe-pf-invoice-sign-alt:before{content:"\f025"}.stripe-pf-invoice-sign-alt-o:before{content:"\f026"}.stripe-pf-invoice-sign-o:before{content:"\f027"}.stripe-pf-jcb:before{content:"\f028"}.stripe-pf-jpy:before{content:"\f029"}.stripe-pf-krw:before{content:"\f02a"}.stripe-pf-maestro:before{content:"\f02b"}.stripe-pf-maestro-alt:before{content:"\f02c"}.stripe-pf-mastercard:before{content:"\f02d"}.stripe-pf-mastercard-alt:before{content:"\f02e"}.stripe-pf-mastercard-securecode:before{content:"\f02f"}.stripe-pf-ogone:before{content:"\f030"}.stripe-pf-paybox:before{content:"\f031"}.stripe-pf-paylife:before{content:"\f032"}.stripe-pf-paypal:before{content:"\f033"}.stripe-pf-paypal-alt:before{content:"\f034"}.stripe-pf-paysafecard:before{content:"\f035"}.stripe-pf-postepay:before{content:"\f036"}.stripe-pf-quick:before{content:"\f037"}.stripe-pf-rechnung:before{content:"\f038"}.stripe-pf-ripple:before{content:"\f039"}.stripe-pf-rub:before{content:"\f03a"}.stripe-pf-skrill:before{content:"\f03b"}.stripe-pf-sofort:before{content:"\f03c"}.stripe-pf-square:before{content:"\f03d"}.stripe-pf-stripe:before{content:"\f03e"}.stripe-pf-truste:before{content:"\f03f"}.stripe-pf-try:before{content:"\f040"}.stripe-pf-unionpay:before{content:"\f041"}.stripe-pf-usd:before{content:"\f042"}.stripe-pf-verified-by-visa:before{content:"\f043"}.stripe-pf-verisign:before{content:"\f044"}.stripe-pf-visa:before{content:"\f045"}.stripe-pf-visa-electron:before{content:"\f046"}.stripe-pf-western-union:before{content:"\f047"}.stripe-pf-western-union-alt:before{content:"\f048"}.stripe-pf-wirecard:before{content:"\f049"}.stripe-pf-sepa:before{content:"\f04a"}.stripe-pf-sepa-alt:before{content:"\f04b"}.stripe-pf-apple-pay:before{content:"\f04c"}.stripe-pf-interac:before{content:"\f04d"}.stripe-pf-paymill:before{content:"\f04e"}.stripe-pf-dankort:before{content:"\f04f"}.stripe-pf-bancontact-mister-cash:before{content:"\f050"}.stripe-pf-moip:before{content:"\f051"}.stripe-pf-pagseguro:before{content:"\f052"}.stripe-pf-cash-on-pickup:before{content:"\f053"}.stripe-pf-sage:before{content:"\f054"}.stripe-pf-elo:before{content:"\f055"}.stripe-pf-elo-alt:before{content:"\f056"}.stripe-pf-payu:before{content:"\f057"}.stripe-pf-mercado-pago:before{content:"\f058"}.stripe-pf-mercado-pago-sign:before{content:"\f059"}.stripe-pf-payshop:before{content:"\f05a"}.stripe-pf-multibanco:before{content:"\f05b"}.stripe-pf-gratipay-sign:before{content:"\f05c"}.stripe-pf-six:before{content:"\f05d"}.stripe-pf-cashcloud:before{content:"\f05e"}.stripe-pf-interac-alt:before{content:"\f05f"}.stripe-pf-klarna:before{content:"\f060"}.stripe-pf-bitpay:before{content:"\f061"}.stripe-pf-venmo:before{content:"\f062"}.stripe-pf-visa-debit:before{content:"\f063"}.stripe-pf-alipay:before{content:"\f064"}.stripe-pf-diners-alt:before{content:"\f065"}.stripe-pf-hipercard:before{content:"\f066"}.stripe-pf-skrill-alt:before{content:"\f067"}.stripe-pf-shopify:before{content:"\f068"}.stripe-pf-direct-debit:before{content:"\f069"}.stripe-pf-sodexo:before{content:"\f06a"}.stripe-pf-bpay:before{content:"\f06b"}.stripe-pf-contactless:before{content:"\f06c"}.stripe-pf-contactless-alt:before{content:"\f06d"}.stripe-pf-eth:before{content:"\f06e"}.stripe-pf-ltc:before{content:"\f06f"}.stripe-pf-visa-pay:before{content:"\f070"}.stripe-pf-wechat-pay:before{content:"\f071"}.stripe-pf-amazon-pay:before{content:"\f072"}.stripe-pf-amazon-pay-alt:before{content:"\f073"}.stripe-pf-p24{background-image:url(../images/p24.svg);background-repeat:no-repeat;width:2.5em;height:2.5em}#add_payment_method #payment_method_stripe {margin:25px 0 25px 25px;}#add_payment_method #payment_method_stripe_sepa {margin:25px 0 25px 25px;}#add_payment_method .woocommerce-PaymentMethod label {margin-left:10px;}#add_payment_method .woocommerce-PaymentMethod label .stripe-pf{margin:25px 0 25px 0;}#add_payment_method .woocommerce-PaymentMethod label .stripe-pf:first-child{margin-right:25px;}#add_payment_method li {clear:right;}#add_payment_method #wc-stripe_sepa-form {padding:10px;}
1
  /*!
2
  * PaymentFont 1.2.5 by @AMPoellmann - http://paymentfont.com
3
  * License - http://paymentfont.io/#license (Font: SIL OFL 1.1, CSS: MIT License)
4
+ */@font-face{font-family:PaymentFont;src:url(../paymentfonts/paymentfont-webfont.eot);src:url(../paymentfonts/paymentfont-webfont.eot?#iefix) format('embedded-opentype'),url(../paymentfonts/paymentfont-webfont.woff) format('woff2'),url(../paymentfonts/paymentfont-webfont.woff) format('woff'),url(../paymentfonts/paymentfont-webfont.ttf) format('truetype'),url(../paymentfonts/paymentfont-webfont.svg#paymentfont-webfont) format('svg');font-weight:400;font-style:normal}.stripe-pf{display:inline-block;font:normal normal normal 14px/1 PaymentFont;text-rendering:auto;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale;font-size:1.2em}.stripe-pf-right{float:right}.stripe-pf-left{float:left}.stripe-pf-lg{font-size:1.33333333em;line-height:.75em;vertical-align:-15%}.stripe-pf-2x{font-size:2em}.stripe-pf-3x{font-size:3em}.stripe-pf-4x{font-size:4em}.stripe-pf-5x{font-size:5em}.stripe-pf-amazon:before{content:"\f000"}.stripe-pf-american-express:before{content:"\f001"}.stripe-pf-american-express-alt:before{content:"\f002"}.stripe-pf-atm:before{content:"\f003"}.stripe-pf-bankomat:before{content:"\f004"}.stripe-pf-bank-transfer:before{content:"\f005"}.stripe-pf-bitcoin:before{content:"\f006"}.stripe-pf-bitcoin-sign:before{content:"\f007"}.stripe-pf-braintree:before{content:"\f008"}.stripe-pf-btc:before{content:"\f009"}.stripe-pf-card:before{content:"\f00a"}.stripe-pf-carta-si:before{content:"\f00b"}.stripe-pf-cash:before{content:"\f00c"}.stripe-pf-cash-on-delivery:before{content:"\f00d"}.stripe-pf-cb:before{content:"\f00e"}.stripe-pf-cirrus:before{content:"\f00f"}.stripe-pf-cirrus-alt:before{content:"\f010"}.stripe-pf-clickandbuy:before{content:"\f011"}.stripe-pf-credit-card:before{content:"\f012"}.stripe-pf-diners:before{content:"\f013"}.stripe-pf-discover:before{content:"\f014"}.stripe-pf-ec:before{content:"\f015"}.stripe-pf-eps:before{content:"\f016"}.stripe-pf-eur:before{content:"\f017"}.stripe-pf-facture:before{content:"\f018"}.stripe-pf-fattura:before{content:"\f019"}.stripe-pf-flattr:before{content:"\f01a"}.stripe-pf-giropay:before{content:"\f01b"}.stripe-pf-google-wallet:before{content:"\f01c"}.stripe-pf-google-wallet-alt:before{content:"\f01d"}.stripe-pf-gpb:before{content:"\f01e"}.stripe-pf-gratipay:before{content:"\f01f"}.stripe-pf-ideal:before{content:"\f020"}.stripe-pf-ils:before{content:"\f021"}.stripe-pf-inr:before{content:"\f022"}.stripe-pf-invoice:before{content:"\f023"}.stripe-pf-invoice-sign:before{content:"\f024"}.stripe-pf-invoice-sign-alt:before{content:"\f025"}.stripe-pf-invoice-sign-alt-o:before{content:"\f026"}.stripe-pf-invoice-sign-o:before{content:"\f027"}.stripe-pf-jcb:before{content:"\f028"}.stripe-pf-jpy:before{content:"\f029"}.stripe-pf-krw:before{content:"\f02a"}.stripe-pf-maestro:before{content:"\f02b"}.stripe-pf-maestro-alt:before{content:"\f02c"}.stripe-pf-mastercard:before{content:"\f02d"}.stripe-pf-mastercard-alt:before{content:"\f02e"}.stripe-pf-mastercard-securecode:before{content:"\f02f"}.stripe-pf-ogone:before{content:"\f030"}.stripe-pf-paybox:before{content:"\f031"}.stripe-pf-paylife:before{content:"\f032"}.stripe-pf-paypal:before{content:"\f033"}.stripe-pf-paypal-alt:before{content:"\f034"}.stripe-pf-paysafecard:before{content:"\f035"}.stripe-pf-postepay:before{content:"\f036"}.stripe-pf-quick:before{content:"\f037"}.stripe-pf-rechnung:before{content:"\f038"}.stripe-pf-ripple:before{content:"\f039"}.stripe-pf-rub:before{content:"\f03a"}.stripe-pf-skrill:before{content:"\f03b"}.stripe-pf-sofort:before{content:"\f03c"}.stripe-pf-square:before{content:"\f03d"}.stripe-pf-stripe:before{content:"\f03e"}.stripe-pf-truste:before{content:"\f03f"}.stripe-pf-try:before{content:"\f040"}.stripe-pf-unionpay:before{content:"\f041"}.stripe-pf-usd:before{content:"\f042"}.stripe-pf-verified-by-visa:before{content:"\f043"}.stripe-pf-verisign:before{content:"\f044"}.stripe-pf-visa:before{content:"\f045"}.stripe-pf-visa-electron:before{content:"\f046"}.stripe-pf-western-union:before{content:"\f047"}.stripe-pf-western-union-alt:before{content:"\f048"}.stripe-pf-wirecard:before{content:"\f049"}.stripe-pf-sepa:before{content:"\f04a"}.stripe-pf-sepa-alt:before{content:"\f04b"}.stripe-pf-apple-pay:before{content:"\f04c"}.stripe-pf-interac:before{content:"\f04d"}.stripe-pf-paymill:before{content:"\f04e"}.stripe-pf-dankort:before{content:"\f04f"}.stripe-pf-bancontact-mister-cash:before{content:"\f050"}.stripe-pf-moip:before{content:"\f051"}.stripe-pf-pagseguro:before{content:"\f052"}.stripe-pf-cash-on-pickup:before{content:"\f053"}.stripe-pf-sage:before{content:"\f054"}.stripe-pf-elo:before{content:"\f055"}.stripe-pf-elo-alt:before{content:"\f056"}.stripe-pf-payu:before{content:"\f057"}.stripe-pf-mercado-pago:before{content:"\f058"}.stripe-pf-mercado-pago-sign:before{content:"\f059"}.stripe-pf-payshop:before{content:"\f05a"}.stripe-pf-multibanco:before{content:"\f05b"}.stripe-pf-gratipay-sign:before{content:"\f05c"}.stripe-pf-six:before{content:"\f05d"}.stripe-pf-cashcloud:before{content:"\f05e"}.stripe-pf-interac-alt:before{content:"\f05f"}.stripe-pf-klarna:before{content:"\f060"}.stripe-pf-bitpay:before{content:"\f061"}.stripe-pf-venmo:before{content:"\f062"}.stripe-pf-visa-debit:before{content:"\f063"}.stripe-pf-alipay:before{content:"\f064"}.stripe-pf-diners-alt:before{content:"\f065"}.stripe-pf-hipercard:before{content:"\f066"}.stripe-pf-skrill-alt:before{content:"\f067"}.stripe-pf-shopify:before{content:"\f068"}.stripe-pf-direct-debit:before{content:"\f069"}.stripe-pf-sodexo:before{content:"\f06a"}.stripe-pf-bpay:before{content:"\f06b"}.stripe-pf-contactless:before{content:"\f06c"}.stripe-pf-contactless-alt:before{content:"\f06d"}.stripe-pf-eth:before{content:"\f06e"}.stripe-pf-ltc:before{content:"\f06f"}.stripe-pf-visa-pay:before{content:"\f070"}.stripe-pf-wechat-pay:before{content:"\f071"}.stripe-pf-amazon-pay:before{content:"\f072"}.stripe-pf-amazon-pay-alt:before{content:"\f073"}.stripe-pf-p24{background-image:url(../images/p24.svg);background-repeat:no-repeat;width:2.5em;height:2.5em}#add_payment_method #payment_method_stripe {margin:25px 0 25px 25px;}#add_payment_method #payment_method_stripe_sepa {margin:25px 0 25px 25px;}#add_payment_method .woocommerce-PaymentMethod label {margin-left:10px;}#add_payment_method .woocommerce-PaymentMethod label .stripe-pf{margin:25px 0 0 0;}#add_payment_method .woocommerce-PaymentMethod label .stripe-pf:first-child{margin-right:25px;}#add_payment_method li {clear:right;}#add_payment_method #wc-stripe_sepa-form {padding:10px;}form#order_review #payment_method_stripe {margin:25px 0 25px 25px;}form#order_review #payment_method_stripe_sepa {margin:25px 0 25px 25px;}form#order_review .payment_methods label {margin-left:10px;}form#order_review .payment_methods label .stripe-pf:first-child{margin-right:25px;}form#order_review li {clear:right;}form#order_review #wc-stripe_sepa-form {padding:10px;}
assets/js/stripe-admin.js CHANGED
@@ -45,9 +45,9 @@ jQuery( function( $ ) {
45
  // Toggle Stripe Checkout settings.
46
  $( '#woocommerce_stripe_stripe_checkout' ).change( function() {
47
  if ( $( this ).is( ':checked' ) ) {
48
- $( '#woocommerce_stripe_stripe_checkout_locale, #woocommerce_stripe_stripe_bitcoin, #woocommerce_stripe_stripe_checkout_image' ).closest( 'tr' ).show();
49
  } else {
50
- $( '#woocommerce_stripe_stripe_checkout_locale, #woocommerce_stripe_stripe_bitcoin, #woocommerce_stripe_stripe_checkout_image' ).closest( 'tr' ).hide();
51
  }
52
  }).change();
53
 
45
  // Toggle Stripe Checkout settings.
46
  $( '#woocommerce_stripe_stripe_checkout' ).change( function() {
47
  if ( $( this ).is( ':checked' ) ) {
48
+ $( '#woocommerce_stripe_stripe_bitcoin, #woocommerce_stripe_stripe_checkout_image' ).closest( 'tr' ).show();
49
  } else {
50
+ $( '#woocommerce_stripe_stripe_bitcoin, #woocommerce_stripe_stripe_checkout_image' ).closest( 'tr' ).hide();
51
  }
52
  }).change();
53
 
assets/js/stripe-admin.min.js CHANGED
@@ -1 +1 @@
1
- jQuery(function(a){"use strict";var b={isTestMode:function(){return a("#woocommerce_stripe_testmode").is(":checked")},getSecretKey:function(){return b.isTestMode()?a("#woocommerce_stripe_test_secret_key").val():a("#woocommerce_stripe_secret_key").val()},init:function(){a(document.body).on("change","#woocommerce_stripe_testmode",function(){var b=a("#woocommerce_stripe_test_secret_key").parents("tr").eq(0),c=a("#woocommerce_stripe_test_publishable_key").parents("tr").eq(0),d=a("#woocommerce_stripe_secret_key").parents("tr").eq(0),e=a("#woocommerce_stripe_publishable_key").parents("tr").eq(0);a(this).is(":checked")?(b.show(),c.show(),d.hide(),e.hide()):(b.hide(),c.hide(),d.show(),e.show())}),a("#woocommerce_stripe_testmode").change(),a("#woocommerce_stripe_stripe_checkout").change(function(){a(this).is(":checked")?a("#woocommerce_stripe_stripe_checkout_locale, #woocommerce_stripe_stripe_bitcoin, #woocommerce_stripe_stripe_checkout_image").closest("tr").show():a("#woocommerce_stripe_stripe_checkout_locale, #woocommerce_stripe_stripe_bitcoin, #woocommerce_stripe_stripe_checkout_image").closest("tr").hide()}).change(),a("#woocommerce_stripe_payment_request").change(function(){a(this).is(":checked")?a("#woocommerce_stripe_payment_request_button_theme, #woocommerce_stripe_payment_request_button_type, #woocommerce_stripe_payment_request_button_height").closest("tr").show():a("#woocommerce_stripe_payment_request_button_theme, #woocommerce_stripe_payment_request_button_type, #woocommerce_stripe_payment_request_button_height").closest("tr").hide()}).change()}};b.init()});
1
+ jQuery(function(a){"use strict";var b={isTestMode:function(){return a("#woocommerce_stripe_testmode").is(":checked")},getSecretKey:function(){return b.isTestMode()?a("#woocommerce_stripe_test_secret_key").val():a("#woocommerce_stripe_secret_key").val()},init:function(){a(document.body).on("change","#woocommerce_stripe_testmode",function(){var b=a("#woocommerce_stripe_test_secret_key").parents("tr").eq(0),c=a("#woocommerce_stripe_test_publishable_key").parents("tr").eq(0),d=a("#woocommerce_stripe_secret_key").parents("tr").eq(0),e=a("#woocommerce_stripe_publishable_key").parents("tr").eq(0);a(this).is(":checked")?(b.show(),c.show(),d.hide(),e.hide()):(b.hide(),c.hide(),d.show(),e.show())}),a("#woocommerce_stripe_testmode").change(),a("#woocommerce_stripe_stripe_checkout").change(function(){a(this).is(":checked")?a("#woocommerce_stripe_stripe_bitcoin, #woocommerce_stripe_stripe_checkout_image").closest("tr").show():a("#woocommerce_stripe_stripe_bitcoin, #woocommerce_stripe_stripe_checkout_image").closest("tr").hide()}).change(),a("#woocommerce_stripe_payment_request").change(function(){a(this).is(":checked")?a("#woocommerce_stripe_payment_request_button_theme, #woocommerce_stripe_payment_request_button_type, #woocommerce_stripe_payment_request_button_height").closest("tr").show():a("#woocommerce_stripe_payment_request_button_theme, #woocommerce_stripe_payment_request_button_type, #woocommerce_stripe_payment_request_button_height").closest("tr").hide()}).change()}};b.init()});
assets/js/stripe-payment-request.js CHANGED
@@ -2,7 +2,8 @@
2
  jQuery( function( $ ) {
3
  'use strict';
4
 
5
- var stripe = Stripe( wc_stripe_payment_request_params.stripe.key );
 
6
 
7
  /**
8
  * Object to handle Stripe payment forms.
@@ -220,7 +221,8 @@ jQuery( function( $ ) {
220
  postcode: address.postalCode,
221
  city: address.city,
222
  address: typeof address.addressLine[0] === 'undefined' ? '' : address.addressLine[0],
223
- address_2: typeof address.addressLine[1] === 'undefined' ? '' : address.addressLine[1]
 
224
  };
225
 
226
  return $.ajax({
@@ -239,7 +241,8 @@ jQuery( function( $ ) {
239
  updateShippingDetails: function( details, shippingOption ) {
240
  var data = {
241
  security: wc_stripe_payment_request_params.nonce.update_shipping,
242
- shipping_method: [ shippingOption.id ]
 
243
  };
244
 
245
  return $.ajax({
@@ -330,9 +333,7 @@ jQuery( function( $ ) {
330
  paymentDetails = cart.order_data;
331
  }
332
 
333
- var paymentRequest = stripe.paymentRequest( options );
334
- var paymentRequestType = '';
335
-
336
 
337
  var elements = stripe.elements({ locale: wc_stripe_payment_request_params.button.locale });
338
  var prButton = elements.create( 'paymentRequestButton', {
2
  jQuery( function( $ ) {
3
  'use strict';
4
 
5
+ var stripe = Stripe( wc_stripe_payment_request_params.stripe.key ),
6
+ paymentRequestType;
7
 
8
  /**
9
  * Object to handle Stripe payment forms.
221
  postcode: address.postalCode,
222
  city: address.city,
223
  address: typeof address.addressLine[0] === 'undefined' ? '' : address.addressLine[0],
224
+ address_2: typeof address.addressLine[1] === 'undefined' ? '' : address.addressLine[1],
225
+ payment_request_type: paymentRequestType
226
  };
227
 
228
  return $.ajax({
241
  updateShippingDetails: function( details, shippingOption ) {
242
  var data = {
243
  security: wc_stripe_payment_request_params.nonce.update_shipping,
244
+ shipping_method: [ shippingOption.id ],
245
+ payment_request_type: paymentRequestType
246
  };
247
 
248
  return $.ajax({
333
  paymentDetails = cart.order_data;
334
  }
335
 
336
+ var paymentRequest = stripe.paymentRequest( options );
 
 
337
 
338
  var elements = stripe.elements({ locale: wc_stripe_payment_request_params.button.locale });
339
  var prButton = elements.create( 'paymentRequestButton', {
assets/js/stripe-payment-request.min.js CHANGED
@@ -1 +1 @@
1
- jQuery(function(a){"use strict";var b=Stripe(wc_stripe_payment_request_params.stripe.key),c={getAjaxURL:function(a){return wc_stripe_payment_request_params.ajax_url.toString().replace("%%endpoint%%","wc_stripe_"+a)},getCartDetails:function(b){var d={security:wc_stripe_payment_request_params.nonce.payment};a.ajax({type:"POST",data:d,url:c.getAjaxURL("get_cart_details"),success:function(a){b.update({total:a.order_data.total})}})},getAttributes:function(){var b=a(".variations_form").find(".variations select"),c={},d=0,e=0;return b.each(function(){var b=a(this).data("attribute_name")||a(this).attr("name"),f=a(this).val()||"";f.length>0&&e++,d++,c[b]=f}),{count:d,chosenCount:e,data:c}},processSource:function(b,d){var e=c.getOrderData(b,d);return a.ajax({type:"POST",data:e,dataType:"json",url:c.getAjaxURL("create_order")})},getOrderData:function(a,b){var c=a.source,d=c.owner.email,e=c.owner.phone,f=c.owner.address,g=c.owner.name,h=a.shippingAddress,i={_wpnonce:wc_stripe_payment_request_params.nonce.checkout,billing_first_name:null!==g?g.split(" ").slice(0,1).join(" "):"",billing_last_name:null!==g?g.split(" ").slice(1).join(" "):"",billing_company:"",billing_email:null!==d?d:a.payerEmail,billing_phone:null!==e?e:a.payerPhone.replace("/[() -]/g",""),billing_country:null!==f?f.country:"",billing_address_1:null!==f?f.line1:"",billing_address_2:null!==f?f.line2:"",billing_city:null!==f?f.city:"",billing_state:null!==f?f.state:"",billing_postcode:null!==f?f.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===a.shippingOption?null:a.shippingOption.id],order_comments:"",payment_method:"stripe",ship_to_different_address:1,terms:1,stripe_source:c.id,payment_request_type:b};return h&&(i.shipping_first_name=h.recipient.split(" ").slice(0,1).join(" "),i.shipping_last_name=h.recipient.split(" ").slice(1).join(" "),i.shipping_company=h.organization,i.shipping_country=h.country,i.shipping_address_1=void 0===h.addressLine[0]?"":h.addressLine[0],i.shipping_address_2=void 0===h.addressLine[1]?"":h.addressLine[1],i.shipping_city=h.city,i.shipping_state=h.region,i.shipping_postcode=h.postalCode),i},getErrorMessageHTML:function(b){return a('<div class="woocommerce-error" />').text(b)},abortPayment:function(b,c){if(b.complete("fail"),a(".woocommerce-error").remove(),wc_stripe_payment_request_params.is_product_page){var d=a(".product");d.before(c),a("html, body").animate({scrollTop:d.prev(".woocommerce-error").offset().top},600)}else{var e=a(".shop_table.cart").closest("form");e.before(c),a("html, body").animate({scrollTop:e.prev(".woocommerce-error").offset().top},600)}},completePayment:function(a,b){c.block(),a.complete("success"),window.location=b},block:function(){a.blockUI({message:null,overlayCSS:{background:"#fff",opacity:.6}})},updateShippingOptions:function(b,d){var e={security:wc_stripe_payment_request_params.nonce.shipping,country:d.country,state:d.region,postcode:d.postalCode,city:d.city,address:void 0===d.addressLine[0]?"":d.addressLine[0],address_2:void 0===d.addressLine[1]?"":d.addressLine[1]};return a.ajax({type:"POST",data:e,url:c.getAjaxURL("get_shipping_options")})},updateShippingDetails:function(b,d){var e={security:wc_stripe_payment_request_params.nonce.update_shipping,shipping_method:[d.id]};return a.ajax({type:"POST",data:e,url:c.getAjaxURL("update_shipping_method")})},addToCart:function(){var b=a(".single_add_to_cart_button").val();a(".single_variation_wrap").length&&(b=a(".single_variation_wrap").find('input[name="product_id"]').val());var d={security:wc_stripe_payment_request_params.nonce.add_to_cart,product_id:b,qty:a(".quantity .qty").val(),attributes:a(".variations_form").length?c.getAttributes().data:[]};return a.ajax({type:"POST",data:d,url:c.getAjaxURL("add_to_cart")})},clearCart:function(){var b={security:wc_stripe_payment_request_params.nonce.clear_cart};return a.ajax({type:"POST",data:b,url:c.getAjaxURL("clear_cart"),success:function(a){}})},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(d){var e,f;wc_stripe_payment_request_params.is_product_page?(f=c.getRequestOptionsFromLocal(),e=f):(f={total:d.order_data.total,currency:d.order_data.currency,country:d.order_data.country_code,requestPayerName:!0,requestPayerEmail:!0,requestPayerPhone:!0,requestShipping:!!d.shipping_required,displayItems:d.order_data.displayItems},e=d.order_data);var g=b.paymentRequest(f),h="",i=b.elements({locale:wc_stripe_payment_request_params.button.locale}),j=i.create("paymentRequestButton",{paymentRequest:g,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"}}});g.canMakePayment().then(function(b){if(b){if(h=b.applePay?"apple_pay":"payment_request_api",wc_stripe_payment_request_params.is_product_page){var d=a(".single_add_to_cart_button");j.on("click",function(a){d.is(".disabled")?(a.preventDefault(),d.is(".wc-variation-is-unavailable")?window.alert(wc_add_to_cart_variation_params.i18n_unavailable_text):d.is(".wc-variation-selection-needed")&&window.alert(wc_add_to_cart_variation_params.i18n_make_a_selection_text)):c.addToCart()}),a(document.body).on("woocommerce_variation_has_changed",function(){a("#wc-stripe-payment-request-button").block({message:null}),a.when(c.getSelectedProductData()).then(function(b){a.when(g.update({total:b.total,displayItems:b.displayItems})).then(function(){a("#wc-stripe-payment-request-button").unblock()})})}),a(".quantity").on("change",".qty",function(){a("#wc-stripe-payment-request-button").block({message:null}),a.when(c.getSelectedProductData()).then(function(b){a.when(g.update({total:b.total,displayItems:b.displayItems})).then(function(){a("#wc-stripe-payment-request-button").unblock()})})})}a("#wc-stripe-payment-request-button").length&&(j.mount("#wc-stripe-payment-request-button"),a("#wc-stripe-payment-request-button-separator").show())}else a("#wc-stripe-payment-request-button").hide(),a("#wc-stripe-payment-request-button-separator").hide()}),g.on("shippingaddresschange",function(b){a.when(c.updateShippingOptions(e,b.shippingAddress)).then(function(a){b.updateWith({status:a.result,shippingOptions:a.shipping_options,total:a.total,displayItems:a.displayItems})})}),g.on("shippingoptionchange",function(b){a.when(c.updateShippingDetails(e,b.shippingOption)).then(function(a){"success"===a.result&&b.updateWith({status:"success",total:a.total,displayItems:a.displayItems}),"fail"===a.result&&b.updateWith({status:"fail"})})}),g.on("source",function(b){"no"===wc_stripe_payment_request_params.stripe.allow_prepaid_card&&"prepaid"===b.source.card.funding?c.abortPayment(b,c.getErrorMessageHTML(wc_stripe_payment_request_params.i18n.no_prepaid_card)):a.when(c.processSource(b,h)).then(function(a){"success"===a.result?c.completePayment(b,a.redirect):c.abortPayment(b,a.messages)})})},getSelectedProductData:function(){var b=a(".single_add_to_cart_button").val();a(".single_variation_wrap").length&&(b=a(".single_variation_wrap").find('input[name="product_id"]').val());var d={security:wc_stripe_payment_request_params.nonce.get_selected_product_data,product_id:b,qty:a(".quantity .qty").val(),attributes:a(".variations_form").length?c.getAttributes().data:[]};return a.ajax({type:"POST",data:d,url:c.getAjaxURL("get_selected_product_data")})},init:function(){var b={security:wc_stripe_payment_request_params.nonce.payment};a.ajax({type:"POST",data:b,url:c.getAjaxURL("get_cart_details"),success:function(a){c.startPaymentRequest(a)}})}};c.init(),a(document.body).on("updated_cart_totals",function(){c.init()}),a(document.body).on("updated_checkout",function(){c.init()})});
1
+ jQuery(function(a){"use strict";var b,c=Stripe(wc_stripe_payment_request_params.stripe.key),d={getAjaxURL:function(a){return wc_stripe_payment_request_params.ajax_url.toString().replace("%%endpoint%%","wc_stripe_"+a)},getCartDetails:function(b){var c={security:wc_stripe_payment_request_params.nonce.payment};a.ajax({type:"POST",data:c,url:d.getAjaxURL("get_cart_details"),success:function(a){b.update({total:a.order_data.total})}})},getAttributes:function(){var b=a(".variations_form").find(".variations select"),c={},d=0,e=0;return b.each(function(){var b=a(this).data("attribute_name")||a(this).attr("name"),f=a(this).val()||"";f.length>0&&e++,d++,c[b]=f}),{count:d,chosenCount:e,data:c}},processSource:function(b,c){var e=d.getOrderData(b,c);return a.ajax({type:"POST",data:e,dataType:"json",url:d.getAjaxURL("create_order")})},getOrderData:function(a,b){var c=a.source,d=c.owner.email,e=c.owner.phone,f=c.owner.address,g=c.owner.name,h=a.shippingAddress,i={_wpnonce:wc_stripe_payment_request_params.nonce.checkout,billing_first_name:null!==g?g.split(" ").slice(0,1).join(" "):"",billing_last_name:null!==g?g.split(" ").slice(1).join(" "):"",billing_company:"",billing_email:null!==d?d:a.payerEmail,billing_phone:null!==e?e:a.payerPhone.replace("/[() -]/g",""),billing_country:null!==f?f.country:"",billing_address_1:null!==f?f.line1:"",billing_address_2:null!==f?f.line2:"",billing_city:null!==f?f.city:"",billing_state:null!==f?f.state:"",billing_postcode:null!==f?f.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===a.shippingOption?null:a.shippingOption.id],order_comments:"",payment_method:"stripe",ship_to_different_address:1,terms:1,stripe_source:c.id,payment_request_type:b};return h&&(i.shipping_first_name=h.recipient.split(" ").slice(0,1).join(" "),i.shipping_last_name=h.recipient.split(" ").slice(1).join(" "),i.shipping_company=h.organization,i.shipping_country=h.country,i.shipping_address_1=void 0===h.addressLine[0]?"":h.addressLine[0],i.shipping_address_2=void 0===h.addressLine[1]?"":h.addressLine[1],i.shipping_city=h.city,i.shipping_state=h.region,i.shipping_postcode=h.postalCode),i},getErrorMessageHTML:function(b){return a('<div class="woocommerce-error" />').text(b)},abortPayment:function(b,c){if(b.complete("fail"),a(".woocommerce-error").remove(),wc_stripe_payment_request_params.is_product_page){var d=a(".product");d.before(c),a("html, body").animate({scrollTop:d.prev(".woocommerce-error").offset().top},600)}else{var e=a(".shop_table.cart").closest("form");e.before(c),a("html, body").animate({scrollTop:e.prev(".woocommerce-error").offset().top},600)}},completePayment:function(a,b){d.block(),a.complete("success"),window.location=b},block:function(){a.blockUI({message:null,overlayCSS:{background:"#fff",opacity:.6}})},updateShippingOptions:function(c,e){var f={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:b};return a.ajax({type:"POST",data:f,url:d.getAjaxURL("get_shipping_options")})},updateShippingDetails:function(c,e){var f={security:wc_stripe_payment_request_params.nonce.update_shipping,shipping_method:[e.id],payment_request_type:b};return a.ajax({type:"POST",data:f,url:d.getAjaxURL("update_shipping_method")})},addToCart:function(){var b=a(".single_add_to_cart_button").val();a(".single_variation_wrap").length&&(b=a(".single_variation_wrap").find('input[name="product_id"]').val());var c={security:wc_stripe_payment_request_params.nonce.add_to_cart,product_id:b,qty:a(".quantity .qty").val(),attributes:a(".variations_form").length?d.getAttributes().data:[]};return a.ajax({type:"POST",data:c,url:d.getAjaxURL("add_to_cart")})},clearCart:function(){var b={security:wc_stripe_payment_request_params.nonce.clear_cart};return a.ajax({type:"POST",data:b,url:d.getAjaxURL("clear_cart"),success:function(a){}})},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(e){var f,g;wc_stripe_payment_request_params.is_product_page?(g=d.getRequestOptionsFromLocal(),f=g):(g={total:e.order_data.total,currency:e.order_data.currency,country:e.order_data.country_code,requestPayerName:!0,requestPayerEmail:!0,requestPayerPhone:!0,requestShipping:!!e.shipping_required,displayItems:e.order_data.displayItems},f=e.order_data);var h=c.paymentRequest(g),i=c.elements({locale:wc_stripe_payment_request_params.button.locale}),j=i.create("paymentRequestButton",{paymentRequest:h,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"}}});h.canMakePayment().then(function(c){if(c){if(b=c.applePay?"apple_pay":"payment_request_api",wc_stripe_payment_request_params.is_product_page){var e=a(".single_add_to_cart_button");j.on("click",function(a){e.is(".disabled")?(a.preventDefault(),e.is(".wc-variation-is-unavailable")?window.alert(wc_add_to_cart_variation_params.i18n_unavailable_text):e.is(".wc-variation-selection-needed")&&window.alert(wc_add_to_cart_variation_params.i18n_make_a_selection_text)):d.addToCart()}),a(document.body).on("woocommerce_variation_has_changed",function(){a("#wc-stripe-payment-request-button").block({message:null}),a.when(d.getSelectedProductData()).then(function(b){a.when(h.update({total:b.total,displayItems:b.displayItems})).then(function(){a("#wc-stripe-payment-request-button").unblock()})})}),a(".quantity").on("change",".qty",function(){a("#wc-stripe-payment-request-button").block({message:null}),a.when(d.getSelectedProductData()).then(function(b){a.when(h.update({total:b.total,displayItems:b.displayItems})).then(function(){a("#wc-stripe-payment-request-button").unblock()})})})}a("#wc-stripe-payment-request-button").length&&(j.mount("#wc-stripe-payment-request-button"),a("#wc-stripe-payment-request-button-separator").show())}else a("#wc-stripe-payment-request-button").hide(),a("#wc-stripe-payment-request-button-separator").hide()}),h.on("shippingaddresschange",function(b){a.when(d.updateShippingOptions(f,b.shippingAddress)).then(function(a){b.updateWith({status:a.result,shippingOptions:a.shipping_options,total:a.total,displayItems:a.displayItems})})}),h.on("shippingoptionchange",function(b){a.when(d.updateShippingDetails(f,b.shippingOption)).then(function(a){"success"===a.result&&b.updateWith({status:"success",total:a.total,displayItems:a.displayItems}),"fail"===a.result&&b.updateWith({status:"fail"})})}),h.on("source",function(c){"no"===wc_stripe_payment_request_params.stripe.allow_prepaid_card&&"prepaid"===c.source.card.funding?d.abortPayment(c,d.getErrorMessageHTML(wc_stripe_payment_request_params.i18n.no_prepaid_card)):a.when(d.processSource(c,b)).then(function(a){"success"===a.result?d.completePayment(c,a.redirect):d.abortPayment(c,a.messages)})})},getSelectedProductData:function(){var b=a(".single_add_to_cart_button").val();a(".single_variation_wrap").length&&(b=a(".single_variation_wrap").find('input[name="product_id"]').val());var c={security:wc_stripe_payment_request_params.nonce.get_selected_product_data,product_id:b,qty:a(".quantity .qty").val(),attributes:a(".variations_form").length?d.getAttributes().data:[]};return a.ajax({type:"POST",data:c,url:d.getAjaxURL("get_selected_product_data")})},init:function(){var b={security:wc_stripe_payment_request_params.nonce.payment};a.ajax({type:"POST",data:b,url:d.getAjaxURL("get_cart_details"),success:function(a){d.startPaymentRequest(a)}})}};d.init(),a(document.body).on("updated_cart_totals",function(){d.init()}),a(document.body).on("updated_checkout",function(){d.init()})});
assets/js/stripe.js CHANGED
@@ -6,7 +6,8 @@ jQuery( function( $ ) {
6
  var stripe = Stripe( wc_stripe_params.key );
7
 
8
  if ( 'yes' === wc_stripe_params.use_elements ) {
9
- var elements = stripe.elements(),
 
10
  stripe_card,
11
  stripe_exp,
12
  stripe_cvc;
@@ -232,6 +233,10 @@ jQuery( function( $ ) {
232
  return $( '#payment_method_stripe_bitcoin' ).is( ':checked' );
233
  },
234
 
 
 
 
 
235
  hasSource: function() {
236
  return 0 < $( 'input.stripe-source' ).length;
237
  },
@@ -354,10 +359,12 @@ jQuery( function( $ ) {
354
 
355
  onError: function( e, result ) {
356
  var message = result.error.message,
357
- errorContainer = wc_stripe_form.getSelectedPaymentElement().parent( '.wc_payment_method, .woocommerce-PaymentMethod' ).find( '.stripe-source-errors' );
358
 
359
- // Customers do not need to know the specifics of the below type of errors
360
- // therefore return a generic localizable error message.
 
 
361
  if (
362
  'invalid_request_error' === result.error.type ||
363
  'api_connection_error' === result.error.type ||
@@ -380,9 +387,12 @@ jQuery( function( $ ) {
380
  $( '.woocommerce-NoticeGroup-checkout' ).remove();
381
  console.log( result.error.message ); // Leave for troubleshooting.
382
  $( errorContainer ).html( '<ul class="woocommerce_error woocommerce-error wc-stripe-error"><li>' + message + '</li></ul>' );
383
- $( 'html, body' ).animate({
384
- scrollTop: ( $( '.wc-stripe-error' ).offset().top - 200 )
385
- }, 200 );
 
 
 
386
  wc_stripe_form.unblock();
387
  },
388
 
@@ -487,9 +497,12 @@ jQuery( function( $ ) {
487
  // Handle special inputs that are unique to a payment method.
488
  switch ( source_type ) {
489
  case 'sepa_debit':
490
- extra_details.currency = $( '#stripe-' + source_type + '-payment-data' ).data( 'currency' );
491
- extra_details.owner.name = $( '#stripe-sepa-owner' ).val();
492
- extra_details.sepa_debit = { iban: $( '#stripe-sepa-iban' ).val() };
 
 
 
493
  break;
494
  case 'ideal':
495
  extra_details.ideal = { bank: $( '#stripe-ideal-bank' ).val() };
@@ -499,6 +512,9 @@ jQuery( function( $ ) {
499
  extra_details.currency = $( '#stripe-' + source_type + '-payment-data' ).data( 'currency' );
500
  extra_details.amount = $( '#stripe-' + source_type + '-payment-data' ).data( 'amount' );
501
  break;
 
 
 
502
  }
503
 
504
  extra_details.type = source_type;
@@ -523,6 +539,19 @@ jQuery( function( $ ) {
523
  }
524
  },
525
 
 
 
 
 
 
 
 
 
 
 
 
 
 
526
  // Legacy
527
  createToken: function() {
528
  var card = $( '#stripe-card-number' ).val(),
@@ -612,11 +641,31 @@ jQuery( function( $ ) {
612
  return false;
613
  }
614
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
615
  if (
616
  wc_stripe_form.isBancontactChosen() ||
617
  wc_stripe_form.isGiropayChosen() ||
618
  wc_stripe_form.isIdealChosen() ||
619
- wc_stripe_form.isAlipayChosen()
 
 
620
  ) {
621
  if ( $( 'form#order_review' ).length ) {
622
  $( 'form#order_review' )
@@ -625,34 +674,48 @@ jQuery( function( $ ) {
625
  this.onSubmit
626
  );
627
 
 
 
 
 
628
  wc_stripe_form.form.submit();
629
  }
630
 
631
- return true;
632
- }
 
 
 
 
633
 
634
- if ( wc_stripe_form.isSofortChosen() ) {
635
- // Check if Sofort bank country is chosen before proceed.
636
- if ( '-1' === $( '#stripe-bank-country' ).val() ) {
637
- var error = { error: { message: wc_stripe_params.no_bank_country_msg } };
638
- $( document.body ).trigger( 'stripeError', error );
639
- return false;
640
  }
641
 
642
- if ( $( 'form#order_review' ).length ) {
643
- $( 'form#order_review' )
644
  .off(
645
  'submit',
646
  this.onSubmit
647
  );
648
 
 
 
 
 
649
  wc_stripe_form.form.submit();
650
  }
651
-
652
- return true;
653
  }
654
 
655
- wc_stripe_form.validateCheckout();
 
 
 
 
 
656
 
657
  // Prevent form submitting
658
  return false;
@@ -666,20 +729,6 @@ jQuery( function( $ ) {
666
  return false;
667
  }
668
 
669
- if ( wc_stripe_form.isSepaChosen() ) {
670
- // Check if SEPA owner is filled before proceed.
671
- if ( '' === $( '#stripe-sepa-owner' ).val() ) {
672
- $( document.body ).trigger( 'stripeError', { error: { message: wc_stripe_params.no_sepa_owner_msg } } );
673
- return false;
674
- }
675
-
676
- // Check if SEPA IBAN is filled before proceed.
677
- if ( '' === $( '#stripe-sepa-iban' ).val() ) {
678
- $( document.body ).trigger( 'stripeError', { error: { message: wc_stripe_params.no_sepa_iban_msg } } );
679
- return false;
680
- }
681
- }
682
-
683
  wc_stripe_form.block();
684
 
685
  // Process legacy card token.
@@ -697,34 +746,6 @@ jQuery( function( $ ) {
697
  wc_stripe_form.reset();
698
  },
699
 
700
- prepareSourceToServer: function( source ) {
701
- var preparedSource = {
702
- id: source.id,
703
- card: source.card ? source.card : '',
704
- bitcoin: source.bitcoin ? source.bitcoin : '',
705
- flow: source.flow,
706
- object: source.object,
707
- status: source.status,
708
- type: source.type,
709
- usage: source.usage
710
- };
711
-
712
- return preparedSource;
713
- },
714
-
715
- processStripeResponse: function( source ) {
716
- wc_stripe_form.reset();
717
-
718
- // Insert the Source into the form so it gets submitted to the server.
719
- wc_stripe_form.form.append( "<input type='hidden' class='stripe-source' name='stripe_source' value='" + source.id + "'/>" );
720
-
721
- if ( $( 'form#add_payment_method' ).length ) {
722
- $( wc_stripe_form.form ).off( 'submit', wc_stripe_form.form.onSubmit );
723
- }
724
-
725
- wc_stripe_form.form.submit();
726
- },
727
-
728
  reset: function() {
729
  $( '.wc-stripe-error, .stripe-source, .stripe_token, .stripe-checkout-object' ).remove();
730
 
6
  var stripe = Stripe( wc_stripe_params.key );
7
 
8
  if ( 'yes' === wc_stripe_params.use_elements ) {
9
+ var stripe_elements_options = wc_stripe_params.elements_options.length ? wc_stripe_params.elements_options : {};
10
+ var elements = stripe.elements( stripe_elements_options ),
11
  stripe_card,
12
  stripe_exp,
13
  stripe_cvc;
233
  return $( '#payment_method_stripe_bitcoin' ).is( ':checked' );
234
  },
235
 
236
+ isP24Chosen: function() {
237
+ return $( '#payment_method_stripe_p24' ).is( ':checked' );
238
+ },
239
+
240
  hasSource: function() {
241
  return 0 < $( 'input.stripe-source' ).length;
242
  },
359
 
360
  onError: function( e, result ) {
361
  var message = result.error.message,
362
+ errorContainer = wc_stripe_form.getSelectedPaymentElement().parents( 'li' ).eq(0).find( '.stripe-source-errors' );
363
 
364
+ /*
365
+ * Customers do not need to know the specifics of the below type of errors
366
+ * therefore return a generic localizable error message.
367
+ */
368
  if (
369
  'invalid_request_error' === result.error.type ||
370
  'api_connection_error' === result.error.type ||
387
  $( '.woocommerce-NoticeGroup-checkout' ).remove();
388
  console.log( result.error.message ); // Leave for troubleshooting.
389
  $( errorContainer ).html( '<ul class="woocommerce_error woocommerce-error wc-stripe-error"><li>' + message + '</li></ul>' );
390
+
391
+ if ( $( '.wc-stripe-error' ).length ) {
392
+ $( 'html, body' ).animate({
393
+ scrollTop: ( $( '.wc-stripe-error' ).offset().top - 200 )
394
+ }, 200 );
395
+ }
396
  wc_stripe_form.unblock();
397
  },
398
 
497
  // Handle special inputs that are unique to a payment method.
498
  switch ( source_type ) {
499
  case 'sepa_debit':
500
+ var owner = $( '#stripe-payment-data' );
501
+ extra_details.currency = $( '#stripe-' + source_type + '-payment-data' ).data( 'currency' );
502
+ extra_details.owner.name = $( '#stripe-sepa-owner' ).val();
503
+ extra_details.owner.email = owner.data( 'email' );
504
+ extra_details.sepa_debit = { iban: $( '#stripe-sepa-iban' ).val() };
505
+ extra_details.mandate = { notification_method: wc_stripe_params.sepa_mandate_notification };
506
  break;
507
  case 'ideal':
508
  extra_details.ideal = { bank: $( '#stripe-ideal-bank' ).val() };
512
  extra_details.currency = $( '#stripe-' + source_type + '-payment-data' ).data( 'currency' );
513
  extra_details.amount = $( '#stripe-' + source_type + '-payment-data' ).data( 'amount' );
514
  break;
515
+ case 'sofort':
516
+ extra_details.sofort = { country: $( '#billing_country' ).val() };
517
+ break;
518
  }
519
 
520
  extra_details.type = source_type;
539
  }
540
  },
541
 
542
+ processStripeResponse: function( source ) {
543
+ wc_stripe_form.reset();
544
+
545
+ // Insert the Source into the form so it gets submitted to the server.
546
+ wc_stripe_form.form.append( "<input type='hidden' class='stripe-source' name='stripe_source' value='" + source.id + "'/>" );
547
+
548
+ if ( $( 'form#add_payment_method' ).length ) {
549
+ $( wc_stripe_form.form ).off( 'submit', wc_stripe_form.form.onSubmit );
550
+ }
551
+
552
+ wc_stripe_form.form.submit();
553
+ },
554
+
555
  // Legacy
556
  createToken: function() {
557
  var card = $( '#stripe-card-number' ).val(),
641
  return false;
642
  }
643
 
644
+ if ( wc_stripe_form.isSepaChosen() ) {
645
+ // Check if SEPA owner is filled before proceed.
646
+ if ( '' === $( '#stripe-sepa-owner' ).val() ) {
647
+ $( document.body ).trigger( 'stripeError', { error: { message: wc_stripe_params.no_sepa_owner_msg } } );
648
+ return false;
649
+ }
650
+
651
+ // Check if SEPA IBAN is filled before proceed.
652
+ if ( '' === $( '#stripe-sepa-iban' ).val() ) {
653
+ $( document.body ).trigger( 'stripeError', { error: { message: wc_stripe_params.no_sepa_iban_msg } } );
654
+ return false;
655
+ }
656
+ }
657
+
658
+ /*
659
+ * For methods that needs redirect, we will create the
660
+ * source server side so we can obtain the order ID.
661
+ */
662
  if (
663
  wc_stripe_form.isBancontactChosen() ||
664
  wc_stripe_form.isGiropayChosen() ||
665
  wc_stripe_form.isIdealChosen() ||
666
+ wc_stripe_form.isAlipayChosen() ||
667
+ wc_stripe_form.isSofortChosen() ||
668
+ wc_stripe_form.isP24Chosen()
669
  ) {
670
  if ( $( 'form#order_review' ).length ) {
671
  $( 'form#order_review' )
674
  this.onSubmit
675
  );
676
 
677
+ if ( wc_stripe_form.isMobile() ) {
678
+ wc_stripe_form.unblock();
679
+ }
680
+
681
  wc_stripe_form.form.submit();
682
  }
683
 
684
+ if ( $( 'form.woocommerce-checkout' ).length ) {
685
+ $( 'form.woocommerce-checkout' )
686
+ .off(
687
+ 'submit',
688
+ this.onSubmit
689
+ );
690
 
691
+ if ( wc_stripe_form.isMobile() ) {
692
+ wc_stripe_form.unblock();
693
+ }
694
+
695
+ return true;
 
696
  }
697
 
698
+ if ( $( 'form#add_payment_method' ).length ) {
699
+ $( 'form#add_payment_method' )
700
  .off(
701
  'submit',
702
  this.onSubmit
703
  );
704
 
705
+ if ( wc_stripe_form.isMobile() ) {
706
+ wc_stripe_form.unblock();
707
+ }
708
+
709
  wc_stripe_form.form.submit();
710
  }
 
 
711
  }
712
 
713
+ // We don't need to run validate on non checkout pages.
714
+ if ( wc_stripe_params.is_checkout ) {
715
+ wc_stripe_form.validateCheckout();
716
+ } else {
717
+ wc_stripe_form.createSource();
718
+ }
719
 
720
  // Prevent form submitting
721
  return false;
729
  return false;
730
  }
731
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
732
  wc_stripe_form.block();
733
 
734
  // Process legacy card token.
746
  wc_stripe_form.reset();
747
  },
748
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
749
  reset: function() {
750
  $( '.wc-stripe-error, .stripe-source, .stripe_token, .stripe-checkout-object' ).remove();
751
 
assets/js/stripe.min.js CHANGED
@@ -1 +1 @@
1
- jQuery(function(a){"use strict";var b=Stripe(wc_stripe_params.key);if("yes"===wc_stripe_params.use_elements)var c,d,e,f=b.elements();var g={getAjaxURL:function(a){return wc_stripe_params.ajaxurl.toString().replace("%%endpoint%%","wc_stripe_"+a)},init:function(){"yes"===wc_stripe_params.is_change_payment_page&&a(document.body).trigger("wc-credit-card-form-init"),this.stripe_checkout_submit=!1,a("form.woocommerce-checkout").length&&(this.form=a("form.woocommerce-checkout")),a("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 checkout_place_order_stripe_bitcoin",this.onSubmit),a("form#order_review").length&&(this.form=a("form#order_review")),a("form#order_review").on("submit",this.onSubmit),a("form#add_payment_method").length&&(this.form=a("form#add_payment_method")),a("form#add_payment_method").on("submit",this.onSubmit),a("form.woocommerce-checkout").on("change","#stripe-bank-country",this.reset),a(document).on("stripeError",this.onError).on("checkout_error",this.reset);var b={base:{iconColor:"#666EE8",color:"#31325F",fontSize:"15px","::placeholder":{color:"#CFD7E0"}}},h={focus:"focused",empty:"empty",invalid:"invalid"};"yes"===wc_stripe_params.use_elements&&a("#stripe-card-element").length&&(b=wc_stripe_params.elements_styling?wc_stripe_params.elements_styling:b,h=wc_stripe_params.elements_classes?wc_stripe_params.elements_classes:h,"yes"===wc_stripe_params.inline_cc_form?(c=f.create("card",{style:b,hidePostalCode:!0}),c.addEventListener("change",function(b){g.onCCFormChange(),b.error&&a(document.body).trigger("stripeError",b)})):(c=f.create("cardNumber",{style:b,classes:h}),d=f.create("cardExpiry",{style:b,classes:h}),e=f.create("cardCvc",{style:b,classes:h}),c.addEventListener("change",function(b){g.onCCFormChange(),b.error&&a(document.body).trigger("stripeError",b)}),d.addEventListener("change",function(b){g.onCCFormChange(),b.error&&a(document.body).trigger("stripeError",b)}),e.addEventListener("change",function(b){g.onCCFormChange(),b.error&&a(document.body).trigger("stripeError",b)})),wc_stripe_params.is_checkout?a(document.body).on("updated_checkout",function(){c&&("yes"===wc_stripe_params.inline_cc_form?c.unmount("#stripe-card-element"):(c.unmount("#stripe-card-element"),d.unmount("#stripe-exp-element"),e.unmount("#stripe-cvc-element"))),"yes"===wc_stripe_params.inline_cc_form?c.mount("#stripe-card-element"):(c.mount("#stripe-card-element"),d.mount("#stripe-exp-element"),e.mount("#stripe-cvc-element"))}):(a("form#add_payment_method").length||a("form#order_review").length)&&("yes"===wc_stripe_params.inline_cc_form?c.mount("#stripe-card-element"):(c.mount("#stripe-card-element"),d.mount("#stripe-exp-element"),e.mount("#stripe-cvc-element"))))},isStripeChosen:function(){return a("#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_bitcoin").is(":checked")||a("#payment_method_stripe").is(":checked")&&"new"===a('input[name="wc-stripe-payment-token"]:checked').val()||a("#payment_method_stripe_sepa").is(":checked")&&"new"===a('input[name="wc-stripe-payment-token"]:checked').val()},isStripeSaveCardChosen:function(){return a("#payment_method_stripe").is(":checked")&&a('input[name="wc-stripe-payment-token"]').is(":checked")&&"new"!==a('input[name="wc-stripe-payment-token"]:checked').val()||a("#payment_method_stripe_sepa").is(":checked")&&a('input[name="wc-stripe_sepa-payment-token"]').is(":checked")&&"new"!==a('input[name="wc-stripe_sepa-payment-token"]:checked').val()},isStripeCardChosen:function(){return a("#payment_method_stripe").is(":checked")},isBancontactChosen:function(){return a("#payment_method_stripe_bancontact").is(":checked")},isGiropayChosen:function(){return a("#payment_method_stripe_giropay").is(":checked")},isIdealChosen:function(){return a("#payment_method_stripe_ideal").is(":checked")},isSofortChosen:function(){return a("#payment_method_stripe_sofort").is(":checked")},isAlipayChosen:function(){return a("#payment_method_stripe_alipay").is(":checked")},isSepaChosen:function(){return a("#payment_method_stripe_sepa").is(":checked")},isBitcoinChosen:function(){return a("#payment_method_stripe_bitcoin").is(":checked")},hasSource:function(){return 0<a("input.stripe-source").length},hasToken:function(){return 0<a("input.stripe_token").length},isMobile:function(){return!!/Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(navigator.userAgent)},isStripeModalNeeded:function(a){var b=g.form.find("input.stripe_token");return(!g.stripe_submit||!b)&&!!g.isStripeChosen()},block:function(){g.isMobile()?a.blockUI({message:null,overlayCSS:{background:"#fff",opacity:.6}}):g.form.block({message:null,overlayCSS:{background:"#fff",opacity:.6}})},unblock:function(){g.isMobile()?a.unblockUI():g.form.unblock()},getSelectedPaymentElement:function(){return a('.payment_methods input[name="payment_method"]:checked')},openModal:function(){var c=g.form,d=a("#stripe-payment-data");g.reset();var e=function(a){if(c.find("input.stripe_source").remove(),"token"===a.object)b.createSource({type:"card",token:a.id}).then(g.sourceResponse);else if("source"===a.object){var d={source:a};g.sourceResponse(d)}};StripeCheckout.open({key:wc_stripe_params.key,billingAddress:"yes"===wc_stripe_params.stripe_checkout_require_billing_address,amount:d.data("amount"),name:d.data("name"),description:d.data("description"),currency:d.data("currency"),image:d.data("image"),bitcoin:d.data("bitcoin"),locale:d.data("locale"),email:a("#billing_email").val()||d.data("email"),panelLabel:d.data("panel-label"),allowRememberMe:d.data("allow-remember-me"),token:e,closed:g.onClose()})},resetModal:function(){g.reset(),g.stripe_checkout_submit=!1},onClose:function(){g.unblock()},onError:function(b,c){var d=c.error.message,e=g.getSelectedPaymentElement().parent(".wc_payment_method, .woocommerce-PaymentMethod").find(".stripe-source-errors");"invalid_request_error"!==c.error.type&&"api_connection_error"!==c.error.type&&"api_error"!==c.error.type&&"authentication_error"!==c.error.type&&"rate_limit_error"!==c.error.type||(d=wc_stripe_params.invalid_request_error),"card_error"===c.error.type&&wc_stripe_params.hasOwnProperty(c.error.code)&&(d=wc_stripe_params[c.error.code]),"validation_error"===c.error.type&&wc_stripe_params.hasOwnProperty(c.error.code)&&(d=wc_stripe_params[c.error.code]),g.reset(),a(".woocommerce-NoticeGroup-checkout").remove(),console.log(c.error.message),a(e).html('<ul class="woocommerce_error woocommerce-error wc-stripe-error"><li>'+d+"</li></ul>"),a("html, body").animate({scrollTop:a(".wc-stripe-error").offset().top-200},200),g.unblock()},getOwnerDetails:function(){var b=a("#billing_first_name").length?a("#billing_first_name").val():wc_stripe_params.billing_first_name,c=a("#billing_last_name").length?a("#billing_last_name").val():wc_stripe_params.billing_last_name,d={owner:{name:"",address:{},email:"",phone:""}};return d.owner.name=b,b&&c&&(d.owner.name=b+" "+c),d.owner.email=a("#billing_email").val(),d.owner.phone=a("#billing_phone").val(),void 0!==d.owner.phone&&0>=d.owner.phone.length&&delete d.owner.phone,void 0!==d.owner.email&&0>=d.owner.email.length&&delete d.owner.email,a("#billing_address_1").length>0?(d.owner.address.line1=a("#billing_address_1").val(),d.owner.address.line2=a("#billing_address_2").val(),d.owner.address.state=a("#billing_state").val(),d.owner.address.city=a("#billing_city").val(),d.owner.address.postal_code=a("#billing_postcode").val(),d.owner.address.country=a("#billing_country").val()):wc_stripe_params.billing_address_1&&(d.owner.address.line1=wc_stripe_params.billing_address_1,d.owner.address.line2=wc_stripe_params.billing_address_2,d.owner.address.state=wc_stripe_params.billing_state,d.owner.address.city=wc_stripe_params.billing_city,d.owner.address.postal_code=wc_stripe_params.billing_postcode,d.owner.address.country=wc_stripe_params.billing_country),d},createSource:function(){var d=g.getOwnerDetails(),e="card";if(g.isBancontactChosen()&&(e="bancontact"),g.isSepaChosen()&&(e="sepa_debit"),g.isIdealChosen()&&(e="ideal"),g.isSofortChosen()&&(e="sofort"),g.isBitcoinChosen()&&(e="bitcoin"),g.isGiropayChosen()&&(e="giropay"),g.isAlipayChosen()&&(e="alipay"),"card"===e)b.createSource(c,d).then(g.sourceResponse);else{switch(e){case"bancontact":case"giropay":case"ideal":case"sofort":case"alipay":d.amount=a("#stripe-"+e+"-payment-data").data("amount"),d.currency=a("#stripe-"+e+"-payment-data").data("currency"),d.redirect={return_url:wc_stripe_params.return_url},wc_stripe_params.statement_descriptor&&(d.statement_descriptor=wc_stripe_params.statement_descriptor)}switch(e){case"sepa_debit":d.currency=a("#stripe-"+e+"-payment-data").data("currency"),d.owner.name=a("#stripe-sepa-owner").val(),d.sepa_debit={iban:a("#stripe-sepa-iban").val()};break;case"ideal":d.ideal={bank:a("#stripe-ideal-bank").val()};break;case"bitcoin":case"alipay":d.currency=a("#stripe-"+e+"-payment-data").data("currency"),d.amount=a("#stripe-"+e+"-payment-data").data("amount")}d.type=e,b.createSource(d).then(g.sourceResponse)}},sourceResponse:function(b){b.error?a(document.body).trigger("stripeError",b):"no"===wc_stripe_params.allow_prepaid_card&&"card"===b.source.type&&"prepaid"===b.source.card.funding?(b.error={message:wc_stripe_params.no_prepaid_card_msg},wc_stripe_params.is_stripe_checkout?g.submitError('<ul class="woocommerce-error"><li>'+wc_stripe_params.no_prepaid_card_msg+"</li></ul>"):a(document.body).trigger("stripeError",b)):g.processStripeResponse(b.source)},createToken:function(){var b=a("#stripe-card-number").val(),c=a("#stripe-card-cvc").val(),d=a("#stripe-card-expiry").payment("cardExpiryVal"),e=a("#billing_first_name").length?a("#billing_first_name").val():wc_stripe_params.billing_first_name,f=a("#billing_last_name").length?a("#billing_last_name").val():wc_stripe_params.billing_last_name,h={number:b,cvc:c,exp_month:parseInt(d.month,10)||0,exp_year:parseInt(d.year,10)||0};e&&f&&(h.name=e+" "+f),a("#billing_address_1").length>0?(h.address_line1=a("#billing_address_1").val(),h.address_line2=a("#billing_address_2").val(),h.address_state=a("#billing_state").val(),h.address_city=a("#billing_city").val(),h.address_zip=a("#billing_postcode").val(),h.address_country=a("#billing_country").val()):wc_stripe_params.billing_address_1&&(h.address_line1=wc_stripe_params.billing_address_1,h.address_line2=wc_stripe_params.billing_address_2,h.address_state=wc_stripe_params.billing_state,h.address_city=wc_stripe_params.billing_city,h.address_zip=wc_stripe_params.billing_postcode,h.address_country=wc_stripe_params.billing_country),Stripe.setPublishableKey(wc_stripe_params.key),Stripe.createToken(h,g.onStripeTokenResponse)},onStripeTokenResponse:function(b,c){if(c.error)a(document).trigger("stripeError",c);else{if("no"===wc_stripe_params.allow_prepaid_card&&"prepaid"===c.card.funding)return c.error={message:wc_stripe_params.no_prepaid_card_msg},a(document).trigger("stripeError",{response:c}),!1;var d=c.id;g.form.append("<input type='hidden' class='stripe_token' name='stripe_token' value='"+d+"'/>"),a("form#add_payment_method").length&&a(g.form).off("submit",g.form.onSubmit),g.form.submit()}},onSubmit:function(b){if(g.isStripeChosen()&&!g.isStripeSaveCardChosen()&&!g.hasSource()&&!g.hasToken()){if(b.preventDefault(),"yes"===wc_stripe_params.is_stripe_checkout&&g.isStripeModalNeeded()&&g.isStripeCardChosen())return g.isMobile()?g.openModal():g.validateCheckout("modal"),!1;if(g.block(),g.isStripeCardChosen()&&"no"===wc_stripe_params.use_elements)return g.createToken(),!1;if(g.isBancontactChosen()||g.isGiropayChosen()||g.isIdealChosen()||g.isAlipayChosen())return a("form#order_review").length&&(a("form#order_review").off("submit",this.onSubmit),g.form.submit()),!0;if(g.isSofortChosen()){if("-1"===a("#stripe-bank-country").val()){var c={error:{message:wc_stripe_params.no_bank_country_msg}};return a(document.body).trigger("stripeError",c),!1}return a("form#order_review").length&&(a("form#order_review").off("submit",this.onSubmit),g.form.submit()),!0}return g.validateCheckout(),!1}if(a("form#add_payment_method").length){if(b.preventDefault(),"yes"===wc_stripe_params.is_stripe_checkout&&g.isStripeModalNeeded()&&g.isStripeCardChosen())return g.openModal(),!1;if(g.isSepaChosen()){if(""===a("#stripe-sepa-owner").val())return a(document.body).trigger("stripeError",{error:{message:wc_stripe_params.no_sepa_owner_msg}}),!1;if(""===a("#stripe-sepa-iban").val())return a(document.body).trigger("stripeError",{error:{message:wc_stripe_params.no_sepa_iban_msg}}),!1}return g.block(),g.isStripeCardChosen()&&"no"===wc_stripe_params.use_elements?(g.createToken(),!1):(g.createSource(),!1)}},onCCFormChange:function(){g.reset()},prepareSourceToServer:function(a){return{id:a.id,card:a.card?a.card:"",bitcoin:a.bitcoin?a.bitcoin:"",flow:a.flow,object:a.object,status:a.status,type:a.type,usage:a.usage}},processStripeResponse:function(b){g.reset(),g.form.append("<input type='hidden' class='stripe-source' name='stripe_source' value='"+b.id+"'/>"),a("form#add_payment_method").length&&a(g.form).off("submit",g.form.onSubmit),g.form.submit()},reset:function(){a(".wc-stripe-error, .stripe-source, .stripe_token, .stripe-checkout-object").remove(),"yes"===wc_stripe_params.is_stripe_checkout&&(g.stripe_submit=!1)},getRequiredFields:function(){return g.form.find(".form-row.validate-required > input, .form-row.validate-required > select, .form-row.validate-required > textarea")},validateCheckout:function(b){void 0===b&&(b="");var c={nonce:wc_stripe_params.stripe_nonce,required_fields:g.getRequiredFields().serialize(),all_fields:g.form.serialize(),source_type:g.getSelectedPaymentElement().val(),is_add_payment_page:wc_stripe_params.is_add_payment_method_page};a.ajax({type:"POST",url:g.getAjaxURL("validate_checkout"),data:c,dataType:"json",success:function(c){if("success"===c)if("modal"===b)g.openModal();else{if(g.isSepaChosen()){if(""===a("#stripe-sepa-owner").val())return a(document.body).trigger("stripeError",{error:{message:wc_stripe_params.no_sepa_owner_msg}}),!1;if(""===a("#stripe-sepa-iban").val())return a(document.body).trigger("stripeError",{error:{message:wc_stripe_params.no_sepa_iban_msg}}),!1}g.createSource()}else c.messages&&(g.resetModal(),g.reset(),g.submitError(c.messages))}})},submitError:function(b){a(".woocommerce-NoticeGroup-checkout, .woocommerce-error, .woocommerce-message").remove(),g.form.prepend('<div class="woocommerce-NoticeGroup woocommerce-NoticeGroup-checkout">'+b+"</div>"),g.form.removeClass("processing").unblock(),g.form.find(".input-text, select, input:checkbox").blur();var c="";a("#add_payment_method").length&&(c=a("#add_payment_method")),a("#order_review").length&&(c=a("#order_review")),a("form.checkout").length&&(c=a("form.checkout")),c.length&&a("html, body").animate({scrollTop:c.offset().top-100},500),a(document.body).trigger("checkout_error"),g.unblock()}};g.init()});
1
+ jQuery(function(a){"use strict";var b=Stripe(wc_stripe_params.key);if("yes"===wc_stripe_params.use_elements)var c,d,e,f=wc_stripe_params.elements_options.length?wc_stripe_params.elements_options:{},g=b.elements(f);var h={getAjaxURL:function(a){return wc_stripe_params.ajaxurl.toString().replace("%%endpoint%%","wc_stripe_"+a)},init:function(){"yes"===wc_stripe_params.is_change_payment_page&&a(document.body).trigger("wc-credit-card-form-init"),this.stripe_checkout_submit=!1,a("form.woocommerce-checkout").length&&(this.form=a("form.woocommerce-checkout")),a("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 checkout_place_order_stripe_bitcoin",this.onSubmit),a("form#order_review").length&&(this.form=a("form#order_review")),a("form#order_review").on("submit",this.onSubmit),a("form#add_payment_method").length&&(this.form=a("form#add_payment_method")),a("form#add_payment_method").on("submit",this.onSubmit),a("form.woocommerce-checkout").on("change","#stripe-bank-country",this.reset),a(document).on("stripeError",this.onError).on("checkout_error",this.reset);var b={base:{iconColor:"#666EE8",color:"#31325F",fontSize:"15px","::placeholder":{color:"#CFD7E0"}}},f={focus:"focused",empty:"empty",invalid:"invalid"};"yes"===wc_stripe_params.use_elements&&a("#stripe-card-element").length&&(b=wc_stripe_params.elements_styling?wc_stripe_params.elements_styling:b,f=wc_stripe_params.elements_classes?wc_stripe_params.elements_classes:f,"yes"===wc_stripe_params.inline_cc_form?(c=g.create("card",{style:b,hidePostalCode:!0}),c.addEventListener("change",function(b){h.onCCFormChange(),b.error&&a(document.body).trigger("stripeError",b)})):(c=g.create("cardNumber",{style:b,classes:f}),d=g.create("cardExpiry",{style:b,classes:f}),e=g.create("cardCvc",{style:b,classes:f}),c.addEventListener("change",function(b){h.onCCFormChange(),b.error&&a(document.body).trigger("stripeError",b)}),d.addEventListener("change",function(b){h.onCCFormChange(),b.error&&a(document.body).trigger("stripeError",b)}),e.addEventListener("change",function(b){h.onCCFormChange(),b.error&&a(document.body).trigger("stripeError",b)})),wc_stripe_params.is_checkout?a(document.body).on("updated_checkout",function(){c&&("yes"===wc_stripe_params.inline_cc_form?c.unmount("#stripe-card-element"):(c.unmount("#stripe-card-element"),d.unmount("#stripe-exp-element"),e.unmount("#stripe-cvc-element"))),"yes"===wc_stripe_params.inline_cc_form?c.mount("#stripe-card-element"):(c.mount("#stripe-card-element"),d.mount("#stripe-exp-element"),e.mount("#stripe-cvc-element"))}):(a("form#add_payment_method").length||a("form#order_review").length)&&("yes"===wc_stripe_params.inline_cc_form?c.mount("#stripe-card-element"):(c.mount("#stripe-card-element"),d.mount("#stripe-exp-element"),e.mount("#stripe-cvc-element"))))},isStripeChosen:function(){return a("#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_bitcoin").is(":checked")||a("#payment_method_stripe").is(":checked")&&"new"===a('input[name="wc-stripe-payment-token"]:checked').val()||a("#payment_method_stripe_sepa").is(":checked")&&"new"===a('input[name="wc-stripe-payment-token"]:checked').val()},isStripeSaveCardChosen:function(){return a("#payment_method_stripe").is(":checked")&&a('input[name="wc-stripe-payment-token"]').is(":checked")&&"new"!==a('input[name="wc-stripe-payment-token"]:checked').val()||a("#payment_method_stripe_sepa").is(":checked")&&a('input[name="wc-stripe_sepa-payment-token"]').is(":checked")&&"new"!==a('input[name="wc-stripe_sepa-payment-token"]:checked').val()},isStripeCardChosen:function(){return a("#payment_method_stripe").is(":checked")},isBancontactChosen:function(){return a("#payment_method_stripe_bancontact").is(":checked")},isGiropayChosen:function(){return a("#payment_method_stripe_giropay").is(":checked")},isIdealChosen:function(){return a("#payment_method_stripe_ideal").is(":checked")},isSofortChosen:function(){return a("#payment_method_stripe_sofort").is(":checked")},isAlipayChosen:function(){return a("#payment_method_stripe_alipay").is(":checked")},isSepaChosen:function(){return a("#payment_method_stripe_sepa").is(":checked")},isBitcoinChosen:function(){return a("#payment_method_stripe_bitcoin").is(":checked")},isP24Chosen:function(){return a("#payment_method_stripe_p24").is(":checked")},hasSource:function(){return 0<a("input.stripe-source").length},hasToken:function(){return 0<a("input.stripe_token").length},isMobile:function(){return!!/Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(navigator.userAgent)},isStripeModalNeeded:function(a){var b=h.form.find("input.stripe_token");return(!h.stripe_submit||!b)&&!!h.isStripeChosen()},block:function(){h.isMobile()?a.blockUI({message:null,overlayCSS:{background:"#fff",opacity:.6}}):h.form.block({message:null,overlayCSS:{background:"#fff",opacity:.6}})},unblock:function(){h.isMobile()?a.unblockUI():h.form.unblock()},getSelectedPaymentElement:function(){return a('.payment_methods input[name="payment_method"]:checked')},openModal:function(){var c=h.form,d=a("#stripe-payment-data");h.reset();var e=function(a){if(c.find("input.stripe_source").remove(),"token"===a.object)b.createSource({type:"card",token:a.id}).then(h.sourceResponse);else if("source"===a.object){var d={source:a};h.sourceResponse(d)}};StripeCheckout.open({key:wc_stripe_params.key,billingAddress:"yes"===wc_stripe_params.stripe_checkout_require_billing_address,amount:d.data("amount"),name:d.data("name"),description:d.data("description"),currency:d.data("currency"),image:d.data("image"),bitcoin:d.data("bitcoin"),locale:d.data("locale"),email:a("#billing_email").val()||d.data("email"),panelLabel:d.data("panel-label"),allowRememberMe:d.data("allow-remember-me"),token:e,closed:h.onClose()})},resetModal:function(){h.reset(),h.stripe_checkout_submit=!1},onClose:function(){h.unblock()},onError:function(b,c){var d=c.error.message,e=h.getSelectedPaymentElement().parents("li").eq(0).find(".stripe-source-errors");"invalid_request_error"!==c.error.type&&"api_connection_error"!==c.error.type&&"api_error"!==c.error.type&&"authentication_error"!==c.error.type&&"rate_limit_error"!==c.error.type||(d=wc_stripe_params.invalid_request_error),"card_error"===c.error.type&&wc_stripe_params.hasOwnProperty(c.error.code)&&(d=wc_stripe_params[c.error.code]),"validation_error"===c.error.type&&wc_stripe_params.hasOwnProperty(c.error.code)&&(d=wc_stripe_params[c.error.code]),h.reset(),a(".woocommerce-NoticeGroup-checkout").remove(),console.log(c.error.message),a(e).html('<ul class="woocommerce_error woocommerce-error wc-stripe-error"><li>'+d+"</li></ul>"),a(".wc-stripe-error").length&&a("html, body").animate({scrollTop:a(".wc-stripe-error").offset().top-200},200),h.unblock()},getOwnerDetails:function(){var b=a("#billing_first_name").length?a("#billing_first_name").val():wc_stripe_params.billing_first_name,c=a("#billing_last_name").length?a("#billing_last_name").val():wc_stripe_params.billing_last_name,d={owner:{name:"",address:{},email:"",phone:""}};return d.owner.name=b,b&&c&&(d.owner.name=b+" "+c),d.owner.email=a("#billing_email").val(),d.owner.phone=a("#billing_phone").val(),void 0!==d.owner.phone&&0>=d.owner.phone.length&&delete d.owner.phone,void 0!==d.owner.email&&0>=d.owner.email.length&&delete d.owner.email,a("#billing_address_1").length>0?(d.owner.address.line1=a("#billing_address_1").val(),d.owner.address.line2=a("#billing_address_2").val(),d.owner.address.state=a("#billing_state").val(),d.owner.address.city=a("#billing_city").val(),d.owner.address.postal_code=a("#billing_postcode").val(),d.owner.address.country=a("#billing_country").val()):wc_stripe_params.billing_address_1&&(d.owner.address.line1=wc_stripe_params.billing_address_1,d.owner.address.line2=wc_stripe_params.billing_address_2,d.owner.address.state=wc_stripe_params.billing_state,d.owner.address.city=wc_stripe_params.billing_city,d.owner.address.postal_code=wc_stripe_params.billing_postcode,d.owner.address.country=wc_stripe_params.billing_country),d},createSource:function(){var d=h.getOwnerDetails(),e="card";if(h.isBancontactChosen()&&(e="bancontact"),h.isSepaChosen()&&(e="sepa_debit"),h.isIdealChosen()&&(e="ideal"),h.isSofortChosen()&&(e="sofort"),h.isBitcoinChosen()&&(e="bitcoin"),h.isGiropayChosen()&&(e="giropay"),h.isAlipayChosen()&&(e="alipay"),"card"===e)b.createSource(c,d).then(h.sourceResponse);else{switch(e){case"bancontact":case"giropay":case"ideal":case"sofort":case"alipay":d.amount=a("#stripe-"+e+"-payment-data").data("amount"),d.currency=a("#stripe-"+e+"-payment-data").data("currency"),d.redirect={return_url:wc_stripe_params.return_url},wc_stripe_params.statement_descriptor&&(d.statement_descriptor=wc_stripe_params.statement_descriptor)}switch(e){case"sepa_debit":var f=a("#stripe-payment-data");d.currency=a("#stripe-"+e+"-payment-data").data("currency"),d.owner.name=a("#stripe-sepa-owner").val(),d.owner.email=f.data("email"),d.sepa_debit={iban:a("#stripe-sepa-iban").val()},d.mandate={notification_method:wc_stripe_params.sepa_mandate_notification};break;case"ideal":d.ideal={bank:a("#stripe-ideal-bank").val()};break;case"bitcoin":case"alipay":d.currency=a("#stripe-"+e+"-payment-data").data("currency"),d.amount=a("#stripe-"+e+"-payment-data").data("amount");break;case"sofort":d.sofort={country:a("#billing_country").val()}}d.type=e,b.createSource(d).then(h.sourceResponse)}},sourceResponse:function(b){b.error?a(document.body).trigger("stripeError",b):"no"===wc_stripe_params.allow_prepaid_card&&"card"===b.source.type&&"prepaid"===b.source.card.funding?(b.error={message:wc_stripe_params.no_prepaid_card_msg},wc_stripe_params.is_stripe_checkout?h.submitError('<ul class="woocommerce-error"><li>'+wc_stripe_params.no_prepaid_card_msg+"</li></ul>"):a(document.body).trigger("stripeError",b)):h.processStripeResponse(b.source)},processStripeResponse:function(b){h.reset(),h.form.append("<input type='hidden' class='stripe-source' name='stripe_source' value='"+b.id+"'/>"),a("form#add_payment_method").length&&a(h.form).off("submit",h.form.onSubmit),h.form.submit()},createToken:function(){var b=a("#stripe-card-number").val(),c=a("#stripe-card-cvc").val(),d=a("#stripe-card-expiry").payment("cardExpiryVal"),e=a("#billing_first_name").length?a("#billing_first_name").val():wc_stripe_params.billing_first_name,f=a("#billing_last_name").length?a("#billing_last_name").val():wc_stripe_params.billing_last_name,g={number:b,cvc:c,exp_month:parseInt(d.month,10)||0,exp_year:parseInt(d.year,10)||0};e&&f&&(g.name=e+" "+f),a("#billing_address_1").length>0?(g.address_line1=a("#billing_address_1").val(),g.address_line2=a("#billing_address_2").val(),g.address_state=a("#billing_state").val(),g.address_city=a("#billing_city").val(),g.address_zip=a("#billing_postcode").val(),g.address_country=a("#billing_country").val()):wc_stripe_params.billing_address_1&&(g.address_line1=wc_stripe_params.billing_address_1,g.address_line2=wc_stripe_params.billing_address_2,g.address_state=wc_stripe_params.billing_state,g.address_city=wc_stripe_params.billing_city,g.address_zip=wc_stripe_params.billing_postcode,g.address_country=wc_stripe_params.billing_country),Stripe.setPublishableKey(wc_stripe_params.key),Stripe.createToken(g,h.onStripeTokenResponse)},onStripeTokenResponse:function(b,c){if(c.error)a(document).trigger("stripeError",c);else{if("no"===wc_stripe_params.allow_prepaid_card&&"prepaid"===c.card.funding)return c.error={message:wc_stripe_params.no_prepaid_card_msg},a(document).trigger("stripeError",{response:c}),!1;var d=c.id;h.form.append("<input type='hidden' class='stripe_token' name='stripe_token' value='"+d+"'/>"),a("form#add_payment_method").length&&a(h.form).off("submit",h.form.onSubmit),h.form.submit()}},onSubmit:function(b){if(h.isStripeChosen()&&!h.isStripeSaveCardChosen()&&!h.hasSource()&&!h.hasToken()){if(b.preventDefault(),"yes"===wc_stripe_params.is_stripe_checkout&&h.isStripeModalNeeded()&&h.isStripeCardChosen())return h.isMobile()?h.openModal():h.validateCheckout("modal"),!1;if(h.block(),h.isStripeCardChosen()&&"no"===wc_stripe_params.use_elements)return h.createToken(),!1;if(h.isSepaChosen()){if(""===a("#stripe-sepa-owner").val())return a(document.body).trigger("stripeError",{error:{message:wc_stripe_params.no_sepa_owner_msg}}),!1;if(""===a("#stripe-sepa-iban").val())return a(document.body).trigger("stripeError",{error:{message:wc_stripe_params.no_sepa_iban_msg}}),!1}if(h.isBancontactChosen()||h.isGiropayChosen()||h.isIdealChosen()||h.isAlipayChosen()||h.isSofortChosen()||h.isP24Chosen()){if(a("form#order_review").length&&(a("form#order_review").off("submit",this.onSubmit),h.isMobile()&&h.unblock(),h.form.submit()),a("form.woocommerce-checkout").length)return a("form.woocommerce-checkout").off("submit",this.onSubmit),h.isMobile()&&h.unblock(),!0;a("form#add_payment_method").length&&(a("form#add_payment_method").off("submit",this.onSubmit),h.isMobile()&&h.unblock(),h.form.submit())}return wc_stripe_params.is_checkout?h.validateCheckout():h.createSource(),!1}if(a("form#add_payment_method").length)return b.preventDefault(),"yes"===wc_stripe_params.is_stripe_checkout&&h.isStripeModalNeeded()&&h.isStripeCardChosen()?(h.openModal(),!1):(h.block(),h.isStripeCardChosen()&&"no"===wc_stripe_params.use_elements?(h.createToken(),!1):(h.createSource(),!1))},onCCFormChange:function(){h.reset()},reset:function(){a(".wc-stripe-error, .stripe-source, .stripe_token, .stripe-checkout-object").remove(),"yes"===wc_stripe_params.is_stripe_checkout&&(h.stripe_submit=!1)},getRequiredFields:function(){return h.form.find(".form-row.validate-required > input, .form-row.validate-required > select, .form-row.validate-required > textarea")},validateCheckout:function(b){void 0===b&&(b="");var c={nonce:wc_stripe_params.stripe_nonce,required_fields:h.getRequiredFields().serialize(),all_fields:h.form.serialize(),source_type:h.getSelectedPaymentElement().val(),is_add_payment_page:wc_stripe_params.is_add_payment_method_page};a.ajax({type:"POST",url:h.getAjaxURL("validate_checkout"),data:c,dataType:"json",success:function(c){if("success"===c)if("modal"===b)h.openModal();else{if(h.isSepaChosen()){if(""===a("#stripe-sepa-owner").val())return a(document.body).trigger("stripeError",{error:{message:wc_stripe_params.no_sepa_owner_msg}}),!1;if(""===a("#stripe-sepa-iban").val())return a(document.body).trigger("stripeError",{error:{message:wc_stripe_params.no_sepa_iban_msg}}),!1}h.createSource()}else c.messages&&(h.resetModal(),h.reset(),h.submitError(c.messages))}})},submitError:function(b){a(".woocommerce-NoticeGroup-checkout, .woocommerce-error, .woocommerce-message").remove(),h.form.prepend('<div class="woocommerce-NoticeGroup woocommerce-NoticeGroup-checkout">'+b+"</div>"),h.form.removeClass("processing").unblock(),h.form.find(".input-text, select, input:checkbox").blur();var c="";a("#add_payment_method").length&&(c=a("#add_payment_method")),a("#order_review").length&&(c=a("#order_review")),a("form.checkout").length&&(c=a("form.checkout")),c.length&&a("html, body").animate({scrollTop:c.offset().top-100},500),a(document.body).trigger("checkout_error"),h.unblock()}};h.init()});
changelog.txt CHANGED
@@ -1,5 +1,27 @@
1
  *** Changelog ***
2
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
3
  = 4.0.3 - 2018-01-18 =
4
  * Fix - Pass Stripe source as id instead of object as some sites may conflict with objects being passed.
5
  * Fix - For Payment Request Button, if test keys are not filled, it can cause live mode not to function.
1
  *** Changelog ***
2
 
3
+ = 4.0.4 - 2018-01-30 =
4
+ * Add - SEPA mandate notification email.
5
+ * Add - Preferred language to SOFORT and Bancontact so it can be localized.
6
+ * Add - Hook to change SEPA mandate notification to none "wc_stripe_sepa_mandate_notification".
7
+ * Add - Hook to change data for product when using Payment Request Button "wc_stripe_payment_request_product_data".
8
+ * Add - Hook to change the behavior of allowing subscriptions to charge a customer's default source "'wc_stripe_use_default_customer_source'".
9
+ * Add - Hook to source object "wc_stripe_sofort_source", "wc_stripe_p24_source", "wc_stripe_ideal_source", "wc_stripe_giropay_source", "wc_stripe_bancontact_source", "wc_stripe_alipay_source", "wc_stripe_3ds_source".
10
+ * Add - Hook to change payment request button total label "wc_stripe_payment_request_total_label".
11
+ * Add - Hook to change locale of Stripe Checkout "wc_stripe_checkout_locale".
12
+ * Add - Hook to change elements options "wc_stripe_elements_options".
13
+ * Fix - When checkout form produces an error on mobile, sometimes the blocking mask is not release blocking new input.
14
+ * Fix - On older subscription payments, the ending card number is not shown on the subscriptions table in my account.
15
+ * Fix - Filter to show payment request button on checkout page not working.
16
+ * Fix - WC session handling compatibility with WC 3.3.
17
+ * Fix - BW compatibility with WC 2.6.x on add_order_meta to prevent errors.
18
+ * Fix - Possible fix for duplicate charges due to webhook and redirect handler firing at the same time by adding delay to the webhook process.
19
+ * Tweak - In a subscription billing, Stripe source ID is no longer a required field.
20
+ * Tweak - On a subscription order renewal-- if source is empty, will now try to charge the default source.
21
+ * Notice - Bitcoin has been soft deprecated and Stripe will no longer support it on April 23, 2018. Please plan accordingly.
22
+ * Remove - Stripe Checkout Locale setting in favor of using store set locale.
23
+ * Update - Stripe API version to 2018-01-23.
24
+
25
  = 4.0.3 - 2018-01-18 =
26
  * Fix - Pass Stripe source as id instead of object as some sites may conflict with objects being passed.
27
  * Fix - For Payment Request Button, if test keys are not filled, it can cause live mode not to function.
includes/abstracts/abstract-wc-stripe-payment-gateway.php CHANGED
@@ -355,7 +355,7 @@ abstract class WC_Stripe_Payment_Gateway extends WC_Payment_Gateway_CC {
355
  *
356
  * @since 4.0.3
357
  */
358
- public function create_source_object() {
359
  $source = ! empty( $_POST['stripe_source'] ) ? wc_clean( $_POST['stripe_source'] ) : '';
360
 
361
  if ( empty( $source ) ) {
@@ -371,6 +371,60 @@ abstract class WC_Stripe_Payment_Gateway extends WC_Payment_Gateway_CC {
371
  return $source_object;
372
  }
373
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
374
  /**
375
  * Get payment source. This can be a new token/source or existing WC token.
376
  * If user is logged in and/or has WC account, create an account on Stripe.
@@ -389,14 +443,13 @@ abstract class WC_Stripe_Payment_Gateway extends WC_Payment_Gateway_CC {
389
  $customer = new WC_Stripe_Customer( $user_id );
390
  $set_customer = true;
391
  $force_save_source = apply_filters( 'wc_stripe_force_save_source', $force_save_source, $customer );
392
- $source = '';
393
  $wc_token_id = false;
394
  $payment_method = isset( $_POST['payment_method'] ) ? wc_clean( $_POST['payment_method'] ) : 'stripe';
395
 
396
  // New CC info was entered and we have a new source to process.
397
  if ( ! empty( $source_object ) ) {
398
- // This gets the source object from Stripe.
399
- $source = $source_object;
400
 
401
  // This checks to see if customer opted to save the payment method to file.
402
  $maybe_saved_card = isset( $_POST[ 'wc-' . $payment_method . '-new-payment-method' ] ) && ! empty( $_POST[ 'wc-' . $payment_method . '-new-payment-method' ] );
@@ -406,18 +459,15 @@ abstract class WC_Stripe_Payment_Gateway extends WC_Payment_Gateway_CC {
406
  * Criteria to save to file is they are logged in, they opted to save or product requirements and the source is
407
  * actually reusable. Either that or force_save_source is true.
408
  */
409
- if ( ( $user_id && $this->saved_cards && $maybe_saved_card && 'reusable' === $source->usage ) || $force_save_source ) {
410
- $source = $customer->add_source( $source->id );
411
 
412
- if ( ! empty( $source->error ) ) {
413
- throw new WC_Stripe_Exception( print_r( $source, true ), $source->error->message );
414
  }
415
- } else {
416
- $source = $source->id;
417
  }
418
  } elseif ( isset( $_POST[ 'wc-' . $payment_method . '-payment-token' ] ) && 'new' !== $_POST[ 'wc-' . $payment_method . '-payment-token' ] ) {
419
  // Use an existing token, and then process the payment
420
-
421
  $wc_token_id = wc_clean( $_POST[ 'wc-' . $payment_method . '-payment-token' ] );
422
  $wc_token = WC_Payment_Tokens::get( $wc_token_id );
423
 
@@ -426,21 +476,21 @@ abstract class WC_Stripe_Payment_Gateway extends WC_Payment_Gateway_CC {
426
  throw new WC_Stripe_Exception( 'Invalid payment method', __( 'Invalid payment method. Please input a new card number.', 'woocommerce-gateway-stripe' ) );
427
  }
428
 
429
- $source = $wc_token->get_token();
430
  } elseif ( isset( $_POST['stripe_token'] ) && 'new' !== $_POST['stripe_token'] ) {
431
  $stripe_token = wc_clean( $_POST['stripe_token'] );
432
  $maybe_saved_card = isset( $_POST[ 'wc-' . $payment_method . '-new-payment-method' ] ) && ! empty( $_POST[ 'wc-' . $payment_method . '-new-payment-method' ] );
433
 
434
  // This is true if the user wants to store the card to their account.
435
  if ( ( $user_id && $this->saved_cards && $maybe_saved_card ) || $force_save_source ) {
436
- $source = $customer->add_source( $stripe_token );
437
 
438
- if ( ! empty( $source->error ) ) {
439
- throw new WC_Stripe_Exception( print_r( $source, true ), $source->error->message );
440
  }
441
  } else {
442
  $set_customer = false;
443
- $source = $stripe_token;
444
  }
445
  }
446
 
@@ -453,43 +503,10 @@ abstract class WC_Stripe_Payment_Gateway extends WC_Payment_Gateway_CC {
453
  return (object) array(
454
  'token_id' => $wc_token_id,
455
  'customer' => $customer_id,
456
- 'source' => $source,
457
  );
458
  }
459
 
460
- /**
461
- * Save source to order.
462
- *
463
- * @since 3.1.0
464
- * @version 4.0.0
465
- * @param WC_Order $order For to which the source applies.
466
- * @param stdClass $source Source information.
467
- */
468
- public function save_source( $order, $source ) {
469
- $order_id = WC_Stripe_Helper::is_pre_30() ? $order->id : $order->get_id();
470
-
471
- // Store source in the order.
472
- if ( $source->customer ) {
473
- if ( WC_Stripe_Helper::is_pre_30() ) {
474
- update_post_meta( $order_id, '_stripe_customer_id', $source->customer );
475
- } else {
476
- $order->update_meta_data( '_stripe_customer_id', $source->customer );
477
- }
478
- }
479
-
480
- if ( $source->source ) {
481
- if ( WC_Stripe_Helper::is_pre_30() ) {
482
- update_post_meta( $order_id, '_stripe_source_id', $source->source );
483
- } else {
484
- $order->update_meta_data( '_stripe_source_id', $source->source );
485
- }
486
- }
487
-
488
- if ( is_callable( array( $order, 'save' ) ) ) {
489
- $order->save();
490
- }
491
- }
492
-
493
  /**
494
  * Get payment source from an order. This could be used in the future for
495
  * a subscription as an example, therefore using the current user ID would
@@ -533,6 +550,12 @@ abstract class WC_Stripe_Payment_Gateway extends WC_Payment_Gateway_CC {
533
 
534
  if ( $source_id ) {
535
  $stripe_source = $source_id;
 
 
 
 
 
 
536
  }
537
  }
538
 
@@ -543,6 +566,39 @@ abstract class WC_Stripe_Payment_Gateway extends WC_Payment_Gateway_CC {
543
  );
544
  }
545
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
546
  /**
547
  * Updates Stripe fees/net.
548
  * e.g usage would be after a refund.
355
  *
356
  * @since 4.0.3
357
  */
358
+ public function get_source_object() {
359
  $source = ! empty( $_POST['stripe_source'] ) ? wc_clean( $_POST['stripe_source'] ) : '';
360
 
361
  if ( empty( $source ) ) {
371
  return $source_object;
372
  }
373
 
374
+ /**
375
+ * Checks if 3DS is required.
376
+ *
377
+ * @since 4.0.4
378
+ * @param object $source_object
379
+ * @return bool
380
+ */
381
+ public function is_3ds_required( $source_object ) {
382
+ return (
383
+ $source_object && ! empty( $source_object->card ) ) &&
384
+ ( 'card' === $source_object->type && 'required' === $source_object->card->three_d_secure ||
385
+ ( $this->three_d_secure && 'optional' === $source_object->card->three_d_secure )
386
+ );
387
+ }
388
+
389
+ /**
390
+ * Checks if card is 3DS.
391
+ *
392
+ * @since 4.0.4
393
+ * @param object $source_object
394
+ * @return bool
395
+ */
396
+ public function is_3ds_card( $source_object ) {
397
+ return ( $source_object && 'three_d_secure' === $source_object->type );
398
+ }
399
+
400
+ /**
401
+ * Creates the 3DS source for charge.
402
+ *
403
+ * @since 4.0.0
404
+ * @since 4.0.4 Add $return_url
405
+ * @param object $order
406
+ * @param object $source_object
407
+ * @param string $return_url
408
+ * @return mixed
409
+ */
410
+ public function create_3ds_source( $order, $source_object, $return_url = '' ) {
411
+ $currency = WC_Stripe_Helper::is_pre_30() ? $order->get_order_currency() : $order->get_currency();
412
+ $order_id = WC_Stripe_Helper::is_pre_30() ? $order->id : $order->get_id();
413
+ $return_url = empty( $return_url ) ? $this->get_stripe_return_url( $order ) : $return_url;
414
+
415
+ $post_data = array();
416
+ $post_data['amount'] = WC_Stripe_Helper::get_stripe_amount( $order->get_total(), $currency );
417
+ $post_data['currency'] = strtolower( $currency );
418
+ $post_data['type'] = 'three_d_secure';
419
+ $post_data['owner'] = $this->get_owner_details( $order );
420
+ $post_data['three_d_secure'] = array( 'card' => $source_object->id );
421
+ $post_data['redirect'] = array( 'return_url' => $return_url );
422
+
423
+ WC_Stripe_Logger::log( 'Info: Begin creating 3DS source...' );
424
+
425
+ return WC_Stripe_API::request( apply_filters( 'wc_stripe_3ds_source', $post_data, $order ), 'sources' );
426
+ }
427
+
428
  /**
429
  * Get payment source. This can be a new token/source or existing WC token.
430
  * If user is logged in and/or has WC account, create an account on Stripe.
443
  $customer = new WC_Stripe_Customer( $user_id );
444
  $set_customer = true;
445
  $force_save_source = apply_filters( 'wc_stripe_force_save_source', $force_save_source, $customer );
446
+ $source_id = '';
447
  $wc_token_id = false;
448
  $payment_method = isset( $_POST['payment_method'] ) ? wc_clean( $_POST['payment_method'] ) : 'stripe';
449
 
450
  // New CC info was entered and we have a new source to process.
451
  if ( ! empty( $source_object ) ) {
452
+ $source_id = $source_object->id;
 
453
 
454
  // This checks to see if customer opted to save the payment method to file.
455
  $maybe_saved_card = isset( $_POST[ 'wc-' . $payment_method . '-new-payment-method' ] ) && ! empty( $_POST[ 'wc-' . $payment_method . '-new-payment-method' ] );
459
  * Criteria to save to file is they are logged in, they opted to save or product requirements and the source is
460
  * actually reusable. Either that or force_save_source is true.
461
  */
462
+ if ( ( $user_id && $this->saved_cards && $maybe_saved_card && 'reusable' === $source_object->usage ) || $force_save_source ) {
463
+ $response = $customer->add_source( $source_object->id );
464
 
465
+ if ( ! empty( $response->error ) ) {
466
+ throw new WC_Stripe_Exception( print_r( $response, true ), $response->error->message );
467
  }
 
 
468
  }
469
  } elseif ( isset( $_POST[ 'wc-' . $payment_method . '-payment-token' ] ) && 'new' !== $_POST[ 'wc-' . $payment_method . '-payment-token' ] ) {
470
  // Use an existing token, and then process the payment
 
471
  $wc_token_id = wc_clean( $_POST[ 'wc-' . $payment_method . '-payment-token' ] );
472
  $wc_token = WC_Payment_Tokens::get( $wc_token_id );
473
 
476
  throw new WC_Stripe_Exception( 'Invalid payment method', __( 'Invalid payment method. Please input a new card number.', 'woocommerce-gateway-stripe' ) );
477
  }
478
 
479
+ $source_id = $wc_token->get_token();
480
  } elseif ( isset( $_POST['stripe_token'] ) && 'new' !== $_POST['stripe_token'] ) {
481
  $stripe_token = wc_clean( $_POST['stripe_token'] );
482
  $maybe_saved_card = isset( $_POST[ 'wc-' . $payment_method . '-new-payment-method' ] ) && ! empty( $_POST[ 'wc-' . $payment_method . '-new-payment-method' ] );
483
 
484
  // This is true if the user wants to store the card to their account.
485
  if ( ( $user_id && $this->saved_cards && $maybe_saved_card ) || $force_save_source ) {
486
+ $response = $customer->add_source( $stripe_token );
487
 
488
+ if ( ! empty( $response->error ) ) {
489
+ throw new WC_Stripe_Exception( print_r( $response, true ), $response->error->message );
490
  }
491
  } else {
492
  $set_customer = false;
493
+ $source_id = $stripe_token;
494
  }
495
  }
496
 
503
  return (object) array(
504
  'token_id' => $wc_token_id,
505
  'customer' => $customer_id,
506
+ 'source' => $source_id,
507
  );
508
  }
509
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
510
  /**
511
  * Get payment source from an order. This could be used in the future for
512
  * a subscription as an example, therefore using the current user ID would
550
 
551
  if ( $source_id ) {
552
  $stripe_source = $source_id;
553
+ } elseif ( apply_filters( 'wc_stripe_use_default_customer_source', true ) ) {
554
+ /*
555
+ * We can attempt to charge the customer's default source
556
+ * by sending empty source id.
557
+ */
558
+ $stripe_source = '';
559
  }
560
  }
561
 
566
  );
567
  }
568
 
569
+ /**
570
+ * Save source to order.
571
+ *
572
+ * @since 3.1.0
573
+ * @version 4.0.0
574
+ * @param WC_Order $order For to which the source applies.
575
+ * @param stdClass $source Source information.
576
+ */
577
+ public function save_source_to_order( $order, $source ) {
578
+ $order_id = WC_Stripe_Helper::is_pre_30() ? $order->id : $order->get_id();
579
+
580
+ // Store source in the order.
581
+ if ( $source->customer ) {
582
+ if ( WC_Stripe_Helper::is_pre_30() ) {
583
+ update_post_meta( $order_id, '_stripe_customer_id', $source->customer );
584
+ } else {
585
+ $order->update_meta_data( '_stripe_customer_id', $source->customer );
586
+ }
587
+ }
588
+
589
+ if ( $source->source ) {
590
+ if ( WC_Stripe_Helper::is_pre_30() ) {
591
+ update_post_meta( $order_id, '_stripe_source_id', $source->source );
592
+ } else {
593
+ $order->update_meta_data( '_stripe_source_id', $source->source );
594
+ }
595
+ }
596
+
597
+ if ( is_callable( array( $order, 'save' ) ) ) {
598
+ $order->save();
599
+ }
600
+ }
601
+
602
  /**
603
  * Updates Stripe fees/net.
604
  * e.g usage would be after a refund.
includes/admin/stripe-settings.php CHANGED
@@ -108,29 +108,6 @@ return apply_filters( 'wc_stripe_settings',
108
  'default' => 'no',
109
  'desc_tip' => true,
110
  ),
111
- 'stripe_checkout_locale' => array(
112
- 'title' => __( 'Stripe Checkout locale', 'woocommerce-gateway-stripe' ),
113
- 'type' => 'select',
114
- 'class' => 'wc-enhanced-select',
115
- 'description' => __( 'Language to display in Stripe Checkout modal. Specify Auto to display Checkout in the user\'s preferred language, if available. English will be used by default.', 'woocommerce-gateway-stripe' ),
116
- 'default' => 'en',
117
- 'desc_tip' => true,
118
- 'options' => array(
119
- 'auto' => __( 'Auto', 'woocommerce-gateway-stripe' ),
120
- 'zh' => __( 'Simplified Chinese', 'woocommerce-gateway-stripe' ),
121
- 'da' => __( 'Danish', 'woocommerce-gateway-stripe' ),
122
- 'nl' => __( 'Dutch', 'woocommerce-gateway-stripe' ),
123
- 'en' => __( 'English', 'woocommerce-gateway-stripe' ),
124
- 'fi' => __( 'Finnish', 'woocommerce-gateway-stripe' ),
125
- 'fr' => __( 'French', 'woocommerce-gateway-stripe' ),
126
- 'de' => __( 'German', 'woocommerce-gateway-stripe' ),
127
- 'it' => __( 'Italian', 'woocommerce-gateway-stripe' ),
128
- 'ja' => __( 'Japanese', 'woocommerce-gateway-stripe' ),
129
- 'no' => __( 'Norwegian', 'woocommerce-gateway-stripe' ),
130
- 'es' => __( 'Spanish', 'woocommerce-gateway-stripe' ),
131
- 'sv' => __( 'Swedish', 'woocommerce-gateway-stripe' ),
132
- ),
133
- ),
134
  'stripe_bitcoin' => array(
135
  'title' => __( 'Bitcoin Currency', 'woocommerce-gateway-stripe' ),
136
  'label' => __( 'Enable Bitcoin Currency', 'woocommerce-gateway-stripe' ),
108
  'default' => 'no',
109
  'desc_tip' => true,
110
  ),
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
111
  'stripe_bitcoin' => array(
112
  'title' => __( 'Bitcoin Currency', 'woocommerce-gateway-stripe' ),
113
  'label' => __( 'Enable Bitcoin Currency', 'woocommerce-gateway-stripe' ),
includes/class-wc-gateway-stripe.php CHANGED
@@ -37,13 +37,6 @@ class WC_Gateway_Stripe extends WC_Stripe_Payment_Gateway {
37
  */
38
  public $three_d_secure;
39
 
40
- /**
41
- * Checkout Locale
42
- *
43
- * @var string
44
- */
45
- public $stripe_checkout_locale;
46
-
47
  /**
48
  * Credit card image
49
  *
@@ -157,7 +150,6 @@ class WC_Gateway_Stripe extends WC_Stripe_Payment_Gateway {
157
  $this->statement_descriptor = WC_Stripe_Helper::clean_statement_descriptor( $this->get_option( 'statement_descriptor' ) );
158
  $this->three_d_secure = 'yes' === $this->get_option( 'three_d_secure' );
159
  $this->stripe_checkout = 'yes' === $this->get_option( 'stripe_checkout' );
160
- $this->stripe_checkout_locale = $this->get_option( 'stripe_checkout_locale' );
161
  $this->stripe_checkout_image = $this->get_option( 'stripe_checkout_image', '' );
162
  $this->saved_cards = 'yes' === $this->get_option( 'saved_cards' );
163
  $this->secret_key = $this->testmode ? $this->get_option( 'test_secret_key' ) : $this->get_option( 'secret_key' );
@@ -412,7 +404,7 @@ class WC_Gateway_Stripe extends WC_Stripe_Payment_Gateway {
412
  data-currency="' . esc_attr( strtolower( get_woocommerce_currency() ) ) . '"
413
  data-image="' . esc_attr( $this->stripe_checkout_image ) . '"
414
  data-bitcoin="' . esc_attr( ( $this->bitcoin && $this->capture ) ? 'true' : 'false' ) . '"
415
- data-locale="' . esc_attr( $this->stripe_checkout_locale ? $this->stripe_checkout_locale : 'en' ) . '"
416
  data-three-d-secure="' . esc_attr( $this->three_d_secure ? 'true' : 'false' ) . '"
417
  data-allow-remember-me="' . esc_attr( $this->saved_cards ? 'true' : 'false' ) . '">';
418
 
@@ -559,9 +551,9 @@ class WC_Gateway_Stripe extends WC_Stripe_Payment_Gateway {
559
  }
560
 
561
  $stripe_params['no_prepaid_card_msg'] = __( 'Sorry, we\'re not accepting prepaid cards at this time. Your credit card has not been charge. Please try with alternative payment method.', 'woocommerce-gateway-stripe' );
562
- $stripe_params['no_bank_country_msg'] = __( 'Please select a country for your bank.', 'woocommerce-gateway-stripe' );
563
  $stripe_params['no_sepa_owner_msg'] = __( 'Please enter your IBAN account name.', 'woocommerce-gateway-stripe' );
564
  $stripe_params['no_sepa_iban_msg'] = __( 'Please enter your IBAN account number.', 'woocommerce-gateway-stripe' );
 
565
  $stripe_params['allow_prepaid_card'] = apply_filters( 'wc_stripe_allow_prepaid_card', true ) ? 'yes' : 'no';
566
  $stripe_params['inline_cc_form'] = $this->inline_cc_form ? 'yes' : 'no';
567
  $stripe_params['stripe_checkout_require_billing_address'] = apply_filters( 'wc_stripe_checkout_require_billing_address', false ) ? 'yes' : 'no';
@@ -571,6 +563,7 @@ class WC_Gateway_Stripe extends WC_Stripe_Payment_Gateway {
571
  $stripe_params['stripe_nonce'] = wp_create_nonce( '_wc_stripe_nonce' );
572
  $stripe_params['statement_descriptor'] = $this->statement_descriptor;
573
  $stripe_params['use_elements'] = apply_filters( 'wc_stripe_use_elements_checkout_form', true ) ? 'yes' : 'no';
 
574
  $stripe_params['is_stripe_checkout'] = $this->stripe_checkout ? 'yes' : 'no';
575
  $stripe_params['is_change_payment_page'] = ( isset( $_GET['pay_for_order'] ) || isset( $_GET['change_payment_method'] ) ) ? 'yes' : 'no';
576
  $stripe_params['is_add_payment_method_page'] = is_add_payment_method_page() ? 'yes' : 'no';
@@ -591,33 +584,6 @@ class WC_Gateway_Stripe extends WC_Stripe_Payment_Gateway {
591
  wp_enqueue_script( 'woocommerce_stripe' );
592
  }
593
 
594
- /**
595
- * Creates the 3DS source for charge.
596
- *
597
- * @since 4.0.0
598
- * @version 4.0.0
599
- * @param object $order
600
- * @param object $source_object
601
- * @return mixed
602
- */
603
- public function create_3ds_source( $order, $source_object ) {
604
- $currency = WC_Stripe_Helper::is_pre_30() ? $order->get_order_currency() : $order->get_currency();
605
- $order_id = WC_Stripe_Helper::is_pre_30() ? $order->id : $order->get_id();
606
- $return_url = $this->get_stripe_return_url( $order );
607
-
608
- $post_data = array();
609
- $post_data['amount'] = WC_Stripe_Helper::get_stripe_amount( $order->get_total(), $currency );
610
- $post_data['currency'] = strtolower( $currency );
611
- $post_data['type'] = 'three_d_secure';
612
- $post_data['owner'] = $this->get_owner_details( $order );
613
- $post_data['three_d_secure'] = array( 'card' => $source_object->id );
614
- $post_data['redirect'] = array( 'return_url' => $return_url );
615
-
616
- WC_Stripe_Logger::log( 'Info: Begin creating 3DS source' );
617
-
618
- return WC_Stripe_API::request( $post_data, 'sources' );
619
- }
620
-
621
  /**
622
  * Process the payment
623
  *
@@ -633,7 +599,7 @@ class WC_Gateway_Stripe extends WC_Stripe_Payment_Gateway {
633
  */
634
  public function process_payment( $order_id, $retry = true, $force_save_source = false ) {
635
  try {
636
- $order = wc_get_order( $order_id );
637
 
638
  // This comes from the create account checkbox in the checkout page.
639
  $create_account = ! empty( $_POST['createaccount'] ) ? true : false;
@@ -644,8 +610,7 @@ class WC_Gateway_Stripe extends WC_Stripe_Payment_Gateway {
644
  $new_stripe_customer->create_customer();
645
  }
646
 
647
- $source_object = $this->create_source_object();
648
-
649
  $prepared_source = $this->prepare_source( $source_object, get_current_user_id(), $force_save_source );
650
 
651
  // Check if we don't allow prepaid credit cards.
@@ -661,8 +626,7 @@ class WC_Gateway_Stripe extends WC_Stripe_Payment_Gateway {
661
  throw new WC_Stripe_Exception( print_r( $prepared_source, true ), $localized_message );
662
  }
663
 
664
- // Store source to order meta.
665
- $this->save_source( $order, $prepared_source );
666
 
667
  // Result from Stripe API request.
668
  $response = null;
@@ -671,15 +635,14 @@ class WC_Gateway_Stripe extends WC_Stripe_Payment_Gateway {
671
  // This will throw exception if not valid.
672
  $this->validate_minimum_order_amount( $order );
673
 
674
- /**
675
  * Check if card 3DS is required or optional with 3DS setting.
676
  * Will need to first create 3DS source and require redirection
677
  * for customer to login to their credit card company.
678
  * Note that if we need to save source, the original source must be first
679
  * attached to a customer in Stripe before it can be charged.
680
  */
681
- if ( ( $source_object && ! empty( $source_object->card ) ) && ( 'card' === $source_object->type && 'required' === $source_object->card->three_d_secure || ( $this->three_d_secure && 'optional' === $source_object->card->three_d_secure ) ) ) {
682
-
683
  $response = $this->create_3ds_source( $order, $source_object );
684
 
685
  if ( ! empty( $response->error ) ) {
@@ -726,7 +689,14 @@ class WC_Gateway_Stripe extends WC_Stripe_Payment_Gateway {
726
 
727
  // Customer param wrong? The user may have been deleted on stripe's end. Remove customer_id. Can be retried without.
728
  if ( preg_match( '/No such customer/i', $response->error->message ) && $retry ) {
729
- delete_user_meta( WC_Stripe_Helper::is_pre_30() ? $order->customer_user : $order->get_customer_id(), '_stripe_customer_id' );
 
 
 
 
 
 
 
730
 
731
  return $this->process_payment( $order_id, false, $force_save_source );
732
  } elseif ( preg_match( '/No such token/i', $response->error->message ) && $prepared_source->token_id ) {
37
  */
38
  public $three_d_secure;
39
 
 
 
 
 
 
 
 
40
  /**
41
  * Credit card image
42
  *
150
  $this->statement_descriptor = WC_Stripe_Helper::clean_statement_descriptor( $this->get_option( 'statement_descriptor' ) );
151
  $this->three_d_secure = 'yes' === $this->get_option( 'three_d_secure' );
152
  $this->stripe_checkout = 'yes' === $this->get_option( 'stripe_checkout' );
 
153
  $this->stripe_checkout_image = $this->get_option( 'stripe_checkout_image', '' );
154
  $this->saved_cards = 'yes' === $this->get_option( 'saved_cards' );
155
  $this->secret_key = $this->testmode ? $this->get_option( 'test_secret_key' ) : $this->get_option( 'secret_key' );
404
  data-currency="' . esc_attr( strtolower( get_woocommerce_currency() ) ) . '"
405
  data-image="' . esc_attr( $this->stripe_checkout_image ) . '"
406
  data-bitcoin="' . esc_attr( ( $this->bitcoin && $this->capture ) ? 'true' : 'false' ) . '"
407
+ data-locale="' . esc_attr( apply_filters( 'wc_stripe_checkout_locale', substr( get_locale(), 0, 2 ) ) ) . '"
408
  data-three-d-secure="' . esc_attr( $this->three_d_secure ? 'true' : 'false' ) . '"
409
  data-allow-remember-me="' . esc_attr( $this->saved_cards ? 'true' : 'false' ) . '">';
410
 
551
  }
552
 
553
  $stripe_params['no_prepaid_card_msg'] = __( 'Sorry, we\'re not accepting prepaid cards at this time. Your credit card has not been charge. Please try with alternative payment method.', 'woocommerce-gateway-stripe' );
 
554
  $stripe_params['no_sepa_owner_msg'] = __( 'Please enter your IBAN account name.', 'woocommerce-gateway-stripe' );
555
  $stripe_params['no_sepa_iban_msg'] = __( 'Please enter your IBAN account number.', 'woocommerce-gateway-stripe' );
556
+ $stripe_params['sepa_mandate_notification'] = apply_filters( 'wc_stripe_sepa_mandate_notification', 'email' );
557
  $stripe_params['allow_prepaid_card'] = apply_filters( 'wc_stripe_allow_prepaid_card', true ) ? 'yes' : 'no';
558
  $stripe_params['inline_cc_form'] = $this->inline_cc_form ? 'yes' : 'no';
559
  $stripe_params['stripe_checkout_require_billing_address'] = apply_filters( 'wc_stripe_checkout_require_billing_address', false ) ? 'yes' : 'no';
563
  $stripe_params['stripe_nonce'] = wp_create_nonce( '_wc_stripe_nonce' );
564
  $stripe_params['statement_descriptor'] = $this->statement_descriptor;
565
  $stripe_params['use_elements'] = apply_filters( 'wc_stripe_use_elements_checkout_form', true ) ? 'yes' : 'no';
566
+ $stripe_params['elements_options'] = apply_filters( 'wc_stripe_elements_options', array() );
567
  $stripe_params['is_stripe_checkout'] = $this->stripe_checkout ? 'yes' : 'no';
568
  $stripe_params['is_change_payment_page'] = ( isset( $_GET['pay_for_order'] ) || isset( $_GET['change_payment_method'] ) ) ? 'yes' : 'no';
569
  $stripe_params['is_add_payment_method_page'] = is_add_payment_method_page() ? 'yes' : 'no';
584
  wp_enqueue_script( 'woocommerce_stripe' );
585
  }
586
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
587
  /**
588
  * Process the payment
589
  *
599
  */
600
  public function process_payment( $order_id, $retry = true, $force_save_source = false ) {
601
  try {
602
+ $order = wc_get_order( $order_id );
603
 
604
  // This comes from the create account checkbox in the checkout page.
605
  $create_account = ! empty( $_POST['createaccount'] ) ? true : false;
610
  $new_stripe_customer->create_customer();
611
  }
612
 
613
+ $source_object = $this->get_source_object();
 
614
  $prepared_source = $this->prepare_source( $source_object, get_current_user_id(), $force_save_source );
615
 
616
  // Check if we don't allow prepaid credit cards.
626
  throw new WC_Stripe_Exception( print_r( $prepared_source, true ), $localized_message );
627
  }
628
 
629
+ $this->save_source_to_order( $order, $prepared_source );
 
630
 
631
  // Result from Stripe API request.
632
  $response = null;
635
  // This will throw exception if not valid.
636
  $this->validate_minimum_order_amount( $order );
637
 
638
+ /*
639
  * Check if card 3DS is required or optional with 3DS setting.
640
  * Will need to first create 3DS source and require redirection
641
  * for customer to login to their credit card company.
642
  * Note that if we need to save source, the original source must be first
643
  * attached to a customer in Stripe before it can be charged.
644
  */
645
+ if ( $this->is_3ds_required( $source_object ) ) {
 
646
  $response = $this->create_3ds_source( $order, $source_object );
647
 
648
  if ( ! empty( $response->error ) ) {
689
 
690
  // Customer param wrong? The user may have been deleted on stripe's end. Remove customer_id. Can be retried without.
691
  if ( preg_match( '/No such customer/i', $response->error->message ) && $retry ) {
692
+ if ( WC_Stripe_Helper::is_pre_30() ) {
693
+ delete_user_meta( $order->customer_user, '_stripe_customer_id' );
694
+ delete_post_meta( $order_id, '_stripe_customer_id' );
695
+ } else {
696
+ delete_user_meta( $order->get_customer_id(), '_stripe_customer_id' );
697
+ $order->delete_meta_data( '_stripe_customer_id' );
698
+ $order->save();
699
+ }
700
 
701
  return $this->process_payment( $order_id, false, $force_save_source );
702
  } elseif ( preg_match( '/No such token/i', $response->error->message ) && $prepared_source->token_id ) {
includes/class-wc-stripe-api.php CHANGED
@@ -14,7 +14,7 @@ class WC_Stripe_API {
14
  * Stripe API Endpoint
15
  */
16
  const ENDPOINT = 'https://api.stripe.com/v1/';
17
- const STRIPE_API_VERSION = '2017-12-14';
18
 
19
  /**
20
  * Secret API Key.
@@ -132,8 +132,6 @@ class WC_Stripe_API {
132
  public static function retrieve( $api ) {
133
  WC_Stripe_Logger::log( "{$api}" );
134
 
135
- $ua = self::get_user_agent();
136
-
137
  $response = wp_safe_remote_get(
138
  self::ENDPOINT . $api,
139
  array(
14
  * Stripe API Endpoint
15
  */
16
  const ENDPOINT = 'https://api.stripe.com/v1/';
17
+ const STRIPE_API_VERSION = '2018-01-23';
18
 
19
  /**
20
  * Secret API Key.
132
  public static function retrieve( $api ) {
133
  WC_Stripe_Logger::log( "{$api}" );
134
 
 
 
135
  $response = wp_safe_remote_get(
136
  self::ENDPOINT . $api,
137
  array(
includes/class-wc-stripe-customer.php CHANGED
@@ -256,20 +256,16 @@ class WC_Stripe_Customer {
256
 
257
  $sources = get_transient( 'stripe_sources_' . $this->get_id() );
258
 
259
- if ( false === $sources ) {
260
- $response = WC_Stripe_API::request( array(
261
- 'limit' => 100,
262
- ), 'customers/' . $this->get_id() . '/sources', 'GET' );
263
-
264
- if ( ! empty( $response->error ) ) {
265
- return array();
266
- }
267
 
268
- if ( is_array( $response->data ) ) {
269
- $sources = $response->data;
270
- }
271
 
272
- set_transient( 'stripe_sources_' . $this->get_id(), $sources, HOUR_IN_SECONDS * 24 );
 
273
  }
274
 
275
  return empty( $sources ) ? array() : $sources;
256
 
257
  $sources = get_transient( 'stripe_sources_' . $this->get_id() );
258
 
259
+ $response = WC_Stripe_API::request( array(
260
+ 'limit' => 100,
261
+ ), 'customers/' . $this->get_id() . '/sources', 'GET' );
 
 
 
 
 
262
 
263
+ if ( ! empty( $response->error ) ) {
264
+ return array();
265
+ }
266
 
267
+ if ( is_array( $response->data ) ) {
268
+ $sources = $response->data;
269
  }
270
 
271
  return empty( $sources ) ? array() : $sources;
includes/class-wc-stripe-helper.php CHANGED
@@ -54,6 +54,7 @@ class WC_Stripe_Helper {
54
  'missing' => __( 'There is no card on a customer that is being charged.', 'woocommerce-gateway-stripe' ),
55
  'processing_error' => __( 'An error occurred while processing the card.', 'woocommerce-gateway-stripe' ),
56
  'invalid_request_error' => __( 'Unable to process this payment, please try again or use alternative method.', 'woocommerce-gateway-stripe' ),
 
57
  ) );
58
  }
59
 
54
  'missing' => __( 'There is no card on a customer that is being charged.', 'woocommerce-gateway-stripe' ),
55
  'processing_error' => __( 'An error occurred while processing the card.', 'woocommerce-gateway-stripe' ),
56
  'invalid_request_error' => __( 'Unable to process this payment, please try again or use alternative method.', 'woocommerce-gateway-stripe' ),
57
+ 'invalid_sofort_country' => __( 'The billing country is not accepted by SOFORT. Please try another country.', 'woocommerce-gateway-stripe' ),
58
  ) );
59
  }
60
 
includes/class-wc-stripe-order-handler.php CHANGED
@@ -76,12 +76,6 @@ class WC_Stripe_Order_Handler extends WC_Stripe_Payment_Gateway {
76
 
77
  WC_Stripe_Logger::log( "Info: (Redirect) Begin processing payment for order $order_id for the amount of {$order->get_total()}" );
78
 
79
- // Prep source object.
80
- $source_object = new stdClass();
81
- $source_object->token_id = '';
82
- $source_object->customer = $this->get_stripe_customer_id( $order );
83
- $source_object->source = $source;
84
-
85
  /**
86
  * First check if the source is chargeable at this time. If not,
87
  * webhook will take care of it later.
@@ -106,6 +100,12 @@ class WC_Stripe_Order_Handler extends WC_Stripe_Payment_Gateway {
106
  return;
107
  }
108
 
 
 
 
 
 
 
109
  // Make the request.
110
  $response = WC_Stripe_API::request( $this->generate_payment_request( $order, $source_object ) );
111
 
@@ -124,7 +124,14 @@ class WC_Stripe_Order_Handler extends WC_Stripe_Payment_Gateway {
124
 
125
  // Customer param wrong? The user may have been deleted on stripe's end. Remove customer_id. Can be retried without.
126
  if ( preg_match( '/No such customer/i', $response->error->message ) && $retry ) {
127
- delete_user_meta( WC_Stripe_Helper::is_pre_30() ? $order->customer_user : $order->get_customer_id(), '_stripe_customer_id' );
 
 
 
 
 
 
 
128
 
129
  return $this->process_redirect_payment( $order_id, false );
130
 
@@ -350,16 +357,6 @@ class WC_Stripe_Order_Handler extends WC_Stripe_Payment_Gateway {
350
  array_walk_recursive( $required_fields, 'wc_clean' );
351
  array_walk_recursive( $all_fields, 'wc_clean' );
352
 
353
- // Remove unneeded required fields depending on source type.
354
- if ( 'stripe_sepa' !== $source_type ) {
355
- unset( $required_fields['stripe_sepa_owner'] );
356
- unset( $required_fields['stripe_sepa_iban'] );
357
- }
358
-
359
- if ( 'stripe_sofort' !== $source_type ) {
360
- unset( $required_fields['stripe_sofort_bank_country'] );
361
- }
362
-
363
  /**
364
  * If ship to different address checkbox is checked then we need
365
  * to validate shipping fields too.
@@ -390,15 +387,6 @@ class WC_Stripe_Order_Handler extends WC_Stripe_Payment_Gateway {
390
  continue;
391
  }
392
 
393
- // Check if is SEPA.
394
- if ( 'stripe_sepa' !== $source_type && 'stripe_sepa_owner' === $field ) {
395
- continue;
396
- }
397
-
398
- if ( 'stripe_sepa' !== $source_type && 'stripe_sepa_iban' === $field ) {
399
- $continue;
400
- }
401
-
402
  if ( empty( $field_value ) || '-1' === $field_value ) {
403
  $error_field = $this->normalize_field( $field );
404
  /* translators: error field name */
76
 
77
  WC_Stripe_Logger::log( "Info: (Redirect) Begin processing payment for order $order_id for the amount of {$order->get_total()}" );
78
 
 
 
 
 
 
 
79
  /**
80
  * First check if the source is chargeable at this time. If not,
81
  * webhook will take care of it later.
100
  return;
101
  }
102
 
103
+ // Prep source object.
104
+ $source_object = new stdClass();
105
+ $source_object->token_id = '';
106
+ $source_object->customer = $this->get_stripe_customer_id( $order );
107
+ $source_object->source = $source_info->id;
108
+
109
  // Make the request.
110
  $response = WC_Stripe_API::request( $this->generate_payment_request( $order, $source_object ) );
111
 
124
 
125
  // Customer param wrong? The user may have been deleted on stripe's end. Remove customer_id. Can be retried without.
126
  if ( preg_match( '/No such customer/i', $response->error->message ) && $retry ) {
127
+ if ( WC_Stripe_Helper::is_pre_30() ) {
128
+ delete_user_meta( $order->customer_user, '_stripe_customer_id' );
129
+ delete_post_meta( $order_id, '_stripe_customer_id' );
130
+ } else {
131
+ delete_user_meta( $order->get_customer_id(), '_stripe_customer_id' );
132
+ $order->delete_meta_data( '_stripe_customer_id' );
133
+ $order->save();
134
+ }
135
 
136
  return $this->process_redirect_payment( $order_id, false );
137
 
357
  array_walk_recursive( $required_fields, 'wc_clean' );
358
  array_walk_recursive( $all_fields, 'wc_clean' );
359
 
 
 
 
 
 
 
 
 
 
 
360
  /**
361
  * If ship to different address checkbox is checked then we need
362
  * to validate shipping fields too.
387
  continue;
388
  }
389
 
 
 
 
 
 
 
 
 
 
390
  if ( empty( $field_value ) || '-1' === $field_value ) {
391
  $error_field = $this->normalize_field( $field );
392
  /* translators: error field name */
includes/class-wc-stripe-webhook-handler.php CHANGED
@@ -162,7 +162,14 @@ class WC_Stripe_Webhook_Handler extends WC_Stripe_Payment_Gateway {
162
 
163
  // Customer param wrong? The user may have been deleted on stripe's end. Remove customer_id. Can be retried without.
164
  if ( preg_match( '/No such customer/i', $response->error->message ) && $retry ) {
165
- delete_user_meta( WC_Stripe_Helper::is_pre_30() ? $order->customer_user : $order->get_customer_id(), '_stripe_customer_id' );
 
 
 
 
 
 
 
166
 
167
  return $this->process_payment( $order_id, false );
168
 
@@ -480,6 +487,13 @@ class WC_Stripe_Webhook_Handler extends WC_Stripe_Payment_Gateway {
480
  public function process_webhook( $request_body ) {
481
  $notification = json_decode( $request_body );
482
 
 
 
 
 
 
 
 
483
  switch ( $notification->type ) {
484
  case 'source.chargeable':
485
  $this->process_webhook_payment( $notification );
162
 
163
  // Customer param wrong? The user may have been deleted on stripe's end. Remove customer_id. Can be retried without.
164
  if ( preg_match( '/No such customer/i', $response->error->message ) && $retry ) {
165
+ if ( WC_Stripe_Helper::is_pre_30() ) {
166
+ delete_user_meta( $order->customer_user, '_stripe_customer_id' );
167
+ delete_post_meta( $order_id, '_stripe_customer_id' );
168
+ } else {
169
+ delete_user_meta( $order->get_customer_id(), '_stripe_customer_id' );
170
+ $order->delete_meta_data( '_stripe_customer_id' );
171
+ $order->save();
172
+ }
173
 
174
  return $this->process_payment( $order_id, false );
175
 
487
  public function process_webhook( $request_body ) {
488
  $notification = json_decode( $request_body );
489
 
490
+ /*
491
+ * Hacky way to possibly prevent duplicate requests due to
492
+ * frontend request and webhook payment firing at the same
493
+ * time.
494
+ */
495
+ sleep( 10 );
496
+
497
  switch ( $notification->type ) {
498
  case 'source.chargeable':
499
  $this->process_webhook_payment( $notification );
includes/compat/class-wc-stripe-compat.php CHANGED
@@ -60,15 +60,97 @@ class WC_Stripe_Compat extends WC_Gateway_Stripe {
60
  return ( function_exists( 'wcs_order_contains_subscription' ) && ( wcs_order_contains_subscription( $order_id ) || wcs_is_subscription( $order_id ) || wcs_order_contains_renewal( $order_id ) ) );
61
  }
62
 
 
 
 
 
 
 
 
 
 
 
63
  /**
64
  * Is $order_id a pre-order?
65
  * @param int $order_id
66
  * @return boolean
67
  */
68
- protected function is_pre_order( $order_id ) {
69
  return ( class_exists( 'WC_Pre_Orders_Order' ) && WC_Pre_Orders_Order::order_contains_pre_order( $order_id ) );
70
  }
71
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
72
  /**
73
  * Process the payment based on type.
74
  * @param int $order_id
@@ -76,6 +158,10 @@ class WC_Stripe_Compat extends WC_Gateway_Stripe {
76
  */
77
  public function process_payment( $order_id, $retry = true, $force_save_source = false ) {
78
  if ( $this->has_subscription( $order_id ) ) {
 
 
 
 
79
  // Regular payment with force customer enabled
80
  return parent::process_payment( $order_id, true, true );
81
  } elseif ( $this->is_pre_order( $order_id ) ) {
@@ -109,10 +195,10 @@ class WC_Stripe_Compat extends WC_Gateway_Stripe {
109
  * @since 3.1.0
110
  * @version 4.0.0
111
  */
112
- public function save_source( $order, $source ) {
113
- parent::save_source( $order, $source );
114
 
115
- $order_id = WC_Stripe_Helper::is_pre_30() ? $order->id : $order->get_id();
116
 
117
  // Also store it on the subscriptions being purchased or paid for in the order
118
  if ( function_exists( 'wcs_order_contains_subscription' ) && wcs_order_contains_subscription( $order_id ) ) {
@@ -131,45 +217,55 @@ class WC_Stripe_Compat extends WC_Gateway_Stripe {
131
  }
132
 
133
  /**
134
- * process_subscription_payment function.
135
- * @param mixed $order
136
- * @param int $amount (default: 0)
137
- * @param string $stripe_token (default: '')
138
- * @param bool initial_payment
 
 
139
  */
140
- public function process_subscription_payment( $order = '', $amount = 0 ) {
141
  if ( $amount * 100 < WC_Stripe_Helper::get_minimum_amount() ) {
142
  /* translators: minimum amount */
143
  return new WP_Error( 'stripe_error', sprintf( __( 'Sorry, the minimum allowed order total is %1$s to use this payment method.', 'woocommerce-gateway-stripe' ), wc_price( WC_Stripe_Helper::get_minimum_amount() / 100 ) ) );
144
  }
145
 
146
- $customer_id = WC_Stripe_Helper::is_pre_30() ? $order->customer_user : $order->get_customer_id();
147
- $order_id = WC_Stripe_Helper::is_pre_30() ? $order->id : $order->get_id();
148
 
149
  // Get source from order
150
- $prepared_source = $this->prepare_order_source( $order );
151
 
152
- // Or fail :(
153
  if ( ! $prepared_source->customer ) {
154
  return new WP_Error( 'stripe_error', __( 'Customer not found', 'woocommerce-gateway-stripe' ) );
155
  }
156
 
157
  WC_Stripe_Logger::log( "Info: Begin processing subscription payment for order {$order_id} for the amount of {$amount}" );
158
 
159
- // Make the request
160
- $request = $this->generate_payment_request( $order, $prepared_source );
161
- $request['capture'] = 'true';
162
- $request['amount'] = WC_Stripe_Helper::get_stripe_amount( $amount, $request['currency'] );
163
- $response = WC_Stripe_API::request( $request );
 
 
 
 
 
 
 
 
 
 
164
 
165
- // Process valid response
166
- if ( ! empty( $response->error ) ) {
167
  return $response; // Default catch all errors.
168
  }
169
 
170
- $this->process_response( $response, $order );
171
 
172
- return $response;
 
 
173
  }
174
 
175
  /**
@@ -195,13 +291,13 @@ class WC_Stripe_Compat extends WC_Gateway_Stripe {
195
  }
196
 
197
  /**
198
- * scheduled_subscription_payment function.
199
  *
200
  * @param $amount_to_charge float The amount to charge.
201
  * @param $renewal_order WC_Order A WC_Order object created to record the renewal payment.
202
  */
203
  public function scheduled_subscription_payment( $amount_to_charge, $renewal_order ) {
204
- $response = $this->process_subscription_payment( $renewal_order, $amount_to_charge );
205
 
206
  if ( is_wp_error( $response ) ) {
207
  /* translators: error message */
@@ -209,14 +305,19 @@ class WC_Stripe_Compat extends WC_Gateway_Stripe {
209
  }
210
 
211
  if ( ! empty( $response->error ) ) {
212
- /* translators: error message */
213
- $renewal_order->update_status( 'failed', sprintf( __( 'Stripe Transaction Failed (%s)', 'woocommerce-gateway-stripe' ), $response->error->message ) );
 
 
 
 
 
214
  }
215
  }
216
 
217
  /**
218
  * Remove order meta
219
- * @param object $order
220
  */
221
  public function remove_order_source_before_retry( $order ) {
222
  $order_id = WC_Stripe_Helper::is_pre_30() ? $order->id : $order->get_id();
@@ -295,6 +396,7 @@ class WC_Stripe_Compat extends WC_Gateway_Stripe {
295
  * manually set up automatic recurring payments for a customer via the Edit Subscriptions screen in 2.0+.
296
  *
297
  * @since 2.5
 
298
  * @param string $payment_method_id The ID of the payment method to validate
299
  * @param array $payment_meta associative array of meta data required for automatic payments
300
  * @return array
@@ -303,13 +405,18 @@ class WC_Stripe_Compat extends WC_Gateway_Stripe {
303
  if ( $this->id === $payment_method_id ) {
304
 
305
  if ( ! isset( $payment_meta['post_meta']['_stripe_customer_id']['value'] ) || empty( $payment_meta['post_meta']['_stripe_customer_id']['value'] ) ) {
306
- throw new Exception( 'A "_stripe_customer_id" value is required.' );
307
  } elseif ( 0 !== strpos( $payment_meta['post_meta']['_stripe_customer_id']['value'], 'cus_' ) ) {
308
- throw new Exception( 'Invalid customer ID. A valid "_stripe_customer_id" must begin with "cus_".' );
309
  }
310
 
311
- if ( ! isset( $payment_meta['post_meta']['_stripe_source_id']['value'] ) || empty( $payment_meta['post_meta']['_stripe_source_id']['value'] ) ) {
312
- throw new Exception( 'A "_stripe_source_id" value is required.' );
 
 
 
 
 
313
  }
314
  }
315
  }
@@ -380,6 +487,8 @@ class WC_Stripe_Compat extends WC_Gateway_Stripe {
380
  foreach ( $sources as $source ) {
381
  if ( isset( $source->type ) && 'card' === $source->type ) {
382
  $card = $source->card;
 
 
383
  }
384
 
385
  if ( $source->id === $stripe_source_id ) {
@@ -427,15 +536,14 @@ class WC_Stripe_Compat extends WC_Gateway_Stripe {
427
  throw new Exception( sprintf( __( 'Sorry, the minimum allowed order total is %1$s to use this payment method.', 'woocommerce-gateway-stripe' ), wc_price( WC_Stripe_Helper::get_minimum_amount() / 100 ) ) );
428
  }
429
 
430
- $source = $this->prepare_source( $this->create_source_object(), get_current_user_id(), true );
431
 
432
  // We need a source on file to continue.
433
  if ( empty( $source->customer ) || empty( $source->source ) ) {
434
  throw new Exception( __( 'Unable to store payment details. Please try again.', 'woocommerce-gateway-stripe' ) );
435
  }
436
 
437
- // Store source to order meta
438
- $this->save_source( $order, $source );
439
 
440
  // Remove cart
441
  WC()->cart->empty_cart();
60
  return ( function_exists( 'wcs_order_contains_subscription' ) && ( wcs_order_contains_subscription( $order_id ) || wcs_is_subscription( $order_id ) || wcs_order_contains_renewal( $order_id ) ) );
61
  }
62
 
63
+ /**
64
+ * Checks if page is pay for order and change subs payment page.
65
+ *
66
+ * @since 4.0.4
67
+ * @return bool
68
+ */
69
+ public function is_subs_change_payment() {
70
+ return ( isset( $_GET['pay_for_order'] ) && isset( $_GET['change_payment_method'] ) );
71
+ }
72
+
73
  /**
74
  * Is $order_id a pre-order?
75
  * @param int $order_id
76
  * @return boolean
77
  */
78
+ public function is_pre_order( $order_id ) {
79
  return ( class_exists( 'WC_Pre_Orders_Order' ) && WC_Pre_Orders_Order::order_contains_pre_order( $order_id ) );
80
  }
81
 
82
+ /**
83
+ * Process the payment method change for subscriptions.
84
+ *
85
+ * @since 4.0.4
86
+ * @param int $order_id
87
+ */
88
+ public function change_subs_payment_method( $order_id ) {
89
+ try {
90
+ $subscription = wc_get_order( $order_id );
91
+ $source_object = $this->get_source_object();
92
+ $prepared_source = $this->prepare_source( $source_object, get_current_user_id(), true );
93
+
94
+ // Check if we don't allow prepaid credit cards.
95
+ if ( ! apply_filters( 'wc_stripe_allow_prepaid_card', true ) ) {
96
+ if ( $source_object && 'token' === $source_object->object && 'prepaid' === $source_object->card->funding ) {
97
+ $localized_message = __( 'Sorry, we\'re not accepting prepaid cards at this time. Your credit card has not been charge. Please try with alternative payment method.', 'woocommerce-gateway-stripe' );
98
+ throw new WC_Stripe_Exception( print_r( $source_object, true ), $localized_message );
99
+ }
100
+ }
101
+
102
+ if ( empty( $prepared_source->source ) ) {
103
+ $localized_message = __( 'Payment processing failed. Please retry.', 'woocommerce-gateway-stripe' );
104
+ throw new WC_Stripe_Exception( print_r( $prepared_source, true ), $localized_message );
105
+ }
106
+
107
+ $this->save_source_to_order( $subscription, $prepared_source );
108
+
109
+ /*
110
+ * Check if card 3DS is required or optional with 3DS setting.
111
+ * Will need to first create 3DS source and require redirection
112
+ * for customer to login to their credit card company.
113
+ * Note that if we need to save source, the original source must be first
114
+ * attached to a customer in Stripe before it can be charged.
115
+ */
116
+ if ( $this->is_3ds_required( $source_object ) ) {
117
+ $order = $subscription->get_parent();
118
+ $response = $this->create_3ds_source( $order, $source_object, $subscription->get_view_order_url() );
119
+
120
+ if ( ! empty( $response->error ) ) {
121
+ $localized_message = $response->error->message;
122
+
123
+ $order->add_order_note( $localized_message );
124
+
125
+ throw new WC_Stripe_Exception( print_r( $response, true ), $localized_message );
126
+ }
127
+
128
+ // Update order meta with 3DS source.
129
+ if ( WC_Stripe_Helper::is_pre_30() ) {
130
+ update_post_meta( $order_id, '_stripe_source_id', $response->id );
131
+ } else {
132
+ $subscription->update_meta_data( '_stripe_source_id', $response->id );
133
+ $subscription->save();
134
+ }
135
+
136
+ WC_Stripe_Logger::log( 'Info: Redirecting to 3DS...' );
137
+
138
+ return array(
139
+ 'result' => 'success',
140
+ 'redirect' => esc_url_raw( $response->redirect->url ),
141
+ );
142
+ }
143
+
144
+ return array(
145
+ 'result' => 'success',
146
+ 'redirect' => $this->get_return_url( $subscription ),
147
+ );
148
+ } catch ( WC_Stripe_Exception $e ) {
149
+ wc_add_notice( $e->getLocalizedMessage(), 'error' );
150
+ WC_Stripe_Logger::log( 'Error: ' . $e->getMessage() );
151
+ }
152
+ }
153
+
154
  /**
155
  * Process the payment based on type.
156
  * @param int $order_id
158
  */
159
  public function process_payment( $order_id, $retry = true, $force_save_source = false ) {
160
  if ( $this->has_subscription( $order_id ) ) {
161
+ if ( $this->is_subs_change_payment() ) {
162
+ return $this->change_subs_payment_method( $order_id );
163
+ }
164
+
165
  // Regular payment with force customer enabled
166
  return parent::process_payment( $order_id, true, true );
167
  } elseif ( $this->is_pre_order( $order_id ) ) {
195
  * @since 3.1.0
196
  * @version 4.0.0
197
  */
198
+ public function save_source_to_order( $order, $source ) {
199
+ parent::save_source_to_order( $order, $source );
200
 
201
+ $order_id = WC_Stripe_Helper::is_pre_30() ? $order->id : $order->get_id();
202
 
203
  // Also store it on the subscriptions being purchased or paid for in the order
204
  if ( function_exists( 'wcs_order_contains_subscription' ) && wcs_order_contains_subscription( $order_id ) ) {
217
  }
218
 
219
  /**
220
+ * Process_subscription_payment function.
221
+ *
222
+ * @since 3.0
223
+ * @since 4.0.4 Add third parameter flag to retry.
224
+ * @param float $amount
225
+ * @param mixed $renewal_order
226
+ * @param bool $is_retry Is this a retry process.
227
  */
228
+ public function process_subscription_payment( $amount = 0.0, $renewal_order, $is_retry = false ) {
229
  if ( $amount * 100 < WC_Stripe_Helper::get_minimum_amount() ) {
230
  /* translators: minimum amount */
231
  return new WP_Error( 'stripe_error', sprintf( __( 'Sorry, the minimum allowed order total is %1$s to use this payment method.', 'woocommerce-gateway-stripe' ), wc_price( WC_Stripe_Helper::get_minimum_amount() / 100 ) ) );
232
  }
233
 
234
+ $order_id = WC_Stripe_Helper::is_pre_30() ? $renewal_order->id : $renewal_order->get_id();
 
235
 
236
  // Get source from order
237
+ $prepared_source = $this->prepare_order_source( $renewal_order );
238
 
 
239
  if ( ! $prepared_source->customer ) {
240
  return new WP_Error( 'stripe_error', __( 'Customer not found', 'woocommerce-gateway-stripe' ) );
241
  }
242
 
243
  WC_Stripe_Logger::log( "Info: Begin processing subscription payment for order {$order_id} for the amount of {$amount}" );
244
 
245
+ if ( $is_retry ) {
246
+ // Passing empty source with charge customer default.
247
+ $prepared_source->source = '';
248
+ }
249
+
250
+ $request = $this->generate_payment_request( $renewal_order, $prepared_source );
251
+ $request['capture'] = 'true';
252
+ $request['amount'] = WC_Stripe_Helper::get_stripe_amount( $amount, $request['currency'] );
253
+ $response = WC_Stripe_API::request( $request );
254
+
255
+ if ( ! empty( $response->error ) || is_wp_error( $response ) ) {
256
+ if ( $is_retry ) {
257
+ /* translators: error message */
258
+ $renewal_order->update_status( 'failed', sprintf( __( 'Stripe Transaction Failed (%s)', 'woocommerce-gateway-stripe' ), $response->error->message ) );
259
+ }
260
 
 
 
261
  return $response; // Default catch all errors.
262
  }
263
 
264
+ $this->process_response( $response, $renewal_order );
265
 
266
+ if ( ! $is_retry ) {
267
+ return $response;
268
+ }
269
  }
270
 
271
  /**
291
  }
292
 
293
  /**
294
+ * Scheduled_subscription_payment function.
295
  *
296
  * @param $amount_to_charge float The amount to charge.
297
  * @param $renewal_order WC_Order A WC_Order object created to record the renewal payment.
298
  */
299
  public function scheduled_subscription_payment( $amount_to_charge, $renewal_order ) {
300
+ $response = $this->process_subscription_payment( $amount_to_charge, $renewal_order );
301
 
302
  if ( is_wp_error( $response ) ) {
303
  /* translators: error message */
305
  }
306
 
307
  if ( ! empty( $response->error ) ) {
308
+ // This is a very generic error to listen for but worth a retry before total fail.
309
+ if ( isset( $response->error->type ) && 'invalid_request_error' === $response->error->type && apply_filters( 'wc_stripe_use_default_customer_source', true ) ) {
310
+ $this->process_subscription_payment( $amount_to_charge, $renewal_order, true );
311
+ } else {
312
+ /* translators: error message */
313
+ $renewal_order->update_status( 'failed', sprintf( __( 'Stripe Transaction Failed (%s)', 'woocommerce-gateway-stripe' ), $response->error->message ) );
314
+ }
315
  }
316
  }
317
 
318
  /**
319
  * Remove order meta
320
+ * @param object $order
321
  */
322
  public function remove_order_source_before_retry( $order ) {
323
  $order_id = WC_Stripe_Helper::is_pre_30() ? $order->id : $order->get_id();
396
  * manually set up automatic recurring payments for a customer via the Edit Subscriptions screen in 2.0+.
397
  *
398
  * @since 2.5
399
+ * @since 4.0.4 Stripe sourd id field no longer needs to be required.
400
  * @param string $payment_method_id The ID of the payment method to validate
401
  * @param array $payment_meta associative array of meta data required for automatic payments
402
  * @return array
405
  if ( $this->id === $payment_method_id ) {
406
 
407
  if ( ! isset( $payment_meta['post_meta']['_stripe_customer_id']['value'] ) || empty( $payment_meta['post_meta']['_stripe_customer_id']['value'] ) ) {
408
+ throw new Exception( __( 'A "Stripe Customer ID" value is required.', 'woocommerce-gateway-stripe' ) );
409
  } elseif ( 0 !== strpos( $payment_meta['post_meta']['_stripe_customer_id']['value'], 'cus_' ) ) {
410
+ throw new Exception( __( 'Invalid customer ID. A valid "Stripe Customer ID" must begin with "cus_".', 'woocommerce-gateway-stripe' ) );
411
  }
412
 
413
+ if (
414
+ ( ! empty( $payment_meta['post_meta']['_stripe_source_id']['value'] )
415
+ && 0 !== strpos( $payment_meta['post_meta']['_stripe_source_id']['value'], 'card_' ) )
416
+ && ( ! empty( $payment_meta['post_meta']['_stripe_source_id']['value'] )
417
+ && 0 !== strpos( $payment_meta['post_meta']['_stripe_source_id']['value'], 'src_' ) ) ) {
418
+
419
+ throw new Exception( __( 'Invalid source ID. A valid source "Stripe Source ID" must begin with "src_" or "card_".', 'woocommerce-gateway-stripe' ) );
420
  }
421
  }
422
  }
487
  foreach ( $sources as $source ) {
488
  if ( isset( $source->type ) && 'card' === $source->type ) {
489
  $card = $source->card;
490
+ } elseif ( isset( $source->object ) && 'card' === $source->object ) {
491
+ $card = $source;
492
  }
493
 
494
  if ( $source->id === $stripe_source_id ) {
536
  throw new Exception( sprintf( __( 'Sorry, the minimum allowed order total is %1$s to use this payment method.', 'woocommerce-gateway-stripe' ), wc_price( WC_Stripe_Helper::get_minimum_amount() / 100 ) ) );
537
  }
538
 
539
+ $source = $this->prepare_source( $this->get_source_object(), get_current_user_id(), true );
540
 
541
  // We need a source on file to continue.
542
  if ( empty( $source->customer ) || empty( $source->source ) ) {
543
  throw new Exception( __( 'Unable to store payment details. Please try again.', 'woocommerce-gateway-stripe' ) );
544
  }
545
 
546
+ $this->save_source_to_order( $order, $source );
 
547
 
548
  // Remove cart
549
  WC()->cart->empty_cart();
includes/compat/class-wc-stripe-sepa-compat.php CHANGED
@@ -109,8 +109,8 @@ class WC_Stripe_Sepa_Compat extends WC_Gateway_Stripe_Sepa {
109
  * @since 3.1.0
110
  * @version 4.0.0
111
  */
112
- public function save_source( $order, $source ) {
113
- parent::save_source( $order, $source );
114
 
115
  $order_id = WC_Stripe_Helper::is_pre_30() ? $order->id : $order->get_id();
116
 
@@ -131,45 +131,55 @@ class WC_Stripe_Sepa_Compat extends WC_Gateway_Stripe_Sepa {
131
  }
132
 
133
  /**
134
- * process_subscription_payment function.
135
- * @param mixed $order
136
- * @param int $amount (default: 0)
137
- * @param string $stripe_token (default: '')
138
- * @param bool initial_payment
 
 
139
  */
140
- public function process_subscription_payment( $order = '', $amount = 0 ) {
141
  if ( $amount * 100 < WC_Stripe_Helper::get_minimum_amount() ) {
142
  /* translators: minimum amount */
143
  return new WP_Error( 'stripe_error', sprintf( __( 'Sorry, the minimum allowed order total is %1$s to use this payment method.', 'woocommerce-gateway-stripe' ), wc_price( WC_Stripe_Helper::get_minimum_amount() / 100 ) ) );
144
  }
145
 
146
- $customer_id = WC_Stripe_Helper::is_pre_30() ? $order->customer_user : $order->get_customer_id();
147
- $order_id = WC_Stripe_Helper::is_pre_30() ? $order->id : $order->get_id();
148
 
149
  // Get source from order
150
- $prepared_source = $this->prepare_order_source( $order );
151
 
152
- // Or fail :(
153
  if ( ! $prepared_source->customer ) {
154
  return new WP_Error( 'stripe_error', __( 'Customer not found', 'woocommerce-gateway-stripe' ) );
155
  }
156
 
157
  WC_Stripe_Logger::log( "Info: Begin processing subscription payment for order {$order_id} for the amount of {$amount}" );
158
 
159
- // Make the request
160
- $request = $this->generate_payment_request( $order, $prepared_source );
161
- $request['capture'] = 'true';
162
- $request['amount'] = WC_Stripe_Helper::get_stripe_amount( $amount, $request['currency'] );
163
- $response = WC_Stripe_API::request( $request );
 
 
 
 
 
 
 
 
 
 
164
 
165
- // Process valid response
166
- if ( ! empty( $response->error ) ) {
167
  return $response; // Default catch all errors.
168
  }
169
 
170
- $this->process_response( $response, $order );
171
 
172
- return $response;
 
 
173
  }
174
 
175
  /**
@@ -195,13 +205,13 @@ class WC_Stripe_Sepa_Compat extends WC_Gateway_Stripe_Sepa {
195
  }
196
 
197
  /**
198
- * scheduled_subscription_payment function.
199
  *
200
  * @param $amount_to_charge float The amount to charge.
201
  * @param $renewal_order WC_Order A WC_Order object created to record the renewal payment.
202
  */
203
  public function scheduled_subscription_payment( $amount_to_charge, $renewal_order ) {
204
- $response = $this->process_subscription_payment( $renewal_order, $amount_to_charge );
205
 
206
  if ( is_wp_error( $response ) ) {
207
  /* translators: error message */
@@ -209,8 +219,13 @@ class WC_Stripe_Sepa_Compat extends WC_Gateway_Stripe_Sepa {
209
  }
210
 
211
  if ( ! empty( $response->error ) ) {
212
- /* translators: error message */
213
- $renewal_order->update_status( 'failed', sprintf( __( 'Stripe Transaction Failed (%s)', 'woocommerce-gateway-stripe' ), $response->error->message ) );
 
 
 
 
 
214
  }
215
  }
216
 
@@ -227,7 +242,7 @@ class WC_Stripe_Sepa_Compat extends WC_Gateway_Stripe_Sepa {
227
 
228
  /**
229
  * Remove order meta
230
- * @param object $order
231
  */
232
  public function remove_order_customer_before_retry( $order ) {
233
  $order_id = WC_Stripe_Helper::is_pre_30() ? $order->id : $order->get_id();
@@ -426,15 +441,14 @@ class WC_Stripe_Sepa_Compat extends WC_Gateway_Stripe_Sepa {
426
  throw new Exception( sprintf( __( 'Sorry, the minimum allowed order total is %1$s to use this payment method.', 'woocommerce-gateway-stripe' ), wc_price( WC_Stripe_Helper::get_minimum_amount() / 100 ) ) );
427
  }
428
 
429
- $source = $this->prepare_source( $this->create_source_object(), get_current_user_id(), true );
430
 
431
  // We need a source on file to continue.
432
  if ( empty( $source->customer ) || empty( $source->source ) ) {
433
  throw new Exception( __( 'Unable to store payment details. Please try again.', 'woocommerce-gateway-stripe' ) );
434
  }
435
 
436
- // Store source to order meta
437
- $this->save_source( $order, $source );
438
 
439
  // Remove cart
440
  WC()->cart->empty_cart();
109
  * @since 3.1.0
110
  * @version 4.0.0
111
  */
112
+ public function save_source_to_order( $order, $source ) {
113
+ parent::save_source_to_order( $order, $source );
114
 
115
  $order_id = WC_Stripe_Helper::is_pre_30() ? $order->id : $order->get_id();
116
 
131
  }
132
 
133
  /**
134
+ * Process_subscription_payment function.
135
+ *
136
+ * @since 3.0
137
+ * @since 4.0.4 Add third parameter flag to retry.
138
+ * @param float $amount
139
+ * @param mixed $renewal_order
140
+ * @param bool $is_retry Is this a retry process.
141
  */
142
+ public function process_subscription_payment( $amount = 0.0, $renewal_order, $is_retry = false ) {
143
  if ( $amount * 100 < WC_Stripe_Helper::get_minimum_amount() ) {
144
  /* translators: minimum amount */
145
  return new WP_Error( 'stripe_error', sprintf( __( 'Sorry, the minimum allowed order total is %1$s to use this payment method.', 'woocommerce-gateway-stripe' ), wc_price( WC_Stripe_Helper::get_minimum_amount() / 100 ) ) );
146
  }
147
 
148
+ $order_id = WC_Stripe_Helper::is_pre_30() ? $renewal_order->id : $renewal_order->get_id();
 
149
 
150
  // Get source from order
151
+ $prepared_source = $this->prepare_order_source( $renewal_order );
152
 
 
153
  if ( ! $prepared_source->customer ) {
154
  return new WP_Error( 'stripe_error', __( 'Customer not found', 'woocommerce-gateway-stripe' ) );
155
  }
156
 
157
  WC_Stripe_Logger::log( "Info: Begin processing subscription payment for order {$order_id} for the amount of {$amount}" );
158
 
159
+ if ( $is_retry ) {
160
+ // Passing empty source with charge customer default.
161
+ $prepared_source->source = '';
162
+ }
163
+
164
+ $request = $this->generate_payment_request( $renewal_order, $prepared_source );
165
+ $request['capture'] = 'true';
166
+ $request['amount'] = WC_Stripe_Helper::get_stripe_amount( $amount, $request['currency'] );
167
+ $response = WC_Stripe_API::request( $request );
168
+
169
+ if ( ! empty( $response->error ) || is_wp_error( $response ) ) {
170
+ if ( $is_retry ) {
171
+ /* translators: error message */
172
+ $renewal_order->update_status( 'failed', sprintf( __( 'Stripe Transaction Failed (%s)', 'woocommerce-gateway-stripe' ), $response->error->message ) );
173
+ }
174
 
 
 
175
  return $response; // Default catch all errors.
176
  }
177
 
178
+ $this->process_response( $response, $renewal_order );
179
 
180
+ if ( ! $is_retry ) {
181
+ return $response;
182
+ }
183
  }
184
 
185
  /**
205
  }
206
 
207
  /**
208
+ * Scheduled_subscription_payment function.
209
  *
210
  * @param $amount_to_charge float The amount to charge.
211
  * @param $renewal_order WC_Order A WC_Order object created to record the renewal payment.
212
  */
213
  public function scheduled_subscription_payment( $amount_to_charge, $renewal_order ) {
214
+ $response = $this->process_subscription_payment( $amount_to_charge, $renewal_order );
215
 
216
  if ( is_wp_error( $response ) ) {
217
  /* translators: error message */
219
  }
220
 
221
  if ( ! empty( $response->error ) ) {
222
+ // This is a very generic error to listen for but worth a retry before total fail.
223
+ if ( isset( $response->error->type ) && 'invalid_request_error' === $response->error->type && apply_filters( 'wc_stripe_use_default_customer_source', true ) ) {
224
+ $this->process_subscription_payment( $amount_to_charge, $renewal_order, true );
225
+ } else {
226
+ /* translators: error message */
227
+ $renewal_order->update_status( 'failed', sprintf( __( 'Stripe Transaction Failed (%s)', 'woocommerce-gateway-stripe' ), $response->error->message ) );
228
+ }
229
  }
230
  }
231
 
242
 
243
  /**
244
  * Remove order meta
245
+ * @param object $order
246
  */
247
  public function remove_order_customer_before_retry( $order ) {
248
  $order_id = WC_Stripe_Helper::is_pre_30() ? $order->id : $order->get_id();
441
  throw new Exception( sprintf( __( 'Sorry, the minimum allowed order total is %1$s to use this payment method.', 'woocommerce-gateway-stripe' ), wc_price( WC_Stripe_Helper::get_minimum_amount() / 100 ) ) );
442
  }
443
 
444
+ $source = $this->prepare_source( $this->get_source_object(), get_current_user_id(), true );
445
 
446
  // We need a source on file to continue.
447
  if ( empty( $source->customer ) || empty( $source->source ) ) {
448
  throw new Exception( __( 'Unable to store payment details. Please try again.', 'woocommerce-gateway-stripe' ) );
449
  }
450
 
451
+ $this->save_source_to_order( $order, $source );
 
452
 
453
  // Remove cart
454
  WC()->cart->empty_cart();
includes/payment-methods/class-wc-gateway-stripe-alipay.php CHANGED
@@ -268,7 +268,7 @@ class WC_Gateway_Stripe_Alipay extends WC_Stripe_Payment_Gateway {
268
 
269
  WC_Stripe_Logger::log( 'Info: Begin creating Alipay source' );
270
 
271
- return WC_Stripe_API::request( $post_data, 'sources' );
272
  }
273
 
274
  /**
268
 
269
  WC_Stripe_Logger::log( 'Info: Begin creating Alipay source' );
270
 
271
+ return WC_Stripe_API::request( apply_filters( 'wc_stripe_alipay_source', $post_data, $order ), 'sources' );
272
  }
273
 
274
  /**
includes/payment-methods/class-wc-gateway-stripe-bancontact.php CHANGED
@@ -242,15 +242,16 @@ class WC_Gateway_Stripe_Bancontact extends WC_Stripe_Payment_Gateway {
242
  * @return mixed
243
  */
244
  public function create_source( $order ) {
245
- $currency = WC_Stripe_Helper::is_pre_30() ? $order->get_order_currency() : $order->get_currency();
246
- $order_id = WC_Stripe_Helper::is_pre_30() ? $order->id : $order->get_id();
247
- $return_url = $this->get_stripe_return_url( $order );
248
- $post_data = array();
249
- $post_data['amount'] = WC_Stripe_Helper::get_stripe_amount( $order->get_total(), $currency );
250
- $post_data['currency'] = strtolower( $currency );
251
- $post_data['type'] = 'bancontact';
252
- $post_data['owner'] = $this->get_owner_details( $order );
253
- $post_data['redirect'] = array( 'return_url' => $return_url );
 
254
 
255
  if ( ! empty( $this->statement_descriptor ) ) {
256
  $post_data['statement_descriptor'] = WC_Stripe_Helper::clean_statement_descriptor( $this->statement_descriptor );
@@ -258,7 +259,7 @@ class WC_Gateway_Stripe_Bancontact extends WC_Stripe_Payment_Gateway {
258
 
259
  WC_Stripe_Logger::log( 'Info: Begin creating Bancontact source' );
260
 
261
- return WC_Stripe_API::request( $post_data, 'sources' );
262
  }
263
 
264
  /**
242
  * @return mixed
243
  */
244
  public function create_source( $order ) {
245
+ $currency = WC_Stripe_Helper::is_pre_30() ? $order->get_order_currency() : $order->get_currency();
246
+ $order_id = WC_Stripe_Helper::is_pre_30() ? $order->id : $order->get_id();
247
+ $return_url = $this->get_stripe_return_url( $order );
248
+ $post_data = array();
249
+ $post_data['amount'] = WC_Stripe_Helper::get_stripe_amount( $order->get_total(), $currency );
250
+ $post_data['currency'] = strtolower( $currency );
251
+ $post_data['type'] = 'bancontact';
252
+ $post_data['owner'] = $this->get_owner_details( $order );
253
+ $post_data['redirect'] = array( 'return_url' => $return_url );
254
+ $post_data['bancontact'] = array( 'preferred_language' => substr( get_locale(), 0, 2 ) );
255
 
256
  if ( ! empty( $this->statement_descriptor ) ) {
257
  $post_data['statement_descriptor'] = WC_Stripe_Helper::clean_statement_descriptor( $this->statement_descriptor );
259
 
260
  WC_Stripe_Logger::log( 'Info: Begin creating Bancontact source' );
261
 
262
+ return WC_Stripe_API::request( apply_filters( 'wc_stripe_bancontact_source', $post_data, $order ), 'sources' );
263
  }
264
 
265
  /**
includes/payment-methods/class-wc-gateway-stripe-bitcoin.php CHANGED
@@ -135,6 +135,11 @@ class WC_Gateway_Stripe_Bitcoin extends WC_Stripe_Payment_Gateway {
135
  * @version 4.0.0
136
  */
137
  public function get_environment_warning() {
 
 
 
 
 
138
  if ( 'yes' === $this->enabled && ! in_array( get_woocommerce_currency(), $this->get_supported_currency() ) ) {
139
  $message = __( 'Bitcoin is enabled - it requires store currency to be set to USD.', 'woocommerce-gateway-stripe' );
140
 
@@ -363,21 +368,19 @@ class WC_Gateway_Stripe_Bitcoin extends WC_Stripe_Payment_Gateway {
363
  $new_stripe_customer->create_customer();
364
  }
365
 
366
- $prepared_source = $this->prepare_source( $this->create_source_object(), get_current_user_id(), $force_save_source );
367
 
368
  if ( empty( $prepared_source->source ) ) {
369
  $localized_message = __( 'Payment processing failed. Please retry.', 'woocommerce-gateway-stripe' );
370
  throw new WC_Stripe_Exception( print_r( $prepared_source, true ), $localized_message );
371
  }
372
 
373
- // Store source to order meta.
374
- $this->save_source( $order, $prepared_source );
375
-
376
 
377
  // This will throw exception if not valid.
378
  $this->validate_minimum_order_amount( $order );
379
 
380
- $this->save_instructions( $order, $this->create_source_object() );
381
 
382
  // Mark as on-hold (we're awaiting the payment)
383
  $order->update_status( 'on-hold', __( 'Awaiting Bitcoin payment', 'woocommerce-gateway-stripe' ) );
135
  * @version 4.0.0
136
  */
137
  public function get_environment_warning() {
138
+ // Add deprecated notice to logs.
139
+ if ( 'yes' === $this->enabled ) {
140
+ WC_Stripe_Logger::log( 'DEPRECATED! Stripe will no longer support Bitcoin and will cease to function on April 23, 2018. Please plan accordingly.' );
141
+ }
142
+
143
  if ( 'yes' === $this->enabled && ! in_array( get_woocommerce_currency(), $this->get_supported_currency() ) ) {
144
  $message = __( 'Bitcoin is enabled - it requires store currency to be set to USD.', 'woocommerce-gateway-stripe' );
145
 
368
  $new_stripe_customer->create_customer();
369
  }
370
 
371
+ $prepared_source = $this->prepare_source( $this->get_source_object(), get_current_user_id(), $force_save_source );
372
 
373
  if ( empty( $prepared_source->source ) ) {
374
  $localized_message = __( 'Payment processing failed. Please retry.', 'woocommerce-gateway-stripe' );
375
  throw new WC_Stripe_Exception( print_r( $prepared_source, true ), $localized_message );
376
  }
377
 
378
+ $this->save_source_to_order( $order, $prepared_source );
 
 
379
 
380
  // This will throw exception if not valid.
381
  $this->validate_minimum_order_amount( $order );
382
 
383
+ $this->save_instructions( $order, $this->get_source_object() );
384
 
385
  // Mark as on-hold (we're awaiting the payment)
386
  $order->update_status( 'on-hold', __( 'Awaiting Bitcoin payment', 'woocommerce-gateway-stripe' ) );
includes/payment-methods/class-wc-gateway-stripe-giropay.php CHANGED
@@ -258,7 +258,7 @@ class WC_Gateway_Stripe_Giropay extends WC_Stripe_Payment_Gateway {
258
 
259
  WC_Stripe_Logger::log( 'Info: Begin creating Giropay source' );
260
 
261
- return WC_Stripe_API::request( $post_data, 'sources' );
262
  }
263
 
264
  /**
258
 
259
  WC_Stripe_Logger::log( 'Info: Begin creating Giropay source' );
260
 
261
+ return WC_Stripe_API::request( apply_filters( 'wc_stripe_giropay_source', $post_data, $order ), 'sources' );
262
  }
263
 
264
  /**
includes/payment-methods/class-wc-gateway-stripe-ideal.php CHANGED
@@ -258,7 +258,7 @@ class WC_Gateway_Stripe_Ideal extends WC_Stripe_Payment_Gateway {
258
 
259
  WC_Stripe_Logger::log( 'Info: Begin creating iDeal source' );
260
 
261
- return WC_Stripe_API::request( $post_data, 'sources' );
262
  }
263
 
264
  /**
258
 
259
  WC_Stripe_Logger::log( 'Info: Begin creating iDeal source' );
260
 
261
+ return WC_Stripe_API::request( apply_filters( 'wc_stripe_ideal_source', $post_data, $order ), 'sources' );
262
  }
263
 
264
  /**
includes/payment-methods/class-wc-gateway-stripe-p24.php CHANGED
@@ -255,7 +255,7 @@ class WC_Gateway_Stripe_P24 extends WC_Stripe_Payment_Gateway {
255
 
256
  WC_Stripe_Logger::log( 'Info: Begin creating P24 source' );
257
 
258
- return WC_Stripe_API::request( $post_data, 'sources' );
259
  }
260
 
261
  /**
255
 
256
  WC_Stripe_Logger::log( 'Info: Begin creating P24 source' );
257
 
258
+ return WC_Stripe_API::request( apply_filters( 'wc_stripe_p24_source', $post_data, $order ), 'sources' );
259
  }
260
 
261
  /**
includes/payment-methods/class-wc-gateway-stripe-sepa.php CHANGED
@@ -241,15 +241,15 @@ class WC_Gateway_Stripe_Sepa extends WC_Stripe_Payment_Gateway {
241
  <fieldset id="wc-<?php echo esc_attr( $this->id ); ?>-form" class="wc-payment-form">
242
  <?php do_action( 'woocommerce_credit_card_form_start', $this->id ); ?>
243
  <p class="wc-stripe-sepa-mandate" style="margin-bottom:40px;"><?php $this->mandate_display(); ?></p>
244
- <p class="form-row form-row-wide validate-required">
245
  <label for="stripe-sepa-owner">
246
- <?php esc_html_e( 'IBAN Account Name.', 'woocommerce-gateway-stripe' ); ?>
247
  </label>
248
  <input id="stripe-sepa-owner" name="stripe_sepa_owner" value="" style="border:1px solid #ddd;margin:5px 0;padding:10px 5px;background-color:#fff;outline:0;" />
249
  </p>
250
- <p class="form-row form-row-wide validate-required">
251
  <label for="stripe-sepa-iban">
252
- <?php esc_html_e( 'IBAN Account Number.', 'woocommerce-gateway-stripe' ); ?>
253
  </label>
254
  <input id="stripe-sepa-iban" name="stripe_sepa_iban" value="" style="border:1px solid #ddd;margin:5px 0;padding:10px 5px;background-color:#fff;outline:0;" />
255
  </p>
@@ -333,10 +333,9 @@ class WC_Gateway_Stripe_Sepa extends WC_Stripe_Payment_Gateway {
333
  $new_stripe_customer->create_customer();
334
  }
335
 
336
- $prepared_source = $this->prepare_source( $this->create_source_object(), get_current_user_id(), $force_save_source );
337
 
338
- // Store source to order meta.
339
- $this->save_source( $order, $prepared_source );
340
 
341
  // Result from Stripe API request.
342
  $response = null;
@@ -365,7 +364,14 @@ class WC_Gateway_Stripe_Sepa extends WC_Stripe_Payment_Gateway {
365
 
366
  // Customer param wrong? The user may have been deleted on stripe's end. Remove customer_id. Can be retried without.
367
  if ( preg_match( '/No such customer/i', $response->error->message ) && $retry ) {
368
- delete_user_meta( WC_Stripe_Helper::is_pre_30() ? $order->customer_user : $order->get_customer_id(), '_stripe_customer_id' );
 
 
 
 
 
 
 
369
 
370
  return $this->process_payment( $order_id, false, $force_save_source );
371
  } elseif ( preg_match( '/No such token/i', $response->error->message ) && $prepared_source->token_id ) {
241
  <fieldset id="wc-<?php echo esc_attr( $this->id ); ?>-form" class="wc-payment-form">
242
  <?php do_action( 'woocommerce_credit_card_form_start', $this->id ); ?>
243
  <p class="wc-stripe-sepa-mandate" style="margin-bottom:40px;"><?php $this->mandate_display(); ?></p>
244
+ <p class="form-row form-row-wide">
245
  <label for="stripe-sepa-owner">
246
+ <?php esc_html_e( 'IBAN Account Name.', 'woocommerce-gateway-stripe' ); ?> <span class="required">*</span>
247
  </label>
248
  <input id="stripe-sepa-owner" name="stripe_sepa_owner" value="" style="border:1px solid #ddd;margin:5px 0;padding:10px 5px;background-color:#fff;outline:0;" />
249
  </p>
250
+ <p class="form-row form-row-wide">
251
  <label for="stripe-sepa-iban">
252
+ <?php esc_html_e( 'IBAN Account Number.', 'woocommerce-gateway-stripe' ); ?> <span class="required">*</span>
253
  </label>
254
  <input id="stripe-sepa-iban" name="stripe_sepa_iban" value="" style="border:1px solid #ddd;margin:5px 0;padding:10px 5px;background-color:#fff;outline:0;" />
255
  </p>
333
  $new_stripe_customer->create_customer();
334
  }
335
 
336
+ $prepared_source = $this->prepare_source( $this->get_source_object(), get_current_user_id(), $force_save_source );
337
 
338
+ $this->save_source_to_order( $order, $prepared_source );
 
339
 
340
  // Result from Stripe API request.
341
  $response = null;
364
 
365
  // Customer param wrong? The user may have been deleted on stripe's end. Remove customer_id. Can be retried without.
366
  if ( preg_match( '/No such customer/i', $response->error->message ) && $retry ) {
367
+ if ( WC_Stripe_Helper::is_pre_30() ) {
368
+ delete_user_meta( $order->customer_user, '_stripe_customer_id' );
369
+ delete_post_meta( $order_id, '_stripe_customer_id' );
370
+ } else {
371
+ delete_user_meta( $order->get_customer_id(), '_stripe_customer_id' );
372
+ $order->delete_meta_data( '_stripe_customer_id' );
373
+ $order->save();
374
+ }
375
 
376
  return $this->process_payment( $order_id, false, $force_save_source );
377
  } elseif ( preg_match( '/No such token/i', $response->error->message ) && $prepared_source->token_id ) {
includes/payment-methods/class-wc-gateway-stripe-sofort.php CHANGED
@@ -251,7 +251,10 @@ class WC_Gateway_Stripe_Sofort extends WC_Stripe_Payment_Gateway {
251
  $post_data['type'] = 'sofort';
252
  $post_data['owner'] = $this->get_owner_details( $order );
253
  $post_data['redirect'] = array( 'return_url' => $return_url );
254
- $post_data['sofort'] = array( 'country' => $bank_country );
 
 
 
255
 
256
  if ( ! empty( $this->statement_descriptor ) ) {
257
  $post_data['statement_descriptor'] = WC_Stripe_Helper::clean_statement_descriptor( $this->statement_descriptor );
@@ -259,7 +262,7 @@ class WC_Gateway_Stripe_Sofort extends WC_Stripe_Payment_Gateway {
259
 
260
  WC_Stripe_Logger::log( 'Info: Begin creating SOFORT source' );
261
 
262
- return WC_Stripe_API::request( $post_data, 'sources' );
263
  }
264
 
265
  /**
@@ -294,7 +297,15 @@ class WC_Gateway_Stripe_Sofort extends WC_Stripe_Payment_Gateway {
294
  if ( ! empty( $response->error ) ) {
295
  $order->add_order_note( $response->error->message );
296
 
297
- throw new WC_Stripe_Exception( print_r( $response, true ), $response->error->message );
 
 
 
 
 
 
 
 
298
  }
299
 
300
  if ( WC_Stripe_Helper::is_pre_30() ) {
251
  $post_data['type'] = 'sofort';
252
  $post_data['owner'] = $this->get_owner_details( $order );
253
  $post_data['redirect'] = array( 'return_url' => $return_url );
254
+ $post_data['sofort'] = array(
255
+ 'country' => $bank_country,
256
+ 'preferred_language' => substr( get_locale(), 0, 2 ),
257
+ );
258
 
259
  if ( ! empty( $this->statement_descriptor ) ) {
260
  $post_data['statement_descriptor'] = WC_Stripe_Helper::clean_statement_descriptor( $this->statement_descriptor );
262
 
263
  WC_Stripe_Logger::log( 'Info: Begin creating SOFORT source' );
264
 
265
+ return WC_Stripe_API::request( apply_filters( 'wc_stripe_sofort_source', $post_data, $order ), 'sources' );
266
  }
267
 
268
  /**
297
  if ( ! empty( $response->error ) ) {
298
  $order->add_order_note( $response->error->message );
299
 
300
+ $localized_messages = WC_Stripe_Helper::get_localized_messages();
301
+
302
+ if ( 'invalid_sofort_country' === $response->error->code ) {
303
+ $localized_message = isset( $localized_messages[ $response->error->code ] ) ? $localized_messages[ $response->error->code ] : $response->error->message;
304
+ } else {
305
+ $localized_message = isset( $localized_messages[ $response->error->type ] ) ? $localized_messages[ $response->error->type ] : $response->error->message;
306
+ }
307
+
308
+ throw new WC_Stripe_Exception( print_r( $response, true ), $localized_message );
309
  }
310
 
311
  if ( WC_Stripe_Helper::is_pre_30() ) {
includes/payment-methods/class-wc-stripe-payment-request.php CHANGED
@@ -88,18 +88,38 @@ class WC_Stripe_Payment_Request {
88
  return;
89
  }
90
 
 
91
  $this->init();
92
  }
93
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
94
  /**
95
  * Initialize hooks.
96
  *
97
  * @since 4.0.0
98
  * @version 4.0.0
99
  */
100
- protected function init() {
101
  add_action( 'wp_enqueue_scripts', array( $this, 'scripts' ) );
102
- add_action( 'wp', array( $this, 'set_session' ) );
103
 
104
  /*
105
  * In order to display the Payment Request button in the correct position,
@@ -117,10 +137,8 @@ class WC_Stripe_Payment_Request {
117
  add_action( 'woocommerce_proceed_to_checkout', array( $this, 'display_payment_request_button_html' ), 1 );
118
  add_action( 'woocommerce_proceed_to_checkout', array( $this, 'display_payment_request_button_separator_html' ), 2 );
119
 
120
- if ( apply_filters( 'wc_stripe_show_payment_request_on_checkout', false ) ) {
121
- add_action( 'woocommerce_checkout_before_customer_details', array( $this, 'display_payment_request_button_html' ), 1 );
122
- add_action( 'woocommerce_checkout_before_customer_details', array( $this, 'display_payment_request_button_separator_html' ), 2 );
123
- }
124
 
125
  add_action( 'wc_ajax_wc_stripe_get_cart_details', array( $this, 'ajax_get_cart_details' ) );
126
  add_action( 'wc_ajax_wc_stripe_get_shipping_options', array( $this, 'ajax_get_shipping_options' ) );
@@ -134,23 +152,7 @@ class WC_Stripe_Payment_Request {
134
  add_filter( 'woocommerce_gateway_title', array( $this, 'filter_gateway_title' ), 10, 2 );
135
  add_filter( 'woocommerce_validate_postcode', array( $this, 'postal_code_validation' ), 10, 3 );
136
 
137
- add_action( 'woocommerce_checkout_order_processed', array( $this, 'add_order_meta' ), 10, 3 );
138
- }
139
-
140
- /**
141
- * Sets the WC customer session if one is not set.
142
- * This is needed so nonces can be verified.
143
- *
144
- * @since 4.0.0
145
- */
146
- public function set_session() {
147
- if ( ! is_user_logged_in() ) {
148
- $wc_session = new WC_Session_Handler();
149
-
150
- if ( ! $wc_session->has_session() ) {
151
- $wc_session->set_customer_session_cookie( true );
152
- }
153
- }
154
  }
155
 
156
  /**
@@ -234,7 +236,7 @@ class WC_Stripe_Payment_Request {
234
 
235
  $data['displayItems'] = $items;
236
  $data['total'] = array(
237
- 'label' => $this->total_label,
238
  'amount' => WC_Stripe_Helper::get_stripe_amount( WC_Stripe_Helper::is_pre_30() ? $product->price : $product->get_price() ),
239
  'pending' => true,
240
  );
@@ -243,7 +245,7 @@ class WC_Stripe_Payment_Request {
243
  $data['currency'] = strtolower( get_woocommerce_currency() );
244
  $data['country_code'] = substr( get_option( 'woocommerce_default_country' ), 0, 2 );
245
 
246
- return $data;
247
  }
248
 
249
  /**
@@ -288,6 +290,12 @@ class WC_Stripe_Payment_Request {
288
  return $valid;
289
  }
290
 
 
 
 
 
 
 
291
  /**
292
  * Currently Apple Pay truncates postal codes from UK and Canada to first 3 characters
293
  * when passing it back from the shippingcontactselected object. This causes WC to invalidate
@@ -308,13 +316,14 @@ class WC_Stripe_Payment_Request {
308
  * @version 4.0.0
309
  * @param int $order_id
310
  * @param array $posted_data The posted data from checkout form.
311
- * @param object $order
312
  */
313
- public function add_order_meta( $order_id, $posted_data, $order ) {
314
  if ( empty( $_POST['payment_request_type'] ) ) {
315
  return;
316
  }
317
 
 
 
318
  $payment_request_type = wc_clean( $_POST['payment_request_type'] );
319
 
320
  if ( 'apple_pay' === $payment_request_type ) {
@@ -470,6 +479,10 @@ class WC_Stripe_Payment_Request {
470
  return;
471
  }
472
 
 
 
 
 
473
  if ( is_product() ) {
474
  global $post;
475
 
@@ -520,6 +533,10 @@ class WC_Stripe_Payment_Request {
520
  return;
521
  }
522
 
 
 
 
 
523
  if ( is_product() ) {
524
  global $post;
525
 
88
  return;
89
  }
90
 
91
+ add_action( 'woocommerce_init', array( $this, 'set_session' ) );
92
  $this->init();
93
  }
94
 
95
+ /**
96
+ * Sets the WC customer session if one is not set.
97
+ * This is needed so nonces can be verified by AJAX Request.
98
+ *
99
+ * @since 4.0.0
100
+ */
101
+ public function set_session() {
102
+ if ( ! is_user_logged_in() ) {
103
+ $wc_session = new WC_Session_Handler();
104
+
105
+ if ( version_compare( WC_VERSION, '3.3', '>=' ) ) {
106
+ $wc_session->init();
107
+ }
108
+
109
+ if ( ! $wc_session->has_session() ) {
110
+ $wc_session->set_customer_session_cookie( true );
111
+ }
112
+ }
113
+ }
114
+
115
  /**
116
  * Initialize hooks.
117
  *
118
  * @since 4.0.0
119
  * @version 4.0.0
120
  */
121
+ public function init() {
122
  add_action( 'wp_enqueue_scripts', array( $this, 'scripts' ) );
 
123
 
124
  /*
125
  * In order to display the Payment Request button in the correct position,
137
  add_action( 'woocommerce_proceed_to_checkout', array( $this, 'display_payment_request_button_html' ), 1 );
138
  add_action( 'woocommerce_proceed_to_checkout', array( $this, 'display_payment_request_button_separator_html' ), 2 );
139
 
140
+ add_action( 'woocommerce_checkout_before_customer_details', array( $this, 'display_payment_request_button_html' ), 1 );
141
+ add_action( 'woocommerce_checkout_before_customer_details', array( $this, 'display_payment_request_button_separator_html' ), 2 );
 
 
142
 
143
  add_action( 'wc_ajax_wc_stripe_get_cart_details', array( $this, 'ajax_get_cart_details' ) );
144
  add_action( 'wc_ajax_wc_stripe_get_shipping_options', array( $this, 'ajax_get_shipping_options' ) );
152
  add_filter( 'woocommerce_gateway_title', array( $this, 'filter_gateway_title' ), 10, 2 );
153
  add_filter( 'woocommerce_validate_postcode', array( $this, 'postal_code_validation' ), 10, 3 );
154
 
155
+ add_action( 'woocommerce_checkout_order_processed', array( $this, 'add_order_meta' ), 10, 2 );
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
156
  }
157
 
158
  /**
236
 
237
  $data['displayItems'] = $items;
238
  $data['total'] = array(
239
+ 'label' => apply_filters( 'wc_stripe_payment_request_total_label', $this->total_label ),
240
  'amount' => WC_Stripe_Helper::get_stripe_amount( WC_Stripe_Helper::is_pre_30() ? $product->price : $product->get_price() ),
241
  'pending' => true,
242
  );
245
  $data['currency'] = strtolower( get_woocommerce_currency() );
246
  $data['country_code'] = substr( get_option( 'woocommerce_default_country' ), 0, 2 );
247
 
248
+ return apply_filters( 'wc_stripe_payment_request_product_data', $data, $product );
249
  }
250
 
251
  /**
290
  return $valid;
291
  }
292
 
293
+ $payment_request_type = isset( $_POST['payment_request_type'] ) ? wc_clean( $_POST['payment_request_type'] ) : '';
294
+
295
+ if ( 'apple_pay' !== $payment_request_type ) {
296
+ return $valid;
297
+ }
298
+
299
  /**
300
  * Currently Apple Pay truncates postal codes from UK and Canada to first 3 characters
301
  * when passing it back from the shippingcontactselected object. This causes WC to invalidate
316
  * @version 4.0.0
317
  * @param int $order_id
318
  * @param array $posted_data The posted data from checkout form.
 
319
  */
320
+ public function add_order_meta( $order_id, $posted_data ) {
321
  if ( empty( $_POST['payment_request_type'] ) ) {
322
  return;
323
  }
324
 
325
+ $order = wc_get_order( $order_id );
326
+
327
  $payment_request_type = wc_clean( $_POST['payment_request_type'] );
328
 
329
  if ( 'apple_pay' === $payment_request_type ) {
479
  return;
480
  }
481
 
482
+ if ( is_checkout() && ! apply_filters( 'wc_stripe_show_payment_request_on_checkout', false ) ) {
483
+ return;
484
+ }
485
+
486
  if ( is_product() ) {
487
  global $post;
488
 
533
  return;
534
  }
535
 
536
+ if ( is_checkout() && ! apply_filters( 'wc_stripe_show_payment_request_on_checkout', false ) ) {
537
+ return;
538
+ }
539
+
540
  if ( is_product() ) {
541
  global $post;
542
 
readme.txt CHANGED
@@ -4,7 +4,7 @@ Tags: credit card, stripe, apple pay, payment request, google pay, sepa, sofort,
4
  Requires at least: 4.4
5
  Tested up to: 4.9
6
  Requires PHP: 5.6
7
- Stable tag: 4.0.3
8
  License: GPLv3
9
  License URI: https://www.gnu.org/licenses/gpl-3.0.html
10
  Attributions: thorsten-stripe
@@ -101,9 +101,27 @@ If you get stuck, you can ask for help in the Plugin Forum.
101
 
102
  == Changelog ==
103
 
104
- = 4.0.3 - 2018-01-18 =
105
- * Fix - Pass Stripe source as id instead of object as some sites may conflict with objects being passed.
106
- * Fix - For Payment Request Button, if test keys are not filled, it can cause live mode not to function.
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
107
 
108
  [See changelog for all versions](https://raw.githubusercontent.com/woothemes/woocommerce-gateway-stripe/master/changelog.txt).
109
 
4
  Requires at least: 4.4
5
  Tested up to: 4.9
6
  Requires PHP: 5.6
7
+ Stable tag: 4.0.4
8
  License: GPLv3
9
  License URI: https://www.gnu.org/licenses/gpl-3.0.html
10
  Attributions: thorsten-stripe
101
 
102
  == Changelog ==
103
 
104
+ = 4.0.4 - 2018-01-30 =
105
+ * Add - SEPA mandate notification email.
106
+ * Add - Preferred language to SOFORT and Bancontact so it can be localized.
107
+ * Add - Hook to change SEPA mandate notification to none "wc_stripe_sepa_mandate_notification".
108
+ * Add - Hook to change data for product when using Payment Request Button "wc_stripe_payment_request_product_data".
109
+ * Add - Hook to change the behavior of allowing subscriptions to charge a customer's default source "'wc_stripe_use_default_customer_source'".
110
+ * Add - Hook to source object "wc_stripe_sofort_source", "wc_stripe_p24_source", "wc_stripe_ideal_source", "wc_stripe_giropay_source", "wc_stripe_bancontact_source", "wc_stripe_alipay_source", "wc_stripe_3ds_source".
111
+ * Add - Hook to change payment request button total label "wc_stripe_payment_request_total_label".
112
+ * Add - Hook to change locale of Stripe Checkout "wc_stripe_checkout_locale".
113
+ * Add - Hook to change elements options "wc_stripe_elements_options".
114
+ * Fix - When checkout form produces an error on mobile, sometimes the blocking mask is not release blocking new input.
115
+ * Fix - On older subscription payments, the ending card number is not shown on the subscriptions table in my account.
116
+ * Fix - Filter to show payment request button on checkout page not working.
117
+ * Fix - WC session handling compatibility with WC 3.3.
118
+ * Fix - BW compatibility with WC 2.6.x on add_order_meta to prevent errors.
119
+ * Fix - Possible fix for duplicate charges due to webhook and redirect handler firing at the same time by adding delay to the webhook process.
120
+ * Tweak - In a subscription billing, Stripe source ID is no longer a required field.
121
+ * Tweak - On a subscription order renewal-- if source is empty, will now try to charge the default source.
122
+ * Notice - Bitcoin has been soft deprecated and Stripe will no longer support it on April 23, 2018. Please plan accordingly.
123
+ * Remove - Stripe Checkout Locale setting in favor of using store set locale.
124
+ * Update - Stripe API version to 2018-01-23.
125
 
126
  [See changelog for all versions](https://raw.githubusercontent.com/woothemes/woocommerce-gateway-stripe/master/changelog.txt).
127
 
woocommerce-gateway-stripe.php CHANGED
@@ -5,7 +5,7 @@
5
  * Description: Take credit card payments on your store using Stripe.
6
  * Author: WooCommerce
7
  * Author URI: https://woocommerce.com/
8
- * Version: 4.0.3
9
  * Requires at least: 4.4
10
  * Tested up to: 4.9
11
  * WC requires at least: 2.6
@@ -22,7 +22,7 @@ if ( ! class_exists( 'WC_Stripe' ) ) :
22
  /**
23
  * Required minimums and constants
24
  */
25
- define( 'WC_STRIPE_VERSION', '4.0.3' );
26
  define( 'WC_STRIPE_MIN_PHP_VER', '5.6.0' );
27
  define( 'WC_STRIPE_MIN_WC_VER', '2.6.0' );
28
  define( 'WC_STRIPE_MAIN_FILE', __FILE__ );
@@ -272,6 +272,11 @@ if ( ! class_exists( 'WC_Stripe' ) ) :
272
  $show_ssl_notice = get_option( 'wc_stripe_show_ssl_notice' );
273
  $show_keys_notice = get_option( 'wc_stripe_show_keys_notice' );
274
  $options = get_option( 'woocommerce_stripe_settings' );
 
 
 
 
 
275
 
276
  if ( isset( $options['enabled'] ) && 'yes' === $options['enabled'] && empty( $show_keys_notice ) ) {
277
  $secret = WC_Stripe_API::get_secret_key();
@@ -281,6 +286,27 @@ if ( ! class_exists( 'WC_Stripe' ) ) :
281
  /* translators: 1) link */
282
  $this->add_admin_notice( 'keys', 'notice notice-warning', sprintf( __( 'Stripe is almost ready. To get started, <a href="%s">set your Stripe account keys</a>.', 'woocommerce-gateway-stripe' ), $setting_link ), true );
283
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
284
  }
285
 
286
  if ( empty( $show_ssl_notice ) && isset( $options['enabled'] ) && 'yes' === $options['enabled'] ) {
5
  * Description: Take credit card payments on your store using Stripe.
6
  * Author: WooCommerce
7
  * Author URI: https://woocommerce.com/
8
+ * Version: 4.0.4
9
  * Requires at least: 4.4
10
  * Tested up to: 4.9
11
  * WC requires at least: 2.6
22
  /**
23
  * Required minimums and constants
24
  */
25
+ define( 'WC_STRIPE_VERSION', '4.0.4' );
26
  define( 'WC_STRIPE_MIN_PHP_VER', '5.6.0' );
27
  define( 'WC_STRIPE_MIN_WC_VER', '2.6.0' );
28
  define( 'WC_STRIPE_MAIN_FILE', __FILE__ );
272
  $show_ssl_notice = get_option( 'wc_stripe_show_ssl_notice' );
273
  $show_keys_notice = get_option( 'wc_stripe_show_keys_notice' );
274
  $options = get_option( 'woocommerce_stripe_settings' );
275
+ $testmode = ( isset( $options['testmode'] ) && 'yes' === $options['testmode'] ) ? true : false;
276
+ $test_pub_key = isset( $options['test_publishable_key'] ) ? $options['test_publishable_key'] : '';
277
+ $test_secret_key = isset( $options['test_secret_key'] ) ? $options['test_secret_key'] : '';
278
+ $live_pub_key = isset( $options['publishable_key'] ) ? $options['publishable_key'] : '';
279
+ $live_secret_key = isset( $options['secret_key'] ) ? $options['secret_key'] : '';
280
 
281
  if ( isset( $options['enabled'] ) && 'yes' === $options['enabled'] && empty( $show_keys_notice ) ) {
282
  $secret = WC_Stripe_API::get_secret_key();
286
  /* translators: 1) link */
287
  $this->add_admin_notice( 'keys', 'notice notice-warning', sprintf( __( 'Stripe is almost ready. To get started, <a href="%s">set your Stripe account keys</a>.', 'woocommerce-gateway-stripe' ), $setting_link ), true );
288
  }
289
+
290
+ // Check if keys are entered properly per live/test mode.
291
+ if ( $testmode ) {
292
+ if (
293
+ ! empty( $test_pub_key ) && ! preg_match( '/^pk_test_/', $test_pub_key )
294
+ || ! empty( $test_secret_key ) && ! preg_match( '/^sk_test_/', $test_secret_key ) )
295
+ {
296
+ $setting_link = $this->get_setting_link();
297
+ /* translators: 1) link */
298
+ $this->add_admin_notice( 'keys', 'notice notice-error', sprintf( __( 'Stripe is in test mode however your test keys may not be valid. Test keys start with pk_test and sk_test. Please go to your settings and, <a href="%s">set your Stripe account keys</a>.', 'woocommerce-gateway-stripe' ), $setting_link ), true );
299
+ }
300
+ } else {
301
+ if (
302
+ ! empty( $live_pub_key ) && ! preg_match( '/^pk_live_/', $live_pub_key )
303
+ || ! empty( $live_secret_key ) && ! preg_match( '/^sk_live_/', $live_secret_key ) )
304
+ {
305
+ $setting_link = $this->get_setting_link();
306
+ /* translators: 1) link */
307
+ $this->add_admin_notice( 'keys', 'notice notice-error', sprintf( __( 'Stripe is in live mode however your test keys may not be valid. Live keys start with pk_live and sk_live. Please go to your settings and, <a href="%s">set your Stripe account keys</a>.', 'woocommerce-gateway-stripe' ), $setting_link ), true );
308
+ }
309
+ }
310
  }
311
 
312
  if ( empty( $show_ssl_notice ) && isset( $options['enabled'] ) && 'yes' === $options['enabled'] ) {