Passed
Push — develop ( 072f5c...8ebc76 )
by Reüel
07:26
created

Plugin::start_recurring()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 2
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
eloc 1
nc 1
nop 2
dl 0
loc 2
rs 10
c 0
b 0
f 0
1
<?php
2
/**
3
 * Plugin
4
 *
5
 * @author    Pronamic <[email protected]>
6
 * @copyright 2005-2018 Pronamic
7
 * @license   GPL-3.0-or-later
8
 * @package   Pronamic\WordPress\Pay
9
 */
10
11
namespace Pronamic\WordPress\Pay;
12
13
use Pronamic\WordPress\Pay\Core\Gateway;
14
use Pronamic\WordPress\Pay\Core\PaymentMethods;
15
use Pronamic\WordPress\Pay\Core\Recurring;
16
use Pronamic\WordPress\Pay\Core\Statuses;
17
use Pronamic\WordPress\Pay\Payments\Payment;
18
use Pronamic\WordPress\Pay\Payments\PaymentDataInterface;
19
use Pronamic\WordPress\Pay\Payments\PaymentPostType;
20
use Pronamic\WordPress\Pay\Payments\StatusChecker;
21
use Pronamic\WordPress\Pay\Subscriptions\Subscription;
22
use Pronamic\WordPress\Pay\Subscriptions\SubscriptionPostType;
23
use WP_Query;
24
25
/**
26
 * Title: WordPress iDEAL plugin
27
 *
28
 * @author Remco Tolsma
29
 * @version 4.5.3
30
 * @since 1.0.0
31
 */
