Completed
Push — master ( 73f1f1...7046e6 )
by Roy
21s
created

WC_Gateway_Stripe_Sepa::is_available()   A

Complexity

Conditions 4
Paths 3

Size

Total Lines 11

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 4
nc 3
nop 0
dl 0
loc 11
rs 9.9
c 0
b 0
f 0
1
<?php
2
if ( ! defined( 'ABSPATH' ) ) {
3
	exit;
4
}
5
6
/**
7
 * Class that handles SEPA payment method.
8
 *
9
 * @extends WC_Gateway_Stripe
10
 *
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
24
	 */
25
	public $notices = array();
26
27
	/**
28
	 * Is test mode active?
29
	 *
30
	 * @var bool
31
	 */
32
	public $testmode;
33
34
	/**
35
	 * Alternate credit card statement name
36
	 *
37
	 * @var bool
38
	 */
39
	public $statement_descriptor;
40
41
	/**
42
	 * API access secret key
43
	 *
44
	 * @var string
45
	 */
46
	public $secret_key;
47
48
	/**
49
	 * Api access publishable key
50
	 *
51
	 * @var string
52
	 */
53
	public $publishable_key;
54
55
	/**
56
	 * Should we store the users credit cards?
57
	 *
58
	 * @var bool
59
	 */
60
	public $saved_cards;
61
62
	/**
63
	 * Pre Orders Object
64
	 *
65
	 * @var object
66
	 */
67
	public $pre_orders;
68
69
	/**
70
	 * Constructor
71
	 */
72
	public function __construct() {
73
		$this->retry_interval = 1;
74
		$this->id             = 'stripe_sepa';
75
		$this->method_title   = __( 'Stripe SEPA Direct Debit', 'woocommerce-gateway-stripe' );
76
		/* translators: link */
77
		$this->method_description = sprintf( __( 'All other general Stripe settings can be adjusted <a href="%s">here</a>.', 'woocommerce-gateway-stripe' ), admin_url( 'admin.php?page=wc-settings&tab=checkout&section=stripe' ) );
78
		$this->has_fields         = true;
79
		$this->supports           = array(
80
			'products',
81
			'refunds',
82
			'tokenization',
83
			'add_payment_method',
84
			'subscriptions',
85
			'subscription_cancellation',
86
			'subscription_suspension',
87
			'subscription_reactivation',
88
			'subscription_amount_changes',
89
			'subscription_date_changes',
90
			'subscription_payment_method_change',
91
			'subscription_payment_method_change_customer',
92
			'subscription_payment_method_change_admin',
93
			'multiple_subscriptions',
94
			'pre-orders',
95
		);
96
97
		// Load the form fields.
98
		$this->init_form_fields();
99
100
		// Load the settings.
101
		$this->init_settings();
102
103
		$main_settings              = get_option( 'woocommerce_stripe_settings' );
104
		$this->title                = $this->get_option( 'title' );
105
		$this->description          = $this->get_option( 'description' );
106
		$this->enabled              = $this->get_option( 'enabled' );
107
		$this->testmode             = ( ! empty( $main_settings['testmode'] ) && 'yes' === $main_settings['testmode'] ) ? true : false;
108
		$this->saved_cards          = ( ! empty( $main_settings['saved_cards'] ) && 'yes' === $main_settings['saved_cards'] ) ? true : false;
109
		$this->publishable_key      = ! empty( $main_settings['publishable_key'] ) ? $main_settings['publishable_key'] : '';
110
		$this->secret_key           = ! empty( $main_settings['secret_key'] ) ? $main_settings['secret_key'] : '';
111
		$this->statement_descriptor = ! empty( $main_settings['statement_descriptor'] ) ? $main_settings['statement_descriptor'] : '';
112
113
		if ( $this->testmode ) {
114
			$this->publishable_key = ! empty( $main_settings['test_publishable_key'] ) ? $main_settings['test_publishable_key'] : '';
115
			$this->secret_key      = ! empty( $main_settings['test_secret_key'] ) ? $main_settings['test_secret_key'] : '';
116
		}
117
118
		add_action( 'woocommerce_update_options_payment_gateways_' . $this->id, array( $this, 'process_admin_options' ) );
119
		add_action( 'wp_enqueue_scripts', array( $this, 'payment_scripts' ) );
120
121
		if ( WC_Stripe_Helper::is_pre_orders_exists() ) {
122
			$this->pre_orders = new WC_Stripe_Pre_Orders_Compat();
123
124
			add_action( 'wc_pre_orders_process_pre_order_completion_payment_' . $this->id, array( $this->pre_orders, 'process_pre_order_release_payment' ) );
125
		}
126
	}
