Completed
Push — master ( 13f1d8...ba1e7e )
by Roy
01:47
created

WC_Gateway_Stripe_Sepa::mandate_display()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
nc 1
nop 0
dl 0
loc 4
rs 10
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( 'wc_stripe_sepa_supported_currencies', array(
137
			'EUR',
138
		) );
139
	}
140
141
	/**
142
	 * Checks to see if all criteria is met before showing payment method.
143
	 *
144
	 * @since 4.0.0
145
	 * @version 4.0.0
146
	 * @return bool
147
	 */
148
	public function is_available() {
149
		if ( ! in_array( get_woocommerce_currency(), $this->get_supported_currency() ) ) {
150
			return false;
151
		}
152
153
		if ( is_add_payment_method_page() && ! $this->saved_cards ) {
154
			return false;
155
		}
156
157
		return parent::is_available();
158
	}
159
160
	/**
161
	 * Get_icon function.
162
	 *
163
	 * @since 1.0.0
164
	 * @version 4.0.0
165
	 * @return string
166
	 */
167
	public function get_icon() {
168
		$icons = $this->payment_icons();
169
170
		$icons_str = '';
171
172
		$icons_str .= $icons['sepa'];
173
174
		return apply_filters( 'woocommerce_gateway_icon', $icons_str, $this->id );
175
	}
176
177
	/**
178
	 * payment_scripts function.
179
	 *
180
	 * Outputs scripts used for stripe payment
181
	 *
182
	 * @access public
183
	 */
184
	public function payment_scripts() {
185
		if ( ! is_cart() && ! is_checkout() && ! isset( $_GET['pay_for_order'] ) && ! is_add_payment_method_page() ) {
186
			return;
187
		}
188
189
		wp_enqueue_style( 'stripe_styles' );
190
		wp_enqueue_script( 'woocommerce_stripe' );
191
	}
192
193
	/**
194
	 * Initialize Gateway Settings Form Fields.
195
	 */
196
	public function init_form_fields() {
197
		$this->form_fields = require( WC_STRIPE_PLUGIN_PATH . '/includes/admin/stripe-sepa-settings.php' );
198
	}
199
200
	/**
201
	 * Displays the mandate acceptance notice to customer.
202
	 *
203
	 * @since 4.0.0
204
	 * @version 4.0.0
205
	 * @return string
206
	 */
207
	public function mandate_display() {
208
		/* translators: statement descriptor */
209
		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...
210
	}
211
212
	/**
213
	 * Renders the Stripe elements form.
214
	 *
215
	 * @since 4.0.0
216
	 * @version 4.0.0
217
	 */
218
	public function form() {
219
		?>
220
		<fieldset id="wc-<?php echo esc_attr( $this->id ); ?>-form" class="wc-payment-form">
221
			<?php do_action( 'woocommerce_credit_card_form_start', $this->id ); ?>
222
			<p class="wc-stripe-sepa-mandate" style="margin-bottom:40px;"><?php $this->mandate_display(); ?></p>
223
			<p class="form-row form-row-wide">
224
				<label for="stripe-iban-element">
225
					<?php esc_html_e( 'IBAN.', 'woocommerce-gateway-stripe' ); ?> <span class="required">*</span>
226
				</label>
227
				<div id="stripe-iban-element" class="wc-stripe-iban-element-field">
228
					<!-- A Stripe Element will be inserted here. -->
229
				</div>
230
			</p>
231
232
			<!-- Used to display form errors -->
233
			<div class="stripe-source-errors" role="alert"></div>
234
			<br />
235
			<?php do_action( 'woocommerce_credit_card_form_end', $this->id ); ?>
236
			<div class="clear"></div>
237
		</fieldset>
238
		<?php
239
	}
240
241
	/**
242
	 * Payment form on checkout page
243
	 */
244
	public function payment_fields() {
245
		$total                = WC()->cart->total;
246
		$display_tokenization = $this->supports( 'tokenization' ) && is_checkout() && $this->saved_cards;
247
		$description          = ! empty( $this->get_description() ) ? $this->get_description() : '';
248
249
		// If paying from order, we need to get total from order not cart.
250
		if ( isset( $_GET['pay_for_order'] ) && ! empty( $_GET['key'] ) ) {
251
			$order = wc_get_order( wc_get_order_id_by_order_key( wc_clean( $_GET['key'] ) ) );
252
			$total = $order->get_total();
253
		}
254
255
		if ( is_add_payment_method_page() ) {
256
			$total = '';
257
		}
258
259
		echo '<div
260
			id="stripe-sepa_debit-payment-data"
261
			data-amount="' . esc_attr( WC_Stripe_Helper::get_stripe_amount( $total ) ) . '"
262
			data-currency="' . esc_attr( strtolower( get_woocommerce_currency() ) ) . '">';
263
264
		if ( $this->testmode ) {
265
			$description .= ' ' . __( 'TEST MODE ENABLED. In test mode, you can use IBAN number DE89370400440532013000.', 'woocommerce-gateway-stripe' );
266
		}
267
268
		$description = trim( $description );
269
270
		echo apply_filters( 'wc_stripe_description', wpautop( wp_kses_post( $description ) ), $this->id );
271
272
		if ( $display_tokenization ) {
273
			$this->tokenization_script();
274
			$this->saved_payment_methods();
275
		}
276
277
		$this->form();
278
279
		if ( apply_filters( 'wc_stripe_display_save_payment_method_checkbox', $display_tokenization ) && ! is_add_payment_method_page() && ! isset( $_GET['change_payment_method'] ) ) {
280
			$this->save_payment_method_checkbox();
281
		}
282
283
		echo '</div>';
284
	}