32
class Plugin {
33
	/**
34
	 * Version.
35
	 *
36
	 * @var string
37
	 */
38
	private $version = '5.0.0';
39
40
	/**
41
	 * The root file of this WordPress plugin
42
	 *
43
	 * @var string
44
	 */
45
	public static $file;
46
47
	/**
48
	 * The plugin dirname
49
	 *
50
	 * @var string
51
	 */
52
	public static $dirname;
53
54
	/**
55
	 * The timezone
56
	 *
57
	 * @var string
58
	 */
59
	const TIMEZONE = 'UTC';
60
61
	/**
62
	 * Instance.
63
	 *
64
	 * @var Plugin
65
	 */
66
	protected static $instance = null;
67
68
	/**
69
	 * Instance.
70
	 *
71
	 * @param string $file The plugin file.
72
	 */
73
	public static function instance( $file = null ) {
74
		if ( is_null( self::$instance ) ) {
75
			self::$instance = new self();
76
77
			// Backward compatibility.
78
			self::$file    = $file;
79
			self::$dirname = dirname( $file );
80
		}
81
82
		return self::$instance;
83
	}
84
85
	/**
86
	 * Plugin settings.
87
	 *
88
	 * @var Settings
89
	 */
90
	public $settings;
91
92
	/**
93
	 * Payment data storing.
94
	 *
95
	 * @var Payments\PaymentsDataStoreCPT
96
	 */
97
	public $payments_data_store;
98
99
	/**
100
	 * Subscription data storing.
101
	 *
102
	 * @var Subscriptions\SubscriptionsDataStoreCPT
103
	 */
104
	public $subscriptions_data_store;
105
106
	/**
107
	 * Gateway post type.
108
	 *
109
	 * @var GatewayPostType
110
	 */
111
	public $gateway_post_type;
112
113
	/**
114
	 * Payment post type.
115
	 *
116
	 * @var PaymentPostType
117
	 */
118
	public $payment_post_type;
119
120
	/**
121
	 * Subscription post type.
122
	 *
123
	 * @var SubscriptionPostType
124
	 */
125
	public $subscription_post_type;
126
127
	/**
128
	 * Licence manager.
129
	 *
130
	 * @var LicenseManager
131
	 */
132
	public $license_manager;
133
134
	/**
135
	 * Forms module.
136
	 *
137
	 * @var Forms\FormsModule
138
	 */
139
	public $forms_module;
140
141
	/**
142
	 * Payments module.
143
	 *
144
	 * @var Payments\PaymentsModule
145
	 */
146
	public $payments_module;
147
148
	/**
149
	 * Subsciptions module.
150
	 *
151
	 * @var Subscriptions\SubscriptionsModule
152
	 */
153
	public $subscriptions_module;
154
155
	/**
156
	 * Google analytics ecommerce.
157
	 *
158
	 * @var GoogleAnalyticsEcommerce
159
	 */
160
	public $google_analytics_ecommerce;
161
162
	/**
163
	 * Construct and initialize an Pronamic Pay plugin object
164
	 */
165
	public function __construct() {
166
		// Bootstrap the add-ons.
167
		Extensions\Charitable\Extension::bootstrap();
168
		Extensions\Give\Extension::bootstrap();
169
		Extensions\WooCommerce\Extension::bootstrap();
170
		Extensions\GravityForms\Extension::bootstrap();
171
		Extensions\Shopp\Extension::bootstrap();
172
		Extensions\Jigoshop\Extension::bootstrap();
173
		Extensions\WPeCommerce\Extension::bootstrap();
174
		Extensions\ClassiPress\Extension::bootstrap();
175
		Extensions\EventEspressoLegacy\Extension::bootstrap();
176
		Extensions\EventEspresso\Extension::bootstrap();
177
		Extensions\AppThemes\Extension::bootstrap();
178
		Extensions\S2Member\Extension::bootstrap();
179
		Extensions\Membership\Extension::bootstrap();
180
		Extensions\EasyDigitalDownloads\Extension::bootstrap();
181
		Extensions\IThemesExchange\Extension::bootstrap();
182
		Extensions\MemberPress\Extension::bootstrap();
183
		Extensions\FormidableForms\Extension::bootstrap();
184
		Extensions\RestrictContentPro\Extension::bootstrap();
185
186
		// Settings.
187
		$this->settings = new Settings( $this );
188
189
		// Data Stores.
190
		$this->payments_data_store      = new Payments\PaymentsDataStoreCPT();
191
		$this->subscriptions_data_store = new Subscriptions\SubscriptionsDataStoreCPT();
192
193
		// Post Types.
194
		$this->gateway_post_type      = new GatewayPostType();
195
		$this->payment_post_type      = new PaymentPostType();
196
		$this->subscription_post_type = new SubscriptionPostType();
197
198
		// License Manager.
199
		$this->license_manager = new LicenseManager( $this );
200
201
		// Modules.
202
		$this->forms_module         = new Forms\FormsModule( $this );
203
		$this->payments_module      = new Payments\PaymentsModule( $this );
204
		$this->subscriptions_module = new Subscriptions\SubscriptionsModule( $this );
205
206
		// Google Analytics Ecommerce.
207
		$this->google_analytics_ecommerce = new GoogleAnalyticsEcommerce();
208
209
		// Admin.
210
		if ( is_admin() ) {
211
			$this->admin = new Admin\AdminModule( $this );
0 ignored issues
show
Bug Best Practice introduced by
The property admin does not exist. Although not strictly required by PHP, it is generally a best practice to declare properties explicitly.
Loading history...
212
		}
213
214
		/*
215
		 * Plugins loaded.
216
		 *
217
		 * Priority should be at least lower then 8 to support the "WP eCommerce" plugin.
218
		 *
219
		 * new WP_eCommerce()
220
		 * add_action( 'plugins_loaded' , array( $this, 'init' ), 8 );
221
		 * $this->load();
222
		 * wpsc_core_load_gateways();
223
		 *
224
		 * @see https://github.com/wp-e-commerce/WP-e-Commerce/blob/branch-3.11.2/wp-shopping-cart.php#L342-L343
225
		 * @see https://github.com/wp-e-commerce/WP-e-Commerce/blob/branch-3.11.2/wp-shopping-cart.php#L26-L35
226
		 * @see https://github.com/wp-e-commerce/WP-e-Commerce/blob/branch-3.11.2/wp-shopping-cart.php#L54
227
		 * @see https://github.com/wp-e-commerce/WP-e-Commerce/blob/branch-3.11.2/wp-shopping-cart.php#L296-L297
228
		 */
229
		add_action( 'plugins_loaded', array( $this, 'plugins_loaded' ), 5 );
230
231
		// Plugin locale.
232
		add_filter( 'plugin_locale', array( $this, 'plugin_locale' ), 10, 2 );
233
234
		// If WordPress is loaded check on returns and maybe redirect requests.
235
		add_action( 'wp_loaded', array( $this, 'handle_returns' ) );
236
		add_action( 'wp_loaded', array( $this, 'maybe_redirect' ) );
237
238
		// Default date time format.
239
		add_filter( 'pronamic_datetime_default_format', array( $this, 'datetime_format' ), 10, 1 );
240
	}
241
242
	/**
243
	 * Get the version number of this plugin.
244
	 *
245
	 * @return string The version number of this plugin.
246
	 */
247
	public function get_version() {
248
		return $this->version;
249
	}
250
251
	/**
252
	 * Get plugin file path.
253
	 *
254
	 * @return string
255
	 */
256
	public function get_file() {
257
		return self::$file;
258
	}
259
260
	/**
261
	 * Get the plugin dir path.
262
	 *
263
	 * @return string
264
	 */
265
	public function get_plugin_dir_path() {
266
		return plugin_dir_path( $this->get_file() );
267
	}
268
269
	/**
270
	 * Update payment.
271
	 *
272
	 * @param Payment $payment      The payment to update.
273
	 * @param bool    $can_redirect Flag to indicate if redirect is allowed after the payment update.
274
	 */
275
	public static function update_payment( $payment = null, $can_redirect = true ) {
276
		if ( empty( $payment ) ) {
277
			return;
278
		}
279
280
		$gateway = Plugin::get_gateway( $payment->config_id );
281
282
		if ( empty( $gateway ) ) {
283
			return;
284
		}
285
286
		$amount = $payment->get_amount()->get_amount();
287
288
		if ( empty( $amount ) ) {
289
			$payment->set_status( Core\Statuses::SUCCESS );
290
		} else {
291
			$gateway->update_status( $payment );
292
293
			if ( $gateway->has_error() ) {
294
				foreach ( $gateway->error->get_error_codes() as $code ) {
295
					$payment->add_note( sprintf( '%s: %s', $code, $gateway->error->get_error_message( $code ) ) );
296
				}
297
			}
298
		}
299
300
		// Update payment in data store.
301
		$payment->save();
302
303
		// Maybe redirect.
304
		if ( defined( 'DOING_CRON' ) && ( empty( $payment->status ) || Statuses::OPEN === $payment->status ) ) {
305
			$can_redirect = false;
306
		}
307
308
		if ( $can_redirect ) {
309
			$url = $payment->get_return_redirect_url();
310
311
			wp_redirect( $url );
312
313
			exit;
0 ignored issues
show
Best Practice introduced by
Using exit here is not recommended.

In general, usage of exit should be done with care and only when running in a scripting context like a CLI script.

Loading history...
314
		}
315
	}
316
317
	/**
318
	 * Handle returns.
319
	 */
320
	public function handle_returns() {
321
		if ( ! filter_has_var( INPUT_GET, 'payment' ) ) {
322
			return;
323
		}
324
325
		$payment_id = filter_input( INPUT_GET, 'payment', FILTER_SANITIZE_NUMBER_INT );
326
327
		$payment = get_pronamic_payment( $payment_id );
328
329
		// Check if payment key is valid.
330
		$valid_key = false;
331
332
		if ( empty( $payment->key ) ) {
333
			$valid_key = true;
334
		} elseif ( filter_has_var( INPUT_GET, 'key' ) ) {
335
			$key = filter_input( INPUT_GET, 'key', FILTER_SANITIZE_STRING );
336
337
			$valid_key = ( $key === $payment->key );
338
		}
339
340
		if ( ! $valid_key ) {
341
			wp_redirect( home_url() );
342
343
			exit;
0 ignored issues
show
Best Practice introduced by
Using exit here is not recommended.

In general, usage of exit should be done with care and only when running in a scripting context like a CLI script.

Loading history...
344
		}
345
346
		// Check if we should redirect.
347
		$should_redirect = true;
348
349
		// Check if the request is an callback request.
350
		// Sisow gatway will extend callback requests with querystring "callback=true".
351
		if ( filter_has_var( INPUT_GET, 'callback' ) && filter_input( INPUT_GET, 'callback', FILTER_VALIDATE_BOOLEAN ) ) {
352
			$should_redirect = false;
353
		}
354
355
		// Check if the request is an notify request.
356
		// Sisow gatway will extend callback requests with querystring "notify=true".
357
		if ( filter_has_var( INPUT_GET, 'notify' ) && filter_input( INPUT_GET, 'notify', FILTER_VALIDATE_BOOLEAN ) ) {
358
			$should_redirect = false;
359
		}
360
361
		self::update_payment( $payment, $should_redirect );
362
	}
363
364
	/**
365
	 * Maybe redirect.
366
	 */
367
	public function maybe_redirect() {
368
		if ( ! filter_has_var( INPUT_GET, 'payment_redirect' ) ) {
369
			return;
370
		}
371
372
		$payment_id = filter_input( INPUT_GET, 'payment_redirect', FILTER_SANITIZE_NUMBER_INT );
373
374
		$payment = get_pronamic_payment( $payment_id );
375
376
		// HTML Answer.
377
		$html_answer = $payment->get_meta( 'ogone_directlink_html_answer' );
378
379
		if ( ! empty( $html_answer ) ) {
380
			echo $html_answer; // WPCS: XSS ok.
381
382
			exit;
0 ignored issues
show
Best Practice introduced by
Using exit here is not recommended.

In general, usage of exit should be done with care and only when running in a scripting context like a CLI script.

Loading history...
383
		}
384
385
		$redirect_message = $payment->get_meta( 'payment_redirect_message' );
386
387
		if ( ! empty( $redirect_message ) ) {
388
			$key = filter_input( INPUT_GET, 'key', FILTER_SANITIZE_STRING );
389
390
			if ( $key !== $payment->key ) {
391
				wp_redirect( home_url() );
392
393
				exit;
0 ignored issues
show
Best Practice introduced by
Using exit here is not recommended.

In general, usage of exit should be done with care and only when running in a scripting context like a CLI script.

Loading history...
394
			}
395
396
			// @see https://github.com/woothemes/woocommerce/blob/2.3.11/includes/class-wc-cache-helper.php
397
			// @see https://www.w3-edge.com/products/w3-total-cache/
398
			if ( ! defined( 'DONOTCACHEPAGE' ) ) {
399
				define( 'DONOTCACHEPAGE', true );
400
			}
401
402
			if ( ! defined( 'DONOTCACHEDB' ) ) {
403
				define( 'DONOTCACHEDB', true );
404
			}
405
406
			if ( ! defined( 'DONOTMINIFY' ) ) {
407
				define( 'DONOTMINIFY', true );
408
			}
409
410
			if ( ! defined( 'DONOTCDN' ) ) {
411
				define( 'DONOTCDN', true );
412
			}
413
414
			if ( ! defined( 'DONOTCACHEOBJECT' ) ) {
415
				define( 'DONOTCACHEOBJECT', true );
416
			}
417
418
			nocache_headers();
419
420
			include Plugin::$dirname . '/views/redirect-message.php';
421
422
			exit;
0 ignored issues
show
Best Practice introduced by
Using exit here is not recommended.

In general, usage of exit should be done with care and only when running in a scripting context like a CLI script.

Loading history...
423
		}
424
425
		$gateway = Plugin::get_gateway( $payment->config_id );
426
427
		if ( $gateway && $gateway->is_html_form() ) {
428
			$gateway->start( $payment );
429
430
			$error = $gateway->get_error();
431
432
			if ( is_wp_error( $error ) ) {
433
				Plugin::render_errors( $error );
434
			} else {
435
				$gateway->redirect( $payment );
436
			}
437
		}
438
439
		if ( ! empty( $payment->action_url ) ) {
440
			wp_redirect( $payment->action_url );
441
442
			exit;
0 ignored issues
show
Best Practice introduced by
Using exit here is not recommended.

In general, usage of exit should be done with care and only when running in a scripting context like a CLI script.

Loading history...
443
		}
444
	}
445
446
	/**
447
	 * Get number payments.
448
	 *
449
	 * @return int
450
	 */
451
	public static function get_number_payments() {
452
		$number = false;
453
454
		$count = wp_count_posts( 'pronamic_payment' );
455
456
		if ( isset( $count, $count->payment_completed ) ) {
457
			$number = intval( $count->payment_completed );
458
		}
459
460
		return $number;
461
	}
462
463
	/**
464
	 * Setup, creates or updates database tables. Will only run when version changes.
465
	 */
466
	public function plugins_loaded() {
467
		// Load plugin text domain.
468
		$rel_path = dirname( plugin_basename( self::$file ) );
469
470
		load_plugin_textdomain( 'pronamic_ideal', false, $rel_path . '/languages' );
0 ignored issues
show
Bug introduced by
false of type false is incompatible with the type string expected by parameter $deprecated of load_plugin_textdomain(). ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

470
		load_plugin_textdomain( 'pronamic_ideal', /** @scrutinizer ignore-type */ false, $rel_path . '/languages' );
Loading history...
471
472
		load_plugin_textdomain( 'pronamic-money', false, $rel_path . '/vendor/pronamic/wp-money/languages' );
473
474
		// Gateway Integrations.
475
		$integrations = new GatewayIntegrations();
476
477
		$this->gateway_integrations = $integrations->register_integrations();
0 ignored issues
show
Bug Best Practice introduced by
The property gateway_integrations does not exist. Although not strictly required by PHP, it is generally a best practice to declare properties explicitly.
Loading history...
478
479
		// Maybes.
480
		self::maybe_set_active_payment_methods();
481
	}
482
483
	/**
484
	 * Filter plugin locale.
485
	 *
486
	 * @param string $locale A WordPress locale identifier.
487
	 * @param string $domain A WordPress text domain indentifier.
488
	 *
489
	 * @return string
490
	 */
491
	public function plugin_locale( $locale, $domain ) {
492
		if ( 'pronamic_ideal' !== $domain ) {
493
			return $locale;
494
		}
495
496
		if ( 'nl_NL_formal' === $locale ) {
497
			return 'nl_NL';
498
		}
499
500
		if ( 'nl_BE' === $locale ) {
501
			return 'nl_NL';
502
		}
503
504
		return $locale;
505
	}
506
507
	/**
508
	 * Default date time format.
509
	 *
510
	 * @param string $format Format.
511
	 *
512
	 * @return string|void
513
	 */
514
	public function datetime_format( $format ) {
0 ignored issues
show
Unused Code introduced by
The parameter $format is not used and could be removed. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-unused  annotation

514
	public function datetime_format( /** @scrutinizer ignore-unused */ $format ) {

This check looks for parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
515
		return _x( 'D j M Y \a\t H:i', 'default datetime format', 'pronamic_ideal' );
516
	}
517
518
	/**
519
	 * Get default error message.
520
	 *
521
	 * @return string
522
	 */
523
	public static function get_default_error_message() {
524
		return __( 'Something went wrong with the payment. Please try again later or pay another way.', 'pronamic_ideal' );
525
	}
526
527
	/**
528
	 * Get config select options.
529
	 *
530
	 * @param null|string $payment_method The gateway configuration options for the specified payment method.
531
	 *
532
	 * @return array
533
	 */
534
	public static function get_config_select_options( $payment_method = null ) {
535
		$args = array(
536
			'post_type' => 'pronamic_gateway',
537
			'orderby'   => 'post_title',
538
			'order'     => 'ASC',
539
			'nopaging'  => true,
540
		);
541
542
		if ( $payment_method ) {
543
			$args['post__in'] = PaymentMethods::get_config_ids( $payment_method );
544
		}
545
546
		$query = new WP_Query( $args );
547
548
		$options = array( __( '— Select Configuration —', 'pronamic_ideal' ) );
549
550
		foreach ( $query->posts as $post ) {
551
			$id = $post->ID;
552
553
			$options[ $id ] = sprintf(
554
				'%s (%s)',
555
				get_the_title( $id ),
556
				get_post_meta( $id, '_pronamic_gateway_mode', true )
0 ignored issues
show
Bug introduced by
It seems like get_post_meta($id, '_pro...ic_gateway_mode', true) can also be of type false; however, parameter $args of sprintf() does only seem to accept string, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

556
				/** @scrutinizer ignore-type */ get_post_meta( $id, '_pronamic_gateway_mode', true )
Loading history...
557
			);
558
		}
559
560
		return $options;
561
	}
562
563
	/**
564
	 * Maybe set active payment methods option.
565
	 *
566
	 * @since unreleased
567
	 */
568
	public static function maybe_set_active_payment_methods() {
569
		$active_methods = get_option( 'pronamic_pay_active_payment_methods' );
570
571
		if ( is_array( $active_methods ) ) {
572
			return;
573
		}
574
575
		PaymentMethods::update_active_payment_methods();
576
	}
577
578
	/**
579
	 * Render errors.
580
	 *
581
	 * @param array|WP_Error $errors An array with errors to render.
0 ignored issues
show
Bug introduced by
The type Pronamic\WordPress\Pay\WP_Error was not found. Did you mean WP_Error? If so, make sure to prefix the type with \.
Loading history...
582
	 */
583
	public static function render_errors( $errors = array() ) {
584
		if ( ! is_array( $errors ) ) {
585
			$errors = array( $errors );
586
		}
587
588
		foreach ( $errors as $error ) {
589
			include Plugin::$dirname . '/views/error.php';
590
		}
591
	}
592
593
	/**
594
	 * Get gateway.
595
	 *
596
	 * @param string|integer|boolean $config_id A gateway configuration ID.
597
	 *
598
	 * @return Gateway|null
599
	 */
600
	public static function get_gateway( $config_id ) {
601
		if ( empty( $config_id ) ) {
602
			return null;
603
		}
604
605
		$gateway_id = get_post_meta( $config_id, '_pronamic_gateway_id', true );
0 ignored issues
show
Bug introduced by
It seems like $config_id can also be of type string and boolean; however, parameter $post_id of get_post_meta() does only seem to accept integer, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

605
		$gateway_id = get_post_meta( /** @scrutinizer ignore-type */ $config_id, '_pronamic_gateway_id', true );
Loading history...
606
		$mode       = get_post_meta( $config_id, '_pronamic_gateway_mode', true );
607
		$is_utf8    = strcasecmp( get_bloginfo( 'charset' ), 'UTF-8' ) === 0;
608
609
		$config = Core\ConfigProvider::get_config( $gateway_id, $config_id );
610
611
		switch ( $gateway_id ) {
612
			case 'abnamro-ideal-easy':
613
			case 'abnamro-ideal-only-kassa':
614
			case 'abnamro-internetkassa':
615
				$config->form_action_url = sprintf(
616
					'https://internetkassa.abnamro.nl/ncol/%s/orderstandard%s.asp',
617
					'test' === $mode ? 'test' : 'prod',
618
					$is_utf8 ? '_utf8' : ''
619
				);
620
621
				break;
622
			case 'abnamro-ideal-zelfbouw-v3':
623
				$config->payment_server_url = 'https://abnamro.ideal-payment.de/ideal/iDEALv3';
624
625
				if ( 'test' === $mode ) {
626
					$config->payment_server_url = 'https://abnamro-test.ideal-payment.de/ideal/iDEALv3';
627
				}
628
629
				$config->certificates = array();
630
631
				break;
632
			case 'deutschebank-ideal-expert-v3':
633
				$config->payment_server_url = 'https://myideal.db.com/ideal/iDealv3';
634
635
				$config->certificates = array();
636
637
				break;
638
			case 'ideal-simulator-ideal-basic':
639
				$config->url = 'https://www.ideal-simulator.nl/lite/';
640
641
				break;
642
			case 'ideal-simulator-ideal-advanced-v3':
643
				$config->payment_server_url = 'https://www.ideal-checkout.nl/simulator/';
644
645
				$config->certificates = array();
646
647
				break;
648
			case 'ing-ideal-basic':
649
				$config->url = 'https://ideal.secure-ing.com/ideal/mpiPayInitIng.do';
650
651
				if ( 'test' === $mode ) {
652
					$config->url = 'https://idealtest.secure-ing.com/ideal/mpiPayInitIng.do';
653
				}
654
655
				break;
656
			case 'ing-ideal-advanced-v3':
657
				$config->payment_server_url = 'https://ideal.secure-ing.com/ideal/iDEALv3';
658
659
				if ( 'test' === $mode ) {
660
					$config->payment_server_url = 'https://idealtest.secure-ing.com/ideal/iDEALv3';
661
				}
662
663
				$config->certificates = array();
664
665
				break;
666
			case 'mollie-ideal-basic':
667
				$config->url = 'https://secure.mollie.nl/xml/idealAcquirer/lite/';
668
669
				if ( 'test' === $mode ) {
670
					$config->url = 'https://secure.mollie.nl/xml/idealAcquirer/testmode/lite/';
671
				}
672
673
				break;
674
			case 'postcode-ideal':
675
				$config->payment_server_url = 'https://ideal.postcode.nl/ideal';
676
677
				if ( 'test' === $mode ) {
678
					$config->payment_server_url = 'https://ideal-test.postcode.nl/ideal';
679
				}
680
681
				$config->certificates = array();
682
683
				break;
684
			case 'rabobank-ideal-professional-v3':
685
				$config->payment_server_url = 'https://ideal.rabobank.nl/ideal/iDEALv3';
686
687
				if ( 'test' === $mode ) {
688
					$config->payment_server_url = 'https://idealtest.rabobank.nl/ideal/iDEALv3';
689
				}
690
691
				$config->certificates = array();
692
693
				break;
694
			case 'sisow-ideal-basic':
695
				$config->url = 'https://www.sisow.nl/Sisow/iDeal/IssuerHandler.ashx';
696
697
				if ( 'test' === $mode ) {
698
					$config->url = 'https://www.sisow.nl/Sisow/iDeal/IssuerHandler.ashx/test';
699
				}
700
701
				break;
702
		}
703
704
		$gateway = Core\GatewayFactory::create( $config );
705
706
		return $gateway;
707
	}
708
709
	/**
710
	 * Start a payment.
711
	 *
712
	 * @param string               $config_id      A gateway configuration ID.
713
	 * @param Gateway              $gateway        The gateway to start the payment at.
714
	 * @param PaymentDataInterface $data           A payment data interface object with all the required payment info.
715
	 * @param string|null          $payment_method The payment method to use to start the payment.
716
	 *
717
	 * @return Payment
718
	 */
719
	public static function start( $config_id, Gateway $gateway, PaymentDataInterface $data, $payment_method = null ) {
720
		$payment = new Payments\Payment();
721
722
		$payment->title               = sprintf( __( 'Payment for %s', 'pronamic_ideal' ), $data->get_title() );
723
		$payment->user_id             = $data->get_user_id();
0 ignored issues
show
Bug introduced by
The method get_user_id() does not exist on Pronamic\WordPress\Pay\P...ts\PaymentDataInterface. Since it exists in all sub-types, consider adding an abstract or default implementation to Pronamic\WordPress\Pay\P...ts\PaymentDataInterface. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

723
		/** @scrutinizer ignore-call */ 
724
  $payment->user_id             = $data->get_user_id();
Loading history...
Bug introduced by
The property user_id does not exist on Pronamic\WordPress\Pay\Payments\Payment. Did you mean user_ip?
Loading history...
724
		$payment->config_id           = $config_id;
0 ignored issues
show
Documentation Bug introduced by
The property $config_id was declared of type integer, but $config_id is of type string. Maybe add a type cast?

This check looks for assignments to scalar types that may be of the wrong type.

To ensure the code behaves as expected, it may be a good idea to add an explicit type cast.

$answer = 42;

$correct = false;

$correct = (bool) $answer;
Loading history...
725
		$payment->key                 = uniqid( 'pay_' );
726
		$payment->order_id            = $data->get_order_id();
0 ignored issues
show
Bug introduced by
The method get_order_id() does not exist on Pronamic\WordPress\Pay\P...ts\PaymentDataInterface. Since it exists in all sub-types, consider adding an abstract or default implementation to Pronamic\WordPress\Pay\P...ts\PaymentDataInterface. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

726
		/** @scrutinizer ignore-call */ 
727
  $payment->order_id            = $data->get_order_id();
Loading history...
727
		$payment->language            = $data->get_language();
0 ignored issues
show
Bug introduced by
The method get_language() does not exist on Pronamic\WordPress\Pay\P...ts\PaymentDataInterface. Since it exists in all sub-types, consider adding an abstract or default implementation to Pronamic\WordPress\Pay\P...ts\PaymentDataInterface. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

727
		/** @scrutinizer ignore-call */ 
728
  $payment->language            = $data->get_language();
Loading history...
728
		$payment->locale              = $data->get_language_and_country();
0 ignored issues
show
Bug introduced by
The method get_language_and_country() does not exist on Pronamic\WordPress\Pay\P...ts\PaymentDataInterface. Since it exists in all sub-types, consider adding an abstract or default implementation to Pronamic\WordPress\Pay\P...ts\PaymentDataInterface. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

728
		/** @scrutinizer ignore-call */ 
729
  $payment->locale              = $data->get_language_and_country();
Loading history...
729
		$payment->entrance_code       = $data->get_entrance_code();
0 ignored issues
show
Bug introduced by
The method get_entrance_code() does not exist on Pronamic\WordPress\Pay\P...ts\PaymentDataInterface. Since it exists in all sub-types, consider adding an abstract or default implementation to Pronamic\WordPress\Pay\P...ts\PaymentDataInterface. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

729
		/** @scrutinizer ignore-call */ 
730
  $payment->entrance_code       = $data->get_entrance_code();
Loading history...
730
		$payment->description         = $data->get_description();
0 ignored issues
show
Bug introduced by
The method get_description() does not exist on Pronamic\WordPress\Pay\P...ts\PaymentDataInterface. Did you maybe mean get_subscription()? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

730
		/** @scrutinizer ignore-call */ 
731
  $payment->description         = $data->get_description();

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
731
		$payment->source              = $data->get_source();
0 ignored issues
show
Bug introduced by
The method get_source() does not exist on Pronamic\WordPress\Pay\P...ts\PaymentDataInterface. Since it exists in all sub-types, consider adding an abstract or default implementation to Pronamic\WordPress\Pay\P...ts\PaymentDataInterface. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

731
		/** @scrutinizer ignore-call */ 
732
  $payment->source              = $data->get_source();
Loading history...
732
		$payment->source_id           = $data->get_source_id();
0 ignored issues
show
Bug introduced by
The method get_source_id() does not exist on Pronamic\WordPress\Pay\P...ts\PaymentDataInterface. Since it exists in all sub-types, consider adding an abstract or default implementation to Pronamic\WordPress\Pay\P...ts\PaymentDataInterface. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

732
		/** @scrutinizer ignore-call */ 
733
  $payment->source_id           = $data->get_source_id();
Loading history...
733
		$payment->email               = $data->get_email();
0 ignored issues
show
Bug introduced by
The method get_email() does not exist on Pronamic\WordPress\Pay\P...ts\PaymentDataInterface. Since it exists in all sub-types, consider adding an abstract or default implementation to Pronamic\WordPress\Pay\P...ts\PaymentDataInterface. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

733
		/** @scrutinizer ignore-call */ 
734
  $payment->email               = $data->get_email();
Loading history...
734
		$payment->status              = null;
735
		$payment->method              = $payment_method;
736
		$payment->issuer              = $data->get_issuer( $payment_method );
0 ignored issues
show
Bug introduced by
The method get_issuer() does not exist on Pronamic\WordPress\Pay\P...ts\PaymentDataInterface. Since it exists in all sub-types, consider adding an abstract or default implementation to Pronamic\WordPress\Pay\P...ts\PaymentDataInterface. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

736
		/** @scrutinizer ignore-call */ 
737
  $payment->issuer              = $data->get_issuer( $payment_method );
Loading history...
737
		$payment->first_name          = $data->get_first_name();
0 ignored issues
show
Bug introduced by
The method get_first_name() does not exist on Pronamic\WordPress\Pay\P...ts\PaymentDataInterface. It seems like you code against a sub-type of Pronamic\WordPress\Pay\P...ts\PaymentDataInterface such as Pronamic\WordPress\Pay\Payments\PaymentData. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

737
		/** @scrutinizer ignore-call */ 
738
  $payment->first_name          = $data->get_first_name();
Loading history...
738
		$payment->last_name           = $data->get_last_name();
0 ignored issues
show
Bug introduced by
The method get_last_name() does not exist on Pronamic\WordPress\Pay\P...ts\PaymentDataInterface. It seems like you code against a sub-type of Pronamic\WordPress\Pay\P...ts\PaymentDataInterface such as Pronamic\WordPress\Pay\Payments\PaymentData. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

738
		/** @scrutinizer ignore-call */ 
739
  $payment->last_name           = $data->get_last_name();
Loading history...
739
		$payment->customer_name       = $data->get_customer_name();
0 ignored issues
show
Bug introduced by
The method get_customer_name() does not exist on Pronamic\WordPress\Pay\P...ts\PaymentDataInterface. Since it exists in all sub-types, consider adding an abstract or default implementation to Pronamic\WordPress\Pay\P...ts\PaymentDataInterface. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

739
		/** @scrutinizer ignore-call */ 
740
  $payment->customer_name       = $data->get_customer_name();
Loading history...
740
		$payment->address             = $data->get_address();
0 ignored issues
show
Bug introduced by
The method get_address() does not exist on Pronamic\WordPress\Pay\P...ts\PaymentDataInterface. Since it exists in all sub-types, consider adding an abstract or default implementation to Pronamic\WordPress\Pay\P...ts\PaymentDataInterface. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

740
		/** @scrutinizer ignore-call */ 
741
  $payment->address             = $data->get_address();
Loading history...
741
		$payment->zip                 = $data->get_zip();
0 ignored issues
show
Bug introduced by
The method get_zip() does not exist on Pronamic\WordPress\Pay\P...ts\PaymentDataInterface. Since it exists in all sub-types, consider adding an abstract or default implementation to Pronamic\WordPress\Pay\P...ts\PaymentDataInterface. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

741
		/** @scrutinizer ignore-call */ 
742
  $payment->zip                 = $data->get_zip();
Loading history...
742
		$payment->city                = $data->get_city();
0 ignored issues
show
Bug introduced by
The method get_city() does not exist on Pronamic\WordPress\Pay\P...ts\PaymentDataInterface. Since it exists in all sub-types, consider adding an abstract or default implementation to Pronamic\WordPress\Pay\P...ts\PaymentDataInterface. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

742
		/** @scrutinizer ignore-call */ 
743
  $payment->city                = $data->get_city();
Loading history...
743
		$payment->country             = $data->get_country();
0 ignored issues
show
Bug introduced by
The method get_country() does not exist on Pronamic\WordPress\Pay\P...ts\PaymentDataInterface. Since it exists in all sub-types, consider adding an abstract or default implementation to Pronamic\WordPress\Pay\P...ts\PaymentDataInterface. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

743
		/** @scrutinizer ignore-call */ 
744
  $payment->country             = $data->get_country();
Loading history...
744
		$payment->telephone_number    = $data->get_telephone_number();
0 ignored issues
show
Bug introduced by
The method get_telephone_number() does not exist on Pronamic\WordPress\Pay\P...ts\PaymentDataInterface. Since it exists in all sub-types, consider adding an abstract or default implementation to Pronamic\WordPress\Pay\P...ts\PaymentDataInterface. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

744
		/** @scrutinizer ignore-call */ 
745
  $payment->telephone_number    = $data->get_telephone_number();
Loading history...
745
		$payment->analytics_client_id = $data->get_analytics_client_id();
0 ignored issues
show
Bug introduced by
The method get_analytics_client_id() does not exist on Pronamic\WordPress\Pay\P...ts\PaymentDataInterface. It seems like you code against a sub-type of Pronamic\WordPress\Pay\P...ts\PaymentDataInterface such as Pronamic\WordPress\Pay\Payments\PaymentData. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

745
		/** @scrutinizer ignore-call */ 
746
  $payment->analytics_client_id = $data->get_analytics_client_id();
Loading history...
746
		$payment->recurring           = $data->get_recurring();
0 ignored issues
show
Bug introduced by
The method get_recurring() does not exist on Pronamic\WordPress\Pay\P...ts\PaymentDataInterface. Since it exists in all sub-types, consider adding an abstract or default implementation to Pronamic\WordPress\Pay\P...ts\PaymentDataInterface. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

746
		/** @scrutinizer ignore-call */ 
747
  $payment->recurring           = $data->get_recurring();
Loading history...
747
		$payment->subscription        = $data->get_subscription();
748
		$payment->subscription_id     = $data->get_subscription_id();
0 ignored issues
show
Bug introduced by
The method get_subscription_id() does not exist on Pronamic\WordPress\Pay\P...ts\PaymentDataInterface. Did you maybe mean get_subscription()? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

748
		/** @scrutinizer ignore-call */ 
749
  $payment->subscription_id     = $data->get_subscription_id();

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
749
		$payment->set_amount( $data->get_amount() );
0 ignored issues
show
Bug introduced by
The method get_amount() does not exist on Pronamic\WordPress\Pay\P...ts\PaymentDataInterface. Since it exists in all sub-types, consider adding an abstract or default implementation to Pronamic\WordPress\Pay\P...ts\PaymentDataInterface. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

749
		$payment->set_amount( $data->/** @scrutinizer ignore-call */ get_amount() );
Loading history...
750
		$payment->set_credit_card( $data->get_credit_card() );
751
752
		// User Agent (@see https://github.com/WordPress/WordPress/blob/4.9.4/wp-includes/comment.php#L1962-L1965).
753
		$payment->user_agent = isset( $_SERVER['HTTP_USER_AGENT'] ) ? $_SERVER['HTTP_USER_AGENT'] : null;
754
755
		// IP (@see https://github.com/WordPress/WordPress/blob/4.9.4/wp-includes/comment.php#L1957-L1960).
756
		$payment->user_ip = isset( $_SERVER['REMOTE_ADDR'] ) ? $_SERVER['REMOTE_ADDR'] : null;
757
758
		return self::start_payment( $payment, $gateway );
759
	}
760
761
	/**
762
	 * Start recurring payment.
763
	 *
764
	 * @param Subscription $subscription Subscription.
765
	 * @param Gateway      $gateway      Gateway.
766
	 *
767
	 * @return Payment
768
	 */
769
	public static function start_recurring( Subscription $subscription, Gateway $gateway ) {
770
		return pronamic_pay_plugin()->subscriptions_module->start_recurring( $subscription, $gateway );
771
	}
772
773
	/**
774
	 * Start payment.
775
	 *
776
	 * @param Payment $payment The payment to start at the specified gateway.
777
	 * @param Gateway $gateway The gateway to start the payment at.
778
	 *
779
	 * @return Payment
780
	 */
781
	public static function start_payment( Payment $payment, Gateway $gateway ) {
782
		global $pronamic_ideal;
783
784
		$pronamic_ideal->payments_data_store->create( $payment );
785
786
		// Prevent payment start at gateway if amount is empty.
787
		$amount = $payment->get_amount()->get_amount();
788
789
		if ( empty( $amount ) ) {
790
			// Keep track of free payments to update during shutdown.
791
			pronamic_pay_plugin()->payments_module->free[] = $payment->get_id();
792
793
			return $payment;
794
		}
795
796
		// Start payment at the gateway.
797
		$result = $gateway->start( $payment );
0 ignored issues
show
Bug introduced by
Are you sure the assignment to $result is correct as $gateway->start($payment) targeting Pronamic\WordPress\Pay\Core\Gateway::start() seems to always return null.

This check looks for function or method calls that always return null and whose return value is assigned to a variable.

class A
{
    function getObject()
    {
        return null;
    }

}

$a = new A();
$object = $a->getObject();

The method getObject() can return nothing but null, so it makes no sense to assign that value to a variable.

The reason is most likely that a function or method is imcomplete or has been reduced for debug purposes.

Loading history...
798
799
		// Add gateway errors as payment notes.
800
		if ( $gateway->has_error() ) {
801
			foreach ( $gateway->error->get_error_codes() as $code ) {
802
				$payment->add_note( sprintf( '%s: %s', $code, $gateway->error->get_error_message( $code ) ) );
803
			}
804
		}
805
806
		// Set payment status.
807
		if ( false === $result ) {
0 ignored issues
show
introduced by
The condition false === $result is always true.
Loading history...
808
			$payment->set_status( Statuses::FAILURE );
809
		} else {
810
			$payment->set_status( Statuses::OPEN );
811
		}
812
813
		// Save payment.
814
		$payment->save();
815
816
		// Update subscription status for failed payments.
817
		if ( false === $result && $payment->get_subscription() ) {
818
			// Reload payment, so subscription is available.
819
			$payment = new Payment( $payment->get_id() );
820
821
			$subscription = $payment->get_subscription();
822
823
			if ( Recurring::FIRST === $payment->recurring_type ) {
824
				// First payment - cancel subscription to prevent unwanted recurring payments
825
				// in the future, when a valid customer ID might be set for the user.
826
				$subscription->set_status( Statuses::CANCELLED );
827
			} else {
828
				$subscription->set_status( Statuses::FAILURE );
829
			}
830
831
			$subscription->save();
832
		}
833
834
		// Schedule payment status check.
835
		if ( $gateway->supports( 'payment_status_request' ) ) {
836
			StatusChecker::schedule_event( $payment );
837
		}
838
839
		return $payment;
840
	}
841
842
	/**
843
	 * Get pages.
844
	 *
845
	 * @return array
846
	 */
847
	public function get_pages() {
848
		$return = array();
849
850
		$pages = array(
851
			'completed' => __( 'Completed', 'pronamic_ideal' ),
852
			'cancel'    => __( 'Canceled', 'pronamic_ideal' ),
853
			'expired'   => __( 'Expired', 'pronamic_ideal' ),
854
			'error'     => __( 'Error', 'pronamic_ideal' ),
855
			'unknown'   => __( 'Unknown', 'pronamic_ideal' ),
856
		);
857
858
		foreach ( $pages as $key => $label ) {
859
			$id = sprintf( 'pronamic_pay_%s_page_id', $key );
860
861
			$return[ $id ] = $label;
862
		}
863
864
		return $return;
865
	}
866
}
867