127
128
	/**
129
	 * Returns all supported currencies for this payment method.
130
	 *
131
	 * @since 4.0.0
132
	 * @version 4.0.0
133
	 * @return array
134
	 */
135
	public function get_supported_currency() {
136
		return apply_filters(
137
			'wc_stripe_sepa_supported_currencies',
138
			array(
139
				'EUR',
140
			)
141
		);
142
	}
143
144
	/**
145
	 * Checks to see if all criteria is met before showing payment method.
146
	 *
147
	 * @since 4.0.0
148
	 * @version 4.0.0
149
	 * @return bool
150
	 */
151
	public function is_available() {
152
		if ( ! in_array( get_woocommerce_currency(), $this->get_supported_currency() ) ) {
153
			return false;
154
		}
155
156
		if ( is_add_payment_method_page() && ! $this->saved_cards ) {
157
			return false;
158
		}
159
160
		return parent::is_available();
161
	}
162
163
	/**
164
	 * Get_icon function.
165
	 *
166
	 * @since 1.0.0
167
	 * @version 4.0.0
168
	 * @return string
169
	 */
170
	public function get_icon() {
171
		$icons = $this->payment_icons();
172
173
		$icons_str = '';
174
175
		$icons_str .= isset( $icons['sepa'] ) ? $icons['sepa'] : '';
176
177
		return apply_filters( 'woocommerce_gateway_icon', $icons_str, $this->id );
178
	}
179
180
	/**
181
	 * payment_scripts function.
182
	 *
183
	 * Outputs scripts used for stripe payment
184
	 *
185
	 * @access public
186
	 */
187
	public function payment_scripts() {
188
		if ( ! is_cart() && ! is_checkout() && ! isset( $_GET['pay_for_order'] ) && ! is_add_payment_method_page() ) {
189
			return;
190
		}
191
192
		wp_enqueue_style( 'stripe_styles' );
193
		wp_enqueue_script( 'woocommerce_stripe' );
194
	}
195
196
	/**
197
	 * Initialize Gateway Settings Form Fields.
198
	 */
199
	public function init_form_fields() {
200
		$this->form_fields = require( WC_STRIPE_PLUGIN_PATH . '/includes/admin/stripe-sepa-settings.php' );
201
	}
202
203
	/**
204
	 * Displays the mandate acceptance notice to customer.
205
	 *
206
	 * @since 4.0.0
207
	 * @version 4.0.0
208
	 * @return string
209
	 */
210
	public function mandate_display() {
211
		/* translators: statement descriptor */
212
		printf( __( 'By providing your IBAN and confirming this payment, you are authorizing %s and Stripe, our payment service provider, to send instructions to your bank to debit your account and your bank to debit your account in accordance with those instructions. You are entitled to a refund from your bank under the terms and conditions of your agreement with your bank. A refund must be claimed within 8 weeks starting from the date on which your account was debited.', 'woocommerce-gateway-stripe' ), WC_Stripe_Helper::clean_statement_descriptor( $this->statement_descriptor ) );
0 ignored issues
show
Documentation introduced by
$this->statement_descriptor is of type boolean, but the function expects a string.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
213
	}
214
215
	/**
216
	 * Renders the Stripe elements form.
217
	 *
218
	 * @since 4.0.0
219
	 * @version 4.0.0
220
	 */