285
286
	/**
287
	 * Process the payment
288
	 *
289
	 * @param int  $order_id Reference.
290
	 * @param bool $retry Should we retry on fail.
291
	 * @param bool $force_save_source Force save the payment source.
292
	 *
293
	 * @throws Exception If payment will not be accepted.
294
	 *
295
	 * @return array|void
296
	 */
297
	public function process_payment( $order_id, $retry = true, $force_save_source = false ) {
298
		try {
299
			$order = wc_get_order( $order_id );
300
301
			if ( $this->maybe_process_pre_orders( $order_id ) ) {
302
				return $this->pre_orders->process_pre_order( $order_id );
303
			}
304
305
			// This comes from the create account checkbox in the checkout page.
306
			$create_account = ! empty( $_POST['createaccount'] ) ? true : false;
307
308
			if ( $create_account ) {
309
				$new_customer_id     = WC_Stripe_Helper::is_pre_30() ? $order->customer_user : $order->get_customer_id();
310
				$new_stripe_customer = new WC_Stripe_Customer( $new_customer_id );
311
				$new_stripe_customer->create_customer();
312
			}
313
314
			$prepared_source = $this->prepare_source( get_current_user_id(), $force_save_source );
315
316
			$this->save_source_to_order( $order, $prepared_source );
317
318
			// Result from Stripe API request.
319
			$response = null;
320
321
			if ( $order->get_total() > 0 ) {
322
				// This will throw exception if not valid.
323
				$this->validate_minimum_order_amount( $order );
324
325
				WC_Stripe_Logger::log( "Info: Begin processing payment for order $order_id for the amount of {$order->get_total()}" );
326
327
				// Make the request.
328
				$response = WC_Stripe_API::request( $this->generate_payment_request( $order, $prepared_source ) );
329
330 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...
331
					// Customer param wrong? The user may have been deleted on stripe's end. Remove customer_id. Can be retried without.
332
					if ( $this->is_no_such_customer_error( $response->error ) ) {
333
						if ( WC_Stripe_Helper::is_pre_30() ) {
334
							delete_user_meta( $order->customer_user, '_stripe_customer_id' );
335
							delete_post_meta( $order_id, '_stripe_customer_id' );
336
						} else {
337
							delete_user_meta( $order->get_customer_id(), '_stripe_customer_id' );
338
							$order->delete_meta_data( '_stripe_customer_id' );
339
							$order->save();
340
						}
341
					}
342
343
					if ( $this->is_no_such_token_error( $response->error ) && $prepared_source->token_id ) {
344
						// Source param wrong? The CARD may have been deleted on stripe's end. Remove token and show message.
345
						$wc_token = WC_Payment_Tokens::get( $prepared_source->token_id );
346
						$wc_token->delete();
347
						$localized_message = __( 'This card is no longer available and has been removed.', 'woocommerce-gateway-stripe' );
348
						$order->add_order_note( $localized_message );
349
						throw new WC_Stripe_Exception( print_r( $response, true ), $localized_message );
350
					}
351
352
					// We want to retry.
353
					if ( $this->is_retryable_error( $response->error ) ) {
354
						if ( $retry ) {
355
							// Don't do anymore retries after this.
356
							if ( 5 <= $this->retry_interval ) {
357
358
								return $this->process_payment( $order_id, false, $force_save_source );
359
							}
360
361
							sleep( $this->retry_interval );
362
363
							$this->retry_interval++;
364
365
							return $this->process_payment( $order_id, true, $force_save_source );
366
						} else {
367
							$localized_message = __( 'Sorry, we are unable to process your payment at this time. Please retry later.', 'woocommerce-gateway-stripe' );
368
							$order->add_order_note( $localized_message );
369
							throw new WC_Stripe_Exception( print_r( $response, true ), $localized_message );
370
						}
371
					}
372
373
					$localized_messages = WC_Stripe_Helper::get_localized_messages();
374
375
					if ( 'card_error' === $response->error->type ) {
376
						$localized_message = isset( $localized_messages[ $response->error->code ] ) ? $localized_messages[ $response->error->code ] : $response->error->message;
377
					} else {
378
						$localized_message = isset( $localized_messages[ $response->error->type ] ) ? $localized_messages[ $response->error->type ] : $response->error->message;
379
					}
380
381
					$order->add_order_note( $localized_message );
382
383
					throw new WC_Stripe_Exception( print_r( $response, true ), $localized_message );
384
				}
385
386
				do_action( 'wc_gateway_stripe_process_payment', $response, $order );
387
388
				// Process valid response.
389
				$this->process_response( $response, $order );
390
			} else {
391
				$order->payment_complete();
392
			}
393
394
			// Remove cart.
395
			WC()->cart->empty_cart();
396
397
			// Return thank you page redirect.
398
			return array(
399
				'result'   => 'success',
400
				'redirect' => $this->get_return_url( $order ),
401
			);
402
403
		} catch ( WC_Stripe_Exception $e ) {
404
			wc_add_notice( $e->getLocalizedMessage(), 'error' );
405
			WC_Stripe_Logger::log( 'Error: ' . $e->getMessage() );
406
407
			do_action( 'wc_gateway_stripe_process_payment_error', $e, $order );
408
409
			if ( $order->has_status( array( 'pending', 'failed' ) ) ) {
410
				$this->send_failed_order_email( $order_id );
411
			}
412
413
			return array(
414
				'result'   => 'fail',
415
				'redirect' => '',
416
			);
417
		}
418
	}
419
}
420