WooCommerce Stripe Payment Gateway - Version 4.0.6

Version Description

  • 2018-02-20 =
  • Fix - A WC 2.6 backwards compat issue with function from WC 3.0.
  • Fix - Subs renewal sometimes failed due to parameters being different.
  • Fix - Stripe accepts only NO for Norwegian language on Stripe Checkout.
  • Fix - Refund fees may not accurately reflect net fees. Props @rvola.
  • Fix - Undefined SERVERNAME property in some cases.
  • Fix - Potential issue when a charge parameter changes due to initial failed request causing retries to fail.
  • Fix - When 3DS is not required, failed payments was not change order status to failed.
  • Fix - Potential duplicate order processes on WC side when webhook and redirect has a race condition.
  • Remove - Checkout validation and let WC handle it.
  • Update - Stripe API version to 2018-02-06.
  • Add - Webhooks for review open/closed for Radar.
  • Add - Hook wc_stripe_refund_request for refund request arguments.
  • Add - Hook wc_stripe_validate_modal_checkout to enable 3rd party checkout validation.
  • Add - Hook wc_stripe_validate_modal_checkout_action to enable 3rd party checkout validation.

See changelog for all versions.

=

Download this release

Release Info

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

Code changes from version 4.0.5 to 4.0.6

assets/js/stripe.js CHANGED
@@ -6,8 +6,8 @@ jQuery( function( $ ) {
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;
@@ -29,12 +29,114 @@ jQuery( function( $ ) {
29
  .replace( '%%endpoint%%', 'wc_stripe_' + endpoint );
30
  },
31
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
32
  /**
33
  * Initialize event handlers and UI state.
34
  */
35
  init: function() {
36
  // Initialize tokenization script if on change payment method page and pay for order page.
37
- if ( 'yes' === wc_stripe_params.is_change_payment_page ) {
38
  $( document.body ).trigger( 'wc-credit-card-form-init' );
39
  }
40
 
@@ -57,7 +159,7 @@ jQuery( function( $ ) {
57
  this.form = $( 'form#order_review' );
58
  }
59
 
60
- $( 'form#order_review' )
61
  .on(
62
  'submit',
63
  this.onSubmit
@@ -68,16 +170,9 @@ jQuery( function( $ ) {
68
  this.form = $( 'form#add_payment_method' );
69
  }
70
 
71
- $( 'form#add_payment_method' )
72
- .on(
73
- 'submit',
74
- this.onSubmit
75
- );
76
-
77
  $( 'form.woocommerce-checkout' )
78
  .on(
79
  'change',
80
- '#stripe-bank-country',
81
  this.reset
82
  );
83
 
@@ -91,101 +186,8 @@ jQuery( function( $ ) {
91
  this.reset
92
  );
93
 
94
- var elementStyles = {
95
- base: {
96
- iconColor: '#666EE8',
97
- color: '#31325F',
98
- fontSize: '15px',
99
- '::placeholder': {
100
- color: '#CFD7E0',
101
- }
102
- }
103
- };
104
-
105
- var elementClasses = {
106
- focus: 'focused',
107
- empty: 'empty',
108
- invalid: 'invalid',
109
- };
110
-
111
- if ( 'yes' === wc_stripe_params.use_elements && $( '#stripe-card-element' ).length ) {
112
- elementStyles = wc_stripe_params.elements_styling ? wc_stripe_params.elements_styling : elementStyles;
113
- elementClasses = wc_stripe_params.elements_classes ? wc_stripe_params.elements_classes : elementClasses;
114
-
115
- if ( 'yes' === wc_stripe_params.inline_cc_form ) {
116
- stripe_card = elements.create( 'card', { style: elementStyles, hidePostalCode: true } );
117
-
118
- stripe_card.addEventListener( 'change', function( event ) {
119
- wc_stripe_form.onCCFormChange();
120
-
121
- if ( event.error ) {
122
- $( document.body ).trigger( 'stripeError', event );
123
- }
124
- } );
125
- } else {
126
- stripe_card = elements.create( 'cardNumber', { style: elementStyles, classes: elementClasses } );
127
- stripe_exp = elements.create( 'cardExpiry', { style: elementStyles, classes: elementClasses } );
128
- stripe_cvc = elements.create( 'cardCvc', { style: elementStyles, classes: elementClasses } );
129
-
130
- stripe_card.addEventListener( 'change', function( event ) {
131
- wc_stripe_form.onCCFormChange();
132
-
133
- if ( event.error ) {
134
- $( document.body ).trigger( 'stripeError', event );
135
- }
136
- } );
137
-
138
- stripe_exp.addEventListener( 'change', function( event ) {
139
- wc_stripe_form.onCCFormChange();
140
-
141
- if ( event.error ) {
142
- $( document.body ).trigger( 'stripeError', event );
143
- }
144
- } );
145
-
146
- stripe_cvc.addEventListener( 'change', function( event ) {
147
- wc_stripe_form.onCCFormChange();
148
-
149
- if ( event.error ) {
150
- $( document.body ).trigger( 'stripeError', event );
151
- }
152
- } );
153
- }
154
-
155
- /**
156
- * Only in checkout page we need to delay the mounting of the
157
- * card as some AJAX process needs to happen before we do.
158
- */
159
- if ( wc_stripe_params.is_checkout ) {
160
- $( document.body ).on( 'updated_checkout', function() {
161
- // Don't mount elements a second time.
162
- if ( stripe_card ) {
163
- if ( 'yes' === wc_stripe_params.inline_cc_form ) {
164
- stripe_card.unmount( '#stripe-card-element' );
165
- } else {
166
- stripe_card.unmount( '#stripe-card-element' );
167
- stripe_exp.unmount( '#stripe-exp-element' );
168
- stripe_cvc.unmount( '#stripe-cvc-element' );
169
- }
170
- }
171
-
172
- if ( 'yes' === wc_stripe_params.inline_cc_form ) {
173
- stripe_card.mount( '#stripe-card-element' );
174
- } else {
175
- stripe_card.mount( '#stripe-card-element' );
176
- stripe_exp.mount( '#stripe-exp-element' );
177
- stripe_cvc.mount( '#stripe-cvc-element' );
178
- }
179
- });
180
- } else if ( $( 'form#add_payment_method' ).length || $( 'form#order_review' ).length ) {
181
- if ( 'yes' === wc_stripe_params.inline_cc_form ) {
182
- stripe_card.mount( '#stripe-card-element' );
183
- } else {
184
- stripe_card.mount( '#stripe-card-element' );
185
- stripe_exp.mount( '#stripe-exp-element' );
186
- stripe_cvc.mount( '#stripe-cvc-element' );
187
- }
188
- }
189
  }
190
  },
191
 
@@ -272,15 +274,7 @@ jQuery( function( $ ) {
272
  },
273
 
274
  block: function() {
275
- if ( wc_stripe_form.isMobile() ) {
276
- $.blockUI({
277
- message: null,
278
- overlayCSS: {
279
- background: '#fff',
280
- opacity: 0.6
281
- }
282
- });
283
- } else {
284
  wc_stripe_form.form.block({
285
  message: null,
286
  overlayCSS: {
@@ -292,11 +286,7 @@ jQuery( function( $ ) {
292
  },
293
 
294
  unblock: function() {
295
- if ( wc_stripe_form.isMobile() ) {
296
- $.unblockUI();
297
- } else {
298
- wc_stripe_form.form.unblock();
299
- }
300
  },
301
 
302
  getSelectedPaymentElement: function() {
@@ -357,45 +347,6 @@ jQuery( function( $ ) {
357
  wc_stripe_form.unblock();
358
  },
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 ||
371
- 'api_error' === result.error.type ||
372
- 'authentication_error' === result.error.type ||
373
- 'rate_limit_error' === result.error.type
374
- ) {
375
- message = wc_stripe_params.invalid_request_error;
376
- }
377
-
378
- if ( 'card_error' === result.error.type && wc_stripe_params.hasOwnProperty( result.error.code ) ) {
379
- message = wc_stripe_params[ result.error.code ];
380
- }
381
-
382
- if ( 'validation_error' === result.error.type && wc_stripe_params.hasOwnProperty( result.error.code ) ) {
383
- message = wc_stripe_params[ result.error.code ];
384
- }
385
-
386
- wc_stripe_form.reset();
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
-
399
  getOwnerDetails: function() {
400
  var first_name = $( '#billing_first_name' ).length ? $( '#billing_first_name' ).val() : wc_stripe_params.billing_first_name,
401
  last_name = $( '#billing_last_name' ).length ? $( '#billing_last_name' ).val() : wc_stripe_params.billing_last_name,
@@ -630,10 +581,10 @@ jQuery( function( $ ) {
630
  // Stripe Checkout.
631
  if ( 'yes' === wc_stripe_params.is_stripe_checkout && wc_stripe_form.isStripeModalNeeded() && wc_stripe_form.isStripeCardChosen() ) {
632
  // Since in mobile actions cannot be deferred, no dynamic validation applied.
633
- if ( wc_stripe_form.isMobile() ) {
634
  wc_stripe_form.openModal();
635
  } else {
636
- wc_stripe_form.validateCheckout( 'modal' );
637
  }
638
 
639
  return false;
@@ -680,10 +631,6 @@ jQuery( function( $ ) {
680
  this.onSubmit
681
  );
682
 
683
- if ( wc_stripe_form.isMobile() ) {
684
- wc_stripe_form.unblock();
685
- }
686
-
687
  wc_stripe_form.form.submit();
688
  }
689
 
@@ -694,10 +641,6 @@ jQuery( function( $ ) {
694
  this.onSubmit
695
  );
696
 
697
- if ( wc_stripe_form.isMobile() ) {
698
- wc_stripe_form.unblock();
699
- }
700
-
701
  return true;
702
  }
703
 
@@ -708,20 +651,11 @@ jQuery( function( $ ) {
708
  this.onSubmit
709
  );
710
 
711
- if ( wc_stripe_form.isMobile() ) {
712
- wc_stripe_form.unblock();
713
- }
714
-
715
  wc_stripe_form.form.submit();
716
  }
717
  }
718
 
719
- // We don't need to run validate on non checkout pages.
720
- if ( wc_stripe_params.is_checkout ) {
721
- wc_stripe_form.validateCheckout();
722
- } else {
723
- wc_stripe_form.createSource();
724
- }
725
 
726
  // Prevent form submitting
727
  return false;
@@ -753,7 +687,7 @@ jQuery( function( $ ) {
753
  },
754
 
755
  reset: function() {
756
- $( '.wc-stripe-error, .stripe-source, .stripe_token, .stripe-checkout-object' ).remove();
757
 
758
  // Stripe Checkout.
759
  if ( 'yes' === wc_stripe_params.is_stripe_checkout ) {
@@ -762,56 +696,70 @@ jQuery( function( $ ) {
762
  },
763
 
764
  getRequiredFields: function() {
765
- return wc_stripe_form.form.find( '.form-row.validate-required > input, .form-row.validate-required > select, .form-row.validate-required > textarea' );
766
  },
767
 
768
- validateCheckout: function( type ) {
769
- if ( typeof type === 'undefined' ) {
770
- type = '';
771
- }
772
-
773
  var data = {
774
  'nonce': wc_stripe_params.stripe_nonce,
775
  'required_fields': wc_stripe_form.getRequiredFields().serialize(),
776
- 'all_fields': wc_stripe_form.form.serialize(),
777
- 'source_type': wc_stripe_form.getSelectedPaymentElement().val(),
778
- 'is_add_payment_page': wc_stripe_params.is_add_payment_method_page
779
  };
780
 
781
- $.ajax({
782
  type: 'POST',
783
  url: wc_stripe_form.getAjaxURL( 'validate_checkout' ),
784
  data: data,
785
  dataType: 'json',
786
  success: function( result ) {
787
  if ( 'success' === result ) {
788
- // Stripe Checkout.
789
- if ( 'modal' === type ) {
790
- wc_stripe_form.openModal();
791
- } else {
792
- if ( wc_stripe_form.isSepaChosen() ) {
793
- // Check if SEPA owner is filled before proceed.
794
- if ( '' === $( '#stripe-sepa-owner' ).val() ) {
795
- $( document.body ).trigger( 'stripeError', { error: { message: wc_stripe_params.no_sepa_owner_msg } } );
796
- return false;
797
- }
798
-
799
- // Check if SEPA IBAN is filled before proceed.
800
- if ( '' === $( '#stripe-sepa-iban' ).val() ) {
801
- $( document.body ).trigger( 'stripeError', { error: { message: wc_stripe_params.no_sepa_iban_msg } } );
802
- return false;
803
- }
804
- }
805
-
806
- wc_stripe_form.createSource();
807
- }
808
  } else if ( result.messages ) {
809
  wc_stripe_form.resetModal();
810
  wc_stripe_form.reset();
811
  wc_stripe_form.submitError( result.messages );
812
  }
813
  }
814
- });
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
815
  },
816
 
817
  submitError: function( error_message ) {
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
+ elements = stripe.elements( stripe_elements_options ),
11
  stripe_card,
12
  stripe_exp,
13
  stripe_cvc;
29
  .replace( '%%endpoint%%', 'wc_stripe_' + endpoint );
30
  },
31
 
32
+ unmountElements: function() {
33
+ if ( 'yes' === wc_stripe_params.inline_cc_form ) {
34
+ stripe_card.unmount( '#stripe-card-element' );
35
+ } else {
36
+ stripe_card.unmount( '#stripe-card-element' );
37
+ stripe_exp.unmount( '#stripe-exp-element' );
38
+ stripe_cvc.unmount( '#stripe-cvc-element' );
39
+ }
40
+ },
41
+
42
+ mountElements: function() {
43
+ if ( ! $( '#stripe-card-element' ).length ) {
44
+ return;
45
+ }
46
+ if ( 'yes' === wc_stripe_params.inline_cc_form ) {
47
+ stripe_card.mount( '#stripe-card-element' );
48
+ } else {
49
+ stripe_card.mount( '#stripe-card-element' );
50
+ stripe_exp.mount( '#stripe-exp-element' );
51
+ stripe_cvc.mount( '#stripe-cvc-element' );
52
+ }
53
+ },
54
+
55
+ createElements: function() {
56
+ var elementStyles = {
57
+ base: {
58
+ iconColor: '#666EE8',
59
+ color: '#31325F',
60
+ fontSize: '15px',
61
+ '::placeholder': {
62
+ color: '#CFD7E0',
63
+ }
64
+ }
65
+ };
66
+
67
+ var elementClasses = {
68
+ focus: 'focused',
69
+ empty: 'empty',
70
+ invalid: 'invalid',
71
+ };
72
+
73
+ elementStyles = wc_stripe_params.elements_styling ? wc_stripe_params.elements_styling : elementStyles;
74
+ elementClasses = wc_stripe_params.elements_classes ? wc_stripe_params.elements_classes : elementClasses;
75
+
76
+ if ( 'yes' === wc_stripe_params.inline_cc_form ) {
77
+ stripe_card = elements.create( 'card', { style: elementStyles, hidePostalCode: true } );
78
+
79
+ stripe_card.addEventListener( 'change', function( event ) {
80
+ wc_stripe_form.onCCFormChange();
81
+
82
+ if ( event.error ) {
83
+ $( document.body ).trigger( 'stripeError', event );
84
+ }
85
+ } );
86
+ } else {
87
+ stripe_card = elements.create( 'cardNumber', { style: elementStyles, classes: elementClasses } );
88
+ stripe_exp = elements.create( 'cardExpiry', { style: elementStyles, classes: elementClasses } );
89
+ stripe_cvc = elements.create( 'cardCvc', { style: elementStyles, classes: elementClasses } );
90
+
91
+ stripe_card.addEventListener( 'change', function( event ) {
92
+ wc_stripe_form.onCCFormChange();
93
+
94
+ if ( event.error ) {
95
+ $( document.body ).trigger( 'stripeError', event );
96
+ }
97
+ } );
98
+
99
+ stripe_exp.addEventListener( 'change', function( event ) {
100
+ wc_stripe_form.onCCFormChange();
101
+
102
+ if ( event.error ) {
103
+ $( document.body ).trigger( 'stripeError', event );
104
+ }
105
+ } );
106
+
107
+ stripe_cvc.addEventListener( 'change', function( event ) {
108
+ wc_stripe_form.onCCFormChange();
109
+
110
+ if ( event.error ) {
111
+ $( document.body ).trigger( 'stripeError', event );
112
+ }
113
+ } );
114
+ }
115
+
116
+ /**
117
+ * Only in checkout page we need to delay the mounting of the
118
+ * card as some AJAX process needs to happen before we do.
119
+ */
120
+ if ( 'yes' === wc_stripe_params.is_checkout ) {
121
+ $( document.body ).on( 'updated_checkout', function() {
122
+ // Don't mount elements a second time.
123
+ if ( stripe_card ) {
124
+ wc_stripe_form.unmountElements();
125
+ }
126
+
127
+ wc_stripe_form.mountElements();
128
+ } );
129
+ } else if ( $( 'form#add_payment_method' ).length || $( 'form#order_review' ).length ) {
130
+ wc_stripe_form.mountElements();
131
+ }
132
+ },
133
+
134
  /**
135
  * Initialize event handlers and UI state.
136
  */
137
  init: function() {
138
  // Initialize tokenization script if on change payment method page and pay for order page.
139
+ if ( 'yes' === wc_stripe_params.is_change_payment_page || 'yes' === wc_stripe_params.is_pay_for_order_page ) {
140
  $( document.body ).trigger( 'wc-credit-card-form-init' );
141
  }
142
 
159
  this.form = $( 'form#order_review' );
160
  }
161
 
162
+ $( 'form#order_review, form#add_payment_method' )
163
  .on(
164
  'submit',
165
  this.onSubmit
170
  this.form = $( 'form#add_payment_method' );
171
  }
172
 
 
 
 
 
 
 
173
  $( 'form.woocommerce-checkout' )
174
  .on(
175
  'change',
 
176
  this.reset
177
  );
178
 
186
  this.reset
187
  );
188
 
189
+ if ( 'yes' === wc_stripe_params.use_elements ) {
190
+ wc_stripe_form.createElements();
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
191
  }
192
  },
193
 
274
  },
275
 
276
  block: function() {
277
+ if ( ! wc_stripe_form.isMobile() ) {
 
 
 
 
 
 
 
 
278
  wc_stripe_form.form.block({
279
  message: null,
280
  overlayCSS: {
286
  },
287
 
288
  unblock: function() {
289
+ wc_stripe_form.form.unblock();
 
 
 
 
290
  },
291
 
292
  getSelectedPaymentElement: function() {
347
  wc_stripe_form.unblock();
348
  },
349
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
350
  getOwnerDetails: function() {
351
  var first_name = $( '#billing_first_name' ).length ? $( '#billing_first_name' ).val() : wc_stripe_params.billing_first_name,
352
  last_name = $( '#billing_last_name' ).length ? $( '#billing_last_name' ).val() : wc_stripe_params.billing_last_name,
581
  // Stripe Checkout.
582
  if ( 'yes' === wc_stripe_params.is_stripe_checkout && wc_stripe_form.isStripeModalNeeded() && wc_stripe_form.isStripeCardChosen() ) {
583
  // Since in mobile actions cannot be deferred, no dynamic validation applied.
584
+ if ( wc_stripe_form.isMobile() || 'no' === wc_stripe_params.validate_modal_checkout ) {
585
  wc_stripe_form.openModal();
586
  } else {
587
+ wc_stripe_form.validateCheckout();
588
  }
589
 
590
  return false;
631
  this.onSubmit
632
  );
633
 
 
 
 
 
634
  wc_stripe_form.form.submit();
635
  }
636
 
641
  this.onSubmit
642
  );
643
 
 
 
 
 
644
  return true;
645
  }
646
 
651
  this.onSubmit
652
  );
653
 
 
 
 
 
654
  wc_stripe_form.form.submit();
655
  }
656
  }
657
 
658
+ wc_stripe_form.createSource();
 
 
 
 
 
659
 
660
  // Prevent form submitting
661
  return false;
687
  },
688
 
689
  reset: function() {
690
+ $( '.wc-stripe-error, .stripe-source, .stripe_token' ).remove();
691
 
692
  // Stripe Checkout.
693
  if ( 'yes' === wc_stripe_params.is_stripe_checkout ) {
696
  },
697
 
698
  getRequiredFields: function() {
699
+ return wc_stripe_form.form.find( '.form-row.validate-required > input:visible, .form-row.validate-required > select:visible, .form-row.validate-required > textarea:visible' );
700
  },
701
 
702
+ validateCheckout: function() {
 
 
 
 
703
  var data = {
704
  'nonce': wc_stripe_params.stripe_nonce,
705
  'required_fields': wc_stripe_form.getRequiredFields().serialize(),
706
+ 'all_fields': wc_stripe_form.form.serialize()
 
 
707
  };
708
 
709
+ $.ajax( {
710
  type: 'POST',
711
  url: wc_stripe_form.getAjaxURL( 'validate_checkout' ),
712
  data: data,
713
  dataType: 'json',
714
  success: function( result ) {
715
  if ( 'success' === result ) {
716
+ wc_stripe_form.openModal();
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
717
  } else if ( result.messages ) {
718
  wc_stripe_form.resetModal();
719
  wc_stripe_form.reset();
720
  wc_stripe_form.submitError( result.messages );
721
  }
722
  }
723
+ } );
724
+ },
725
+
726
+ onError: function( e, result ) {
727
+ var message = result.error.message,
728
+ errorContainer = wc_stripe_form.getSelectedPaymentElement().parents( 'li' ).eq(0).find( '.stripe-source-errors' );
729
+
730
+ /*
731
+ * Customers do not need to know the specifics of the below type of errors
732
+ * therefore return a generic localizable error message.
733
+ */
734
+ if (
735
+ 'invalid_request_error' === result.error.type ||
736
+ 'api_connection_error' === result.error.type ||
737
+ 'api_error' === result.error.type ||
738
+ 'authentication_error' === result.error.type ||
739
+ 'rate_limit_error' === result.error.type
740
+ ) {
741
+ message = wc_stripe_params.invalid_request_error;
742
+ }
743
+
744
+ if ( 'card_error' === result.error.type && wc_stripe_params.hasOwnProperty( result.error.code ) ) {
745
+ message = wc_stripe_params[ result.error.code ];
746
+ }
747
+
748
+ if ( 'validation_error' === result.error.type && wc_stripe_params.hasOwnProperty( result.error.code ) ) {
749
+ message = wc_stripe_params[ result.error.code ];
750
+ }
751
+
752
+ wc_stripe_form.reset();
753
+ $( '.woocommerce-NoticeGroup-checkout' ).remove();
754
+ console.log( result.error.message ); // Leave for troubleshooting.
755
+ $( errorContainer ).html( '<ul class="woocommerce_error woocommerce-error wc-stripe-error"><li>' + message + '</li></ul>' );
756
+
757
+ if ( $( '.wc-stripe-error' ).length ) {
758
+ $( 'html, body' ).animate({
759
+ scrollTop: ( $( '.wc-stripe-error' ).offset().top - 200 )
760
+ }, 200 );
761
+ }
762
+ wc_stripe_form.unblock();
763
  },
764
 
765
  submitError: function( error_message ) {
assets/js/stripe.min.js CHANGED
@@ -1 +1 @@
1
- jQuery(function(e){"use strict";var r=Stripe(wc_stripe_params.key);if("yes"===wc_stripe_params.use_elements)var t,i,o,s=wc_stripe_params.elements_options.length?wc_stripe_params.elements_options:{},a=r.elements(s);var n={getAjaxURL:function(e){return wc_stripe_params.ajaxurl.toString().replace("%%endpoint%%","wc_stripe_"+e)},init:function(){"yes"===wc_stripe_params.is_change_payment_page&&e(document.body).trigger("wc-credit-card-form-init"),this.stripe_checkout_submit=!1,e("form.woocommerce-checkout").length&&(this.form=e("form.woocommerce-checkout")),e("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),e("form#order_review").length&&(this.form=e("form#order_review")),e("form#order_review").on("submit",this.onSubmit),e("form#add_payment_method").length&&(this.form=e("form#add_payment_method")),e("form#add_payment_method").on("submit",this.onSubmit),e("form.woocommerce-checkout").on("change","#stripe-bank-country",this.reset),e(document).on("stripeError",this.onError).on("checkout_error",this.reset);var r={base:{iconColor:"#666EE8",color:"#31325F",fontSize:"15px","::placeholder":{color:"#CFD7E0"}}},s={focus:"focused",empty:"empty",invalid:"invalid"};"yes"===wc_stripe_params.use_elements&&e("#stripe-card-element").length&&(r=wc_stripe_params.elements_styling?wc_stripe_params.elements_styling:r,s=wc_stripe_params.elements_classes?wc_stripe_params.elements_classes:s,"yes"===wc_stripe_params.inline_cc_form?(t=a.create("card",{style:r,hidePostalCode:!0})).addEventListener("change",function(r){n.onCCFormChange(),r.error&&e(document.body).trigger("stripeError",r)}):(t=a.create("cardNumber",{style:r,classes:s}),i=a.create("cardExpiry",{style:r,classes:s}),o=a.create("cardCvc",{style:r,classes:s}),t.addEventListener("change",function(r){n.onCCFormChange(),r.error&&e(document.body).trigger("stripeError",r)}),i.addEventListener("change",function(r){n.onCCFormChange(),r.error&&e(document.body).trigger("stripeError",r)}),o.addEventListener("change",function(r){n.onCCFormChange(),r.error&&e(document.body).trigger("stripeError",r)})),wc_stripe_params.is_checkout?e(document.body).on("updated_checkout",function(){t&&("yes"===wc_stripe_params.inline_cc_form?t.unmount("#stripe-card-element"):(t.unmount("#stripe-card-element"),i.unmount("#stripe-exp-element"),o.unmount("#stripe-cvc-element"))),"yes"===wc_stripe_params.inline_cc_form?t.mount("#stripe-card-element"):(t.mount("#stripe-card-element"),i.mount("#stripe-exp-element"),o.mount("#stripe-cvc-element"))}):(e("form#add_payment_method").length||e("form#order_review").length)&&("yes"===wc_stripe_params.inline_cc_form?t.mount("#stripe-card-element"):(t.mount("#stripe-card-element"),i.mount("#stripe-exp-element"),o.mount("#stripe-cvc-element"))))},isStripeChosen:function(){return e("#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")||e("#payment_method_stripe").is(":checked")&&"new"===e('input[name="wc-stripe-payment-token"]:checked').val()||e("#payment_method_stripe_sepa").is(":checked")&&"new"===e('input[name="wc-stripe-payment-token"]:checked').val()},isStripeSaveCardChosen:function(){return e("#payment_method_stripe").is(":checked")&&e('input[name="wc-stripe-payment-token"]').is(":checked")&&"new"!==e('input[name="wc-stripe-payment-token"]:checked').val()||e("#payment_method_stripe_sepa").is(":checked")&&e('input[name="wc-stripe_sepa-payment-token"]').is(":checked")&&"new"!==e('input[name="wc-stripe_sepa-payment-token"]:checked').val()},isStripeCardChosen:function(){return e("#payment_method_stripe").is(":checked")},isBancontactChosen:function(){return e("#payment_method_stripe_bancontact").is(":checked")},isGiropayChosen:function(){return e("#payment_method_stripe_giropay").is(":checked")},isIdealChosen:function(){return e("#payment_method_stripe_ideal").is(":checked")},isSofortChosen:function(){return e("#payment_method_stripe_sofort").is(":checked")},isAlipayChosen:function(){return e("#payment_method_stripe_alipay").is(":checked")},isSepaChosen:function(){return e("#payment_method_stripe_sepa").is(":checked")},isBitcoinChosen:function(){return e("#payment_method_stripe_bitcoin").is(":checked")},isP24Chosen:function(){return e("#payment_method_stripe_p24").is(":checked")},hasSource:function(){return 0<e("input.stripe-source").length},hasToken:function(){return 0<e("input.stripe_token").length},isMobile:function(){return!!/Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(navigator.userAgent)},isStripeModalNeeded:function(e){var r=n.form.find("input.stripe_token");return(!n.stripe_submit||!r)&&!!n.isStripeChosen()},block:function(){n.isMobile()?e.blockUI({message:null,overlayCSS:{background:"#fff",opacity:.6}}):n.form.block({message:null,overlayCSS:{background:"#fff",opacity:.6}})},unblock:function(){n.isMobile()?e.unblockUI():n.form.unblock()},getSelectedPaymentElement:function(){return e('.payment_methods input[name="payment_method"]:checked')},openModal:function(){var t=n.form,i=e("#stripe-payment-data");n.reset();StripeCheckout.open({key:wc_stripe_params.key,billingAddress:"yes"===wc_stripe_params.stripe_checkout_require_billing_address,amount:i.data("amount"),name:i.data("name"),description:i.data("description"),currency:i.data("currency"),image:i.data("image"),bitcoin:i.data("bitcoin"),locale:i.data("locale"),email:e("#billing_email").val()||i.data("email"),panelLabel:i.data("panel-label"),allowRememberMe:i.data("allow-remember-me"),token:function(e){if(t.find("input.stripe_source").remove(),"token"===e.object)r.createSource({type:"card",token:e.id}).then(n.sourceResponse);else if("source"===e.object){var i={source:e};n.sourceResponse(i)}},closed:n.onClose()})},resetModal:function(){n.reset(),n.stripe_checkout_submit=!1},onClose:function(){n.unblock()},onError:function(r,t){var i=t.error.message,o=n.getSelectedPaymentElement().parents("li").eq(0).find(".stripe-source-errors");"invalid_request_error"!==t.error.type&&"api_connection_error"!==t.error.type&&"api_error"!==t.error.type&&"authentication_error"!==t.error.type&&"rate_limit_error"!==t.error.type||(i=wc_stripe_params.invalid_request_error),"card_error"===t.error.type&&wc_stripe_params.hasOwnProperty(t.error.code)&&(i=wc_stripe_params[t.error.code]),"validation_error"===t.error.type&&wc_stripe_params.hasOwnProperty(t.error.code)&&(i=wc_stripe_params[t.error.code]),n.reset(),e(".woocommerce-NoticeGroup-checkout").remove(),console.log(t.error.message),e(o).html('<ul class="woocommerce_error woocommerce-error wc-stripe-error"><li>'+i+"</li></ul>"),e(".wc-stripe-error").length&&e("html, body").animate({scrollTop:e(".wc-stripe-error").offset().top-200},200),n.unblock()},getOwnerDetails:function(){var r=e("#billing_first_name").length?e("#billing_first_name").val():wc_stripe_params.billing_first_name,t=e("#billing_last_name").length?e("#billing_last_name").val():wc_stripe_params.billing_last_name,i={owner:{name:"",address:{},email:"",phone:""}};return i.owner.name=r,r&&t&&(i.owner.name=r+" "+t),i.owner.email=e("#billing_email").val(),i.owner.phone=e("#billing_phone").val(),void 0!==i.owner.phone&&0>=i.owner.phone.length&&delete i.owner.phone,void 0!==i.owner.email&&0>=i.owner.email.length&&delete i.owner.email,void 0!==i.owner.name&&0>=i.owner.name.length&&delete i.owner.name,e("#billing_address_1").length>0?(i.owner.address.line1=e("#billing_address_1").val(),i.owner.address.line2=e("#billing_address_2").val(),i.owner.address.state=e("#billing_state").val(),i.owner.address.city=e("#billing_city").val(),i.owner.address.postal_code=e("#billing_postcode").val(),i.owner.address.country=e("#billing_country").val()):wc_stripe_params.billing_address_1&&(i.owner.address.line1=wc_stripe_params.billing_address_1,i.owner.address.line2=wc_stripe_params.billing_address_2,i.owner.address.state=wc_stripe_params.billing_state,i.owner.address.city=wc_stripe_params.billing_city,i.owner.address.postal_code=wc_stripe_params.billing_postcode,i.owner.address.country=wc_stripe_params.billing_country),i},createSource:function(){var i=n.getOwnerDetails(),o="card";if(n.isBancontactChosen()&&(o="bancontact"),n.isSepaChosen()&&(o="sepa_debit"),n.isIdealChosen()&&(o="ideal"),n.isSofortChosen()&&(o="sofort"),n.isBitcoinChosen()&&(o="bitcoin"),n.isGiropayChosen()&&(o="giropay"),n.isAlipayChosen()&&(o="alipay"),"card"===o)r.createSource(t,i).then(n.sourceResponse);else{switch(o){case"bancontact":case"giropay":case"ideal":case"sofort":case"alipay":i.amount=e("#stripe-"+o+"-payment-data").data("amount"),i.currency=e("#stripe-"+o+"-payment-data").data("currency"),i.redirect={return_url:wc_stripe_params.return_url},wc_stripe_params.statement_descriptor&&(i.statement_descriptor=wc_stripe_params.statement_descriptor)}switch(o){case"sepa_debit":var s=e("#stripe-payment-data"),a=e("#billing_email").length?e("#billing_email").val():s.data("email");i.currency=e("#stripe-"+o+"-payment-data").data("currency"),i.owner.name=e("#stripe-sepa-owner").val(),i.owner.email=a,i.sepa_debit={iban:e("#stripe-sepa-iban").val()},i.mandate={notification_method:wc_stripe_params.sepa_mandate_notification};break;case"ideal":i.ideal={bank:e("#stripe-ideal-bank").val()};break;case"bitcoin":case"alipay":i.currency=e("#stripe-"+o+"-payment-data").data("currency"),i.amount=e("#stripe-"+o+"-payment-data").data("amount");break;case"sofort":i.sofort={country:e("#billing_country").val()}}i.type=o,r.createSource(i).then(n.sourceResponse)}},sourceResponse:function(r){r.error?e(document.body).trigger("stripeError",r):"no"===wc_stripe_params.allow_prepaid_card&&"card"===r.source.type&&"prepaid"===r.source.card.funding?(r.error={message:wc_stripe_params.no_prepaid_card_msg},wc_stripe_params.is_stripe_checkout?n.submitError('<ul class="woocommerce-error"><li>'+wc_stripe_params.no_prepaid_card_msg+"</li></ul>"):e(document.body).trigger("stripeError",r)):n.processStripeResponse(r.source)},processStripeResponse:function(r){n.reset(),n.form.append("<input type='hidden' class='stripe-source' name='stripe_source' value='"+r.id+"'/>"),e("form#add_payment_method").length&&e(n.form).off("submit",n.form.onSubmit),n.form.submit()},createToken:function(){var r=e("#stripe-card-number").val(),t=e("#stripe-card-cvc").val(),i=e("#stripe-card-expiry").payment("cardExpiryVal"),o=e("#billing_first_name").length?e("#billing_first_name").val():wc_stripe_params.billing_first_name,s=e("#billing_last_name").length?e("#billing_last_name").val():wc_stripe_params.billing_last_name,a={number:r,cvc:t,exp_month:parseInt(i.month,10)||0,exp_year:parseInt(i.year,10)||0};o&&s&&(a.name=o+" "+s),e("#billing_address_1").length>0?(a.address_line1=e("#billing_address_1").val(),a.address_line2=e("#billing_address_2").val(),a.address_state=e("#billing_state").val(),a.address_city=e("#billing_city").val(),a.address_zip=e("#billing_postcode").val(),a.address_country=e("#billing_country").val()):wc_stripe_params.billing_address_1&&(a.address_line1=wc_stripe_params.billing_address_1,a.address_line2=wc_stripe_params.billing_address_2,a.address_state=wc_stripe_params.billing_state,a.address_city=wc_stripe_params.billing_city,a.address_zip=wc_stripe_params.billing_postcode,a.address_country=wc_stripe_params.billing_country),Stripe.setPublishableKey(wc_stripe_params.key),Stripe.createToken(a,n.onStripeTokenResponse)},onStripeTokenResponse:function(r,t){if(t.error)e(document).trigger("stripeError",t);else{if("no"===wc_stripe_params.allow_prepaid_card&&"prepaid"===t.card.funding)return t.error={message:wc_stripe_params.no_prepaid_card_msg},e(document).trigger("stripeError",{response:t}),!1;var i=t.id;n.form.append("<input type='hidden' class='stripe_token' name='stripe_token' value='"+i+"'/>"),e("form#add_payment_method").length&&e(n.form).off("submit",n.form.onSubmit),n.form.submit()}},onSubmit:function(r){if(n.isStripeChosen()&&!n.isStripeSaveCardChosen()&&!n.hasSource()&&!n.hasToken()){if(r.preventDefault(),"yes"===wc_stripe_params.is_stripe_checkout&&n.isStripeModalNeeded()&&n.isStripeCardChosen())return n.isMobile()?n.openModal():n.validateCheckout("modal"),!1;if(n.block(),n.isStripeCardChosen()&&"no"===wc_stripe_params.use_elements)return n.createToken(),!1;if(n.isSepaChosen()){if(""===e("#stripe-sepa-owner").val())return e(document.body).trigger("stripeError",{error:{message:wc_stripe_params.no_sepa_owner_msg}}),!1;if(""===e("#stripe-sepa-iban").val())return e(document.body).trigger("stripeError",{error:{message:wc_stripe_params.no_sepa_iban_msg}}),!1}if(n.isBancontactChosen()||n.isGiropayChosen()||n.isIdealChosen()||n.isAlipayChosen()||n.isSofortChosen()||n.isP24Chosen()){if(e("form#order_review").length&&(e("form#order_review").off("submit",this.onSubmit),n.isMobile()&&n.unblock(),n.form.submit()),e("form.woocommerce-checkout").length)return e("form.woocommerce-checkout").off("submit",this.onSubmit),n.isMobile()&&n.unblock(),!0;e("form#add_payment_method").length&&(e("form#add_payment_method").off("submit",this.onSubmit),n.isMobile()&&n.unblock(),n.form.submit())}return wc_stripe_params.is_checkout?n.validateCheckout():n.createSource(),!1}if(e("form#add_payment_method").length)return r.preventDefault(),"yes"===wc_stripe_params.is_stripe_checkout&&n.isStripeModalNeeded()&&n.isStripeCardChosen()?(n.openModal(),!1):(n.block(),n.isStripeCardChosen()&&"no"===wc_stripe_params.use_elements?(n.createToken(),!1):(n.createSource(),!1))},onCCFormChange:function(){n.reset()},reset:function(){e(".wc-stripe-error, .stripe-source, .stripe_token, .stripe-checkout-object").remove(),"yes"===wc_stripe_params.is_stripe_checkout&&(n.stripe_submit=!1)},getRequiredFields:function(){return n.form.find(".form-row.validate-required > input, .form-row.validate-required > select, .form-row.validate-required > textarea")},validateCheckout:function(r){void 0===r&&(r="");var t={nonce:wc_stripe_params.stripe_nonce,required_fields:n.getRequiredFields().serialize(),all_fields:n.form.serialize(),source_type:n.getSelectedPaymentElement().val(),is_add_payment_page:wc_stripe_params.is_add_payment_method_page};e.ajax({type:"POST",url:n.getAjaxURL("validate_checkout"),data:t,dataType:"json",success:function(t){if("success"===t)if("modal"===r)n.openModal();else{if(n.isSepaChosen()){if(""===e("#stripe-sepa-owner").val())return e(document.body).trigger("stripeError",{error:{message:wc_stripe_params.no_sepa_owner_msg}}),!1;if(""===e("#stripe-sepa-iban").val())return e(document.body).trigger("stripeError",{error:{message:wc_stripe_params.no_sepa_iban_msg}}),!1}n.createSource()}else t.messages&&(n.resetModal(),n.reset(),n.submitError(t.messages))}})},submitError:function(r){e(".woocommerce-NoticeGroup-checkout, .woocommerce-error, .woocommerce-message").remove(),n.form.prepend('<div class="woocommerce-NoticeGroup woocommerce-NoticeGroup-checkout">'+r+"</div>"),n.form.removeClass("processing").unblock(),n.form.find(".input-text, select, input:checkbox").blur();var t="";e("#add_payment_method").length&&(t=e("#add_payment_method")),e("#order_review").length&&(t=e("#order_review")),e("form.checkout").length&&(t=e("form.checkout")),t.length&&e("html, body").animate({scrollTop:t.offset().top-100},500),e(document.body).trigger("checkout_error"),n.unblock()}};n.init()});
1
+ jQuery(function(e){"use strict";var r=Stripe(wc_stripe_params.key);if("yes"===wc_stripe_params.use_elements)var t,i,o,s=wc_stripe_params.elements_options.length?wc_stripe_params.elements_options:{},a=r.elements(s);var n={getAjaxURL:function(e){return wc_stripe_params.ajaxurl.toString().replace("%%endpoint%%","wc_stripe_"+e)},unmountElements:function(){"yes"===wc_stripe_params.inline_cc_form?t.unmount("#stripe-card-element"):(t.unmount("#stripe-card-element"),i.unmount("#stripe-exp-element"),o.unmount("#stripe-cvc-element"))},mountElements:function(){e("#stripe-card-element").length&&("yes"===wc_stripe_params.inline_cc_form?t.mount("#stripe-card-element"):(t.mount("#stripe-card-element"),i.mount("#stripe-exp-element"),o.mount("#stripe-cvc-element")))},createElements:function(){var r={base:{iconColor:"#666EE8",color:"#31325F",fontSize:"15px","::placeholder":{color:"#CFD7E0"}}},s={focus:"focused",empty:"empty",invalid:"invalid"};r=wc_stripe_params.elements_styling?wc_stripe_params.elements_styling:r,s=wc_stripe_params.elements_classes?wc_stripe_params.elements_classes:s,"yes"===wc_stripe_params.inline_cc_form?(t=a.create("card",{style:r,hidePostalCode:!0})).addEventListener("change",function(r){n.onCCFormChange(),r.error&&e(document.body).trigger("stripeError",r)}):(t=a.create("cardNumber",{style:r,classes:s}),i=a.create("cardExpiry",{style:r,classes:s}),o=a.create("cardCvc",{style:r,classes:s}),t.addEventListener("change",function(r){n.onCCFormChange(),r.error&&e(document.body).trigger("stripeError",r)}),i.addEventListener("change",function(r){n.onCCFormChange(),r.error&&e(document.body).trigger("stripeError",r)}),o.addEventListener("change",function(r){n.onCCFormChange(),r.error&&e(document.body).trigger("stripeError",r)})),"yes"===wc_stripe_params.is_checkout?e(document.body).on("updated_checkout",function(){t&&n.unmountElements(),n.mountElements()}):(e("form#add_payment_method").length||e("form#order_review").length)&&n.mountElements()},init:function(){"yes"!==wc_stripe_params.is_change_payment_page&&"yes"!==wc_stripe_params.is_pay_for_order_page||e(document.body).trigger("wc-credit-card-form-init"),this.stripe_checkout_submit=!1,e("form.woocommerce-checkout").length&&(this.form=e("form.woocommerce-checkout")),e("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),e("form#order_review").length&&(this.form=e("form#order_review")),e("form#order_review, form#add_payment_method").on("submit",this.onSubmit),e("form#add_payment_method").length&&(this.form=e("form#add_payment_method")),e("form.woocommerce-checkout").on("change",this.reset),e(document).on("stripeError",this.onError).on("checkout_error",this.reset),"yes"===wc_stripe_params.use_elements&&n.createElements()},isStripeChosen:function(){return e("#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")||e("#payment_method_stripe").is(":checked")&&"new"===e('input[name="wc-stripe-payment-token"]:checked').val()||e("#payment_method_stripe_sepa").is(":checked")&&"new"===e('input[name="wc-stripe-payment-token"]:checked').val()},isStripeSaveCardChosen:function(){return e("#payment_method_stripe").is(":checked")&&e('input[name="wc-stripe-payment-token"]').is(":checked")&&"new"!==e('input[name="wc-stripe-payment-token"]:checked').val()||e("#payment_method_stripe_sepa").is(":checked")&&e('input[name="wc-stripe_sepa-payment-token"]').is(":checked")&&"new"!==e('input[name="wc-stripe_sepa-payment-token"]:checked').val()},isStripeCardChosen:function(){return e("#payment_method_stripe").is(":checked")},isBancontactChosen:function(){return e("#payment_method_stripe_bancontact").is(":checked")},isGiropayChosen:function(){return e("#payment_method_stripe_giropay").is(":checked")},isIdealChosen:function(){return e("#payment_method_stripe_ideal").is(":checked")},isSofortChosen:function(){return e("#payment_method_stripe_sofort").is(":checked")},isAlipayChosen:function(){return e("#payment_method_stripe_alipay").is(":checked")},isSepaChosen:function(){return e("#payment_method_stripe_sepa").is(":checked")},isBitcoinChosen:function(){return e("#payment_method_stripe_bitcoin").is(":checked")},isP24Chosen:function(){return e("#payment_method_stripe_p24").is(":checked")},hasSource:function(){return 0<e("input.stripe-source").length},hasToken:function(){return 0<e("input.stripe_token").length},isMobile:function(){return!!/Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(navigator.userAgent)},isStripeModalNeeded:function(e){var r=n.form.find("input.stripe_token");return(!n.stripe_submit||!r)&&!!n.isStripeChosen()},block:function(){n.isMobile()||n.form.block({message:null,overlayCSS:{background:"#fff",opacity:.6}})},unblock:function(){n.form.unblock()},getSelectedPaymentElement:function(){return e('.payment_methods input[name="payment_method"]:checked')},openModal:function(){var t=n.form,i=e("#stripe-payment-data");n.reset();StripeCheckout.open({key:wc_stripe_params.key,billingAddress:"yes"===wc_stripe_params.stripe_checkout_require_billing_address,amount:i.data("amount"),name:i.data("name"),description:i.data("description"),currency:i.data("currency"),image:i.data("image"),bitcoin:i.data("bitcoin"),locale:i.data("locale"),email:e("#billing_email").val()||i.data("email"),panelLabel:i.data("panel-label"),allowRememberMe:i.data("allow-remember-me"),token:function(e){if(t.find("input.stripe_source").remove(),"token"===e.object)r.createSource({type:"card",token:e.id}).then(n.sourceResponse);else if("source"===e.object){var i={source:e};n.sourceResponse(i)}},closed:n.onClose()})},resetModal:function(){n.reset(),n.stripe_checkout_submit=!1},onClose:function(){n.unblock()},getOwnerDetails:function(){var r=e("#billing_first_name").length?e("#billing_first_name").val():wc_stripe_params.billing_first_name,t=e("#billing_last_name").length?e("#billing_last_name").val():wc_stripe_params.billing_last_name,i={owner:{name:"",address:{},email:"",phone:""}};return i.owner.name=r,r&&t&&(i.owner.name=r+" "+t),i.owner.email=e("#billing_email").val(),i.owner.phone=e("#billing_phone").val(),void 0!==i.owner.phone&&0>=i.owner.phone.length&&delete i.owner.phone,void 0!==i.owner.email&&0>=i.owner.email.length&&delete i.owner.email,void 0!==i.owner.name&&0>=i.owner.name.length&&delete i.owner.name,e("#billing_address_1").length>0?(i.owner.address.line1=e("#billing_address_1").val(),i.owner.address.line2=e("#billing_address_2").val(),i.owner.address.state=e("#billing_state").val(),i.owner.address.city=e("#billing_city").val(),i.owner.address.postal_code=e("#billing_postcode").val(),i.owner.address.country=e("#billing_country").val()):wc_stripe_params.billing_address_1&&(i.owner.address.line1=wc_stripe_params.billing_address_1,i.owner.address.line2=wc_stripe_params.billing_address_2,i.owner.address.state=wc_stripe_params.billing_state,i.owner.address.city=wc_stripe_params.billing_city,i.owner.address.postal_code=wc_stripe_params.billing_postcode,i.owner.address.country=wc_stripe_params.billing_country),i},createSource:function(){var i=n.getOwnerDetails(),o="card";if(n.isBancontactChosen()&&(o="bancontact"),n.isSepaChosen()&&(o="sepa_debit"),n.isIdealChosen()&&(o="ideal"),n.isSofortChosen()&&(o="sofort"),n.isBitcoinChosen()&&(o="bitcoin"),n.isGiropayChosen()&&(o="giropay"),n.isAlipayChosen()&&(o="alipay"),"card"===o)r.createSource(t,i).then(n.sourceResponse);else{switch(o){case"bancontact":case"giropay":case"ideal":case"sofort":case"alipay":i.amount=e("#stripe-"+o+"-payment-data").data("amount"),i.currency=e("#stripe-"+o+"-payment-data").data("currency"),i.redirect={return_url:wc_stripe_params.return_url},wc_stripe_params.statement_descriptor&&(i.statement_descriptor=wc_stripe_params.statement_descriptor)}switch(o){case"sepa_debit":var s=e("#stripe-payment-data"),a=e("#billing_email").length?e("#billing_email").val():s.data("email");i.currency=e("#stripe-"+o+"-payment-data").data("currency"),i.owner.name=e("#stripe-sepa-owner").val(),i.owner.email=a,i.sepa_debit={iban:e("#stripe-sepa-iban").val()},i.mandate={notification_method:wc_stripe_params.sepa_mandate_notification};break;case"ideal":i.ideal={bank:e("#stripe-ideal-bank").val()};break;case"bitcoin":case"alipay":i.currency=e("#stripe-"+o+"-payment-data").data("currency"),i.amount=e("#stripe-"+o+"-payment-data").data("amount");break;case"sofort":i.sofort={country:e("#billing_country").val()}}i.type=o,r.createSource(i).then(n.sourceResponse)}},sourceResponse:function(r){r.error?e(document.body).trigger("stripeError",r):"no"===wc_stripe_params.allow_prepaid_card&&"card"===r.source.type&&"prepaid"===r.source.card.funding?(r.error={message:wc_stripe_params.no_prepaid_card_msg},wc_stripe_params.is_stripe_checkout?n.submitError('<ul class="woocommerce-error"><li>'+wc_stripe_params.no_prepaid_card_msg+"</li></ul>"):e(document.body).trigger("stripeError",r)):n.processStripeResponse(r.source)},processStripeResponse:function(r){n.reset(),n.form.append("<input type='hidden' class='stripe-source' name='stripe_source' value='"+r.id+"'/>"),e("form#add_payment_method").length&&e(n.form).off("submit",n.form.onSubmit),n.form.submit()},createToken:function(){var r=e("#stripe-card-number").val(),t=e("#stripe-card-cvc").val(),i=e("#stripe-card-expiry").payment("cardExpiryVal"),o=e("#billing_first_name").length?e("#billing_first_name").val():wc_stripe_params.billing_first_name,s=e("#billing_last_name").length?e("#billing_last_name").val():wc_stripe_params.billing_last_name,a={number:r,cvc:t,exp_month:parseInt(i.month,10)||0,exp_year:parseInt(i.year,10)||0};o&&s&&(a.name=o+" "+s),e("#billing_address_1").length>0?(a.address_line1=e("#billing_address_1").val(),a.address_line2=e("#billing_address_2").val(),a.address_state=e("#billing_state").val(),a.address_city=e("#billing_city").val(),a.address_zip=e("#billing_postcode").val(),a.address_country=e("#billing_country").val()):wc_stripe_params.billing_address_1&&(a.address_line1=wc_stripe_params.billing_address_1,a.address_line2=wc_stripe_params.billing_address_2,a.address_state=wc_stripe_params.billing_state,a.address_city=wc_stripe_params.billing_city,a.address_zip=wc_stripe_params.billing_postcode,a.address_country=wc_stripe_params.billing_country),Stripe.setPublishableKey(wc_stripe_params.key),Stripe.createToken(a,n.onStripeTokenResponse)},onStripeTokenResponse:function(r,t){if(t.error)e(document).trigger("stripeError",t);else{if("no"===wc_stripe_params.allow_prepaid_card&&"prepaid"===t.card.funding)return t.error={message:wc_stripe_params.no_prepaid_card_msg},e(document).trigger("stripeError",{response:t}),!1;var i=t.id;n.form.append("<input type='hidden' class='stripe_token' name='stripe_token' value='"+i+"'/>"),e("form#add_payment_method").length&&e(n.form).off("submit",n.form.onSubmit),n.form.submit()}},onSubmit:function(r){if(n.isStripeChosen()&&!n.isStripeSaveCardChosen()&&!n.hasSource()&&!n.hasToken()){if(r.preventDefault(),"yes"===wc_stripe_params.is_stripe_checkout&&n.isStripeModalNeeded()&&n.isStripeCardChosen())return n.isMobile()||"no"===wc_stripe_params.validate_modal_checkout?n.openModal():n.validateCheckout(),!1;if(n.block(),n.isStripeCardChosen()&&"no"===wc_stripe_params.use_elements)return n.createToken(),!1;if(n.isSepaChosen()){if(""===e("#stripe-sepa-owner").val())return e(document.body).trigger("stripeError",{error:{message:wc_stripe_params.no_sepa_owner_msg}}),!1;if(""===e("#stripe-sepa-iban").val())return e(document.body).trigger("stripeError",{error:{message:wc_stripe_params.no_sepa_iban_msg}}),!1}if(n.isBancontactChosen()||n.isGiropayChosen()||n.isIdealChosen()||n.isAlipayChosen()||n.isSofortChosen()||n.isP24Chosen()){if(e("form#order_review").length&&(e("form#order_review").off("submit",this.onSubmit),n.form.submit()),e("form.woocommerce-checkout").length)return e("form.woocommerce-checkout").off("submit",this.onSubmit),!0;e("form#add_payment_method").length&&(e("form#add_payment_method").off("submit",this.onSubmit),n.form.submit())}return n.createSource(),!1}if(e("form#add_payment_method").length)return r.preventDefault(),"yes"===wc_stripe_params.is_stripe_checkout&&n.isStripeModalNeeded()&&n.isStripeCardChosen()?(n.openModal(),!1):(n.block(),n.isStripeCardChosen()&&"no"===wc_stripe_params.use_elements?(n.createToken(),!1):(n.createSource(),!1))},onCCFormChange:function(){n.reset()},reset:function(){e(".wc-stripe-error, .stripe-source, .stripe_token").remove(),"yes"===wc_stripe_params.is_stripe_checkout&&(n.stripe_submit=!1)},getRequiredFields:function(){return n.form.find(".form-row.validate-required > input:visible, .form-row.validate-required > select:visible, .form-row.validate-required > textarea:visible")},validateCheckout:function(){var r={nonce:wc_stripe_params.stripe_nonce,required_fields:n.getRequiredFields().serialize(),all_fields:n.form.serialize()};e.ajax({type:"POST",url:n.getAjaxURL("validate_checkout"),data:r,dataType:"json",success:function(e){"success"===e?n.openModal():e.messages&&(n.resetModal(),n.reset(),n.submitError(e.messages))}})},onError:function(r,t){var i=t.error.message,o=n.getSelectedPaymentElement().parents("li").eq(0).find(".stripe-source-errors");"invalid_request_error"!==t.error.type&&"api_connection_error"!==t.error.type&&"api_error"!==t.error.type&&"authentication_error"!==t.error.type&&"rate_limit_error"!==t.error.type||(i=wc_stripe_params.invalid_request_error),"card_error"===t.error.type&&wc_stripe_params.hasOwnProperty(t.error.code)&&(i=wc_stripe_params[t.error.code]),"validation_error"===t.error.type&&wc_stripe_params.hasOwnProperty(t.error.code)&&(i=wc_stripe_params[t.error.code]),n.reset(),e(".woocommerce-NoticeGroup-checkout").remove(),console.log(t.error.message),e(o).html('<ul class="woocommerce_error woocommerce-error wc-stripe-error"><li>'+i+"</li></ul>"),e(".wc-stripe-error").length&&e("html, body").animate({scrollTop:e(".wc-stripe-error").offset().top-200},200),n.unblock()},submitError:function(r){e(".woocommerce-NoticeGroup-checkout, .woocommerce-error, .woocommerce-message").remove(),n.form.prepend('<div class="woocommerce-NoticeGroup woocommerce-NoticeGroup-checkout">'+r+"</div>"),n.form.removeClass("processing").unblock(),n.form.find(".input-text, select, input:checkbox").blur();var t="";e("#add_payment_method").length&&(t=e("#add_payment_method")),e("#order_review").length&&(t=e("#order_review")),e("form.checkout").length&&(t=e("form.checkout")),t.length&&e("html, body").animate({scrollTop:t.offset().top-100},500),e(document.body).trigger("checkout_error"),n.unblock()}};n.init()});
changelog.txt CHANGED
@@ -1,5 +1,21 @@
1
  *** Changelog ***
2
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
3
  = 4.0.5 - 2018-02-02 =
4
  * Fix - Illegal offset error on settings when non is defined or saved.
5
  * Fix - Wrong ID used for dispute webhook handler.
1
  *** Changelog ***
2
 
3
+ = 4.0.6 - 2018-02-20 =
4
+ * Fix - A WC 2.6 backwards compat issue with function from WC 3.0.
5
+ * Fix - Subs renewal sometimes failed due to parameters being different.
6
+ * Fix - Stripe accepts only NO for Norwegian language on Stripe Checkout.
7
+ * Fix - Refund fees may not accurately reflect net fees. Props @rvola.
8
+ * Fix - Undefined SERVERNAME property in some cases.
9
+ * Fix - Potential issue when a charge parameter changes due to initial failed request causing retries to fail.
10
+ * Fix - When 3DS is not required, failed payments was not change order status to failed.
11
+ * Fix - Potential duplicate order processes on WC side when webhook and redirect has a race condition.
12
+ * Remove - Checkout validation and let WC handle it.
13
+ * Update - Stripe API version to 2018-02-06.
14
+ * Add - Webhooks for review open/closed for Radar.
15
+ * Add - Hook `wc_stripe_refund_request` for refund request arguments.
16
+ * Add - Hook `wc_stripe_validate_modal_checkout` to enable 3rd party checkout validation.
17
+ * Add - Hook `wc_stripe_validate_modal_checkout_action`.
18
+
19
  = 4.0.5 - 2018-02-02 =
20
  * Fix - Illegal offset error on settings when non is defined or saved.
21
  * Fix - Wrong ID used for dispute webhook handler.
includes/abstracts/abstract-wc-stripe-payment-gateway.php CHANGED
@@ -25,7 +25,9 @@ abstract class WC_Stripe_Payment_Gateway extends WC_Payment_Gateway_CC {
25
  return (
26
  'invalid_request_error' === $error->type ||
27
  'idempotency_error' === $error->type ||
28
- 'rate_limit_error' === $error->type
 
 
29
  );
30
  }
31
 
@@ -180,16 +182,25 @@ abstract class WC_Stripe_Payment_Gateway extends WC_Payment_Gateway_CC {
180
  return esc_url_raw( add_query_arg( array( 'utm_nooverride' => '1' ), $this->get_return_url() ) );
181
  }
182
 
 
 
 
 
 
 
 
 
 
183
  /**
184
  * Generate the request for the payment.
185
  *
186
  * @since 3.1.0
187
  * @version 4.0.0
188
  * @param WC_Order $order
189
- * @param object $source
190
  * @return array()
191
  */
192
- public function generate_payment_request( $order, $source ) {
193
  $settings = get_option( 'woocommerce_stripe_settings', array() );
194
  $statement_descriptor = ! empty( $settings['statement_descriptor'] ) ? str_replace( "'", '', $settings['statement_descriptor'] ) : '';
195
  $capture = ! empty( $settings['capture'] ) && 'yes' === $settings['capture'] ? true : false;
@@ -229,14 +240,21 @@ abstract class WC_Stripe_Payment_Gateway extends WC_Payment_Gateway_CC {
229
  'order_id' => WC_Stripe_Helper::is_pre_30() ? $order->id : $order->get_id(),
230
  );
231
 
232
- $post_data['metadata'] = apply_filters( 'wc_stripe_payment_metadata', $metadata, $order, $source );
 
 
 
 
 
233
 
234
- if ( $source->customer ) {
235
- $post_data['customer'] = $source->customer;
 
 
236
  }
237
 
238
- if ( $source->source ) {
239
- $post_data['source'] = $source->source;
240
  }
241
 
242
  /**
@@ -247,7 +265,7 @@ abstract class WC_Stripe_Payment_Gateway extends WC_Payment_Gateway_CC {
247
  * @param WC_Order $order
248
  * @param object $source
249
  */
250
- return apply_filters( 'wc_stripe_generate_payment_request', $post_data, $order, $source );
251
  }
252
 
253
  /**
@@ -260,10 +278,10 @@ abstract class WC_Stripe_Payment_Gateway extends WC_Payment_Gateway_CC {
260
 
261
  $captured = ( isset( $response->captured ) && $response->captured ) ? 'yes' : 'no';
262
 
263
- // Store charge data
264
  WC_Stripe_Helper::is_pre_30() ? update_post_meta( $order_id, '_stripe_charge_captured', $captured ) : $order->update_meta_data( '_stripe_charge_captured', $captured );
265
 
266
- // Store other data such as fees
267
  if ( isset( $response->balance_transaction ) && isset( $response->balance_transaction->fee ) ) {
268
  // Fees and Net needs to both come from Stripe to be accurate as the returned
269
  // values are in the local currency of the Stripe account, not from WC.
@@ -280,7 +298,9 @@ abstract class WC_Stripe_Payment_Gateway extends WC_Payment_Gateway_CC {
280
  * take care of the status changes.
281
  */
282
  if ( 'pending' === $response->status ) {
283
- if ( ! wc_string_to_bool( get_post_meta( $order_id, '_order_stock_reduced', true ) ) ) {
 
 
284
  WC_Stripe_Helper::is_pre_30() ? $order->reduce_order_stock() : wc_reduce_stock_levels( $order_id );
285
  }
286
 
@@ -371,18 +391,17 @@ abstract class WC_Stripe_Payment_Gateway extends WC_Payment_Gateway_CC {
371
  }
372
 
373
  /**
374
- * Create source object by source id.
375
  *
376
  * @since 4.0.3
 
377
  */
378
- public function get_source_object() {
379
- $source = ! empty( $_POST['stripe_source'] ) ? wc_clean( $_POST['stripe_source'] ) : '';
380
-
381
- if ( empty( $source ) ) {
382
  return '';
383
  }
384
 
385
- $source_object = WC_Stripe_API::retrieve( 'sources/' . $source );
386
 
387
  if ( ! empty( $source_object->error ) ) {
388
  throw new WC_Stripe_Exception( print_r( $source_object, true ), $source_object->error->message );
@@ -417,6 +436,17 @@ abstract class WC_Stripe_Payment_Gateway extends WC_Payment_Gateway_CC {
417
  return ( $source_object && 'three_d_secure' === $source_object->type );
418
  }
419
 
 
 
 
 
 
 
 
 
 
 
 
420
  /**
421
  * Creates the 3DS source for charge.
422
  *
@@ -452,24 +482,25 @@ abstract class WC_Stripe_Payment_Gateway extends WC_Payment_Gateway_CC {
452
  *
453
  * @since 3.1.0
454
  * @version 4.0.0
455
- * @param object $source_object
456
  * @param string $user_id
457
  * @param bool $force_save_source Should we force save payment source.
458
  *
459
  * @throws Exception When card was not added or for and invalid card.
460
  * @return object
461
  */
462
- public function prepare_source( $source_object = '', $user_id, $force_save_source = false ) {
463
  $customer = new WC_Stripe_Customer( $user_id );
464
  $set_customer = true;
465
  $force_save_source = apply_filters( 'wc_stripe_force_save_source', $force_save_source, $customer );
 
466
  $source_id = '';
467
  $wc_token_id = false;
468
  $payment_method = isset( $_POST['payment_method'] ) ? wc_clean( $_POST['payment_method'] ) : 'stripe';
469
 
470
  // New CC info was entered and we have a new source to process.
471
- if ( ! empty( $source_object ) ) {
472
- $source_id = $source_object->id;
 
473
 
474
  // This checks to see if customer opted to save the payment method to file.
475
  $maybe_saved_card = isset( $_POST[ 'wc-' . $payment_method . '-new-payment-method' ] ) && ! empty( $_POST[ 'wc-' . $payment_method . '-new-payment-method' ] );
@@ -487,7 +518,7 @@ abstract class WC_Stripe_Payment_Gateway extends WC_Payment_Gateway_CC {
487
  }
488
  }
489
  } elseif ( isset( $_POST[ 'wc-' . $payment_method . '-payment-token' ] ) && 'new' !== $_POST[ 'wc-' . $payment_method . '-payment-token' ] ) {
490
- // Use an existing token, and then process the payment
491
  $wc_token_id = wc_clean( $_POST[ 'wc-' . $payment_method . '-payment-token' ] );
492
  $wc_token = WC_Payment_Tokens::get( $wc_token_id );
493
 
@@ -520,10 +551,15 @@ abstract class WC_Stripe_Payment_Gateway extends WC_Payment_Gateway_CC {
520
  $customer_id = $customer->get_id() ? $customer->get_id() : false;
521
  }
522
 
 
 
 
 
523
  return (object) array(
524
- 'token_id' => $wc_token_id,
525
- 'customer' => $customer_id,
526
- 'source' => $source_id,
 
527
  );
528
  }
529
 
@@ -624,7 +660,7 @@ abstract class WC_Stripe_Payment_Gateway extends WC_Payment_Gateway_CC {
624
  * e.g usage would be after a refund.
625
  *
626
  * @since 4.0.0
627
- * @version 4.0.0
628
  * @param object $order The order object
629
  * @param int $balance_transaction_id
630
  */
@@ -637,8 +673,16 @@ abstract class WC_Stripe_Payment_Gateway extends WC_Payment_Gateway_CC {
637
  if ( isset( $balance_transaction ) && isset( $balance_transaction->fee ) ) {
638
  // Fees and Net needs to both come from Stripe to be accurate as the returned
639
  // values are in the local currency of the Stripe account, not from WC.
640
- $fee = ! empty( $balance_transaction->fee ) ? WC_Stripe_Helper::format_balance_fee( $balance_transaction, 'fee' ) : 0;
641
- $net = ! empty( $balance_transaction->net ) ? WC_Stripe_Helper::format_balance_fee( $balance_transaction, 'net' ) : 0;
 
 
 
 
 
 
 
 
642
 
643
  WC_Stripe_Helper::is_pre_30() ? update_post_meta( $order_id, self::META_NAME_FEE, $fee ) : $order->update_meta_data( self::META_NAME_FEE, $fee );
644
  WC_Stripe_Helper::is_pre_30() ? update_post_meta( $order_id, self::META_NAME_NET, $net ) : $order->update_meta_data( self::META_NAME_NET, $net );
@@ -697,6 +741,8 @@ abstract class WC_Stripe_Payment_Gateway extends WC_Payment_Gateway_CC {
697
 
698
  WC_Stripe_Logger::log( "Info: Beginning refund for order {$order->get_transaction_id()} for the amount of {$amount}" );
699
 
 
 
700
  $response = WC_Stripe_API::request( $request, 'refunds' );
701
 
702
  if ( ! empty( $response->error ) ) {
@@ -776,4 +822,58 @@ abstract class WC_Stripe_Payment_Gateway extends WC_Payment_Gateway_CC {
776
  'redirect' => wc_get_endpoint_url( 'payment-methods' ),
777
  );
778
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
779
  }
25
  return (
26
  'invalid_request_error' === $error->type ||
27
  'idempotency_error' === $error->type ||
28
+ 'rate_limit_error' === $error->type ||
29
+ 'api_connection_error' === $error->type ||
30
+ 'api_error' === $error->type
31
  );
32
  }
33
 
182
  return esc_url_raw( add_query_arg( array( 'utm_nooverride' => '1' ), $this->get_return_url() ) );
183
  }
184
 
185
+ /**
186
+ * Is $order_id a subscription?
187
+ * @param int $order_id
188
+ * @return boolean
189
+ */
190
+ public function has_subscription( $order_id ) {
191
+ return ( function_exists( 'wcs_order_contains_subscription' ) && ( wcs_order_contains_subscription( $order_id ) || wcs_is_subscription( $order_id ) || wcs_order_contains_renewal( $order_id ) ) );
192
+ }
193
+
194
  /**
195
  * Generate the request for the payment.
196
  *
197
  * @since 3.1.0
198
  * @version 4.0.0
199
  * @param WC_Order $order
200
+ * @param object $prepared_source
201
  * @return array()
202
  */
203
+ public function generate_payment_request( $order, $prepared_source ) {
204
  $settings = get_option( 'woocommerce_stripe_settings', array() );
205
  $statement_descriptor = ! empty( $settings['statement_descriptor'] ) ? str_replace( "'", '', $settings['statement_descriptor'] ) : '';
206
  $capture = ! empty( $settings['capture'] ) && 'yes' === $settings['capture'] ? true : false;
240
  'order_id' => WC_Stripe_Helper::is_pre_30() ? $order->id : $order->get_id(),
241
  );
242
 
243
+ if ( $this->has_subscription( WC_Stripe_Helper::is_pre_30() ? $order->id : $order->get_id() ) ) {
244
+ $metadata += array(
245
+ 'payment_type' => 'recurring',
246
+ 'site_url' => esc_url( get_site_url() ),
247
+ );
248
+ }
249
 
250
+ $post_data['metadata'] = apply_filters( 'wc_stripe_payment_metadata', $metadata, $order, $prepared_source );
251
+
252
+ if ( $prepared_source->customer ) {
253
+ $post_data['customer'] = $prepared_source->customer;
254
  }
255
 
256
+ if ( $prepared_source->source ) {
257
+ $post_data['source'] = $prepared_source->source;
258
  }
259
 
260
  /**
265
  * @param WC_Order $order
266
  * @param object $source
267
  */
268
+ return apply_filters( 'wc_stripe_generate_payment_request', $post_data, $order, $prepared_source );
269
  }
270
 
271
  /**
278
 
279
  $captured = ( isset( $response->captured ) && $response->captured ) ? 'yes' : 'no';
280
 
281
+ // Store charge data.
282
  WC_Stripe_Helper::is_pre_30() ? update_post_meta( $order_id, '_stripe_charge_captured', $captured ) : $order->update_meta_data( '_stripe_charge_captured', $captured );
283
 
284
+ // Store other data such as fees.
285
  if ( isset( $response->balance_transaction ) && isset( $response->balance_transaction->fee ) ) {
286
  // Fees and Net needs to both come from Stripe to be accurate as the returned
287
  // values are in the local currency of the Stripe account, not from WC.
298
  * take care of the status changes.
299
  */
300
  if ( 'pending' === $response->status ) {
301
+ $order_stock_reduced = WC_Stripe_Helper::is_pre_30() ? get_post_meta( $order_id, '_order_stock_reduced', true ) : $order->get_meta( '_order_stock_reduced', true );
302
+
303
+ if ( ! $order_stock_reduced ) {
304
  WC_Stripe_Helper::is_pre_30() ? $order->reduce_order_stock() : wc_reduce_stock_levels( $order_id );
305
  }
306
 
391
  }
392
 
393
  /**
394
+ * Get source object by source id.
395
  *
396
  * @since 4.0.3
397
+ * @param string $source_id The source ID to get source object for.
398
  */
399
+ public function get_source_object( $source_id = '' ) {
400
+ if ( empty( $source_id ) ) {
 
 
401
  return '';
402
  }
403
 
404
+ $source_object = WC_Stripe_API::retrieve( 'sources/' . $source_id );
405
 
406
  if ( ! empty( $source_object->error ) ) {
407
  throw new WC_Stripe_Exception( print_r( $source_object, true ), $source_object->error->message );
436
  return ( $source_object && 'three_d_secure' === $source_object->type );
437
  }
438
 
439
+ /**
440
+ * Checks if card is a prepaid card.
441
+ *
442
+ * @since 4.0.6
443
+ * @param object $source_object
444
+ * @return bool
445
+ */
446
+ public function is_prepaid_card( $source_object ) {
447
+ return ( $source_object && 'token' === $source_object->object && 'prepaid' === $source_object->card->funding );
448
+ }
449
+
450
  /**
451
  * Creates the 3DS source for charge.
452
  *
482
  *
483
  * @since 3.1.0
484
  * @version 4.0.0
 
485
  * @param string $user_id
486
  * @param bool $force_save_source Should we force save payment source.
487
  *
488
  * @throws Exception When card was not added or for and invalid card.
489
  * @return object
490
  */
491
+ public function prepare_source( $user_id, $force_save_source = false ) {
492
  $customer = new WC_Stripe_Customer( $user_id );
493
  $set_customer = true;
494
  $force_save_source = apply_filters( 'wc_stripe_force_save_source', $force_save_source, $customer );
495
+ $source_object = '';
496
  $source_id = '';
497
  $wc_token_id = false;
498
  $payment_method = isset( $_POST['payment_method'] ) ? wc_clean( $_POST['payment_method'] ) : 'stripe';
499
 
500
  // New CC info was entered and we have a new source to process.
501
+ if ( ! empty( $_POST['stripe_source'] ) ) {
502
+ $source_object = self::get_source_object( wc_clean( $_POST['stripe_source'] ) );
503
+ $source_id = $source_object->id;
504
 
505
  // This checks to see if customer opted to save the payment method to file.
506
  $maybe_saved_card = isset( $_POST[ 'wc-' . $payment_method . '-new-payment-method' ] ) && ! empty( $_POST[ 'wc-' . $payment_method . '-new-payment-method' ] );
518
  }
519
  }
520
  } elseif ( isset( $_POST[ 'wc-' . $payment_method . '-payment-token' ] ) && 'new' !== $_POST[ 'wc-' . $payment_method . '-payment-token' ] ) {
521
+ // Use an existing token, and then process the payment.
522
  $wc_token_id = wc_clean( $_POST[ 'wc-' . $payment_method . '-payment-token' ] );
523
  $wc_token = WC_Payment_Tokens::get( $wc_token_id );
524
 
551
  $customer_id = $customer->get_id() ? $customer->get_id() : false;
552
  }
553
 
554
+ if ( empty( $source_object ) ) {
555
+ $source_object = self::get_source_object( $source_id );
556
+ }
557
+
558
  return (object) array(
559
+ 'token_id' => $wc_token_id,
560
+ 'customer' => $customer_id,
561
+ 'source' => $source_id,
562
+ 'source_object' => $source_object,
563
  );
564
  }
565
 
660
  * e.g usage would be after a refund.
661
  *
662
  * @since 4.0.0
663
+ * @version 4.0.6
664
  * @param object $order The order object
665
  * @param int $balance_transaction_id
666
  */
673
  if ( isset( $balance_transaction ) && isset( $balance_transaction->fee ) ) {
674
  // Fees and Net needs to both come from Stripe to be accurate as the returned
675
  // values are in the local currency of the Stripe account, not from WC.
676
+ $fee_refund = ! empty( $balance_transaction->fee ) ? WC_Stripe_Helper::format_balance_fee( $balance_transaction, 'fee' ) : 0;
677
+ $net_refund = ! empty( $balance_transaction->net ) ? WC_Stripe_Helper::format_balance_fee( $balance_transaction, 'net' ) : 0;
678
+
679
+ // Current data fee & net.
680
+ $fee_current = WC_Stripe_Helper::is_pre_30() ? get_post_meta( $order_id, self::META_NAME_FEE, true ) : $order->get_meta( self::META_NAME_FEE, true );
681
+ $net_current = WC_Stripe_Helper::is_pre_30() ? get_post_meta( $order_id, self::META_NAME_NET, true ) : $order->get_meta( self::META_NAME_NET, true );
682
+
683
+ // Calculation.
684
+ $fee = (float) $fee_current + (float) $fee_refund;
685
+ $net = (float) $net_current + (float) $net_refund;
686
 
687
  WC_Stripe_Helper::is_pre_30() ? update_post_meta( $order_id, self::META_NAME_FEE, $fee ) : $order->update_meta_data( self::META_NAME_FEE, $fee );
688
  WC_Stripe_Helper::is_pre_30() ? update_post_meta( $order_id, self::META_NAME_NET, $net ) : $order->update_meta_data( self::META_NAME_NET, $net );
741
 
742
  WC_Stripe_Logger::log( "Info: Beginning refund for order {$order->get_transaction_id()} for the amount of {$amount}" );
743
 
744
+ $request = apply_filters( 'wc_stripe_refund_request', $request, $order );
745
+
746
  $response = WC_Stripe_API::request( $request, 'refunds' );
747
 
748
  if ( ! empty( $response->error ) ) {
822
  'redirect' => wc_get_endpoint_url( 'payment-methods' ),
823
  );
824
  }
825
+
826
+ /**
827
+ * Gets the locale with normalization that only Stripe accepts.
828
+ *
829
+ * @since 4.0.6
830
+ * @return string $locale
831
+ */
832
+ public function get_locale() {
833
+ $locale = get_locale();
834
+
835
+ /*
836
+ * Stripe expects Norwegian to only be passed NO.
837
+ * But WP has different dialects.
838
+ */
839
+ if ( 'NO' === substr( $locale, 3, 2 ) ) {
840
+ $locale = 'no';
841
+ } else {
842
+ $locale = substr( get_locale(), 0, 2 );
843
+ }
844
+
845
+ return $locale;
846
+ }
847
+
848
+ /**
849
+ * Change the idempotency key so charge can
850
+ * process order as a different transaction.
851
+ *
852
+ * @since 4.0.6
853
+ * @param string $idempotency_key
854
+ * @param array $request
855
+ */
856
+ public function change_idempotency_key( $idempotency_key, $request ) {
857
+ $customer = ! empty( $request['customer'] ) ? $request['customer'] : '';
858
+ $source = ! empty( $request['source'] ) ? $request['source'] : $customer;
859
+ $count = $this->retry_interval;
860
+
861
+ return $request['metadata']['order_id'] . '-' . $count . '-' . $source;
862
+ }
863
+
864
+ /**
865
+ * Checks if request is the original to prevent double processing
866
+ * on WC side. The original-request header and request-id header
867
+ * needs to be the same to mean its the original request.
868
+ *
869
+ * @since 4.0.6
870
+ * @param array $headers
871
+ */
872
+ public function is_original_request( $headers ) {
873
+ if ( $headers['original-request'] === $headers['request-id'] ) {
874
+ return true;
875
+ }
876
+
877
+ return false;
878
+ }
879
  }
includes/class-wc-gateway-stripe.php CHANGED
@@ -9,6 +9,11 @@ if ( ! defined( 'ABSPATH' ) ) {
9
  * @extends WC_Payment_Gateway
10
  */
11
  class WC_Gateway_Stripe extends WC_Stripe_Payment_Gateway {
 
 
 
 
 
12
  public $retry_interval;
13
 
14
  /**
@@ -81,13 +86,6 @@ class WC_Gateway_Stripe extends WC_Stripe_Payment_Gateway {
81
  */
82
  public $payment_request;
83
 
84
- /**
85
- * Apple Pay Domain Set.
86
- *
87
- * @var bool
88
- */
89
- public $apple_pay_domain_set;
90
-
91
  /**
92
  * Is test mode active?
93
  *
@@ -95,13 +93,6 @@ class WC_Gateway_Stripe extends WC_Stripe_Payment_Gateway {
95
  */
96
  public $testmode;
97
 
98
- /**
99
- * Stores Apple Pay domain verification issues.
100
- *
101
- * @var string
102
- */
103
- public $apple_pay_verify_notice;
104
-
105
  /**
106
  * Inline CC form styling
107
  *
@@ -113,7 +104,7 @@ class WC_Gateway_Stripe extends WC_Stripe_Payment_Gateway {
113
  * Constructor
114
  */
115
  public function __construct() {
116
- $this->retry_interval = 2;
117
  $this->id = 'stripe';
118
  $this->method_title = __( 'Stripe', 'woocommerce-gateway-stripe' );
119
  /* translators: 1) link to Stripe register page 2) link to Stripe api keys page */
@@ -159,8 +150,6 @@ class WC_Gateway_Stripe extends WC_Stripe_Payment_Gateway {
159
  $this->publishable_key = $this->testmode ? $this->get_option( 'test_publishable_key' ) : $this->get_option( 'publishable_key' );
160
  $this->bitcoin = 'USD' === strtoupper( get_woocommerce_currency() ) && 'yes' === $this->get_option( 'stripe_bitcoin' );
161
  $this->payment_request = 'yes' === $this->get_option( 'payment_request', 'yes' );
162
- $this->apple_pay_domain_set = 'yes' === $this->get_option( 'apple_pay_domain_set', 'no' );
163
- $this->apple_pay_verify_notice = '';
164
 
165
  if ( $this->stripe_checkout ) {
166
  $this->order_button_text = __( 'Continue to payment', 'woocommerce-gateway-stripe' );
@@ -168,15 +157,26 @@ class WC_Gateway_Stripe extends WC_Stripe_Payment_Gateway {
168
 
169
  WC_Stripe_API::set_secret_key( $this->secret_key );
170
 
171
- $this->init_apple_pay();
172
-
173
  // Hooks.
174
  add_action( 'wp_enqueue_scripts', array( $this, 'payment_scripts' ) );
175
  add_action( 'admin_enqueue_scripts', array( $this, 'admin_scripts' ) );
176
- add_action( 'admin_notices', array( $this, 'admin_notices' ) );
177
  add_action( 'woocommerce_update_options_payment_gateways_' . $this->id, array( $this, 'process_admin_options' ) );
178
  }
179
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
180
  /**
181
  * Checks if gateway should be available to use.
182
  *
@@ -219,149 +219,6 @@ class WC_Gateway_Stripe extends WC_Stripe_Payment_Gateway {
219
  return apply_filters( 'woocommerce_gateway_icon', $icons_str, $this->id );
220
  }
221
 
222
- /**
223
- * Initializes Apple Pay process on settings page.
224
- *
225
- * @since 3.1.0
226
- * @version 3.1.0
227
- */
228
- public function init_apple_pay() {
229
- if (
230
- is_admin() &&
231
- isset( $_GET['page'] ) && 'wc-settings' === $_GET['page'] &&
232
- isset( $_GET['tab'] ) && 'checkout' === $_GET['tab'] &&
233
- isset( $_GET['section'] ) && 'stripe' === $_GET['section'] &&
234
- $this->payment_request
235
- ) {
236
- $this->process_apple_pay_verification();
237
- }
238
- }
239
-
240
- /**
241
- * Registers the domain with Stripe/Apple Pay
242
- *
243
- * @since 3.1.0
244
- * @version 3.1.0
245
- * @param string $secret_key
246
- */
247
- private function register_apple_pay_domain( $secret_key = '' ) {
248
- if ( empty( $secret_key ) ) {
249
- throw new Exception( __( 'Unable to verify domain - missing secret key.', 'woocommerce-gateway-stripe' ) );
250
- }
251
-
252
- $endpoint = 'https://api.stripe.com/v1/apple_pay/domains';
253
-
254
- $data = array(
255
- 'domain_name' => $_SERVER['HTTP_HOST'],
256
- );
257
-
258
- $headers = array(
259
- 'User-Agent' => 'WooCommerce Stripe Apple Pay',
260
- 'Authorization' => 'Bearer ' . $secret_key,
261
- );
262
-
263
- $response = wp_remote_post( $endpoint, array(
264
- 'headers' => $headers,
265
- 'body' => http_build_query( $data ),
266
- ) );
267
-
268
- if ( is_wp_error( $response ) ) {
269
- /* translators: error message */
270
- throw new Exception( sprintf( __( 'Unable to verify domain - %s', 'woocommerce-gateway-stripe' ), $response->get_error_message() ) );
271
- }
272
-
273
- if ( 200 !== $response['response']['code'] ) {
274
- $parsed_response = json_decode( $response['body'] );
275
-
276
- $this->apple_pay_verify_notice = $parsed_response->error->message;
277
-
278
- /* translators: error message */
279
- throw new Exception( sprintf( __( 'Unable to verify domain - %s', 'woocommerce-gateway-stripe' ), $parsed_response->error->message ) );
280
- }
281
- }
282
-
283
- /**
284
- * Processes the Apple Pay domain verification.
285
- *
286
- * @since 3.1.0
287
- * @version 3.1.0
288
- */
289
- public function process_apple_pay_verification() {
290
- $gateway_settings = get_option( 'woocommerce_stripe_settings', array() );
291
-
292
- try {
293
- $path = untrailingslashit( $_SERVER['DOCUMENT_ROOT'] );
294
- $dir = '.well-known';
295
- $file = 'apple-developer-merchantid-domain-association';
296
- $fullpath = $path . '/' . $dir . '/' . $file;
297
-
298
- if ( ! empty( $gateway_settings['apple_pay_domain_set'] ) && 'yes' === $gateway_settings['apple_pay_domain_set'] && file_exists( $fullpath ) ) {
299
- return;
300
- }
301
-
302
- if ( ! file_exists( $path . '/' . $dir ) ) {
303
- if ( ! @mkdir( $path . '/' . $dir, 0755 ) ) {
304
- throw new Exception( __( 'Unable to create domain association folder to domain root.', 'woocommerce-gateway-stripe' ) );
305
- }
306
- }
307
-
308
- if ( ! file_exists( $fullpath ) ) {
309
- if ( ! @copy( WC_STRIPE_PLUGIN_PATH . '/' . $file, $fullpath ) ) {
310
- throw new Exception( __( 'Unable to copy domain association file to domain root.', 'woocommerce-gateway-stripe' ) );
311
- }
312
- }
313
-
314
- // At this point then the domain association folder and file should be available.
315
- // Proceed to verify/and or verify again.
316
- $this->register_apple_pay_domain( $this->secret_key );
317
-
318
- // No errors to this point, verification success!
319
- $gateway_settings['apple_pay_domain_set'] = 'yes';
320
- $this->apple_pay_domain_set = true;
321
-
322
- update_option( 'woocommerce_stripe_settings', $gateway_settings );
323
-
324
- WC_Stripe_Logger::log( 'Your domain has been verified with Apple Pay!' );
325
-
326
- } catch ( Exception $e ) {
327
- $gateway_settings['apple_pay_domain_set'] = 'no';
328
-
329
- update_option( 'woocommerce_stripe_settings', $gateway_settings );
330
-
331
- WC_Stripe_Logger::log( 'Error: ' . $e->getMessage() );
332
- }
333
- }
334
-
335
- /**
336
- * Check if SSL is enabled and notify the user
337
- */
338
- public function admin_notices() {
339
- if ( 'no' === $this->enabled ) {
340
- return;
341
- }
342
-
343
- if ( $this->payment_request && ! empty( $this->apple_pay_verify_notice ) ) {
344
- $allowed_html = array(
345
- 'a' => array(
346
- 'href' => array(),
347
- 'title' => array(),
348
- ),
349
- );
350
-
351
- echo '<div class="error stripe-apple-pay-message"><p>' . wp_kses( make_clickable( $this->apple_pay_verify_notice ), $allowed_html ) . '</p></div>';
352
- }
353
-
354
- /**
355
- * Apple pay is enabled by default and domain verification initializes
356
- * when setting screen is displayed. So if domain verification is not set,
357
- * something went wrong so lets notify user.
358
- */
359
- if ( ! empty( $this->secret_key ) && $this->payment_request && ! $this->apple_pay_domain_set ) {
360
- /* translators: 1) HTML anchor open tag 2) HTML anchor closing tag */
361
- echo '<div class="error stripe-apple-pay-message"><p>' . sprintf( __( 'Apple Pay domain verification failed. Please check the %1$slog%2$s to see the issue. (Logging must be enabled to see recorded logs)', 'woocommerce-gateway-stripe' ), '<a href="' . admin_url( 'admin.php?page=wc-status&tab=logs' ) . '">', '</a>' ) . '</p></div>';
362
- }
363
- }
364
-
365
  /**
366
  * Initialise Gateway Settings Form Fields
367
  */
@@ -407,7 +264,7 @@ class WC_Gateway_Stripe extends WC_Stripe_Payment_Gateway {
407
  data-currency="' . esc_attr( strtolower( get_woocommerce_currency() ) ) . '"
408
  data-image="' . esc_attr( $this->stripe_checkout_image ) . '"
409
  data-bitcoin="' . esc_attr( ( $this->bitcoin && $this->capture ) ? 'true' : 'false' ) . '"
410
- data-locale="' . esc_attr( apply_filters( 'wc_stripe_checkout_locale', substr( get_locale(), 0, 2 ) ) ) . '"
411
  data-three-d-secure="' . esc_attr( $this->three_d_secure ? 'true' : 'false' ) . '"
412
  data-allow-remember-me="' . esc_attr( $this->saved_cards ? 'true' : 'false' ) . '">';
413
 
@@ -429,6 +286,7 @@ class WC_Gateway_Stripe extends WC_Stripe_Payment_Gateway {
429
  if ( apply_filters( 'wc_stripe_use_elements_checkout_form', true ) ) {
430
  $this->elements_form();
431
  } else {
 
432
  $this->form();
433
  echo '<div class="stripe-source-errors" role="alert"></div>';
434
  }
@@ -523,6 +381,23 @@ class WC_Gateway_Stripe extends WC_Stripe_Payment_Gateway {
523
  return;
524
  }
525
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
526
  $suffix = defined( 'SCRIPT_DEBUG' ) && SCRIPT_DEBUG ? '' : '.min';
527
 
528
  wp_register_style( 'stripe_paymentfonts', plugins_url( 'assets/css/stripe-paymentfonts.css', WC_STRIPE_MAIN_FILE ), array(), '1.2.5' );
@@ -560,7 +435,7 @@ class WC_Gateway_Stripe extends WC_Stripe_Payment_Gateway {
560
  $stripe_params['allow_prepaid_card'] = apply_filters( 'wc_stripe_allow_prepaid_card', true ) ? 'yes' : 'no';
561
  $stripe_params['inline_cc_form'] = $this->inline_cc_form ? 'yes' : 'no';
562
  $stripe_params['stripe_checkout_require_billing_address'] = apply_filters( 'wc_stripe_checkout_require_billing_address', false ) ? 'yes' : 'no';
563
- $stripe_params['is_checkout'] = ( is_checkout() && empty( $_GET['pay_for_order'] ) );
564
  $stripe_params['return_url'] = $this->get_stripe_return_url();
565
  $stripe_params['ajaxurl'] = WC_AJAX::get_endpoint( '%%endpoint%%' );
566
  $stripe_params['stripe_nonce'] = wp_create_nonce( '_wc_stripe_nonce' );
@@ -568,8 +443,9 @@ class WC_Gateway_Stripe extends WC_Stripe_Payment_Gateway {
568
  $stripe_params['use_elements'] = apply_filters( 'wc_stripe_use_elements_checkout_form', true ) ? 'yes' : 'no';
569
  $stripe_params['elements_options'] = apply_filters( 'wc_stripe_elements_options', array() );
570
  $stripe_params['is_stripe_checkout'] = $this->stripe_checkout ? 'yes' : 'no';
571
- $stripe_params['is_change_payment_page'] = ( isset( $_GET['pay_for_order'] ) || isset( $_GET['change_payment_method'] ) ) ? 'yes' : 'no';
572
- $stripe_params['is_add_payment_method_page'] = is_add_payment_method_page() ? 'yes' : 'no';
 
573
  $stripe_params['elements_styling'] = apply_filters( 'wc_stripe_elements_styling', false );
574
  $stripe_params['elements_classes'] = apply_filters( 'wc_stripe_elements_classes', false );
575
 
@@ -613,15 +489,13 @@ class WC_Gateway_Stripe extends WC_Stripe_Payment_Gateway {
613
  $new_stripe_customer->create_customer();
614
  }
615
 
616
- $source_object = $this->get_source_object();
617
- $prepared_source = $this->prepare_source( $source_object, get_current_user_id(), $force_save_source );
618
 
619
  // Check if we don't allow prepaid credit cards.
620
- if ( ! apply_filters( 'wc_stripe_allow_prepaid_card', true ) ) {
621
- if ( $source_object && 'token' === $source_object->object && 'prepaid' === $source_object->card->funding ) {
622
- $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' );
623
- throw new WC_Stripe_Exception( print_r( $source_object, true ), $localized_message );
624
- }
625
  }
626
 
627
  if ( empty( $prepared_source->source ) ) {
@@ -674,20 +548,36 @@ class WC_Gateway_Stripe extends WC_Stripe_Payment_Gateway {
674
 
675
  WC_Stripe_Logger::log( "Info: Begin processing payment for order $order_id for the amount of {$order->get_total()}" );
676
 
 
 
 
 
 
 
 
677
  // Make the request.
678
  $response = WC_Stripe_API::request( $this->generate_payment_request( $order, $prepared_source ) );
679
 
680
  if ( ! empty( $response->error ) ) {
681
- // If it is an API error such connection or server, let's retry.
682
- if ( 'api_connection_error' === $response->error->type || 'api_error' === $response->error->type ) {
683
- if ( $retry ) {
684
- sleep( 5 );
685
- return $this->process_payment( $order_id, false, $force_save_source );
686
  } else {
687
- $localized_message = 'API connection error and retries exhausted.';
688
- $order->add_order_note( $localized_message );
689
- throw new WC_Stripe_Exception( print_r( $response, true ), $localized_message );
690
  }
 
 
 
 
 
 
 
 
 
691
  }
692
 
693
  // We want to retry.
@@ -702,6 +592,7 @@ class WC_Gateway_Stripe extends WC_Stripe_Payment_Gateway {
702
  sleep( $this->retry_interval );
703
 
704
  $this->retry_interval++;
 
705
  return $this->process_payment( $order_id, true, $force_save_source );
706
  } else {
707
  $localized_message = __( 'On going requests error and retries exhausted.', 'woocommerce-gateway-stripe' );
@@ -710,27 +601,6 @@ class WC_Gateway_Stripe extends WC_Stripe_Payment_Gateway {
710
  }
711
  }
712
 
713
- // Customer param wrong? The user may have been deleted on stripe's end. Remove customer_id. Can be retried without.
714
- if ( preg_match( '/No such customer/i', $response->error->message ) && $retry ) {
715
- if ( WC_Stripe_Helper::is_pre_30() ) {
716
- delete_user_meta( $order->customer_user, '_stripe_customer_id' );
717
- delete_post_meta( $order_id, '_stripe_customer_id' );
718
- } else {
719
- delete_user_meta( $order->get_customer_id(), '_stripe_customer_id' );
720
- $order->delete_meta_data( '_stripe_customer_id' );
721
- $order->save();
722
- }
723
-
724
- return $this->process_payment( $order_id, false, $force_save_source );
725
- } elseif ( preg_match( '/No such token/i', $response->error->message ) && $prepared_source->token_id ) {
726
- // Source param wrong? The CARD may have been deleted on stripe's end. Remove token and show message.
727
- $wc_token = WC_Payment_Tokens::get( $prepared_source->token_id );
728
- $wc_token->delete();
729
- $localized_message = __( 'This card is no longer available and has been removed.', 'woocommerce-gateway-stripe' );
730
- $order->add_order_note( $localized_message );
731
- throw new WC_Stripe_Exception( print_r( $response, true ), $localized_message );
732
- }
733
-
734
  $localized_messages = WC_Stripe_Helper::get_localized_messages();
735
 
736
  if ( 'card_error' === $response->error->type ) {
@@ -767,6 +637,9 @@ class WC_Gateway_Stripe extends WC_Stripe_Payment_Gateway {
767
 
768
  do_action( 'wc_gateway_stripe_process_payment_error', $e, $order );
769
 
 
 
 
770
  if ( $order->has_status( array( 'pending', 'failed' ) ) ) {
771
  $this->send_failed_order_email( $order_id );
772
  }
9
  * @extends WC_Payment_Gateway
10
  */
11
  class WC_Gateway_Stripe extends WC_Stripe_Payment_Gateway {
12
+ /**
13
+ * The delay between retries.
14
+ *
15
+ * @var int
16
+ */
17
  public $retry_interval;
18
 
19
  /**
86
  */
87
  public $payment_request;
88
 
 
 
 
 
 
 
 
89
  /**
90
  * Is test mode active?
91
  *
93
  */
94
  public $testmode;
95
 
 
 
 
 
 
 
 
96
  /**
97
  * Inline CC form styling
98
  *
104
  * Constructor
105
  */
106
  public function __construct() {
107
+ $this->retry_interval = 1;
108
  $this->id = 'stripe';
109
  $this->method_title = __( 'Stripe', 'woocommerce-gateway-stripe' );
110
  /* translators: 1) link to Stripe register page 2) link to Stripe api keys page */
150
  $this->publishable_key = $this->testmode ? $this->get_option( 'test_publishable_key' ) : $this->get_option( 'publishable_key' );
151
  $this->bitcoin = 'USD' === strtoupper( get_woocommerce_currency() ) && 'yes' === $this->get_option( 'stripe_bitcoin' );
152
  $this->payment_request = 'yes' === $this->get_option( 'payment_request', 'yes' );
 
 
153
 
154
  if ( $this->stripe_checkout ) {
155
  $this->order_button_text = __( 'Continue to payment', 'woocommerce-gateway-stripe' );
157
 
158
  WC_Stripe_API::set_secret_key( $this->secret_key );
159
 
 
 
160
  // Hooks.
161
  add_action( 'wp_enqueue_scripts', array( $this, 'payment_scripts' ) );
162
  add_action( 'admin_enqueue_scripts', array( $this, 'admin_scripts' ) );
 
163
  add_action( 'woocommerce_update_options_payment_gateways_' . $this->id, array( $this, 'process_admin_options' ) );
164
  }
165
 
166
+ /**
167
+ * Checks if keys are set.
168
+ *
169
+ * @since 4.0.6
170
+ * @return bool
171
+ */
172
+ public function are_keys_set() {
173
+ if ( empty( $this->secret_key ) || empty( $this->publishable_key ) ) {
174
+ return false;
175
+ }
176
+
177
+ return true;
178
+ }
179
+
180
  /**
181
  * Checks if gateway should be available to use.
182
  *
219
  return apply_filters( 'woocommerce_gateway_icon', $icons_str, $this->id );
220
  }
221
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
222
  /**
223
  * Initialise Gateway Settings Form Fields
224
  */
264
  data-currency="' . esc_attr( strtolower( get_woocommerce_currency() ) ) . '"
265
  data-image="' . esc_attr( $this->stripe_checkout_image ) . '"
266
  data-bitcoin="' . esc_attr( ( $this->bitcoin && $this->capture ) ? 'true' : 'false' ) . '"
267
+ data-locale="' . esc_attr( apply_filters( 'wc_stripe_checkout_locale', $this->get_locale() ) ) . '"
268
  data-three-d-secure="' . esc_attr( $this->three_d_secure ? 'true' : 'false' ) . '"
269
  data-allow-remember-me="' . esc_attr( $this->saved_cards ? 'true' : 'false' ) . '">';
270
 
286
  if ( apply_filters( 'wc_stripe_use_elements_checkout_form', true ) ) {
287
  $this->elements_form();
288
  } else {
289
+ WC_Stripe_Logger::log( 'DEPRECATED! Since version 4.0. Stripe Elements is used. This legacy credit card form will be removed by version 5.0!' );
290
  $this->form();
291
  echo '<div class="stripe-source-errors" role="alert"></div>';
292
  }
381
  return;
382
  }
383
 
384
+ // If Stripe is not enabled bail.
385
+ if ( 'no' === $this->enabled ) {
386
+ return;
387
+ }
388
+
389
+ // If keys are not set bail.
390
+ if ( ! $this->are_keys_set() ) {
391
+ WC_Stripe_Logger::log( 'Keys are not set correctly.' );
392
+ return;
393
+ }
394
+
395
+ // If no SSL bail.
396
+ if ( ! $this->testmode && ! is_ssl() ) {
397
+ WC_Stripe_Logger::log( 'Stripe requires SSL.' );
398
+ return;
399
+ }
400
+
401
  $suffix = defined( 'SCRIPT_DEBUG' ) && SCRIPT_DEBUG ? '' : '.min';
402
 
403
  wp_register_style( 'stripe_paymentfonts', plugins_url( 'assets/css/stripe-paymentfonts.css', WC_STRIPE_MAIN_FILE ), array(), '1.2.5' );
435
  $stripe_params['allow_prepaid_card'] = apply_filters( 'wc_stripe_allow_prepaid_card', true ) ? 'yes' : 'no';
436
  $stripe_params['inline_cc_form'] = $this->inline_cc_form ? 'yes' : 'no';
437
  $stripe_params['stripe_checkout_require_billing_address'] = apply_filters( 'wc_stripe_checkout_require_billing_address', false ) ? 'yes' : 'no';
438
+ $stripe_params['is_checkout'] = ( is_checkout() && empty( $_GET['pay_for_order'] ) ) ? 'yes' : 'no';
439
  $stripe_params['return_url'] = $this->get_stripe_return_url();
440
  $stripe_params['ajaxurl'] = WC_AJAX::get_endpoint( '%%endpoint%%' );
441
  $stripe_params['stripe_nonce'] = wp_create_nonce( '_wc_stripe_nonce' );
443
  $stripe_params['use_elements'] = apply_filters( 'wc_stripe_use_elements_checkout_form', true ) ? 'yes' : 'no';
444
  $stripe_params['elements_options'] = apply_filters( 'wc_stripe_elements_options', array() );
445
  $stripe_params['is_stripe_checkout'] = $this->stripe_checkout ? 'yes' : 'no';
446
+ $stripe_params['is_change_payment_page'] = isset( $_GET['change_payment_method'] ) ? 'yes' : 'no';
447
+ $stripe_params['is_pay_for_order_page'] = isset( $_GET['pay_for_order'] ) ? 'yes' : 'no';
448
+ $stripe_params['validate_modal_checkout'] = apply_filters( 'wc_stripe_validate_modal_checkout', false ) ? 'yes' : 'no';
449
  $stripe_params['elements_styling'] = apply_filters( 'wc_stripe_elements_styling', false );
450
  $stripe_params['elements_classes'] = apply_filters( 'wc_stripe_elements_classes', false );
451
 
489
  $new_stripe_customer->create_customer();
490
  }
491
 
492
+ $prepared_source = $this->prepare_source( get_current_user_id(), $force_save_source );
493
+ $source_object = $prepared_source->source_object;
494
 
495
  // Check if we don't allow prepaid credit cards.
496
+ if ( ! apply_filters( 'wc_stripe_allow_prepaid_card', true ) && $this->is_prepaid_card( $source_object ) ) {
497
+ $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' );
498
+ throw new WC_Stripe_Exception( print_r( $source_object, true ), $localized_message );
 
 
499
  }
500
 
501
  if ( empty( $prepared_source->source ) ) {
548
 
549
  WC_Stripe_Logger::log( "Info: Begin processing payment for order $order_id for the amount of {$order->get_total()}" );
550
 
551
+ /* If we're doing a retry and source is chargeable, we need to pass
552
+ * a different idempotency key and retry for success.
553
+ */
554
+ if ( 1 < $this->retry_interval && ! empty( $source_object ) && 'chargeable' === $source_object->status ) {
555
+ add_filter( 'wc_stripe_idempotency_key', array( $this, 'change_idempotency_key' ), 10, 2 );
556
+ }
557
+
558
  // Make the request.
559
  $response = WC_Stripe_API::request( $this->generate_payment_request( $order, $prepared_source ) );
560
 
561
  if ( ! empty( $response->error ) ) {
562
+ // Customer param wrong? The user may have been deleted on stripe's end. Remove customer_id. Can be retried without.
563
+ if ( preg_match( '/No such customer/i', $response->error->message ) && $retry ) {
564
+ if ( WC_Stripe_Helper::is_pre_30() ) {
565
+ delete_user_meta( $order->customer_user, '_stripe_customer_id' );
566
+ delete_post_meta( $order_id, '_stripe_customer_id' );
567
  } else {
568
+ delete_user_meta( $order->get_customer_id(), '_stripe_customer_id' );
569
+ $order->delete_meta_data( '_stripe_customer_id' );
570
+ $order->save();
571
  }
572
+
573
+ return $this->process_payment( $order_id, false, $force_save_source );
574
+ } elseif ( preg_match( '/No such token/i', $response->error->message ) && $prepared_source->token_id ) {
575
+ // Source param wrong? The CARD may have been deleted on stripe's end. Remove token and show message.
576
+ $wc_token = WC_Payment_Tokens::get( $prepared_source->token_id );
577
+ $wc_token->delete();
578
+ $localized_message = __( 'This card is no longer available and has been removed.', 'woocommerce-gateway-stripe' );
579
+ $order->add_order_note( $localized_message );
580
+ throw new WC_Stripe_Exception( print_r( $response, true ), $localized_message );
581
  }
582
 
583
  // We want to retry.
592
  sleep( $this->retry_interval );
593
 
594
  $this->retry_interval++;
595
+
596
  return $this->process_payment( $order_id, true, $force_save_source );
597
  } else {
598
  $localized_message = __( 'On going requests error and retries exhausted.', 'woocommerce-gateway-stripe' );
601
  }
602
  }
603
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
604
  $localized_messages = WC_Stripe_Helper::get_localized_messages();
605
 
606
  if ( 'card_error' === $response->error->type ) {
637
 
638
  do_action( 'wc_gateway_stripe_process_payment_error', $e, $order );
639
 
640
+ /* translators: error message */
641
+ $order->update_status( 'failed' );
642
+
643
  if ( $order->has_status( array( 'pending', 'failed' ) ) ) {
644
  $this->send_failed_order_email( $order_id );
645
  }
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 = '2018-01-23';
18
 
19
  /**
20
  * Secret API Key.
@@ -90,12 +90,13 @@ class WC_Stripe_API {
90
  * Send the request to Stripe's API
91
  *
92
  * @since 3.1.0
93
- * @version 4.0.0
94
  * @param array $request
95
  * @param string $api
 
96
  * @return array|WP_Error
97
  */
98
- public static function request( $request, $api = 'charges', $method = 'POST' ) {
99
  WC_Stripe_Logger::log( "{$api} request: " . print_r( $request, true ) );
100
 
101
  $headers = self::get_headers();
@@ -104,7 +105,7 @@ class WC_Stripe_API {
104
  $customer = ! empty( $request['customer'] ) ? $request['customer'] : '';
105
  $source = ! empty( $request['source'] ) ? $request['source'] : $customer;
106
 
107
- $headers['Idempotency-Key'] = $request['metadata']['order_id'] . '-' . $source;
108
  }
109
 
110
  $response = wp_safe_remote_post(
@@ -122,6 +123,10 @@ class WC_Stripe_API {
122
  throw new WC_Stripe_Exception( print_r( $response, true ), __( 'There was a problem connecting to the Stripe API endpoint.', 'woocommerce-gateway-stripe' ) );
123
  }
124
 
 
 
 
 
125
  return json_decode( $response['body'] );
126
  }
127
 
14
  * Stripe API Endpoint
15
  */
16
  const ENDPOINT = 'https://api.stripe.com/v1/';
17
+ const STRIPE_API_VERSION = '2018-02-06';
18
 
19
  /**
20
  * Secret API Key.
90
  * Send the request to Stripe's API
91
  *
92
  * @since 3.1.0
93
+ * @version 4.0.6
94
  * @param array $request
95
  * @param string $api
96
+ * @param bool $with_headers To get the response with headers.
97
  * @return array|WP_Error
98
  */
99
+ public static function request( $request, $api = 'charges', $method = 'POST', $with_headers = false ) {
100
  WC_Stripe_Logger::log( "{$api} request: " . print_r( $request, true ) );
101
 
102
  $headers = self::get_headers();
105
  $customer = ! empty( $request['customer'] ) ? $request['customer'] : '';
106
  $source = ! empty( $request['source'] ) ? $request['source'] : $customer;
107
 
108
+ $headers['Idempotency-Key'] = apply_filters( 'wc_stripe_idempotency_key', $request['metadata']['order_id'] . '-' . $source, $request );
109
  }
110
 
111
  $response = wp_safe_remote_post(
123
  throw new WC_Stripe_Exception( print_r( $response, true ), __( 'There was a problem connecting to the Stripe API endpoint.', 'woocommerce-gateway-stripe' ) );
124
  }
125
 
126
+ if ( $with_headers ) {
127
+ return array( 'headers' => wp_remote_retrieve_headers( $response ), 'body' => json_decode( $response['body'] ) );
128
+ }
129
+
130
  return json_decode( $response['body'] );
131
  }
132
 
includes/class-wc-stripe-apple-pay-registration.php ADDED
@@ -0,0 +1,244 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Stripe Apple Pay Registration Class.
4
+ *
5
+ * @since 4.0.6
6
+ */
7
+
8
+ if ( ! defined( 'ABSPATH' ) ) {
9
+ exit;
10
+ }
11
+
12
+ class WC_Stripe_Apple_Pay_Registration {
13
+ /**
14
+ * Enabled.
15
+ *
16
+ * @var
17
+ */
18
+ public $stripe_settings;
19
+
20
+ /**
21
+ * Main Stripe Enabled.
22
+ *
23
+ * @var bool
24
+ */
25
+ public $stripe_enabled;
26
+
27
+ /**
28
+ * Do we accept Payment Request?
29
+ *
30
+ * @var bool
31
+ */
32
+ public $payment_request;
33
+
34
+ /**
35
+ * Apple Pay Domain Set.
36
+ *
37
+ * @var bool
38
+ */
39
+ public $apple_pay_domain_set;
40
+
41
+ /**
42
+ * Testmode.
43
+ *
44
+ * @var bool
45
+ */
46
+ public $testmode;
47
+
48
+ /**
49
+ * Secret Key.
50
+ *
51
+ * @var string
52
+ */
53
+ public $secret_key;
54
+
55
+ /**
56
+ * Stores Apple Pay domain verification issues.
57
+ *
58
+ * @var string
59
+ */
60
+ public $apple_pay_verify_notice;
61
+
62
+ public function __construct() {
63
+ $this->stripe_settings = get_option( 'woocommerce_stripe_settings', array() );
64
+ $this->stripe_enabled = $this->get_option( 'enabled' );
65
+ $this->payment_request = 'yes' === $this->get_option( 'payment_request', 'yes' );
66
+ $this->apple_pay_domain_set = 'yes' === $this->get_option( 'apple_pay_domain_set', 'no' );
67
+ $this->apple_pay_verify_notice = '';
68
+ $this->testmode = 'yes' === $this->get_option( 'testmode', 'no' );
69
+ $this->secret_key = $this->testmode ? $this->get_option( 'test_secret_key' ) : $this->get_option( 'secret_key' );
70
+
71
+ if ( empty( $this->stripe_settings ) ) {
72
+ return;
73
+ }
74
+
75
+ $this->init_apple_pay();
76
+
77
+ add_action( 'admin_notices', array( $this, 'admin_notices' ) );
78
+ }
79
+
80
+ /**
81
+ * Gets the Stripe settings.
82
+ *
83
+ * @since 4.0.6
84
+ * @param string $setting
85
+ * @param string default
86
+ * @return string $setting_value
87
+ */
88
+ public function get_option( $setting = '', $default = '' ) {
89
+ if ( empty( $this->stripe_settings ) ) {
90
+ return $default;
91
+ }
92
+
93
+ if ( ! empty( $this->stripe_settings[ $setting ] ) ) {
94
+ return $this->stripe_settings[ $setting ];
95
+ }
96
+
97
+ return $default;
98
+ }
99
+
100
+ /**
101
+ * Initializes Apple Pay process on settings page.
102
+ *
103
+ * @since 3.1.0
104
+ * @version 3.1.0
105
+ */
106
+ public function init_apple_pay() {
107
+ if (
108
+ is_admin() &&
109
+ isset( $_GET['page'] ) && 'wc-settings' === $_GET['page'] &&
110
+ isset( $_GET['tab'] ) && 'checkout' === $_GET['tab'] &&
111
+ isset( $_GET['section'] ) && 'stripe' === $_GET['section'] &&
112
+ $this->payment_request
113
+ ) {
114
+ $this->process_apple_pay_verification();
115
+ }
116
+ }
117
+
118
+ /**
119
+ * Registers the domain with Stripe/Apple Pay
120
+ *
121
+ * @since 3.1.0
122
+ * @version 3.1.0
123
+ * @param string $secret_key
124
+ */
125
+ private function register_apple_pay_domain( $secret_key = '' ) {
126
+ if ( empty( $secret_key ) ) {
127
+ throw new Exception( __( 'Unable to verify domain - missing secret key.', 'woocommerce-gateway-stripe' ) );
128
+ }
129
+
130
+ $endpoint = 'https://api.stripe.com/v1/apple_pay/domains';
131
+
132
+ $data = array(
133
+ 'domain_name' => $_SERVER['HTTP_HOST'],
134
+ );
135
+
136
+ $headers = array(
137
+ 'User-Agent' => 'WooCommerce Stripe Apple Pay',
138
+ 'Authorization' => 'Bearer ' . $secret_key,
139
+ );
140
+
141
+ $response = wp_remote_post( $endpoint, array(
142
+ 'headers' => $headers,
143
+ 'body' => http_build_query( $data ),
144
+ ) );
145
+
146
+ if ( is_wp_error( $response ) ) {
147
+ /* translators: error message */
148
+ throw new Exception( sprintf( __( 'Unable to verify domain - %s', 'woocommerce-gateway-stripe' ), $response->get_error_message() ) );
149
+ }
150
+
151
+ if ( 200 !== $response['response']['code'] ) {
152
+ $parsed_response = json_decode( $response['body'] );
153
+
154
+ $this->apple_pay_verify_notice = $parsed_response->error->message;
155
+
156
+ /* translators: error message */
157
+ throw new Exception( sprintf( __( 'Unable to verify domain - %s', 'woocommerce-gateway-stripe' ), $parsed_response->error->message ) );
158
+ }
159
+ }
160
+
161
+ /**
162
+ * Processes the Apple Pay domain verification.
163
+ *
164
+ * @since 3.1.0
165
+ * @version 3.1.0
166
+ */
167
+ public function process_apple_pay_verification() {
168
+ try {
169
+ $path = untrailingslashit( $_SERVER['DOCUMENT_ROOT'] );
170
+ $dir = '.well-known';
171
+ $file = 'apple-developer-merchantid-domain-association';
172
+ $fullpath = $path . '/' . $dir . '/' . $file;
173
+
174
+ if ( $this->apple_pay_domain_set && file_exists( $fullpath ) ) {
175
+ return;
176
+ }
177
+
178
+ if ( ! file_exists( $path . '/' . $dir ) ) {
179
+ if ( ! @mkdir( $path . '/' . $dir, 0755 ) ) { // @codingStandardsIgnoreLine
180
+ throw new Exception( __( 'Unable to create domain association folder to domain root.', 'woocommerce-gateway-stripe' ) );
181
+ }
182
+ }
183
+
184
+ if ( ! file_exists( $fullpath ) ) {
185
+ if ( ! @copy( WC_STRIPE_PLUGIN_PATH . '/' . $file, $fullpath ) ) { // @codingStandardsIgnoreLine
186
+ throw new Exception( __( 'Unable to copy domain association file to domain root.', 'woocommerce-gateway-stripe' ) );
187
+ }
188
+ }
189
+
190
+ // At this point then the domain association folder and file should be available.
191
+ // Proceed to verify/and or verify again.
192
+ $this->register_apple_pay_domain( $this->secret_key );
193
+
194
+ // No errors to this point, verification success!
195
+ $this->stripe_settings['apple_pay_domain_set'] = 'yes';
196
+ $this->apple_pay_domain_set = true;
197
+
198
+ update_option( 'woocommerce_stripe_settings', $this->stripe_settings );
199
+
200
+ WC_Stripe_Logger::log( 'Your domain has been verified with Apple Pay!' );
201
+
202
+ } catch ( Exception $e ) {
203
+ $this->stripe_settings['apple_pay_domain_set'] = 'no';
204
+
205
+ update_option( 'woocommerce_stripe_settings', $this->stripe_settings );
206
+
207
+ WC_Stripe_Logger::log( 'Error: ' . $e->getMessage() );
208
+ }
209
+ }
210
+
211
+ /**
212
+ * Display any admin notices to the user.
213
+ *
214
+ * @since 4.0.6
215
+ */
216
+ public function admin_notices() {
217
+ if ( ! $this->stripe_enabled ) {
218
+ return;
219
+ }
220
+
221
+ if ( $this->payment_request && ! empty( $this->apple_pay_verify_notice ) ) {
222
+ $allowed_html = array(
223
+ 'a' => array(
224
+ 'href' => array(),
225
+ 'title' => array(),
226
+ ),
227
+ );
228
+
229
+ echo '<div class="error stripe-apple-pay-message"><p>' . wp_kses( make_clickable( $this->apple_pay_verify_notice ), $allowed_html ) . '</p></div>';
230
+ }
231
+
232
+ /**
233
+ * Apple pay is enabled by default and domain verification initializes
234
+ * when setting screen is displayed. So if domain verification is not set,
235
+ * something went wrong so lets notify user.
236
+ */
237
+ if ( ! empty( $this->secret_key ) && $this->payment_request && ! $this->apple_pay_domain_set ) {
238
+ /* translators: 1) HTML anchor open tag 2) HTML anchor closing tag */
239
+ echo '<div class="error stripe-apple-pay-message"><p>' . sprintf( __( 'Apple Pay domain verification failed. Please check the %1$slog%2$s to see the issue. (Logging must be enabled to see recorded logs)', 'woocommerce-gateway-stripe' ), '<a href="' . admin_url( 'admin.php?page=wc-status&tab=logs' ) . '">', '</a>' ) . '</p></div>';
240
+ }
241
+ }
242
+ }
243
+
244
+ new WC_Stripe_Apple_Pay_Registration();
includes/class-wc-stripe-order-handler.php CHANGED
@@ -21,7 +21,7 @@ class WC_Stripe_Order_Handler extends WC_Stripe_Payment_Gateway {
21
  public function __construct() {
22
  self::$_this = $this;
23
 
24
- $this->retry_interval = 2;
25
 
26
  add_action( 'wp', array( $this, 'maybe_process_redirect_order' ) );
27
  add_action( 'woocommerce_order_status_on-hold_to_processing', array( $this, 'capture_payment' ) );
@@ -109,41 +109,19 @@ class WC_Stripe_Order_Handler extends WC_Stripe_Payment_Gateway {
109
  $source_object->customer = $this->get_stripe_customer_id( $order );
110
  $source_object->source = $source_info->id;
111
 
 
 
 
 
 
 
 
112
  // Make the request.
113
- $response = WC_Stripe_API::request( $this->generate_payment_request( $order, $source_object ) );
 
 
114
 
115
  if ( ! empty( $response->error ) ) {
116
- // If it is an API error such connection or server, let's retry.
117
- if ( 'api_connection_error' === $response->error->type || 'api_error' === $response->error->type ) {
118
- if ( $retry ) {
119
- sleep( 5 );
120
- return $this->process_redirect_payment( $order_id, false );
121
- } else {
122
- $localized_message = __( 'API connection error and retries exhausted.', 'woocommerce-gateway-stripe' );
123
- $order->add_order_note( $localized_message );
124
- throw new WC_Stripe_Exception( print_r( $response, true ), $localized_message );
125
- }
126
- }
127
-
128
- // We want to retry.
129
- if ( $this->is_retryable_error( $response->error ) ) {
130
- if ( $retry ) {
131
- // Don't do anymore retries after this.
132
- if ( 5 <= $this->retry_interval ) {
133
- return $this->process_redirect_payment( $order_id, false );
134
- }
135
-
136
- sleep( $this->retry_interval );
137
-
138
- $this->retry_interval++;
139
- return $this->process_redirect_payment( $order_id, true );
140
- } else {
141
- $localized_message = __( 'On going requests error and retries exhausted.', 'woocommerce-gateway-stripe' );
142
- $order->add_order_note( $localized_message );
143
- throw new WC_Stripe_Exception( print_r( $response, true ), $localized_message );
144
- }
145
- }
146
-
147
  // Customer param wrong? The user may have been deleted on stripe's end. Remove customer_id. Can be retried without.
148
  if ( preg_match( '/No such customer/i', $response->error->message ) && $retry ) {
149
  if ( WC_Stripe_Helper::is_pre_30() ) {
@@ -167,6 +145,25 @@ class WC_Stripe_Order_Handler extends WC_Stripe_Payment_Gateway {
167
  throw new WC_Stripe_Exception( print_r( $response, true ), $message );
168
  }
169
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
170
  $localized_messages = WC_Stripe_Helper::get_localized_messages();
171
 
172
  if ( 'card_error' === $response->error->type ) {
@@ -178,6 +175,11 @@ class WC_Stripe_Order_Handler extends WC_Stripe_Payment_Gateway {
178
  throw new WC_Stripe_Exception( print_r( $response, true ), $message );
179
  }
180
 
 
 
 
 
 
181
  do_action( 'wc_gateway_stripe_process_redirect_payment', $response, $order );
182
 
183
  $this->process_response( $response, $order );
@@ -291,51 +293,6 @@ class WC_Stripe_Order_Handler extends WC_Stripe_Payment_Gateway {
291
  }
292
  }
293
 
294
- /**
295
- * Normalize the error field name with appropriate locale.
296
- *
297
- * @since 4.0.0
298
- * @since 4.0.1 Map localized checkout fields.
299
- * @param string $field
300
- * @return string $error_field
301
- */
302
- public function normalize_field( $field ) {
303
- $checkout_fields = WC()->checkout->get_checkout_fields();
304
- $org_str = array();
305
- $replace_str = array();
306
-
307
- if ( array_key_exists( $field, $checkout_fields['billing'] ) ) {
308
- $error_field = __( 'Billing', 'woocommerce-gateway-stripe' ) . ' ' . $checkout_fields['billing'][ $field ]['label'];
309
- } elseif ( array_key_exists( $field, $checkout_fields['shipping'] ) ) {
310
- $error_field = __( 'Shipping', 'woocommerce-gateway-stripe' ) . ' ' . $checkout_fields['shipping'][ $field ]['label'];
311
- } elseif ( array_key_exists( $field, $checkout_fields['order'] ) ) {
312
- $error_field = $checkout_fields['order'][ $field ]['label'];
313
- } elseif ( array_key_exists( $field, $checkout_fields['account'] ) ) {
314
- $error_field = $checkout_fields['account'][ $field ]['label'];
315
- } else {
316
- $error_field = str_replace( '_', ' ', $field );
317
-
318
- $org_str[] = 'stripe';
319
- $replace_str[] = '';
320
-
321
- $org_str[] = 'sepa';
322
- $replace_str[] = 'SEPA';
323
-
324
- $org_str[] = 'iban';
325
- $replace_str[] = 'IBAN';
326
-
327
- $org_str[] = 'sofort';
328
- $replace_str[] = 'SOFORT';
329
-
330
- $org_str[] = 'owner';
331
- $replace_str[] = __( 'Owner', 'woocommerce-gateway-stripe' );
332
-
333
- $error_field = str_replace( $org_str, $replace_str, $error_field );
334
- }
335
-
336
- return $error_field;
337
- }
338
-
339
  /**
340
  * Validates the checkout before submitting checkout form.
341
  *
@@ -347,166 +304,12 @@ class WC_Stripe_Order_Handler extends WC_Stripe_Payment_Gateway {
347
  wp_die( __( 'Cheatin&#8217; huh?', 'woocommerce-gateway-stripe' ) );
348
  }
349
 
350
- $errors = new WP_Error();
351
- parse_str( $_POST['required_fields'], $required_fields );
352
- parse_str( $_POST['all_fields'], $all_fields );
353
- $source_type = isset( $_POST['source_type'] ) ? wc_clean( $_POST['source_type'] ) : '';
354
- $validate_shipping_fields = false;
355
- $create_account = false;
356
-
357
- $all_fields = apply_filters( 'wc_stripe_validate_checkout_all_fields', $all_fields );
358
- $required_fields = apply_filters( 'wc_stripe_validate_checkout_required_fields', $required_fields );
359
-
360
- array_walk_recursive( $required_fields, 'wc_clean' );
361
- array_walk_recursive( $all_fields, 'wc_clean' );
362
-
363
- /**
364
- * If ship to different address checkbox is checked then we need
365
- * to validate shipping fields too.
366
  */
367
- if ( isset( $all_fields['ship_to_different_address'] ) ) {
368
- $validate_shipping_fields = true;
369
- }
370
-
371
- // Check if createaccount is checked.
372
- if ( isset( $all_fields['createaccount'] ) ) {
373
- $create_account = true;
374
- }
375
-
376
- // Check if required fields are empty.
377
- foreach ( $required_fields as $field => $field_value ) {
378
- // Check for shipping field.
379
- if ( preg_match( '/^shipping_/', $field ) && ! $validate_shipping_fields ) {
380
- continue;
381
- }
382
-
383
- // Check create account name.
384
- if ( 'account_username' === $field && ! $create_account ) {
385
- continue;
386
- }
387
-
388
- // Check create account password.
389
- if ( 'account_password' === $field && ! $create_account ) {
390
- continue;
391
- }
392
-
393
- if ( empty( $field_value ) || '-1' === $field_value ) {
394
- $error_field = $this->normalize_field( $field );
395
- /* translators: error field name */
396
- $errors->add( 'validation', sprintf( __( '<strong>%s</strong> cannot be empty', 'woocommerce-gateway-stripe' ), $error_field ) );
397
- }
398
- }
399
-
400
- // Check if email is valid format.
401
- if ( ! empty( $required_fields['billing_email'] ) && ! is_email( $required_fields['billing_email'] ) ) {
402
- $errors->add( 'validation', __( 'Email is not valid', 'woocommerce-gateway-stripe' ) );
403
- }
404
-
405
- // Check if phone number is valid format.
406
- if ( ! empty( $required_fields['billing_phone'] ) ) {
407
- $phone = wc_format_phone_number( $required_fields['billing_phone'] );
408
-
409
- if ( '' !== $phone && ! WC_Validation::is_phone( $phone ) ) {
410
- /* translators: %s: phone number */
411
- $errors->add( 'validation', __( 'Please enter a valid phone number.', 'woocommerce-gateway-stripe' ) );
412
- }
413
- }
414
-
415
- // Check if postal code is valid format.
416
- if ( ! empty( $required_fields['billing_postcode'] ) ) {
417
- $country = isset( $required_fields['billing_country'] ) ? $required_fields['billing_country'] : WC()->customer->get_billing_country();
418
- $postcode = wc_format_postcode( $required_fields['billing_postcode'], $country );
419
-
420
- if ( '' !== $required_fields['billing_postcode'] && ! WC_Validation::is_postcode( $postcode, $country ) ) {
421
- $errors->add( 'validation', __( 'Please enter a valid billing postcode / ZIP.', 'woocommerce-gateway-stripe' ) );
422
- }
423
- }
424
-
425
- // Don't check this on add payment method page.
426
- if ( ( isset( $_POST['is_add_payment_page'] ) && 'no' === $_POST['is_add_payment_page'] ) ) {
427
- if ( empty( $all_fields['woocommerce_checkout_update_totals'] ) && empty( $all_fields['terms'] ) && apply_filters( 'woocommerce_checkout_show_terms', wc_get_page_id( 'terms' ) > 0 ) ) {
428
- $errors->add( 'terms', __( 'You must accept our Terms &amp; Conditions.', 'woocommerce-gateway-stripe' ) );
429
- }
430
- }
431
-
432
- if ( WC()->cart->needs_shipping() && $validate_shipping_fields ) {
433
- // Check if postal code is valid format.
434
- if ( ! empty( $required_fields['shipping_postcode'] ) ) {
435
- $country = isset( $required_fields['shipping_country'] ) ? $required_fields['shipping_country'] : WC()->customer->get_shipping_country();
436
- $postcode = wc_format_postcode( $required_fields['shipping_postcode'], $country );
437
-
438
- if ( '' !== $required_fields['shipping_postcode'] && ! WC_Validation::is_postcode( $postcode, $country ) ) {
439
- $errors->add( 'validation', __( 'Please enter a valid shipping postcode / ZIP.', 'woocommerce-gateway-stripe' ) );
440
- }
441
- }
442
- }
443
-
444
- if ( WC()->cart->needs_shipping() ) {
445
- $shipping_country = WC()->customer->get_shipping_country();
446
-
447
- if ( empty( $shipping_country ) ) {
448
- $errors->add( 'shipping', __( 'Please enter an address to continue.', 'woocommerce-gateway-stripe' ) );
449
- } elseif ( ! in_array( WC()->customer->get_shipping_country(), array_keys( WC()->countries->get_shipping_countries() ) ) ) {
450
- /* translators: country name */
451
- $errors->add( 'shipping', sprintf( __( 'Unfortunately <strong>we do not ship %s</strong>. Please enter an alternative shipping address.', 'woocommerce-gateway-stripe' ), WC()->countries->shipping_to_prefix() . ' ' . WC()->customer->get_shipping_country() ) );
452
- } else {
453
- $chosen_shipping_methods = WC()->session->get( 'chosen_shipping_methods' );
454
-
455
- foreach ( WC()->shipping->get_packages() as $i => $package ) {
456
- if ( ! isset( $chosen_shipping_methods[ $i ], $package['rates'][ $chosen_shipping_methods[ $i ] ] ) ) {
457
- $errors->add( 'shipping', __( 'No shipping method has been selected. Please double check your address, or contact us if you need any help.', 'woocommerce-gateway-stripe' ) );
458
- }
459
- }
460
- }
461
- }
462
-
463
- if ( WC()->cart->needs_payment() ) {
464
- $available_gateways = WC()->payment_gateways->get_available_payment_gateways();
465
-
466
- if ( ! isset( $available_gateways[ $all_fields['payment_method'] ] ) ) {
467
- $errors->add( 'payment', __( 'Invalid payment method.', 'woocommerce-gateway-stripe' ) );
468
- } else {
469
- $available_gateways[ $all_fields['payment_method'] ]->validate_fields();
470
- }
471
- }
472
-
473
- if ( 0 === count( $errors->errors ) ) {
474
- wp_send_json( 'success' );
475
- } else {
476
- foreach ( $errors->get_error_messages() as $message ) {
477
- wc_add_notice( $message, 'error' );
478
- }
479
-
480
- $this->send_ajax_failure_response();
481
- }
482
- }
483
-
484
- /**
485
- * Preps the error messages to be displayed.
486
- *
487
- * @since 4.0.0
488
- * @version 4.0.0
489
- */
490
- public function send_ajax_failure_response() {
491
- if ( is_ajax() ) {
492
- // only print notices if not reloading the checkout, otherwise they're lost in the page reload.
493
- if ( ! isset( WC()->session->reload_checkout ) ) {
494
- ob_start();
495
- wc_print_notices();
496
- $messages = ob_get_clean();
497
- }
498
-
499
- $response = array(
500
- 'result' => 'failure',
501
- 'messages' => isset( $messages ) ? $messages : '',
502
- 'refresh' => isset( WC()->session->refresh_totals ),
503
- 'reload' => isset( WC()->session->reload_checkout ),
504
- );
505
-
506
- unset( WC()->session->refresh_totals, WC()->session->reload_checkout );
507
-
508
- wp_send_json( $response );
509
- }
510
  }
511
  }
512
 
21
  public function __construct() {
22
  self::$_this = $this;
23
 
24
+ $this->retry_interval = 1;
25
 
26
  add_action( 'wp', array( $this, 'maybe_process_redirect_order' ) );
27
  add_action( 'woocommerce_order_status_on-hold_to_processing', array( $this, 'capture_payment' ) );
109
  $source_object->customer = $this->get_stripe_customer_id( $order );
110
  $source_object->source = $source_info->id;
111
 
112
+ /* If we're doing a retry and source is chargeable, we need to pass
113
+ * a different idempotency key and retry for success.
114
+ */
115
+ if ( 1 < $this->retry_interval && 'chargeable' === $source_info->status ) {
116
+ add_filter( 'wc_stripe_idempotency_key', array( $this, 'change_idempotency_key' ), 10, 2 );
117
+ }
118
+
119
  // Make the request.
120
+ $response = WC_Stripe_API::request( $this->generate_payment_request( $order, $source_object ), 'charges', 'POST', true );
121
+ $headers = $response['headers'];
122
+ $response = $response['body'];
123
 
124
  if ( ! empty( $response->error ) ) {
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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() ) {
145
  throw new WC_Stripe_Exception( print_r( $response, true ), $message );
146
  }
147
 
148
+ // We want to retry.
149
+ if ( $this->is_retryable_error( $response->error ) ) {
150
+ if ( $retry ) {
151
+ // Don't do anymore retries after this.
152
+ if ( 5 <= $this->retry_interval ) {
153
+ return $this->process_redirect_payment( $order_id, false );
154
+ }
155
+
156
+ sleep( $this->retry_interval );
157
+
158
+ $this->retry_interval++;
159
+ return $this->process_redirect_payment( $order_id, true );
160
+ } else {
161
+ $localized_message = __( 'On going requests error and retries exhausted.', 'woocommerce-gateway-stripe' );
162
+ $order->add_order_note( $localized_message );
163
+ throw new WC_Stripe_Exception( print_r( $response, true ), $localized_message );
164
+ }
165
+ }
166
+
167
  $localized_messages = WC_Stripe_Helper::get_localized_messages();
168
 
169
  if ( 'card_error' === $response->error->type ) {
175
  throw new WC_Stripe_Exception( print_r( $response, true ), $message );
176
  }
177
 
178
+ // To prevent double processing the order on WC side.
179
+ if ( ! $this->is_original_request( $headers ) ) {
180
+ return;
181
+ }
182
+
183
  do_action( 'wc_gateway_stripe_process_redirect_payment', $response, $order );
184
 
185
  $this->process_response( $response, $order );
293
  }
294
  }
295
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
296
  /**
297
  * Validates the checkout before submitting checkout form.
298
  *
304
  wp_die( __( 'Cheatin&#8217; huh?', 'woocommerce-gateway-stripe' ) );
305
  }
306
 
307
+ /*
308
+ * Client expects json encoded results to be "success" or message of HTML errors.
309
+ * i.e. wp_send_json( 'success' ); // On successful validation.
310
+ * i.e. For errors follow WC https://github.com/woocommerce/woocommerce/blob/master/includes/class-wc-checkout.php#L918-L938
 
 
 
 
 
 
 
 
 
 
 
 
311
  */
312
+ do_action( 'wc_stripe_validate_modal_checkout_action', $_POST['required_fields'], $_POST['all_fields'] );
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
313
  }
314
  }
315
 
includes/class-wc-stripe-webhook-handler.php CHANGED
@@ -10,8 +10,20 @@ if ( ! defined( 'ABSPATH' ) ) {
10
  * @since 4.0.0
11
  */
12
  class WC_Stripe_Webhook_Handler extends WC_Stripe_Payment_Gateway {
 
 
 
 
 
13
  public $retry_interval;
14
 
 
 
 
 
 
 
 
15
  /**
16
  * Constructor.
17
  *
@@ -20,6 +32,8 @@ class WC_Stripe_Webhook_Handler extends WC_Stripe_Payment_Gateway {
20
  */
21
  public function __construct() {
22
  $this->retry_interval = 2;
 
 
23
  add_action( 'woocommerce_api_wc_stripe', array( $this, 'check_for_webhook' ) );
24
  }
25
 
@@ -148,21 +162,11 @@ class WC_Stripe_Webhook_Handler extends WC_Stripe_Payment_Gateway {
148
  $source_object->source = $source_id;
149
 
150
  // Make the request.
151
- $response = WC_Stripe_API::request( $this->generate_payment_request( $order, $source_object ) );
 
 
152
 
153
  if ( ! empty( $response->error ) ) {
154
- // If it is an API error such connection or server, let's retry.
155
- if ( 'api_connection_error' === $response->error->type || 'api_error' === $response->error->type ) {
156
- if ( $retry ) {
157
- sleep( 5 );
158
- return $this->process_webhook_payment( $notification, false );
159
- } else {
160
- $localized_message = 'API connection error and retries exhausted.';
161
- $order->add_order_note( $localized_message );
162
- throw new WC_Stripe_Exception( print_r( $response, true ), $localized_message );
163
- }
164
- }
165
-
166
  // We want to retry.
167
  if ( $this->is_retryable_error( $response->error ) ) {
168
  if ( $retry ) {
@@ -218,6 +222,11 @@ class WC_Stripe_Webhook_Handler extends WC_Stripe_Payment_Gateway {
218
  throw new WC_Stripe_Exception( print_r( $response, true ), $localized_message );
219
  }
220
 
 
 
 
 
 
221
  do_action( 'wc_gateway_stripe_process_webhook_payment', $response, $order );
222
 
223
  $this->process_response( $response, $order );
@@ -251,7 +260,8 @@ class WC_Stripe_Webhook_Handler extends WC_Stripe_Payment_Gateway {
251
  return;
252
  }
253
 
254
- $order->update_status( 'on-hold', __( 'A dispute was created for this order. Response is needed. Please go to your Stripe Dashboard to review this dispute.', 'woocommerce-gateway-stripe' ) );
 
255
 
256
  do_action( 'wc_gateway_stripe_process_webhook_payment_error', $order, $notification );
257
 
@@ -301,7 +311,7 @@ class WC_Stripe_Webhook_Handler extends WC_Stripe_Payment_Gateway {
301
  // Check and see if capture is partial.
302
  if ( $this->is_partial_capture( $notification ) ) {
303
  $order->set_total( $this->get_partial_amount_to_charge( $notification ) );
304
- $order->add_note( __( 'This charge was partially captured via Stripe Dashboard', 'woocommerce-gateway-stripe' ) );
305
  $order->save();
306
  }
307
  }
@@ -452,6 +462,58 @@ class WC_Stripe_Webhook_Handler extends WC_Stripe_Payment_Gateway {
452
  }
453
  }
454
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
455
  /**
456
  * Checks if capture is partial.
457
  *
@@ -544,6 +606,14 @@ class WC_Stripe_Webhook_Handler extends WC_Stripe_Payment_Gateway {
544
  $this->process_webhook_refund( $notification );
545
  break;
546
 
 
 
 
 
 
 
 
 
547
  }
548
  }
549
  }
10
  * @since 4.0.0
11
  */
12
  class WC_Stripe_Webhook_Handler extends WC_Stripe_Payment_Gateway {
13
+ /**
14
+ * Delay of retries.
15
+ *
16
+ * @var int
17
+ */
18
  public $retry_interval;
19
 
20
+ /**
21
+ * Is test mode active?
22
+ *
23
+ * @var bool
24
+ */
25
+ public $testmode;
26
+
27
  /**
28
  * Constructor.
29
  *
32
  */
33
  public function __construct() {
34
  $this->retry_interval = 2;
35
+ $stripe_settings = get_option( 'woocommerce_stripe_settings', array() );
36
+ $this->testmode = ( ! empty( $stripe_settings['testmode'] ) && 'yes' === $stripe_settings['testmode'] ) ? true : false;
37
  add_action( 'woocommerce_api_wc_stripe', array( $this, 'check_for_webhook' ) );
38
  }
39
 
162
  $source_object->source = $source_id;
163
 
164
  // Make the request.
165
+ $response = WC_Stripe_API::request( $this->generate_payment_request( $order, $source_object ), 'charges', 'POST', true );
166
+ $headers = $response['headers'];
167
+ $response = $response['body'];
168
 
169
  if ( ! empty( $response->error ) ) {
 
 
 
 
 
 
 
 
 
 
 
 
170
  // We want to retry.
171
  if ( $this->is_retryable_error( $response->error ) ) {
172
  if ( $retry ) {
222
  throw new WC_Stripe_Exception( print_r( $response, true ), $localized_message );
223
  }
224
 
225
+ // To prevent double processing the order on WC side.
226
+ if ( ! $this->is_original_request( $headers ) ) {
227
+ return;
228
+ }
229
+
230
  do_action( 'wc_gateway_stripe_process_webhook_payment', $response, $order );
231
 
232
  $this->process_response( $response, $order );
260
  return;
261
  }
262
 
263
+ /* translators: 1) The URL to the order. */
264
+ $order->update_status( 'on-hold', sprintf( __( 'A dispute was created for this order. Response is needed. Please go to your <a href="%s" title="Stripe Dashboard" target="_blank">Stripe Dashboard</a> to review this dispute.', 'woocommerce-gateway-stripe' ), $this->get_transaction_url( $order ) ) );
265
 
266
  do_action( 'wc_gateway_stripe_process_webhook_payment_error', $order, $notification );
267
 
311
  // Check and see if capture is partial.
312
  if ( $this->is_partial_capture( $notification ) ) {
313
  $order->set_total( $this->get_partial_amount_to_charge( $notification ) );
314
+ $order->add_order_note( __( 'This charge was partially captured via Stripe Dashboard', 'woocommerce-gateway-stripe' ) );
315
  $order->save();
316
  }
317
  }
462
  }
463
  }
464
 
465
+ /**
466
+ * Process webhook reviews that are opened. i.e Radar.
467
+ *
468
+ * @since 4.0.6
469
+ * @param object $notification
470
+ */
471
+ public function process_review_opened( $notification ) {
472
+ $order = WC_Stripe_Helper::get_order_by_charge_id( $notification->data->object->charge );
473
+
474
+ if ( ! $order ) {
475
+ WC_Stripe_Logger::log( 'Could not find order via charge ID: ' . $notification->data->object->charge );
476
+ return;
477
+ }
478
+
479
+ /* translators: 1) The URL to the order. 2) The reason type. */
480
+ $message = sprintf( __( 'A review has been opened for this order. Action is needed. Please go to your <a href="%1$s" title="Stripe Dashboard" target="_blank">Stripe Dashboard</a> to review the issue. Reason: (%2$s)', 'woocommerce-gateway-stripe' ), $this->get_transaction_url( $order ), $notification->data->object->reason );
481
+
482
+ if ( apply_filters( 'wc_stripe_webhook_review_change_order_status', true, $order, $notification ) ) {
483
+ $order->update_status( 'on-hold', $message );
484
+ } else {
485
+ $order->add_order_note( $message );
486
+ }
487
+ }
488
+
489
+ /**
490
+ * Process webhook reviews that are closed. i.e Radar.
491
+ *
492
+ * @since 4.0.6
493
+ * @param object $notification
494
+ */
495
+ public function process_review_closed( $notification ) {
496
+ $order = WC_Stripe_Helper::get_order_by_charge_id( $notification->data->object->charge );
497
+
498
+ if ( ! $order ) {
499
+ WC_Stripe_Logger::log( 'Could not find order via charge ID: ' . $notification->data->object->charge );
500
+ return;
501
+ }
502
+
503
+ /* translators: 1) The reason type. */
504
+ $message = sprintf( __( 'The opened review for this order is now closed. Reason: (%s)', 'woocommerce-gateway-stripe' ), $notification->data->object->reason );
505
+
506
+ if ( 'on-hold' === $order->get_status() ) {
507
+ if ( apply_filters( 'wc_stripe_webhook_review_change_order_status', true, $order, $notification ) ) {
508
+ $order->update_status( 'processing', $message );
509
+ } else {
510
+ $order->add_order_note( $message );
511
+ }
512
+ } else {
513
+ $order->add_order_note( $message );
514
+ }
515
+ }
516
+
517
  /**
518
  * Checks if capture is partial.
519
  *
606
  $this->process_webhook_refund( $notification );
607
  break;
608
 
609
+ case 'review.opened':
610
+ $this->process_review_opened( $notification );
611
+ break;
612
+
613
+ case 'review.closed':
614
+ $this->process_review_closed( $notification );
615
+ break;
616
+
617
  }
618
  }
619
  }
includes/compat/class-wc-stripe-compat.php CHANGED
@@ -28,7 +28,6 @@ class WC_Stripe_Compat extends WC_Gateway_Stripe {
28
  add_filter( 'woocommerce_subscription_payment_meta', array( $this, 'add_subscription_payment_meta' ), 10, 2 );
29
  add_filter( 'woocommerce_subscription_validate_payment_meta', array( $this, 'validate_subscription_payment_meta' ), 10, 2 );
30
  add_filter( 'wc_stripe_display_save_payment_method_checkbox', array( $this, 'maybe_hide_save_checkbox' ) );
31
- add_filter( 'wc_stripe_payment_metadata', array( $this, 'add_subscription_meta_data' ), 10, 2 );
32
  }
33
 
34
  if ( class_exists( 'WC_Pre_Orders_Order' ) ) {
@@ -88,15 +87,13 @@ class WC_Stripe_Compat extends WC_Gateway_Stripe {
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 ) ) {
@@ -171,24 +168,6 @@ class WC_Stripe_Compat extends WC_Gateway_Stripe {
171
  }
172
  }
173
 
174
- /**
175
- * Adds subscription related meta data on charge request.
176
- *
177
- * @since 4.0.0
178
- * @param array $metadata
179
- * @param object $order
180
- */
181
- public function add_subscription_meta_data( $metadata, $order ) {
182
- if ( ! $this->has_subscription( WC_Stripe_Helper::is_pre_30() ? $order->id : $order->get_id() ) ) {
183
- return $metadata;
184
- }
185
-
186
- return $metadata += array(
187
- 'payment_type' => 'recurring',
188
- 'site_url' => esc_url( get_site_url() ),
189
- );
190
- }
191
-
192
  /**
193
  * Updates other subscription sources.
194
  *
@@ -536,14 +515,14 @@ class WC_Stripe_Compat extends WC_Gateway_Stripe {
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();
28
  add_filter( 'woocommerce_subscription_payment_meta', array( $this, 'add_subscription_payment_meta' ), 10, 2 );
29
  add_filter( 'woocommerce_subscription_validate_payment_meta', array( $this, 'validate_subscription_payment_meta' ), 10, 2 );
30
  add_filter( 'wc_stripe_display_save_payment_method_checkbox', array( $this, 'maybe_hide_save_checkbox' ) );
 
31
  }
32
 
33
  if ( class_exists( 'WC_Pre_Orders_Order' ) ) {
87
  public function change_subs_payment_method( $order_id ) {
88
  try {
89
  $subscription = wc_get_order( $order_id );
90
+ $prepared_source = $this->prepare_source( get_current_user_id(), true );
91
+ $source_object = $prepared_source->source_object;
92
 
93
  // Check if we don't allow prepaid credit cards.
94
+ if ( ! apply_filters( 'wc_stripe_allow_prepaid_card', true ) && $this->is_prepaid_card( $source_object ) ) {
95
+ $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' );
96
+ throw new WC_Stripe_Exception( print_r( $source_object, true ), $localized_message );
 
 
97
  }
98
 
99
  if ( empty( $prepared_source->source ) ) {
168
  }
169
  }
170
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
171
  /**
172
  * Updates other subscription sources.
173
  *
515
  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 ) ) );
516
  }
517
 
518
+ $prepared_source = $this->prepare_source( get_current_user_id(), true );
519
 
520
  // We need a source on file to continue.
521
+ if ( empty( $prepared_source->customer ) || empty( $prepared_source->source ) ) {
522
  throw new Exception( __( 'Unable to store payment details. Please try again.', 'woocommerce-gateway-stripe' ) );
523
  }
524
 
525
+ $this->save_source_to_order( $order, $prepared_source );
526
 
527
  // Remove cart
528
  WC()->cart->empty_cart();
includes/compat/class-wc-stripe-sepa-compat.php CHANGED
@@ -21,10 +21,10 @@ class WC_Stripe_Sepa_Compat extends WC_Gateway_Stripe_Sepa {
21
  add_action( 'wcs_renewal_order_created', array( $this, 'delete_renewal_meta' ), 10 );
22
  add_action( 'woocommerce_subscription_failing_payment_method_updated_stripe', array( $this, 'update_failing_payment_method' ), 10, 2 );
23
 
24
- // display the credit card used for a subscription in the "My Subscriptions" table
25
  add_filter( 'woocommerce_my_subscriptions_payment_method', array( $this, 'maybe_render_subscription_payment_method' ), 10, 2 );
26
 
27
- // allow store managers to manually set Stripe as the payment method on a subscription
28
  add_filter( 'woocommerce_subscription_payment_meta', array( $this, 'add_subscription_payment_meta' ), 10, 2 );
29
  add_filter( 'woocommerce_subscription_validate_payment_meta', array( $this, 'validate_subscription_payment_meta' ), 10, 2 );
30
  add_filter( 'wc_stripe_display_save_payment_method_checkbox', array( $this, 'maybe_hide_save_checkbox' ) );
@@ -76,7 +76,7 @@ class WC_Stripe_Sepa_Compat extends WC_Gateway_Stripe_Sepa {
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 ) ) {
82
  return $this->process_pre_order( $order_id, $retry, $force_save_source );
@@ -114,7 +114,7 @@ class WC_Stripe_Sepa_Compat extends WC_Gateway_Stripe_Sepa {
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 ) ) {
119
  $subscriptions = wcs_get_subscriptions_for_order( $order_id );
120
  } elseif ( function_exists( 'wcs_order_contains_renewal' ) && wcs_order_contains_renewal( $order_id ) ) {
@@ -147,7 +147,7 @@ class WC_Stripe_Sepa_Compat extends WC_Gateway_Stripe_Sepa {
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 ) {
@@ -446,14 +446,14 @@ class WC_Stripe_Sepa_Compat extends WC_Gateway_Stripe_Sepa {
446
  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 ) ) );
447
  }
448
 
449
- $source = $this->prepare_source( $this->get_source_object(), get_current_user_id(), true );
450
 
451
  // We need a source on file to continue.
452
- if ( empty( $source->customer ) || empty( $source->source ) ) {
453
  throw new Exception( __( 'Unable to store payment details. Please try again.', 'woocommerce-gateway-stripe' ) );
454
  }
455
 
456
- $this->save_source_to_order( $order, $source );
457
 
458
  // Remove cart
459
  WC()->cart->empty_cart();
21
  add_action( 'wcs_renewal_order_created', array( $this, 'delete_renewal_meta' ), 10 );
22
  add_action( 'woocommerce_subscription_failing_payment_method_updated_stripe', array( $this, 'update_failing_payment_method' ), 10, 2 );
23
 
24
+ // Display the credit card used for a subscription in the "My Subscriptions" table.
25
  add_filter( 'woocommerce_my_subscriptions_payment_method', array( $this, 'maybe_render_subscription_payment_method' ), 10, 2 );
26
 
27
+ // Allow store managers to manually set Stripe as the payment method on a subscription.
28
  add_filter( 'woocommerce_subscription_payment_meta', array( $this, 'add_subscription_payment_meta' ), 10, 2 );
29
  add_filter( 'woocommerce_subscription_validate_payment_meta', array( $this, 'validate_subscription_payment_meta' ), 10, 2 );
30
  add_filter( 'wc_stripe_display_save_payment_method_checkbox', array( $this, 'maybe_hide_save_checkbox' ) );
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 ) ) {
82
  return $this->process_pre_order( $order_id, $retry, $force_save_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 ) ) {
119
  $subscriptions = wcs_get_subscriptions_for_order( $order_id );
120
  } elseif ( function_exists( 'wcs_order_contains_renewal' ) && wcs_order_contains_renewal( $order_id ) ) {
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 ) {
446
  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 ) ) );
447
  }
448
 
449
+ $prepared_source = $this->prepare_source( get_current_user_id(), true );
450
 
451
  // We need a source on file to continue.
452
+ if ( empty( $prepared_source->customer ) || empty( $prepared_source->source ) ) {
453
  throw new Exception( __( 'Unable to store payment details. Please try again.', 'woocommerce-gateway-stripe' ) );
454
  }
455
 
456
+ $this->save_source_to_order( $order, $prepared_source );
457
 
458
  // Remove cart
459
  WC()->cart->empty_cart();
includes/deprecated/class-wc-stripe-apple-pay.php CHANGED
@@ -20,7 +20,7 @@ if ( ! class_exists( 'WC_Stripe_Apple_Pay' ) ) {
20
  }
21
 
22
  public static function instance() {
23
- WC_Stripe_Logger::log( "DEPRECATED! WC_Stripe_Apple_Pay class has been hard deprecated. Please remove any code that references this class or instance." );
24
  return self::$_this;
25
  }
26
 
20
  }
21
 
22
  public static function instance() {
23
+ WC_Stripe_Logger::log( 'DEPRECATED! WC_Stripe_Apple_Pay class has been hard deprecated. Please remove any code that references this class or instance. This class will be removed by version 5.0' );
24
  return self::$_this;
25
  }
26
 
includes/payment-methods/class-wc-gateway-stripe-bancontact.php CHANGED
@@ -251,7 +251,7 @@ class WC_Gateway_Stripe_Bancontact extends WC_Stripe_Payment_Gateway {
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 );
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' => $this->get_locale() );
255
 
256
  if ( ! empty( $this->statement_descriptor ) ) {
257
  $post_data['statement_descriptor'] = WC_Stripe_Helper::clean_statement_descriptor( $this->statement_descriptor );
includes/payment-methods/class-wc-gateway-stripe-bitcoin.php CHANGED
@@ -99,7 +99,7 @@ class WC_Gateway_Stripe_Bitcoin extends WC_Stripe_Payment_Gateway {
99
  add_action( 'wp_enqueue_scripts', array( $this, 'payment_scripts' ) );
100
  add_action( 'woocommerce_thankyou_stripe_bitcoin', array( $this, 'thankyou_page' ) );
101
 
102
- // Customer Emails
103
  add_action( 'woocommerce_email_before_order_table', array( $this, 'email_instructions' ), 10, 3 );
104
  }
105
 
@@ -368,7 +368,7 @@ class WC_Gateway_Stripe_Bitcoin extends WC_Stripe_Payment_Gateway {
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' );
@@ -380,17 +380,17 @@ class WC_Gateway_Stripe_Bitcoin extends WC_Stripe_Payment_Gateway {
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' ) );
387
 
388
  wc_reduce_stock_levels( $order_id );
389
 
390
- // Remove cart
391
  WC()->cart->empty_cart();
392
 
393
- // Return thankyou redirect
394
  return array(
395
  'result' => 'success',
396
  'redirect' => $this->get_return_url( $order ),
99
  add_action( 'wp_enqueue_scripts', array( $this, 'payment_scripts' ) );
100
  add_action( 'woocommerce_thankyou_stripe_bitcoin', array( $this, 'thankyou_page' ) );
101
 
102
+ // Customer Emails.
103
  add_action( 'woocommerce_email_before_order_table', array( $this, 'email_instructions' ), 10, 3 );
104
  }
105
 
368
  $new_stripe_customer->create_customer();
369
  }
370
 
371
+ $prepared_source = $this->prepare_source( 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' );
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( $prepared_source->source ) );
384
 
385
+ // Mark as on-hold (we're awaiting the payment).
386
  $order->update_status( 'on-hold', __( 'Awaiting Bitcoin payment', 'woocommerce-gateway-stripe' ) );
387
 
388
  wc_reduce_stock_levels( $order_id );
389
 
390
+ // Remove cart.
391
  WC()->cart->empty_cart();
392
 
393
+ // Return thankyou redirect.
394
  return array(
395
  'result' => 'success',
396
  'redirect' => $this->get_return_url( $order ),
includes/payment-methods/class-wc-gateway-stripe-sepa.php CHANGED
@@ -11,6 +11,13 @@ if ( ! defined( 'ABSPATH' ) ) {
11
  * @since 4.0.0
12
  */
13
  class WC_Gateway_Stripe_Sepa extends WC_Stripe_Payment_Gateway {
 
 
 
 
 
 
 
14
  /**
15
  * Notices (array)
16
  * @var array
@@ -56,6 +63,7 @@ class WC_Gateway_Stripe_Sepa extends WC_Stripe_Payment_Gateway {
56
  * Constructor
57
  */
58
  public function __construct() {
 
59
  $this->id = 'stripe_sepa';
60
  $this->method_title = __( 'Stripe SEPA Direct Debit', 'woocommerce-gateway-stripe' );
61
  /* translators: link */
@@ -333,7 +341,7 @@ 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->get_source_object(), get_current_user_id(), $force_save_source );
337
 
338
  $this->save_source_to_order( $order, $prepared_source );
339
 
@@ -350,18 +358,6 @@ class WC_Gateway_Stripe_Sepa extends WC_Stripe_Payment_Gateway {
350
  $response = WC_Stripe_API::request( $this->generate_payment_request( $order, $prepared_source ) );
351
 
352
  if ( ! empty( $response->error ) ) {
353
- // If it is an API error such connection or server, let's retry.
354
- if ( 'api_connection_error' === $response->error->type || 'api_error' === $response->error->type ) {
355
- if ( $retry ) {
356
- sleep( 5 );
357
- return $this->process_payment( $order_id, false, $force_save_source );
358
- } else {
359
- $localized_message = 'API connection error and retries exhausted.';
360
- $order->add_order_note( $localized_message );
361
- throw new WC_Stripe_Exception( print_r( $response, true ), $localized_message );
362
- }
363
- }
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() ) {
@@ -383,6 +379,27 @@ class WC_Gateway_Stripe_Sepa extends WC_Stripe_Payment_Gateway {
383
  throw new WC_Stripe_Exception( print_r( $response, true ), $localized_message );
384
  }
385
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
386
  $localized_messages = WC_Stripe_Helper::get_localized_messages();
387
 
388
  if ( 'card_error' === $response->error->type ) {
11
  * @since 4.0.0
12
  */
13
  class WC_Gateway_Stripe_Sepa extends WC_Stripe_Payment_Gateway {
14
+ /**
15
+ * The delay between retries.
16
+ *
17
+ * @var int
18
+ */
19
+ public $retry_interval;
20
+
21
  /**
22
  * Notices (array)
23
  * @var array
63
  * Constructor
64
  */
65
  public function __construct() {
66
+ $this->retry_interval = 1;
67
  $this->id = 'stripe_sepa';
68
  $this->method_title = __( 'Stripe SEPA Direct Debit', 'woocommerce-gateway-stripe' );
69
  /* translators: link */
341
  $new_stripe_customer->create_customer();
342
  }
343
 
344
+ $prepared_source = $this->prepare_source( get_current_user_id(), $force_save_source );
345
 
346
  $this->save_source_to_order( $order, $prepared_source );
347
 
358
  $response = WC_Stripe_API::request( $this->generate_payment_request( $order, $prepared_source ) );
359
 
360
  if ( ! empty( $response->error ) ) {
 
 
 
 
 
 
 
 
 
 
 
 
361
  // Customer param wrong? The user may have been deleted on stripe's end. Remove customer_id. Can be retried without.
362
  if ( preg_match( '/No such customer/i', $response->error->message ) && $retry ) {
363
  if ( WC_Stripe_Helper::is_pre_30() ) {
379
  throw new WC_Stripe_Exception( print_r( $response, true ), $localized_message );
380
  }
381
 
382
+ // We want to retry.
383
+ if ( $this->is_retryable_error( $response->error ) ) {
384
+ if ( $retry ) {
385
+ // Don't do anymore retries after this.
386
+ if ( 5 <= $this->retry_interval ) {
387
+
388
+ return $this->process_payment( $order_id, false, $force_save_source );
389
+ }
390
+
391
+ sleep( $this->retry_interval );
392
+
393
+ $this->retry_interval++;
394
+
395
+ return $this->process_payment( $order_id, true, $force_save_source );
396
+ } else {
397
+ $localized_message = __( 'On going requests error and retries exhausted.', 'woocommerce-gateway-stripe' );
398
+ $order->add_order_note( $localized_message );
399
+ throw new WC_Stripe_Exception( print_r( $response, true ), $localized_message );
400
+ }
401
+ }
402
+
403
  $localized_messages = WC_Stripe_Helper::get_localized_messages();
404
 
405
  if ( 'card_error' === $response->error->type ) {
includes/payment-methods/class-wc-gateway-stripe-sofort.php CHANGED
@@ -253,7 +253,7 @@ class WC_Gateway_Stripe_Sofort extends WC_Stripe_Payment_Gateway {
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 ) ) {
253
  $post_data['redirect'] = array( 'return_url' => $return_url );
254
  $post_data['sofort'] = array(
255
  'country' => $bank_country,
256
+ 'preferred_language' => $this->get_locale(),
257
  );
258
 
259
  if ( ! empty( $this->statement_descriptor ) ) {
includes/payment-methods/class-wc-stripe-payment-request.php CHANGED
@@ -3,7 +3,7 @@
3
  * Stripe Payment Request API
4
  *
5
  * @package WooCommerce_Stripe/Classes/Payment_Request
6
- * @since 3.1.0
7
  */
8
 
9
  if ( ! defined( 'ABSPATH' ) ) {
@@ -42,6 +42,13 @@ class WC_Stripe_Payment_Request {
42
  */
43
  public $publishable_key;
44
 
 
 
 
 
 
 
 
45
  /**
46
  * Is test mode active?
47
  *
@@ -49,6 +56,13 @@ class WC_Stripe_Payment_Request {
49
  */
50
  public $testmode;
51
 
 
 
 
 
 
 
 
52
  /**
53
  * Initialize class actions.
54
  *
@@ -56,19 +70,17 @@ class WC_Stripe_Payment_Request {
56
  * @version 4.0.0
57
  */
58
  public function __construct() {
 
59
  $this->stripe_settings = get_option( 'woocommerce_stripe_settings', array() );
60
  $this->testmode = ( ! empty( $this->stripe_settings['testmode'] ) && 'yes' === $this->stripe_settings['testmode'] ) ? true : false;
61
  $this->publishable_key = ! empty( $this->stripe_settings['publishable_key'] ) ? $this->stripe_settings['publishable_key'] : '';
 
62
  $this->stripe_checkout_enabled = isset( $this->stripe_settings['stripe_checkout'] ) && 'yes' === $this->stripe_settings['stripe_checkout'];
63
  $this->total_label = ! empty( $this->stripe_settings['statement_descriptor'] ) ? WC_Stripe_Helper::clean_statement_descriptor( $this->stripe_settings['statement_descriptor'] ) : '';
64
 
65
  if ( $this->testmode ) {
66
  $this->publishable_key = ! empty( $this->stripe_settings['test_publishable_key'] ) ? $this->stripe_settings['test_publishable_key'] : '';
67
- }
68
-
69
- // If both site title and statement descriptor is not set. Fallback.
70
- if ( empty( $this->total_label ) ) {
71
- $this->total_label = $_SERVER['SERVER_NAME'];
72
  }
73
 
74
  $this->total_label = str_replace( "'", '', $this->total_label ) . apply_filters( 'wc_stripe_payment_request_total_label_suffix', ' (via WooCommerce)' );
@@ -92,6 +104,30 @@ class WC_Stripe_Payment_Request {
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.
@@ -391,6 +427,18 @@ class WC_Stripe_Payment_Request {
391
  * @version 4.0.0
392
  */
393
  public function scripts() {
 
 
 
 
 
 
 
 
 
 
 
 
394
  if ( ! is_product() && ! is_cart() && ! is_checkout() && ! isset( $_GET['pay_for_order'] ) ) {
395
  return;
396
  }
3
  * Stripe Payment Request API
4
  *
5
  * @package WooCommerce_Stripe/Classes/Payment_Request
6
+ * @since 4.0.0
7
  */
8
 
9
  if ( ! defined( 'ABSPATH' ) ) {
42
  */
43
  public $publishable_key;
44
 
45
+ /**
46
+ * Key
47
+ *
48
+ * @var
49
+ */
50
+ public $secret_key;
51
+
52
  /**
53
  * Is test mode active?
54
  *
56
  */
57
  public $testmode;
58
 
59
+ /**
60
+ * This Instance.
61
+ *
62
+ * @var
63
+ */
64
+ private static $_this;
65
+
66
  /**
67
  * Initialize class actions.
68
  *
70
  * @version 4.0.0
71
  */
72
  public function __construct() {
73
+ self::$_this = $this;
74
  $this->stripe_settings = get_option( 'woocommerce_stripe_settings', array() );
75
  $this->testmode = ( ! empty( $this->stripe_settings['testmode'] ) && 'yes' === $this->stripe_settings['testmode'] ) ? true : false;
76
  $this->publishable_key = ! empty( $this->stripe_settings['publishable_key'] ) ? $this->stripe_settings['publishable_key'] : '';
77
+ $this->secret_key = ! empty( $this->stripe_settings['secret_key'] ) ? $this->stripe_settings['secret_key'] : '';
78
  $this->stripe_checkout_enabled = isset( $this->stripe_settings['stripe_checkout'] ) && 'yes' === $this->stripe_settings['stripe_checkout'];
79
  $this->total_label = ! empty( $this->stripe_settings['statement_descriptor'] ) ? WC_Stripe_Helper::clean_statement_descriptor( $this->stripe_settings['statement_descriptor'] ) : '';
80
 
81
  if ( $this->testmode ) {
82
  $this->publishable_key = ! empty( $this->stripe_settings['test_publishable_key'] ) ? $this->stripe_settings['test_publishable_key'] : '';
83
+ $this->secret_key = ! empty( $this->stripe_settings['test_secret_key'] ) ? $this->stripe_settings['test_secret_key'] : '';
 
 
 
 
84
  }
85
 
86
  $this->total_label = str_replace( "'", '', $this->total_label ) . apply_filters( 'wc_stripe_payment_request_total_label_suffix', ' (via WooCommerce)' );
104
  $this->init();
105
  }
106
 
107
+ /**
108
+ * Checks if keys are set.
109
+ *
110
+ * @since 4.0.6
111
+ * @return bool
112
+ */
113
+ public function are_keys_set() {
114
+ if ( empty( $this->secret_key ) || empty( $this->publishable_key ) ) {
115
+ return false;
116
+ }
117
+
118
+ return true;
119
+ }
120
+
121
+ /**
122
+ * Get this instance.
123
+ *
124
+ * @since 4.0.6
125
+ * @return class
126
+ */
127
+ public static function instance() {
128
+ return self::$_this;
129
+ }
130
+
131
  /**
132
  * Sets the WC customer session if one is not set.
133
  * This is needed so nonces can be verified by AJAX Request.
427
  * @version 4.0.0
428
  */
429
  public function scripts() {
430
+ // If keys are not set bail.
431
+ if ( ! $this->are_keys_set() ) {
432
+ WC_Stripe_Logger::log( 'Keys are not set correctly.' );
433
+ return;
434
+ }
435
+
436
+ // If no SSL bail.
437
+ if ( ! $this->testmode && ! is_ssl() ) {
438
+ WC_Stripe_Logger::log( 'Stripe requires SSL.' );
439
+ return;
440
+ }
441
+
442
  if ( ! is_product() && ! is_cart() && ! is_checkout() && ! isset( $_GET['pay_for_order'] ) ) {
443
  return;
444
  }
languages/woocommerce-gateway-stripe.pot CHANGED
@@ -2,10 +2,10 @@
2
  # This file is distributed under the same license as the WooCommerce Stripe Gateway package.
3
  msgid ""
4
  msgstr ""
5
- "Project-Id-Version: WooCommerce Stripe Gateway 4.0.4\n"
6
  "Report-Msgid-Bugs-To: "
7
  "https://github.com/woocommerce/woocommerce-gateway-stripe/issues\n"
8
- "POT-Creation-Date: 2018-02-03 00:03:14+00:00\n"
9
  "MIME-Version: 1.0\n"
10
  "Content-Type: text/plain; charset=utf-8\n"
11
  "Content-Transfer-Encoding: 8bit\n"
@@ -14,9 +14,9 @@ msgstr ""
14
  "Language-Team: LANGUAGE <EMAIL@ADDRESS>\n"
15
  "X-Generator: grunt-wp-i18n1.0.1\n"
16
 
17
- #: includes/abstracts/abstract-wc-stripe-payment-gateway.php:113
18
- #: includes/compat/class-wc-stripe-compat.php:231
19
- #: includes/compat/class-wc-stripe-compat.php:536
20
  #: includes/compat/class-wc-stripe-sepa-compat.php:145
21
  #: includes/compat/class-wc-stripe-sepa-compat.php:446
22
  #. translators: 1) dollar amount
@@ -24,60 +24,60 @@ msgstr ""
24
  msgid "Sorry, the minimum allowed order total is %1$s to use this payment method."
25
  msgstr ""
26
 
27
- #: includes/abstracts/abstract-wc-stripe-payment-gateway.php:200
28
  #. translators: 1) blog name 2) order number
29
  msgid "%1$s - Order %2$s"
30
  msgstr ""
31
 
32
- #: includes/abstracts/abstract-wc-stripe-payment-gateway.php:227
33
  msgid "customer_name"
34
  msgstr ""
35
 
36
- #: includes/abstracts/abstract-wc-stripe-payment-gateway.php:228
37
  msgid "customer_email"
38
  msgstr ""
39
 
40
- #: includes/abstracts/abstract-wc-stripe-payment-gateway.php:289
41
  #. translators: transaction id
42
  msgid "Stripe charge awaiting payment: %s."
43
  msgstr ""
44
 
45
- #: includes/abstracts/abstract-wc-stripe-payment-gateway.php:296
46
- #: includes/class-wc-stripe-order-handler.php:250
47
- #: includes/class-wc-stripe-webhook-handler.php:299
48
- #: includes/class-wc-stripe-webhook-handler.php:350
49
  #. translators: transaction id
50
  msgid "Stripe charge complete (Charge ID: %s)"
51
  msgstr ""
52
 
53
- #: includes/abstracts/abstract-wc-stripe-payment-gateway.php:301
54
- #: includes/class-wc-gateway-stripe.php:628
55
- #: includes/compat/class-wc-stripe-compat.php:103
56
  #: includes/payment-methods/class-wc-gateway-stripe-bitcoin.php:374
57
  msgid "Payment processing failed. Please retry."
58
  msgstr ""
59
 
60
- #: includes/abstracts/abstract-wc-stripe-payment-gateway.php:313
61
  #. translators: transaction id
62
  msgid ""
63
  "Stripe charge authorized (Charge ID: %s). Process order to take payment, or "
64
  "cancel to remove the pre-authorization."
65
  msgstr ""
66
 
67
- #: includes/abstracts/abstract-wc-stripe-payment-gateway.php:496
68
  msgid "Invalid payment method. Please input a new card number."
69
  msgstr ""
70
 
71
- #: includes/abstracts/abstract-wc-stripe-payment-gateway.php:721
72
  #. translators: 1) dollar amount 2) transaction id 3) refund message
73
  msgid "Refunded %1$s - Refund ID: %2$s - Reason: %3$s"
74
  msgstr ""
75
 
76
- #: includes/abstracts/abstract-wc-stripe-payment-gateway.php:721
77
  msgid "Pre-Authorization Released"
78
  msgstr ""
79
 
80
- #: includes/abstracts/abstract-wc-stripe-payment-gateway.php:739
81
  msgid "There was a problem adding the card."
82
  msgstr ""
83
 
@@ -601,11 +601,11 @@ msgstr ""
601
  msgid "You will be redirected to SOFORT."
602
  msgstr ""
603
 
604
- #: includes/class-wc-gateway-stripe.php:118
605
  msgid "Stripe"
606
  msgstr ""
607
 
608
- #: includes/class-wc-gateway-stripe.php:120
609
  #. translators: 1) link to Stripe register page 2) link to Stripe api keys page
610
  msgid ""
611
  "Stripe works by adding payment fields on the checkout and then sending the "
@@ -614,40 +614,15 @@ msgid ""
614
  "your Stripe account keys</a>."
615
  msgstr ""
616
 
617
- #: includes/class-wc-gateway-stripe.php:166
618
  msgid "Continue to payment"
619
  msgstr ""
620
 
621
- #: includes/class-wc-gateway-stripe.php:249
622
- msgid "Unable to verify domain - missing secret key."
623
- msgstr ""
624
-
625
- #: includes/class-wc-gateway-stripe.php:270
626
- #: includes/class-wc-gateway-stripe.php:279
627
- #. translators: error message
628
- msgid "Unable to verify domain - %s"
629
- msgstr ""
630
-
631
- #: includes/class-wc-gateway-stripe.php:304
632
- msgid "Unable to create domain association folder to domain root."
633
- msgstr ""
634
-
635
- #: includes/class-wc-gateway-stripe.php:310
636
- msgid "Unable to copy domain association file to domain root."
637
- msgstr ""
638
-
639
- #: includes/class-wc-gateway-stripe.php:361
640
- #. translators: 1) HTML anchor open tag 2) HTML anchor closing tag
641
- msgid ""
642
- "Apple Pay domain verification failed. Please check the %1$slog%2$s to see "
643
- "the issue. (Logging must be enabled to see recorded logs)"
644
- msgstr ""
645
-
646
- #: includes/class-wc-gateway-stripe.php:394
647
  msgid "Add Card"
648
  msgstr ""
649
 
650
- #: includes/class-wc-gateway-stripe.php:417
651
  #. translators: link to Stripe testing page
652
  msgid ""
653
  "TEST MODE ENABLED. In test mode, you can use the card number "
@@ -656,63 +631,89 @@ msgid ""
656
  "more card numbers."
657
  msgstr ""
658
 
659
- #: includes/class-wc-gateway-stripe.php:457
660
  msgid "Credit or debit card"
661
  msgstr ""
662
 
663
- #: includes/class-wc-gateway-stripe.php:465
664
  msgid "Card Number"
665
  msgstr ""
666
 
667
- #: includes/class-wc-gateway-stripe.php:473
668
  msgid "Expiry Date"
669
  msgstr ""
670
 
671
- #: includes/class-wc-gateway-stripe.php:481
672
  msgid "Card Code (CVC)"
673
  msgstr ""
674
 
675
- #: includes/class-wc-gateway-stripe.php:537
676
  msgid "Please accept the terms and conditions first"
677
  msgstr ""
678
 
679
- #: includes/class-wc-gateway-stripe.php:538
680
  msgid "Please fill in required checkout fields first"
681
  msgstr ""
682
 
683
- #: includes/class-wc-gateway-stripe.php:556
684
- #: includes/class-wc-gateway-stripe.php:622
685
- #: includes/compat/class-wc-stripe-compat.php:97
686
  msgid ""
687
  "Sorry, we're not accepting prepaid cards at this time. Your credit card has "
688
  "not been charge. Please try with alternative payment method."
689
  msgstr ""
690
 
691
- #: includes/class-wc-gateway-stripe.php:557
692
  msgid "Please enter your IBAN account name."
693
  msgstr ""
694
 
695
- #: includes/class-wc-gateway-stripe.php:558
696
  msgid "Please enter your IBAN account number."
697
  msgstr ""
698
 
699
- #: includes/class-wc-gateway-stripe.php:707
700
- #: includes/class-wc-stripe-order-handler.php:141
701
- #: includes/class-wc-stripe-webhook-handler.php:180
702
- msgid "On going requests error and retries exhausted."
 
703
  msgstr ""
704
 
705
- #: includes/class-wc-gateway-stripe.php:729
706
- #: includes/class-wc-stripe-order-handler.php:165
707
- #: includes/class-wc-stripe-webhook-handler.php:203
708
- #: includes/payment-methods/class-wc-gateway-stripe-sepa.php:381
709
- msgid "This card is no longer available and has been removed."
710
  msgstr ""
711
 
712
- #: includes/class-wc-stripe-api.php:122 includes/class-wc-stripe-api.php:149
713
  msgid "There was a problem connecting to the Stripe API endpoint."
714
  msgstr ""
715
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
716
  #: includes/class-wc-stripe-customer.php:164
717
  msgid "Unable to add payment source."
718
  msgstr ""
@@ -786,87 +787,21 @@ msgstr ""
786
  msgid "The billing country is not accepted by SOFORT. Please try another country."
787
  msgstr ""
788
 
789
- #: includes/class-wc-stripe-order-handler.php:122
790
- msgid "API connection error and retries exhausted."
791
- msgstr ""
792
-
793
- #: includes/class-wc-stripe-order-handler.php:191
794
  #. translators: error message
795
  msgid "Stripe payment failed: %s"
796
  msgstr ""
797
 
798
- #: includes/class-wc-stripe-order-handler.php:247
799
  #. translators: error message
800
  msgid "Unable to capture charge! %s"
801
  msgstr ""
802
 
803
- #: includes/class-wc-stripe-order-handler.php:308
804
- msgid "Billing"
805
- msgstr ""
806
-
807
- #: includes/class-wc-stripe-order-handler.php:310
808
- #: includes/payment-methods/class-wc-stripe-payment-request.php:224
809
- #: includes/payment-methods/class-wc-stripe-payment-request.php:771
810
- #: includes/payment-methods/class-wc-stripe-payment-request.php:1059
811
- msgid "Shipping"
812
- msgstr ""
813
-
814
- #: includes/class-wc-stripe-order-handler.php:331
815
- msgid "Owner"
816
- msgstr ""
817
-
818
- #: includes/class-wc-stripe-order-handler.php:347
819
- #: woocommerce-gateway-stripe.php:149
820
  msgid "Cheatin&#8217; huh?"
821
  msgstr ""
822
 
823
- #: includes/class-wc-stripe-order-handler.php:396
824
- #. translators: error field name
825
- msgid "<strong>%s</strong> cannot be empty"
826
- msgstr ""
827
-
828
- #: includes/class-wc-stripe-order-handler.php:402
829
- msgid "Email is not valid"
830
- msgstr ""
831
-
832
- #: includes/class-wc-stripe-order-handler.php:411
833
- #. translators: %s: phone number
834
- msgid "Please enter a valid phone number."
835
- msgstr ""
836
-
837
- #: includes/class-wc-stripe-order-handler.php:421
838
- msgid "Please enter a valid billing postcode / ZIP."
839
- msgstr ""
840
-
841
- #: includes/class-wc-stripe-order-handler.php:428
842
- msgid "You must accept our Terms &amp; Conditions."
843
- msgstr ""
844
-
845
- #: includes/class-wc-stripe-order-handler.php:439
846
- msgid "Please enter a valid shipping postcode / ZIP."
847
- msgstr ""
848
-
849
- #: includes/class-wc-stripe-order-handler.php:448
850
- msgid "Please enter an address to continue."
851
- msgstr ""
852
-
853
- #: includes/class-wc-stripe-order-handler.php:451
854
- #. translators: country name
855
- msgid ""
856
- "Unfortunately <strong>we do not ship %s</strong>. Please enter an "
857
- "alternative shipping address."
858
- msgstr ""
859
-
860
- #: includes/class-wc-stripe-order-handler.php:457
861
- msgid ""
862
- "No shipping method has been selected. Please double check your address, or "
863
- "contact us if you need any help."
864
- msgstr ""
865
-
866
- #: includes/class-wc-stripe-order-handler.php:467
867
- msgid "Invalid payment method."
868
- msgstr ""
869
-
870
  #: includes/class-wc-stripe-payment-tokens.php:150
871
  msgid "SEPA IBAN"
872
  msgstr ""
@@ -876,41 +811,56 @@ msgstr ""
876
  msgid "SEPA IBAN ending in %s"
877
  msgstr ""
878
 
879
- #: includes/class-wc-stripe-webhook-handler.php:254
 
880
  msgid ""
881
  "A dispute was created for this order. Response is needed. Please go to your "
882
- "Stripe Dashboard to review this dispute."
 
883
  msgstr ""
884
 
885
- #: includes/class-wc-stripe-webhook-handler.php:304
886
  msgid "This charge was partially captured via Stripe Dashboard"
887
  msgstr ""
888
 
889
- #: includes/class-wc-stripe-webhook-handler.php:375
890
  msgid "This payment failed to clear."
891
  msgstr ""
892
 
893
- #: includes/class-wc-stripe-webhook-handler.php:402
894
  msgid "This payment has cancelled."
895
  msgstr ""
896
 
897
- #: includes/class-wc-stripe-webhook-handler.php:437
898
  msgid "Refunded via Stripe Dashboard"
899
  msgstr ""
900
 
901
- #: includes/class-wc-stripe-webhook-handler.php:437
902
  msgid "Pre-Authorization Released via Stripe Dashboard"
903
  msgstr ""
904
 
905
- #: includes/compat/class-wc-stripe-compat.php:240
 
 
 
 
 
 
 
 
 
 
 
 
 
906
  #: includes/compat/class-wc-stripe-sepa-compat.php:154
907
  msgid "Customer not found"
908
  msgstr ""
909
 
910
- #: includes/compat/class-wc-stripe-compat.php:258
911
- #: includes/compat/class-wc-stripe-compat.php:304
912
- #: includes/compat/class-wc-stripe-compat.php:313
913
- #: includes/compat/class-wc-stripe-compat.php:600
914
  #: includes/compat/class-wc-stripe-sepa-compat.php:172
915
  #: includes/compat/class-wc-stripe-sepa-compat.php:218
916
  #: includes/compat/class-wc-stripe-sepa-compat.php:227
@@ -919,37 +869,37 @@ msgstr ""
919
  msgid "Stripe Transaction Failed (%s)"
920
  msgstr ""
921
 
922
- #: includes/compat/class-wc-stripe-compat.php:408
923
  #: includes/compat/class-wc-stripe-sepa-compat.php:320
924
  msgid "A \"Stripe Customer ID\" value is required."
925
  msgstr ""
926
 
927
- #: includes/compat/class-wc-stripe-compat.php:410
928
  #: includes/compat/class-wc-stripe-sepa-compat.php:322
929
  msgid ""
930
  "Invalid customer ID. A valid \"Stripe Customer ID\" must begin with "
931
  "\"cus_\"."
932
  msgstr ""
933
 
934
- #: includes/compat/class-wc-stripe-compat.php:419
935
  #: includes/compat/class-wc-stripe-sepa-compat.php:331
936
  msgid ""
937
  "Invalid source ID. A valid source \"Stripe Source ID\" must begin with "
938
  "\"src_\" or \"card_\"."
939
  msgstr ""
940
 
941
- #: includes/compat/class-wc-stripe-compat.php:499
942
- #: includes/compat/class-wc-stripe-compat.php:514
943
  #: includes/compat/class-wc-stripe-sepa-compat.php:409
944
  #: includes/compat/class-wc-stripe-sepa-compat.php:424
945
  #. translators: 1) card brand 2) last 4 digits
946
  msgid "Via %1$s card ending in %2$s"
947
  msgstr ""
948
 
949
- #: includes/compat/class-wc-stripe-compat.php:499
950
- #: includes/compat/class-wc-stripe-compat.php:501
951
- #: includes/compat/class-wc-stripe-compat.php:514
952
- #: includes/compat/class-wc-stripe-compat.php:516
953
  #: includes/compat/class-wc-stripe-sepa-compat.php:409
954
  #: includes/compat/class-wc-stripe-sepa-compat.php:411
955
  #: includes/compat/class-wc-stripe-sepa-compat.php:424
@@ -957,13 +907,13 @@ msgstr ""
957
  msgid "N/A"
958
  msgstr ""
959
 
960
- #: includes/compat/class-wc-stripe-compat.php:543
961
  #: includes/compat/class-wc-stripe-sepa-compat.php:453
962
  msgid "Unable to store payment details. Please try again."
963
  msgstr ""
964
 
965
  #: includes/payment-methods/class-wc-gateway-stripe-alipay.php:60
966
- #: woocommerce-gateway-stripe.php:413
967
  msgid "Stripe Alipay"
968
  msgstr ""
969
 
@@ -973,7 +923,7 @@ msgstr ""
973
  #: includes/payment-methods/class-wc-gateway-stripe-giropay.php:62
974
  #: includes/payment-methods/class-wc-gateway-stripe-ideal.php:62
975
  #: includes/payment-methods/class-wc-gateway-stripe-p24.php:62
976
- #: includes/payment-methods/class-wc-gateway-stripe-sepa.php:62
977
  #: includes/payment-methods/class-wc-gateway-stripe-sofort.php:62
978
  #. translators: link
979
  msgid "All other general Stripe settings can be adjusted <a href=\"%s\">here</a>."
@@ -990,13 +940,13 @@ msgstr ""
990
  #: includes/payment-methods/class-wc-gateway-stripe-giropay.php:218
991
  #: includes/payment-methods/class-wc-gateway-stripe-ideal.php:218
992
  #: includes/payment-methods/class-wc-gateway-stripe-p24.php:219
993
- #: includes/payment-methods/class-wc-gateway-stripe-sepa.php:279
994
  #: includes/payment-methods/class-wc-gateway-stripe-sofort.php:218
995
  msgid "Add Payment"
996
  msgstr ""
997
 
998
  #: includes/payment-methods/class-wc-gateway-stripe-bancontact.php:60
999
- #: woocommerce-gateway-stripe.php:408
1000
  msgid "Stripe Bancontact"
1001
  msgstr ""
1002
 
@@ -1005,7 +955,7 @@ msgid "Bancontact is enabled - it requires store currency to be set to Euros."
1005
  msgstr ""
1006
 
1007
  #: includes/payment-methods/class-wc-gateway-stripe-bitcoin.php:67
1008
- #: woocommerce-gateway-stripe.php:415
1009
  msgid "Stripe Bitcoin"
1010
  msgstr ""
1011
 
@@ -1043,7 +993,7 @@ msgid "Awaiting Bitcoin payment"
1043
  msgstr ""
1044
 
1045
  #: includes/payment-methods/class-wc-gateway-stripe-giropay.php:60
1046
- #: woocommerce-gateway-stripe.php:410
1047
  msgid "Stripe Giropay"
1048
  msgstr ""
1049
 
@@ -1052,7 +1002,7 @@ msgid "Giropay is enabled - it requires store currency to be set to Euros."
1052
  msgstr ""
1053
 
1054
  #: includes/payment-methods/class-wc-gateway-stripe-ideal.php:60
1055
- #: woocommerce-gateway-stripe.php:411
1056
  msgid "Stripe iDeal"
1057
  msgstr ""
1058
 
@@ -1061,7 +1011,7 @@ msgid "iDeal is enabled - it requires store currency to be set to Euros."
1061
  msgstr ""
1062
 
1063
  #: includes/payment-methods/class-wc-gateway-stripe-p24.php:60
1064
- #: woocommerce-gateway-stripe.php:412
1065
  msgid "Stripe P24"
1066
  msgstr ""
1067
 
@@ -1071,16 +1021,16 @@ msgid ""
1071
  "Zloty."
1072
  msgstr ""
1073
 
1074
- #: includes/payment-methods/class-wc-gateway-stripe-sepa.php:60
1075
- #: woocommerce-gateway-stripe.php:414
1076
  msgid "Stripe SEPA Direct Debit"
1077
  msgstr ""
1078
 
1079
- #: includes/payment-methods/class-wc-gateway-stripe-sepa.php:141
1080
  msgid "SEPA is enabled - it requires store currency to be set to Euros."
1081
  msgstr ""
1082
 
1083
- #: includes/payment-methods/class-wc-gateway-stripe-sepa.php:230
1084
  #. translators: statement descriptor
1085
  msgid ""
1086
  "By providing your IBAN and confirming this payment, you are authorizing %s "
@@ -1092,22 +1042,22 @@ msgid ""
1092
  "debited."
1093
  msgstr ""
1094
 
1095
- #: includes/payment-methods/class-wc-gateway-stripe-sepa.php:246
1096
  msgid "IBAN Account Name."
1097
  msgstr ""
1098
 
1099
- #: includes/payment-methods/class-wc-gateway-stripe-sepa.php:252
1100
  msgid "IBAN Account Number."
1101
  msgstr ""
1102
 
1103
- #: includes/payment-methods/class-wc-gateway-stripe-sepa.php:292
1104
  msgid ""
1105
  "TEST MODE ENABLED. In test mode, you can use IBAN number "
1106
  "DE89370400440532013000."
1107
  msgstr ""
1108
 
1109
  #: includes/payment-methods/class-wc-gateway-stripe-sofort.php:60
1110
- #: woocommerce-gateway-stripe.php:409
1111
  msgid "Stripe SOFORT"
1112
  msgstr ""
1113
 
@@ -1115,77 +1065,83 @@ msgstr ""
1115
  msgid "SOFORT is enabled - it requires store currency to be set to Euros."
1116
  msgstr ""
1117
 
1118
- #: includes/payment-methods/class-wc-stripe-payment-request.php:216
1119
- #: includes/payment-methods/class-wc-stripe-payment-request.php:763
1120
- #: includes/payment-methods/class-wc-stripe-payment-request.php:1052
1121
  msgid "Tax"
1122
  msgstr ""
1123
 
1124
- #: includes/payment-methods/class-wc-stripe-payment-request.php:231
1125
- #: includes/payment-methods/class-wc-stripe-payment-request.php:778
 
 
 
 
 
 
1126
  msgid "Pending"
1127
  msgstr ""
1128
 
1129
- #: includes/payment-methods/class-wc-stripe-payment-request.php:437
1130
  msgid "Sorry, we're not accepting prepaid cards at this time."
1131
  msgstr ""
1132
 
1133
- #: includes/payment-methods/class-wc-stripe-payment-request.php:439
1134
  #. translators: Do not translate the [option] placeholder
1135
  msgid "Unknown shipping option \"[option]\"."
1136
  msgstr ""
1137
 
1138
- #: includes/payment-methods/class-wc-stripe-payment-request.php:561
1139
  msgid "OR"
1140
  msgstr ""
1141
 
1142
- #: includes/payment-methods/class-wc-stripe-payment-request.php:652
1143
- #: includes/payment-methods/class-wc-stripe-payment-request.php:665
1144
  msgid "Unable to find shipping method for address."
1145
  msgstr ""
1146
 
1147
- #: includes/payment-methods/class-wc-stripe-payment-request.php:898
1148
  msgid "Empty cart"
1149
  msgstr ""
1150
 
1151
- #: includes/payment-methods/class-wc-stripe-payment-request.php:1066
1152
  msgid "Discount"
1153
  msgstr ""
1154
 
1155
- #: woocommerce-gateway-stripe.php:145
1156
  msgid "Action failed. Please refresh the page and retry."
1157
  msgstr ""
1158
 
1159
- #: woocommerce-gateway-stripe.php:215
1160
  #. translators: 1) int version 2) int version
1161
  msgid ""
1162
  "WooCommerce Stripe - The minimum PHP version required for this plugin is "
1163
  "%1$s. You are running %2$s."
1164
  msgstr ""
1165
 
1166
- #: woocommerce-gateway-stripe.php:221
1167
  msgid "WooCommerce Stripe requires WooCommerce to be activated to work."
1168
  msgstr ""
1169
 
1170
- #: woocommerce-gateway-stripe.php:226
1171
  #. translators: 1) int version 2) int version
1172
  msgid ""
1173
  "WooCommerce Stripe - The minimum WooCommerce version required for this "
1174
  "plugin is %1$s. You are running %2$s."
1175
  msgstr ""
1176
 
1177
- #: woocommerce-gateway-stripe.php:232
1178
  msgid "WooCommerce Stripe - cURL is not installed."
1179
  msgstr ""
1180
 
1181
- #: woocommerce-gateway-stripe.php:288
1182
  #. translators: 1) link
1183
  msgid ""
1184
  "Stripe is almost ready. To get started, <a href=\"%s\">set your Stripe "
1185
  "account keys</a>."
1186
  msgstr ""
1187
 
1188
- #: woocommerce-gateway-stripe.php:300
1189
  #. translators: 1) link
1190
  msgid ""
1191
  "Stripe is in test mode however your test keys may not be valid. Test keys "
@@ -1193,7 +1149,7 @@ msgid ""
1193
  "<a href=\"%s\">set your Stripe account keys</a>."
1194
  msgstr ""
1195
 
1196
- #: woocommerce-gateway-stripe.php:310
1197
  #. translators: 1) link
1198
  msgid ""
1199
  "Stripe is in live mode however your test keys may not be valid. Live keys "
@@ -1201,7 +1157,7 @@ msgid ""
1201
  "<a href=\"%s\">set your Stripe account keys</a>."
1202
  msgstr ""
1203
 
1204
- #: woocommerce-gateway-stripe.php:319
1205
  #. translators: 1) link 2) link
1206
  msgid ""
1207
  "Stripe is enabled, but the <a href=\"%1$s\">force SSL option</a> is "
@@ -1210,15 +1166,15 @@ msgid ""
1210
  "certificate</a> - Stripe will only work in test mode."
1211
  msgstr ""
1212
 
1213
- #: woocommerce-gateway-stripe.php:357
1214
  msgid "Settings"
1215
  msgstr ""
1216
 
1217
- #: woocommerce-gateway-stripe.php:358
1218
  msgid "Docs"
1219
  msgstr ""
1220
 
1221
- #: woocommerce-gateway-stripe.php:359
1222
  msgid "Support"
1223
  msgstr ""
1224
 
2
  # This file is distributed under the same license as the WooCommerce Stripe Gateway package.
3
  msgid ""
4
  msgstr ""
5
+ "Project-Id-Version: WooCommerce Stripe Gateway 4.0.5\n"
6
  "Report-Msgid-Bugs-To: "
7
  "https://github.com/woocommerce/woocommerce-gateway-stripe/issues\n"
8
+ "POT-Creation-Date: 2018-02-20 16:36:16+00:00\n"
9
  "MIME-Version: 1.0\n"
10
  "Content-Type: text/plain; charset=utf-8\n"
11
  "Content-Transfer-Encoding: 8bit\n"
14
  "Language-Team: LANGUAGE <EMAIL@ADDRESS>\n"
15
  "X-Generator: grunt-wp-i18n1.0.1\n"
16
 
17
+ #: includes/abstracts/abstract-wc-stripe-payment-gateway.php:115
18
+ #: includes/compat/class-wc-stripe-compat.php:210
19
+ #: includes/compat/class-wc-stripe-compat.php:515
20
  #: includes/compat/class-wc-stripe-sepa-compat.php:145
21
  #: includes/compat/class-wc-stripe-sepa-compat.php:446
22
  #. translators: 1) dollar amount
24
  msgid "Sorry, the minimum allowed order total is %1$s to use this payment method."
25
  msgstr ""
26
 
27
+ #: includes/abstracts/abstract-wc-stripe-payment-gateway.php:211
28
  #. translators: 1) blog name 2) order number
29
  msgid "%1$s - Order %2$s"
30
  msgstr ""
31
 
32
+ #: includes/abstracts/abstract-wc-stripe-payment-gateway.php:238
33
  msgid "customer_name"
34
  msgstr ""
35
 
36
+ #: includes/abstracts/abstract-wc-stripe-payment-gateway.php:239
37
  msgid "customer_email"
38
  msgstr ""
39
 
40
+ #: includes/abstracts/abstract-wc-stripe-payment-gateway.php:309
41
  #. translators: transaction id
42
  msgid "Stripe charge awaiting payment: %s."
43
  msgstr ""
44
 
45
+ #: includes/abstracts/abstract-wc-stripe-payment-gateway.php:316
46
+ #: includes/class-wc-stripe-order-handler.php:252
47
+ #: includes/class-wc-stripe-webhook-handler.php:309
48
+ #: includes/class-wc-stripe-webhook-handler.php:360
49
  #. translators: transaction id
50
  msgid "Stripe charge complete (Charge ID: %s)"
51
  msgstr ""
52
 
53
+ #: includes/abstracts/abstract-wc-stripe-payment-gateway.php:321
54
+ #: includes/class-wc-gateway-stripe.php:502
55
+ #: includes/compat/class-wc-stripe-compat.php:100
56
  #: includes/payment-methods/class-wc-gateway-stripe-bitcoin.php:374
57
  msgid "Payment processing failed. Please retry."
58
  msgstr ""
59
 
60
+ #: includes/abstracts/abstract-wc-stripe-payment-gateway.php:333
61
  #. translators: transaction id
62
  msgid ""
63
  "Stripe charge authorized (Charge ID: %s). Process order to take payment, or "
64
  "cancel to remove the pre-authorization."
65
  msgstr ""
66
 
67
+ #: includes/abstracts/abstract-wc-stripe-payment-gateway.php:527
68
  msgid "Invalid payment method. Please input a new card number."
69
  msgstr ""
70
 
71
+ #: includes/abstracts/abstract-wc-stripe-payment-gateway.php:767
72
  #. translators: 1) dollar amount 2) transaction id 3) refund message
73
  msgid "Refunded %1$s - Refund ID: %2$s - Reason: %3$s"
74
  msgstr ""
75
 
76
+ #: includes/abstracts/abstract-wc-stripe-payment-gateway.php:767
77
  msgid "Pre-Authorization Released"
78
  msgstr ""
79
 
80
+ #: includes/abstracts/abstract-wc-stripe-payment-gateway.php:785
81
  msgid "There was a problem adding the card."
82
  msgstr ""
83
 
601
  msgid "You will be redirected to SOFORT."
602
  msgstr ""
603
 
604
+ #: includes/class-wc-gateway-stripe.php:109
605
  msgid "Stripe"
606
  msgstr ""
607
 
608
+ #: includes/class-wc-gateway-stripe.php:111
609
  #. translators: 1) link to Stripe register page 2) link to Stripe api keys page
610
  msgid ""
611
  "Stripe works by adding payment fields on the checkout and then sending the "
614
  "your Stripe account keys</a>."
615
  msgstr ""
616
 
617
+ #: includes/class-wc-gateway-stripe.php:155
618
  msgid "Continue to payment"
619
  msgstr ""
620
 
621
+ #: includes/class-wc-gateway-stripe.php:251
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
622
  msgid "Add Card"
623
  msgstr ""
624
 
625
+ #: includes/class-wc-gateway-stripe.php:274
626
  #. translators: link to Stripe testing page
627
  msgid ""
628
  "TEST MODE ENABLED. In test mode, you can use the card number "
631
  "more card numbers."
632
  msgstr ""
633
 
634
+ #: includes/class-wc-gateway-stripe.php:315
635
  msgid "Credit or debit card"
636
  msgstr ""
637
 
638
+ #: includes/class-wc-gateway-stripe.php:323
639
  msgid "Card Number"
640
  msgstr ""
641
 
642
+ #: includes/class-wc-gateway-stripe.php:331
643
  msgid "Expiry Date"
644
  msgstr ""
645
 
646
+ #: includes/class-wc-gateway-stripe.php:339
647
  msgid "Card Code (CVC)"
648
  msgstr ""
649
 
650
+ #: includes/class-wc-gateway-stripe.php:412
651
  msgid "Please accept the terms and conditions first"
652
  msgstr ""
653
 
654
+ #: includes/class-wc-gateway-stripe.php:413
655
  msgid "Please fill in required checkout fields first"
656
  msgstr ""
657
 
658
+ #: includes/class-wc-gateway-stripe.php:431
659
+ #: includes/class-wc-gateway-stripe.php:497
660
+ #: includes/compat/class-wc-stripe-compat.php:95
661
  msgid ""
662
  "Sorry, we're not accepting prepaid cards at this time. Your credit card has "
663
  "not been charge. Please try with alternative payment method."
664
  msgstr ""
665
 
666
+ #: includes/class-wc-gateway-stripe.php:432
667
  msgid "Please enter your IBAN account name."
668
  msgstr ""
669
 
670
+ #: includes/class-wc-gateway-stripe.php:433
671
  msgid "Please enter your IBAN account number."
672
  msgstr ""
673
 
674
+ #: includes/class-wc-gateway-stripe.php:578
675
+ #: includes/class-wc-stripe-order-handler.php:143
676
+ #: includes/class-wc-stripe-webhook-handler.php:207
677
+ #: includes/payment-methods/class-wc-gateway-stripe-sepa.php:377
678
+ msgid "This card is no longer available and has been removed."
679
  msgstr ""
680
 
681
+ #: includes/class-wc-gateway-stripe.php:598
682
+ #: includes/class-wc-stripe-order-handler.php:161
683
+ #: includes/class-wc-stripe-webhook-handler.php:184
684
+ #: includes/payment-methods/class-wc-gateway-stripe-sepa.php:397
685
+ msgid "On going requests error and retries exhausted."
686
  msgstr ""
687
 
688
+ #: includes/class-wc-stripe-api.php:123 includes/class-wc-stripe-api.php:154
689
  msgid "There was a problem connecting to the Stripe API endpoint."
690
  msgstr ""
691
 
692
+ #: includes/class-wc-stripe-apple-pay-registration.php:122
693
+ msgid "Unable to verify domain - missing secret key."
694
+ msgstr ""
695
+
696
+ #: includes/class-wc-stripe-apple-pay-registration.php:143
697
+ #: includes/class-wc-stripe-apple-pay-registration.php:152
698
+ #. translators: error message
699
+ msgid "Unable to verify domain - %s"
700
+ msgstr ""
701
+
702
+ #: includes/class-wc-stripe-apple-pay-registration.php:175
703
+ msgid "Unable to create domain association folder to domain root."
704
+ msgstr ""
705
+
706
+ #: includes/class-wc-stripe-apple-pay-registration.php:181
707
+ msgid "Unable to copy domain association file to domain root."
708
+ msgstr ""
709
+
710
+ #: includes/class-wc-stripe-apple-pay-registration.php:234
711
+ #. translators: 1) HTML anchor open tag 2) HTML anchor closing tag
712
+ msgid ""
713
+ "Apple Pay domain verification failed. Please check the %1$slog%2$s to see "
714
+ "the issue. (Logging must be enabled to see recorded logs)"
715
+ msgstr ""
716
+
717
  #: includes/class-wc-stripe-customer.php:164
718
  msgid "Unable to add payment source."
719
  msgstr ""
787
  msgid "The billing country is not accepted by SOFORT. Please try another country."
788
  msgstr ""
789
 
790
+ #: includes/class-wc-stripe-order-handler.php:193
 
 
 
 
791
  #. translators: error message
792
  msgid "Stripe payment failed: %s"
793
  msgstr ""
794
 
795
+ #: includes/class-wc-stripe-order-handler.php:249
796
  #. translators: error message
797
  msgid "Unable to capture charge! %s"
798
  msgstr ""
799
 
800
+ #: includes/class-wc-stripe-order-handler.php:304
801
+ #: woocommerce-gateway-stripe.php:150
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
802
  msgid "Cheatin&#8217; huh?"
803
  msgstr ""
804
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
805
  #: includes/class-wc-stripe-payment-tokens.php:150
806
  msgid "SEPA IBAN"
807
  msgstr ""
811
  msgid "SEPA IBAN ending in %s"
812
  msgstr ""
813
 
814
+ #: includes/class-wc-stripe-webhook-handler.php:264
815
+ #. translators: 1) The URL to the order.
816
  msgid ""
817
  "A dispute was created for this order. Response is needed. Please go to your "
818
+ "<a href=\"%s\" title=\"Stripe Dashboard\" target=\"_blank\">Stripe "
819
+ "Dashboard</a> to review this dispute."
820
  msgstr ""
821
 
822
+ #: includes/class-wc-stripe-webhook-handler.php:314
823
  msgid "This charge was partially captured via Stripe Dashboard"
824
  msgstr ""
825
 
826
+ #: includes/class-wc-stripe-webhook-handler.php:385
827
  msgid "This payment failed to clear."
828
  msgstr ""
829
 
830
+ #: includes/class-wc-stripe-webhook-handler.php:412
831
  msgid "This payment has cancelled."
832
  msgstr ""
833
 
834
+ #: includes/class-wc-stripe-webhook-handler.php:447
835
  msgid "Refunded via Stripe Dashboard"
836
  msgstr ""
837
 
838
+ #: includes/class-wc-stripe-webhook-handler.php:447
839
  msgid "Pre-Authorization Released via Stripe Dashboard"
840
  msgstr ""
841
 
842
+ #: includes/class-wc-stripe-webhook-handler.php:480
843
+ #. translators: 1) The URL to the order. 2) The reason type.
844
+ msgid ""
845
+ "A review has been opened for this order. Action is needed. Please go to "
846
+ "your <a href=\"%1$s\" title=\"Stripe Dashboard\" target=\"_blank\">Stripe "
847
+ "Dashboard</a> to review the issue. Reason: (%2$s)"
848
+ msgstr ""
849
+
850
+ #: includes/class-wc-stripe-webhook-handler.php:504
851
+ #. translators: 1) The reason type.
852
+ msgid "The opened review for this order is now closed. Reason: (%s)"
853
+ msgstr ""
854
+
855
+ #: includes/compat/class-wc-stripe-compat.php:219
856
  #: includes/compat/class-wc-stripe-sepa-compat.php:154
857
  msgid "Customer not found"
858
  msgstr ""
859
 
860
+ #: includes/compat/class-wc-stripe-compat.php:237
861
+ #: includes/compat/class-wc-stripe-compat.php:283
862
+ #: includes/compat/class-wc-stripe-compat.php:292
863
+ #: includes/compat/class-wc-stripe-compat.php:579
864
  #: includes/compat/class-wc-stripe-sepa-compat.php:172
865
  #: includes/compat/class-wc-stripe-sepa-compat.php:218
866
  #: includes/compat/class-wc-stripe-sepa-compat.php:227
869
  msgid "Stripe Transaction Failed (%s)"
870
  msgstr ""
871
 
872
+ #: includes/compat/class-wc-stripe-compat.php:387
873
  #: includes/compat/class-wc-stripe-sepa-compat.php:320
874
  msgid "A \"Stripe Customer ID\" value is required."
875
  msgstr ""
876
 
877
+ #: includes/compat/class-wc-stripe-compat.php:389
878
  #: includes/compat/class-wc-stripe-sepa-compat.php:322
879
  msgid ""
880
  "Invalid customer ID. A valid \"Stripe Customer ID\" must begin with "
881
  "\"cus_\"."
882
  msgstr ""
883
 
884
+ #: includes/compat/class-wc-stripe-compat.php:398
885
  #: includes/compat/class-wc-stripe-sepa-compat.php:331
886
  msgid ""
887
  "Invalid source ID. A valid source \"Stripe Source ID\" must begin with "
888
  "\"src_\" or \"card_\"."
889
  msgstr ""
890
 
891
+ #: includes/compat/class-wc-stripe-compat.php:478
892
+ #: includes/compat/class-wc-stripe-compat.php:493
893
  #: includes/compat/class-wc-stripe-sepa-compat.php:409
894
  #: includes/compat/class-wc-stripe-sepa-compat.php:424
895
  #. translators: 1) card brand 2) last 4 digits
896
  msgid "Via %1$s card ending in %2$s"
897
  msgstr ""
898
 
899
+ #: includes/compat/class-wc-stripe-compat.php:478
900
+ #: includes/compat/class-wc-stripe-compat.php:480
901
+ #: includes/compat/class-wc-stripe-compat.php:493
902
+ #: includes/compat/class-wc-stripe-compat.php:495
903
  #: includes/compat/class-wc-stripe-sepa-compat.php:409
904
  #: includes/compat/class-wc-stripe-sepa-compat.php:411
905
  #: includes/compat/class-wc-stripe-sepa-compat.php:424
907
  msgid "N/A"
908
  msgstr ""
909
 
910
+ #: includes/compat/class-wc-stripe-compat.php:522
911
  #: includes/compat/class-wc-stripe-sepa-compat.php:453
912
  msgid "Unable to store payment details. Please try again."
913
  msgstr ""
914
 
915
  #: includes/payment-methods/class-wc-gateway-stripe-alipay.php:60
916
+ #: woocommerce-gateway-stripe.php:414
917
  msgid "Stripe Alipay"
918
  msgstr ""
919
 
923
  #: includes/payment-methods/class-wc-gateway-stripe-giropay.php:62
924
  #: includes/payment-methods/class-wc-gateway-stripe-ideal.php:62
925
  #: includes/payment-methods/class-wc-gateway-stripe-p24.php:62
926
+ #: includes/payment-methods/class-wc-gateway-stripe-sepa.php:70
927
  #: includes/payment-methods/class-wc-gateway-stripe-sofort.php:62
928
  #. translators: link
929
  msgid "All other general Stripe settings can be adjusted <a href=\"%s\">here</a>."
940
  #: includes/payment-methods/class-wc-gateway-stripe-giropay.php:218
941
  #: includes/payment-methods/class-wc-gateway-stripe-ideal.php:218
942
  #: includes/payment-methods/class-wc-gateway-stripe-p24.php:219
943
+ #: includes/payment-methods/class-wc-gateway-stripe-sepa.php:287
944
  #: includes/payment-methods/class-wc-gateway-stripe-sofort.php:218
945
  msgid "Add Payment"
946
  msgstr ""
947
 
948
  #: includes/payment-methods/class-wc-gateway-stripe-bancontact.php:60
949
+ #: woocommerce-gateway-stripe.php:409
950
  msgid "Stripe Bancontact"
951
  msgstr ""
952
 
955
  msgstr ""
956
 
957
  #: includes/payment-methods/class-wc-gateway-stripe-bitcoin.php:67
958
+ #: woocommerce-gateway-stripe.php:416
959
  msgid "Stripe Bitcoin"
960
  msgstr ""
961
 
993
  msgstr ""
994
 
995
  #: includes/payment-methods/class-wc-gateway-stripe-giropay.php:60
996
+ #: woocommerce-gateway-stripe.php:411
997
  msgid "Stripe Giropay"
998
  msgstr ""
999
 
1002
  msgstr ""
1003
 
1004
  #: includes/payment-methods/class-wc-gateway-stripe-ideal.php:60
1005
+ #: woocommerce-gateway-stripe.php:412
1006
  msgid "Stripe iDeal"
1007
  msgstr ""
1008
 
1011
  msgstr ""
1012
 
1013
  #: includes/payment-methods/class-wc-gateway-stripe-p24.php:60
1014
+ #: woocommerce-gateway-stripe.php:413
1015
  msgid "Stripe P24"
1016
  msgstr ""
1017
 
1021
  "Zloty."
1022
  msgstr ""
1023
 
1024
+ #: includes/payment-methods/class-wc-gateway-stripe-sepa.php:68
1025
+ #: woocommerce-gateway-stripe.php:415
1026
  msgid "Stripe SEPA Direct Debit"
1027
  msgstr ""
1028
 
1029
+ #: includes/payment-methods/class-wc-gateway-stripe-sepa.php:149
1030
  msgid "SEPA is enabled - it requires store currency to be set to Euros."
1031
  msgstr ""
1032
 
1033
+ #: includes/payment-methods/class-wc-gateway-stripe-sepa.php:238
1034
  #. translators: statement descriptor
1035
  msgid ""
1036
  "By providing your IBAN and confirming this payment, you are authorizing %s "
1042
  "debited."
1043
  msgstr ""
1044
 
1045
+ #: includes/payment-methods/class-wc-gateway-stripe-sepa.php:254
1046
  msgid "IBAN Account Name."
1047
  msgstr ""
1048
 
1049
+ #: includes/payment-methods/class-wc-gateway-stripe-sepa.php:260
1050
  msgid "IBAN Account Number."
1051
  msgstr ""
1052
 
1053
+ #: includes/payment-methods/class-wc-gateway-stripe-sepa.php:300
1054
  msgid ""
1055
  "TEST MODE ENABLED. In test mode, you can use IBAN number "
1056
  "DE89370400440532013000."
1057
  msgstr ""
1058
 
1059
  #: includes/payment-methods/class-wc-gateway-stripe-sofort.php:60
1060
+ #: woocommerce-gateway-stripe.php:410
1061
  msgid "Stripe SOFORT"
1062
  msgstr ""
1063
 
1065
  msgid "SOFORT is enabled - it requires store currency to be set to Euros."
1066
  msgstr ""
1067
 
1068
+ #: includes/payment-methods/class-wc-stripe-payment-request.php:252
1069
+ #: includes/payment-methods/class-wc-stripe-payment-request.php:811
1070
+ #: includes/payment-methods/class-wc-stripe-payment-request.php:1100
1071
  msgid "Tax"
1072
  msgstr ""
1073
 
1074
+ #: includes/payment-methods/class-wc-stripe-payment-request.php:260
1075
+ #: includes/payment-methods/class-wc-stripe-payment-request.php:819
1076
+ #: includes/payment-methods/class-wc-stripe-payment-request.php:1107
1077
+ msgid "Shipping"
1078
+ msgstr ""
1079
+
1080
+ #: includes/payment-methods/class-wc-stripe-payment-request.php:267
1081
+ #: includes/payment-methods/class-wc-stripe-payment-request.php:826
1082
  msgid "Pending"
1083
  msgstr ""
1084
 
1085
+ #: includes/payment-methods/class-wc-stripe-payment-request.php:485
1086
  msgid "Sorry, we're not accepting prepaid cards at this time."
1087
  msgstr ""
1088
 
1089
+ #: includes/payment-methods/class-wc-stripe-payment-request.php:487
1090
  #. translators: Do not translate the [option] placeholder
1091
  msgid "Unknown shipping option \"[option]\"."
1092
  msgstr ""
1093
 
1094
+ #: includes/payment-methods/class-wc-stripe-payment-request.php:609
1095
  msgid "OR"
1096
  msgstr ""
1097
 
1098
+ #: includes/payment-methods/class-wc-stripe-payment-request.php:700
1099
+ #: includes/payment-methods/class-wc-stripe-payment-request.php:713
1100
  msgid "Unable to find shipping method for address."
1101
  msgstr ""
1102
 
1103
+ #: includes/payment-methods/class-wc-stripe-payment-request.php:946
1104
  msgid "Empty cart"
1105
  msgstr ""
1106
 
1107
+ #: includes/payment-methods/class-wc-stripe-payment-request.php:1114
1108
  msgid "Discount"
1109
  msgstr ""
1110
 
1111
+ #: woocommerce-gateway-stripe.php:146
1112
  msgid "Action failed. Please refresh the page and retry."
1113
  msgstr ""
1114
 
1115
+ #: woocommerce-gateway-stripe.php:216
1116
  #. translators: 1) int version 2) int version
1117
  msgid ""
1118
  "WooCommerce Stripe - The minimum PHP version required for this plugin is "
1119
  "%1$s. You are running %2$s."
1120
  msgstr ""
1121
 
1122
+ #: woocommerce-gateway-stripe.php:222
1123
  msgid "WooCommerce Stripe requires WooCommerce to be activated to work."
1124
  msgstr ""
1125
 
1126
+ #: woocommerce-gateway-stripe.php:227
1127
  #. translators: 1) int version 2) int version
1128
  msgid ""
1129
  "WooCommerce Stripe - The minimum WooCommerce version required for this "
1130
  "plugin is %1$s. You are running %2$s."
1131
  msgstr ""
1132
 
1133
+ #: woocommerce-gateway-stripe.php:233
1134
  msgid "WooCommerce Stripe - cURL is not installed."
1135
  msgstr ""
1136
 
1137
+ #: woocommerce-gateway-stripe.php:289
1138
  #. translators: 1) link
1139
  msgid ""
1140
  "Stripe is almost ready. To get started, <a href=\"%s\">set your Stripe "
1141
  "account keys</a>."
1142
  msgstr ""
1143
 
1144
+ #: woocommerce-gateway-stripe.php:301
1145
  #. translators: 1) link
1146
  msgid ""
1147
  "Stripe is in test mode however your test keys may not be valid. Test keys "
1149
  "<a href=\"%s\">set your Stripe account keys</a>."
1150
  msgstr ""
1151
 
1152
+ #: woocommerce-gateway-stripe.php:311
1153
  #. translators: 1) link
1154
  msgid ""
1155
  "Stripe is in live mode however your test keys may not be valid. Live keys "
1157
  "<a href=\"%s\">set your Stripe account keys</a>."
1158
  msgstr ""
1159
 
1160
+ #: woocommerce-gateway-stripe.php:320
1161
  #. translators: 1) link 2) link
1162
  msgid ""
1163
  "Stripe is enabled, but the <a href=\"%1$s\">force SSL option</a> is "
1166
  "certificate</a> - Stripe will only work in test mode."
1167
  msgstr ""
1168
 
1169
+ #: woocommerce-gateway-stripe.php:358
1170
  msgid "Settings"
1171
  msgstr ""
1172
 
1173
+ #: woocommerce-gateway-stripe.php:359
1174
  msgid "Docs"
1175
  msgstr ""
1176
 
1177
+ #: woocommerce-gateway-stripe.php:360
1178
  msgid "Support"
1179
  msgstr ""
1180
 
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.5
8
  License: GPLv3
9
  License URI: https://www.gnu.org/licenses/gpl-3.0.html
10
  Attributions: thorsten-stripe
@@ -91,6 +91,10 @@ For help setting up and configuring, please refer to our [user guide](https://do
91
 
92
  If you get stuck, you can ask for help in the Plugin Forum.
93
 
 
 
 
 
94
  == Screenshots ==
95
 
96
  1. The settings panel used to configure the gateway.
@@ -101,16 +105,21 @@ If you get stuck, you can ask for help in the Plugin Forum.
101
 
102
  == Changelog ==
103
 
104
- = 4.0.5 - 2018-02-02 =
105
- * Fix - Illegal offset error on settings when non is defined or saved.
106
- * Fix - Wrong ID used for dispute webhook handler.
107
- * Fix - A WC 2.6 backwards compat issue while trying to get order id in subscriptions.
108
- * Fix - Processing SEPA can't find email when not logged in.
109
- * Add - Allow restricted secret keys to be used.
110
- * Add - Statement Descriptor to SEPA Direct Debit.
111
- * Add - Idempotency failure retry with easing to prevent multirequest issue.
112
- * Add - POT file.
113
- * Tweak - Make billing name optional on pay for order page.
 
 
 
 
 
114
 
115
  [See changelog for all versions](https://raw.githubusercontent.com/woothemes/woocommerce-gateway-stripe/master/changelog.txt).
116
 
4
  Requires at least: 4.4
5
  Tested up to: 4.9
6
  Requires PHP: 5.6
7
+ Stable tag: 4.0.6
8
  License: GPLv3
9
  License URI: https://www.gnu.org/licenses/gpl-3.0.html
10
  Attributions: thorsten-stripe
91
 
92
  If you get stuck, you can ask for help in the Plugin Forum.
93
 
94
+ = When will the older credit card form ( pre version 4.0.0 ) be deprecated? =
95
+
96
+ We will completely remove the older form by version 4.1.0.
97
+
98
  == Screenshots ==
99
 
100
  1. The settings panel used to configure the gateway.
105
 
106
  == Changelog ==
107
 
108
+ = 4.0.6 - 2018-02-20 =
109
+ * Fix - A WC 2.6 backwards compat issue with function from WC 3.0.
110
+ * Fix - Subs renewal sometimes failed due to parameters being different.
111
+ * Fix - Stripe accepts only NO for Norwegian language on Stripe Checkout.
112
+ * Fix - Refund fees may not accurately reflect net fees. Props @rvola.
113
+ * Fix - Undefined SERVERNAME property in some cases.
114
+ * Fix - Potential issue when a charge parameter changes due to initial failed request causing retries to fail.
115
+ * Fix - When 3DS is not required, failed payments was not change order status to failed.
116
+ * Fix - Potential duplicate order processes on WC side when webhook and redirect has a race condition.
117
+ * Remove - Checkout validation and let WC handle it.
118
+ * Update - Stripe API version to 2018-02-06.
119
+ * Add - Webhooks for review open/closed for Radar.
120
+ * Add - Hook `wc_stripe_refund_request` for refund request arguments.
121
+ * Add - Hook `wc_stripe_validate_modal_checkout` to enable 3rd party checkout validation.
122
+ * Add - Hook `wc_stripe_validate_modal_checkout_action` to enable 3rd party checkout validation.
123
 
124
  [See changelog for all versions](https://raw.githubusercontent.com/woothemes/woocommerce-gateway-stripe/master/changelog.txt).
125
 
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.5
9
  * Requires at least: 4.4
10
  * Tested up to: 4.9
11
  * WC requires at least: 2.6
@@ -23,7 +23,7 @@ if ( ! class_exists( 'WC_Stripe' ) ) :
23
  /**
24
  * Required minimums and constants
25
  */
26
- define( 'WC_STRIPE_VERSION', '4.0.5' );
27
  define( 'WC_STRIPE_MIN_PHP_VER', '5.6.0' );
28
  define( 'WC_STRIPE_MIN_WC_VER', '2.6.0' );
29
  define( 'WC_STRIPE_MAIN_FILE', __FILE__ );
@@ -99,7 +99,7 @@ if ( ! class_exists( 'WC_Stripe' ) ) :
99
  require_once( dirname( __FILE__ ) . '/includes/class-wc-stripe-helper.php' );
100
  include_once( dirname( __FILE__ ) . '/includes/class-wc-stripe-api.php' );
101
 
102
- // Don't hook anything else in the plugin if we're in an incompatible environment
103
  if ( self::get_environment_warning() ) {
104
  return;
105
  }
@@ -109,6 +109,7 @@ if ( ! class_exists( 'WC_Stripe' ) ) :
109
  require_once( dirname( __FILE__ ) . '/includes/abstracts/abstract-wc-stripe-payment-gateway.php' );
110
  require_once( dirname( __FILE__ ) . '/includes/class-wc-stripe-webhook-handler.php' );
111
  require_once( dirname( __FILE__ ) . '/includes/class-wc-stripe-sepa-payment-token.php' );
 
112
  require_once( dirname( __FILE__ ) . '/includes/class-wc-gateway-stripe.php' );
113
  require_once( dirname( __FILE__ ) . '/includes/payment-methods/class-wc-gateway-stripe-bancontact.php' );
114
  require_once( dirname( __FILE__ ) . '/includes/payment-methods/class-wc-gateway-stripe-sofort.php' );
5
  * Description: Take credit card payments on your store using Stripe.
6
  * Author: WooCommerce
7
  * Author URI: https://woocommerce.com/
8
+ * Version: 4.0.6
9
  * Requires at least: 4.4
10
  * Tested up to: 4.9
11
  * WC requires at least: 2.6
23
  /**
24
  * Required minimums and constants
25
  */
26
+ define( 'WC_STRIPE_VERSION', '4.0.6' );
27
  define( 'WC_STRIPE_MIN_PHP_VER', '5.6.0' );
28
  define( 'WC_STRIPE_MIN_WC_VER', '2.6.0' );
29
  define( 'WC_STRIPE_MAIN_FILE', __FILE__ );
99
  require_once( dirname( __FILE__ ) . '/includes/class-wc-stripe-helper.php' );
100
  include_once( dirname( __FILE__ ) . '/includes/class-wc-stripe-api.php' );
101
 
102
+ // Don't hook anything else in the plugin if we're in an incompatible environment.
103
  if ( self::get_environment_warning() ) {
104
  return;
105
  }
109
  require_once( dirname( __FILE__ ) . '/includes/abstracts/abstract-wc-stripe-payment-gateway.php' );
110
  require_once( dirname( __FILE__ ) . '/includes/class-wc-stripe-webhook-handler.php' );
111
  require_once( dirname( __FILE__ ) . '/includes/class-wc-stripe-sepa-payment-token.php' );
112
+ require_once( dirname( __FILE__ ) . '/includes/class-wc-stripe-apple-pay-registration.php' );
113
  require_once( dirname( __FILE__ ) . '/includes/class-wc-gateway-stripe.php' );
114
  require_once( dirname( __FILE__ ) . '/includes/payment-methods/class-wc-gateway-stripe-bancontact.php' );
115
  require_once( dirname( __FILE__ ) . '/includes/payment-methods/class-wc-gateway-stripe-sofort.php' );