221
	public function form() {
222
		?>
223
		<fieldset id="wc-<?php echo esc_attr( $this->id ); ?>-form" class="wc-payment-form">
224
			<?php do_action( 'woocommerce_credit_card_form_start', $this->id ); ?>
225
			<p class="wc-stripe-sepa-mandate" style="margin-bottom:40px;"><?php $this->mandate_display(); ?></p>
226
			<p class="form-row form-row-wide">
227
				<label for="stripe-iban-element">
228
					<?php esc_html_e( 'IBAN.', 'woocommerce-gateway-stripe' ); ?> <span class="required">*</span>
229
				</label>
230
				<div id="stripe-iban-element" class="wc-stripe-iban-element-field">
231
					<!-- A Stripe Element will be inserted here. -->
232
				</div>
233
			</p>
234
235
			<!-- Used to display form errors -->
236
			<div class="stripe-source-errors" role="alert"></div>
237
			<br />
238
			<?php do_action( 'woocommerce_credit_card_form_end', $this->id ); ?>
239
			<div class="clear"></div>
240
		</fieldset>
241
		<?php
242
	}
243
244
	/**
245
	 * Payment form on checkout page
246
	 */
247
	public function payment_fields() {
248
		$total                = WC()->cart->total;
249
		$display_tokenization = $this->supports( 'tokenization' ) && is_checkout() && $this->saved_cards;
250
		$description          = $this->get_description();
251
		$description          = ! empty( $description ) ? $description : '';
252
253
		// If paying from order, we need to get total from order not cart.
254
		if ( isset( $_GET['pay_for_order'] ) && ! empty( $_GET['key'] ) ) {
255
			$order = wc_get_order( wc_get_order_id_by_order_key( wc_clean( $_GET['key'] ) ) );
256
			$total = $order->get_total();
257
		}
258
259
		if ( is_add_payment_method_page() ) {
260
			$total = '';
261
		}
262
263
		echo '<div
264
			id="stripe-sepa_debit-payment-data"
265
			data-amount="' . esc_attr( WC_Stripe_Helper::get_stripe_amount( $total ) ) . '"
266
			data-currency="' . esc_attr( strtolower( get_woocommerce_currency() ) ) . '">';
267
268
		if ( $this->testmode ) {
269
			$description .= ' ' . __( 'TEST MODE ENABLED. In test mode, you can use IBAN number DE89370400440532013000.', 'woocommerce-gateway-stripe' );
270
		}
271
272
		$description = trim( $description );
273
274
		echo apply_filters( 'wc_stripe_description', wpautop( wp_kses_post( $description ) ), $this->id );
275
276
		if ( $display_tokenization ) {
277
			$this->tokenization_script();
278
			$this->saved_payment_methods();
279
		}
280
281
		$this->form();
282
283
		if ( apply_filters( 'wc_stripe_display_save_payment_method_checkbox', $display_tokenization ) && ! is_add_payment_method_page() && ! isset( $_GET['change_payment_method'] ) ) {
284
			$this->save_payment_method_checkbox();
285
		}
286
287
		do_action( 'wc_stripe_sepa_payment_fields', $this->id );
288
289
		echo '</div>';
290
	}
291
292
	/**
293
	 * Process the payment
294
	 *
295
	 * @param int  $order_id Reference.
296
	 * @param bool $retry Should we retry on fail.
297
	 * @param bool $force_save_source Force save the payment source.
298
	 *
299
	 * @throws Exception If payment will not be accepted.
300
	 *
301
	 * @return array|void
302
	 */
303
	public function process_payment( $order_id, $retry = true, $force_save_source = false ) {
304
		try {
305
			$order = wc_get_order( $order_id );
306
307
			if ( $this->maybe_process_pre_orders( $order_id ) ) {
308
				return $this->pre_orders->process_pre_order( $order_id );
309
			}
310
311
			// This comes from the create account checkbox in the checkout page.
312
			$create_account = ! empty( $_POST['createaccount'] ) ? true : false;
313
314
			if ( $create_account ) {
315
				$new_customer_id     = WC_Stripe_Helper::is_wc_lt( '3.0' ) ? $order->customer_user : $order->get_customer_id();
316
				$new_stripe_customer = new WC_Stripe_Customer( $new_customer_id );
317
				$new_stripe_customer->create_customer();
318
			}
319
320
			$prepared_source = $this->prepare_source( get_current_user_id(), $force_save_source );
321
322
			$this->save_source_to_order( $order, $prepared_source );
323
324
			// Result from Stripe API request.
325
			$response = null;
326
327
			if ( $order->get_total() > 0 ) {
328
				// This will throw exception if not valid.
329
				$this->validate_minimum_order_amount( $order );
330
331
				WC_Stripe_Logger::log( "Info: Begin processing payment for order $order_id for the amount of {$order->get_total()}" );
332
333
				// Make the request.
334
				$response = WC_Stripe_API::request( $this->generate_payment_request( $order, $prepared_source ) );
335
336 View Code Duplication
				if ( ! empty( $response->error ) ) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
337
					// Customer param wrong? The user may have been deleted on stripe's end. Remove customer_id. Can be retried without.
338
					if ( $this->is_no_such_customer_error( $response->error ) ) {
339
						if ( WC_Stripe_Helper::is_wc_lt( '3.0' ) ) {
340
							delete_user_meta( $order->customer_user, '_stripe_customer_id' );
341
							delete_post_meta( $order_id, '_stripe_customer_id' );
342
						} else {
343
							delete_user_meta( $order->get_customer_id(), '_stripe_customer_id' );
344
							$order->delete_meta_data( '_stripe_customer_id' );
345
							$order->save();
346
						}
347
					}
348
349
					if ( $this->is_no_such_token_error( $response->error ) && $prepared_source->token_id ) {
350
						// Source param wrong? The CARD may have been deleted on stripe's end. Remove token and show message.
351
						$wc_token = WC_Payment_Tokens::get( $prepared_source->token_id );
352
						$wc_token->delete();
353
						$localized_message = __( 'This card is no longer available and has been removed.', 'woocommerce-gateway-stripe' );
354
						$order->add_order_note( $localized_message );
355
						throw new WC_Stripe_Exception( print_r( $response, true ), $localized_message );
356
					}
357
358
					// We want to retry.
359
					if ( $this->is_retryable_error( $response->error ) ) {
360
						if ( $retry ) {
361
							// Don't do anymore retries after this.
362
							if ( 5 <= $this->retry_interval ) {
363
364
								return $this->process_payment( $order_id, false, $force_save_source );
365
							}
366
367
							sleep( $this->retry_interval );
368
369
							$this->retry_interval++;
370
371
							return $this->process_payment( $order_id, true, $force_save_source );
372
						} else {
373
							$localized_message = __( 'Sorry, we are unable to process your payment at this time. Please retry later.', 'woocommerce-gateway-stripe' );
374
							$order->add_order_note( $localized_message );
375
							throw new WC_Stripe_Exception( print_r( $response, true ), $localized_message );
376
						}
377
					}
378
379
					$localized_messages = WC_Stripe_Helper::get_localized_messages();
380
381
					if ( 'card_error' === $response->error->type ) {
382
						$localized_message = isset( $localized_messages[ $response->error->code ] ) ? $localized_messages[ $response->error->code ] : $response->error->message;
383
					} else {
384
						$localized_message = isset( $localized_messages[ $response->error->type ] ) ? $localized_messages[ $response->error->type ] : $response->error->message;
385
					}
386
387
					$order->add_order_note( $localized_message );
388
389
					throw new WC_Stripe_Exception( print_r( $response, true ), $localized_message );
390
				}
391
392
				do_action( 'wc_gateway_stripe_process_payment', $response, $order );
393
394
				// Process valid response.
395
				$this->process_response( $response, $order );
396
			} else {
397
				$order->payment_complete();
398
			}
399
400
			// Remove cart.
401
			WC()->cart->empty_cart();
402
403
			// Return thank you page redirect.
404
			return array(
405
				'result'   => 'success',
406
				'redirect' => $this->get_return_url( $order ),
407
			);
408
409
		} catch ( WC_Stripe_Exception $e ) {
410
			wc_add_notice( $e->getLocalizedMessage(), 'error' );
411
			WC_Stripe_Logger::log( 'Error: ' . $e->getMessage() );
412
413
			do_action( 'wc_gateway_stripe_process_payment_error', $e, $order );
414
415
			if ( $order->has_status( array( 'pending', 'failed' ) ) ) {
416
				$this->send_failed_order_email( $order_id );
417
			}
418
419
			return array(
420
				'result'   => 'fail',
421
				'redirect' => '',
422
			);
423
		}
424
	}
425
}
426