Test Failed
Push — develop ( 9cf97e...8028c8 )
by Reüel
04:13
created

Gateway::get_available_payment_methods()   B

Complexity

Conditions 11
Paths 35

Size

Total Lines 66
Code Lines 34

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 18
CRAP Score 18.744

Importance

Changes 6
Bugs 0 Features 0
Metric Value
cc 11
eloc 34
c 6
b 0
f 0
nc 35
nop 0
dl 0
loc 66
ccs 18
cts 30
cp 0.6
crap 18.744
rs 7.3166

How to fix   Long Method    Complexity   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

1
<?php
2
/**
3
 * Mollie gateway.
4
 *
5
 * @author    Pronamic <[email protected]>
6
 * @copyright 2005-2020 Pronamic
7
 * @license   GPL-3.0-or-later
8
 * @package   Pronamic\WordPress\Pay
9
 */
10
11
namespace Pronamic\WordPress\Pay\Gateways\Mollie;
12
13
use DateInterval;
14
use Pronamic\WordPress\DateTime\DateTime;
15
use Pronamic\WordPress\Pay\Banks\BankAccountDetails;
16
use Pronamic\WordPress\Pay\Banks\BankTransferDetails;
17
use Pronamic\WordPress\Pay\Core\Gateway as Core_Gateway;
18
use Pronamic\WordPress\Pay\Core\PaymentMethods;
19
use Pronamic\WordPress\Pay\Core\Recurring as Core_Recurring;
20
use Pronamic\WordPress\Pay\Payments\FailureReason;
0 ignored issues
show
Bug introduced by
The type Pronamic\WordPress\Pay\Payments\FailureReason was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
21
use Pronamic\WordPress\Pay\Payments\PaymentStatus;
22
use Pronamic\WordPress\Pay\Payments\Payment;
23
use Pronamic\WordPress\Pay\Subscriptions\Subscription;
24
25
/**
26
 * Title: Mollie
27
 * Description:
28
 * Copyright: 2005-2020 Pronamic
29
 * Company: Pronamic
30
 *
31
 * @author  Remco Tolsma
32
 * @version 2.0.9
33
 * @since   1.1.0
34
 */
35
class Gateway extends Core_Gateway {
36
	/**
37
	 * Client.
38
	 *
39
	 * @var Client
40
	 */
41
	protected $client;
42
43
	/**
44
	 * Constructs and initializes an Mollie gateway
45
	 *
46
	 * @param Config $config Config.
47
	 */
48
	public function __construct( Config $config ) {
49
		parent::__construct( $config );
50
51
		$this->set_method( self::METHOD_HTTP_REDIRECT );
52
53 39
		// Supported features.
54 39
		$this->supports = array(
55
			'payment_status_request',
56 39
			'recurring_direct_debit',
57
			'recurring_credit_card',
58
			'recurring',
59 39
			'webhook',
60
			'webhook_log',
61
			'webhook_no_config',
62
		);
63
64
		// Client.
65
		$this->client = new Client( \strval( $config->api_key ) );
66
67
		// Data Stores.
68
		$this->profile_data_store  = new ProfileDataStore();
0 ignored issues
show
Bug Best Practice introduced by
The property profile_data_store does not exist. Although not strictly required by PHP, it is generally a best practice to declare properties explicitly.
Loading history...
69
		$this->customer_data_store = new CustomerDataStore();
0 ignored issues
show
Bug Best Practice introduced by
The property customer_data_store does not exist. Although not strictly required by PHP, it is generally a best practice to declare properties explicitly.
Loading history...
70 39
	}
71 39
72
	/**
73
	 * Get issuers
74 39
	 *
75 38
	 * @see Core_Gateway::get_issuers()
76
	 * @return array<int, array<string, array<string>>>
77
	 */
78
	public function get_issuers() {
79 39
		$groups = array();
80 39
81
		try {
82
			$result = $this->client->get_issuers();
83
84
			$groups[] = array(
85
				'options' => $result,
86
			);
87 3
		} catch ( Error $e ) {
88 3
			// Catch Mollie error.
89
			$error = new \WP_Error(
90
				'mollie_error',
91 3
				sprintf( '%1$s (%2$s) - %3$s', $e->get_title(), $e->getCode(), $e->get_detail() )
92
			);
93
94
			$this->set_error( $error );
95
		} catch ( \Exception $e ) {
96 3
			// Catch exceptions.
97
			$error = new \WP_Error( 'mollie_error', $e->getMessage() );
98 3
99 3
			$this->set_error( $error );
100 3
		}
101
102
		return $groups;
103 3
	}
104
105
	/**
106
	 * Get available payment methods.
107
	 *
108
	 * @see Core_Gateway::get_available_payment_methods()
109
	 * @return array<string>
110
	 */
111 3
	public function get_available_payment_methods() {
112
		$payment_methods = array();
113
114
		// Set sequence types to get payment methods for.
115
		$sequence_types = array( Sequence::ONE_OFF, Sequence::RECURRING, Sequence::FIRST );
116
117
		$results = array();
118
119 2
		foreach ( $sequence_types as $sequence_type ) {
120 2
			// Get active payment methods for Mollie account.
121
			try {
122
				$result = $this->client->get_payment_methods( $sequence_type );
123 2
			} catch ( Error $e ) {
124
				// Catch Mollie error.
125 2
				$error = new \WP_Error(
126
					'mollie_error',
127 2
					sprintf( '%1$s (%2$s) - %3$s', $e->get_title(), $e->getCode(), $e->get_detail() )
128
				);
129
130 2
				$this->set_error( $error );
131 2
132
				break;
133
			} catch ( \Exception $e ) {
134
				// Catch exceptions.
135
				$error = new \WP_Error( 'mollie_error', $e->getMessage() );
136
137
				$this->set_error( $error );
138
139
				break;
140
			}
141 2
142
			if ( Sequence::FIRST === $sequence_type ) {
143 2
				foreach ( $result as $method => $title ) {
144
					unset( $result[ $method ] );
145 2
146
					// Get WordPress payment method for direct debit method.
147 2
					$method         = Methods::transform_gateway_method( $method );
148
					$payment_method = array_search( $method, PaymentMethods::get_recurring_methods(), true );
149
150 2
					if ( $payment_method ) {
151
						$results[ $payment_method ] = $title;
152
					}
153
				}
154
			}
155
156
			if ( is_array( $result ) ) {
157
				$results = array_merge( $results, $result );
158
			}
159
		}
160
161
		// Transform to WordPress payment methods.
162
		foreach ( $results as $method => $title ) {
163
			if ( PaymentMethods::is_recurring_method( $method ) ) {
164 2
				$payment_method = $method;
165 2
			} else {
166
				$payment_method = Methods::transform_gateway_method( $method );
167
			}
168
169
			if ( $payment_method ) {
170 2
				$payment_methods[] = $payment_method;
171 2
			}
172
		}
173
174 2
		$payment_methods = array_unique( $payment_methods );
175
176
		return $payment_methods;
177 2
	}
178 2
179
	/**
180
	 * Get supported payment methods
181
	 *
182 2
	 * @see Pronamic_WP_Pay_Gateway::get_supported_payment_methods()
183
	 * @return array<string>
184 2
	 */
185
	public function get_supported_payment_methods() {
186
		return array(
187
			PaymentMethods::BANCONTACT,
188
			PaymentMethods::BANK_TRANSFER,
189
			PaymentMethods::BELFIUS,
190
			PaymentMethods::CREDIT_CARD,
191
			PaymentMethods::DIRECT_DEBIT,
192
			PaymentMethods::DIRECT_DEBIT_BANCONTACT,
193 2
			PaymentMethods::DIRECT_DEBIT_IDEAL,
194
			PaymentMethods::DIRECT_DEBIT_SOFORT,
195 2
			PaymentMethods::EPS,
196
			PaymentMethods::GIROPAY,
197
			PaymentMethods::IDEAL,
198
			PaymentMethods::KBC,
199
			PaymentMethods::PAYPAL,
200
			PaymentMethods::SOFORT,
201
		);
202
	}
203
204
	/**
205
	 * Get webhook URL for Mollie.
206
	 *
207
	 * @return string|null
208
	 */
209
	public function get_webhook_url() {
210
		$url = \rest_url( Integration::REST_ROUTE_NAMESPACE . '/webhook' );
211
212
		$host = wp_parse_url( $url, PHP_URL_HOST );
213
214
		if ( is_array( $host ) ) {
215
			// Parsing failure.
216
			$host = '';
217 4
		}
218 4
219
		if ( 'localhost' === $host ) {
220 4
			// Mollie doesn't allow localhost.
221
			return null;
222 4
		} elseif ( '.dev' === substr( $host, -4 ) ) {
223
			// Mollie doesn't allow the .dev TLD.
224
			return null;
225
		} elseif ( '.local' === substr( $host, -6 ) ) {
226
			// Mollie doesn't allow the .local TLD.
227 4
			return null;
228
		} elseif ( '.test' === substr( $host, -5 ) ) {
229 1
			// Mollie doesn't allow the .test TLD.
230 3
			return null;
231
		}
232 1
233 2
		return $url;
234
	}
235 1
236 1
	/**
237
	 * Start
238
	 *
239
	 * @see Pronamic_WP_Pay_Gateway::start()
240
	 * @param Payment $payment Payment.
241 1
	 * @return void
242
	 */
243 1
	public function start( Payment $payment ) {
244
		$request = new PaymentRequest(
245
			AmountTransformer::transform( $payment->get_total_amount() ),
246
			\strval( $payment->get_description() )
247
		);
248
249
		$request->redirect_url = $payment->get_return_url();
250
		$request->webhook_url  = $this->get_webhook_url();
251
252
		// Locale.
253
		$customer = $payment->get_customer();
254
255
		if ( null !== $customer ) {
256
			$request->locale = LocaleHelper::transform( $customer->get_locale() );
257
		}
258
259
		// Customer ID.
260
		$customer_id = $this->get_customer_id_for_payment( $payment );
261
262
		if ( null === $customer_id ) {
263
			$customer_id = $this->create_customer_for_payment( $payment );
264
		}
265
266
		if ( null !== $customer_id ) {
267
			$request->customer_id = $customer_id;
268
		}
269
270
		// Payment method.
271
		$payment_method = $payment->get_method();
272
273
		// Recurring payment method.
274
		$is_recurring_method = ( $payment->get_subscription() && PaymentMethods::is_recurring_method( $payment_method ) );
275
276
		// Consumer bank details.
277
		$consumer_bank_details = $payment->get_consumer_bank_details();
278
279
		if ( PaymentMethods::DIRECT_DEBIT === $payment_method && null !== $consumer_bank_details ) {
280
			$consumer_name = $consumer_bank_details->get_name();
281
			$consumer_iban = $consumer_bank_details->get_iban();
282
283
			$request->consumer_name    = $consumer_name;
284
			$request->consumer_account = $consumer_iban;
285
286
			// Check if one-off SEPA Direct Debit can be used, otherwise short circuit payment.
287
			if ( null !== $customer_id ) {
288
				// Find or create mandate.
289
				$mandate_id = $this->client->has_valid_mandate( $customer_id, PaymentMethods::DIRECT_DEBIT, $consumer_iban );
290
291
				if ( false === $mandate_id ) {
292
					$mandate = $this->client->create_mandate( $customer_id, $consumer_bank_details );
293
294
					$mandate_id = $mandate->id;
295
				}
296
297
				// Charge immediately on-demand.
298
				$request->sequence_type = Sequence::RECURRING;
299
				$request->mandate_id    = $mandate_id;
300
301
				$is_recurring_method = true;
302
303
				$payment->recurring = true;
304
			}
305
		}
306
307
		if ( false === $is_recurring_method ) {
308
			// Always use 'direct debit mandate via iDEAL/Bancontact/Sofort' payment methods as recurring method.
309
			$is_recurring_method = PaymentMethods::is_direct_debit_method( $payment_method );
310
		}
311
312
		if ( $is_recurring_method ) {
313
			$request->sequence_type = $payment->get_recurring() ? Sequence::RECURRING : Sequence::FIRST;
314
315
			if ( Sequence::FIRST === $request->sequence_type ) {
316
				$payment_method = PaymentMethods::get_first_payment_method( $payment_method );
317
			}
318
319
			if ( Sequence::RECURRING === $request->sequence_type ) {
320
				$payment->set_action_url( $payment->get_return_url() );
321
			}
322
		}
323
324
		// Leap of faith if the WordPress payment method could not transform to a Mollie method?
325
		$request->method = Methods::transform( $payment_method, $payment_method );
326
327
		// Issuer.
328
		if ( Methods::IDEAL === $request->method ) {
329
			$request->issuer = $payment->get_issuer();
330
		}
331
332
		// Due date.
333
		try {
334
			$due_date = new DateTime( sprintf( '+%s days', $this->config->due_date_days ) );
335
		} catch ( \Exception $e ) {
336
			$due_date = null;
337
		}
338
339
		$request->set_due_date( $due_date );
340
341
		// Create payment.
342
		$result = $this->client->create_payment( $request );
343
344
		// Set transaction ID.
345
		if ( isset( $result->id ) ) {
346
			$payment->set_transaction_id( $result->id );
347
		}
348
349
		// Set expiry date.
350
		/* phpcs:disable WordPress.NamingConventions.ValidVariableName.UsedPropertyNotSnakeCase */
351
		if ( isset( $result->expiresAt ) ) {
352
			try {
353
				$expires_at = new DateTime( $result->expiresAt );
354
			} catch ( \Exception $e ) {
355
				$expires_at = null;
356
			}
357
358
			$payment->set_expiry_date( $expires_at );
359
		}
360
		/* phpcs:enable WordPress.NamingConventions.ValidVariableName.UsedPropertyNotSnakeCase */
361
362
		// Set status.
363
		if ( isset( $result->status ) ) {
364
			$payment->set_status( Statuses::transform( $result->status ) );
365
		}
366
367
		// Set bank transfer recipient details.
368
		if ( isset( $result->details ) ) {
369
			$bank_transfer_recipient_details = $payment->get_bank_transfer_recipient_details();
370
371
			if ( null === $bank_transfer_recipient_details ) {
372
				$bank_transfer_recipient_details = new BankTransferDetails();
373
374
				$payment->set_bank_transfer_recipient_details( $bank_transfer_recipient_details );
375
			}
376
377
			$bank_details = $bank_transfer_recipient_details->get_bank_account();
378
379
			if ( null === $bank_details ) {
380
				$bank_details = new BankAccountDetails();
381
382
				$bank_transfer_recipient_details->set_bank_account( $bank_details );
383
			}
384
385
			$details = $result->details;
386
387
			/*
388
			 * @codingStandardsIgnoreStart
389
			 *
390
			 * Ignore coding standards because of sniff WordPress.NamingConventions.ValidVariableName.NotSnakeCaseMemberVar
391
			 */
392
			if ( isset( $details->bankName ) ) {
393
				/**
394
				 * Set `bankName` as bank details name, as result "Stichting Mollie Payments"
395
				 * is not the name of a bank, but the account holder name.
396
				 */
397
				$bank_details->set_name( $details->bankName );
398
			}
399
400
			if ( isset( $details->bankAccount ) ) {
401
				$bank_details->set_iban( $details->bankAccount );
402
			}
403
404
			if ( isset( $details->bankBic ) ) {
405
				$bank_details->set_bic( $details->bankBic );
406
			}
407
408
			if ( isset( $details->transferReference ) ) {
409
				$bank_transfer_recipient_details->set_reference( $details->transferReference );
410
			}
411
			// @codingStandardsIgnoreEnd
412
		}
413
414
		// Set action URL.
415
		if ( isset( $result->_links ) ) {
416
			if ( isset( $result->_links->checkout->href ) ) {
417
				$payment->set_action_url( $result->_links->checkout->href );
418
			}
419
		}
420
	}
421
422
	/**
423
	 * Update status of the specified payment
424
	 *
425
	 * @param Payment $payment Payment.
426
	 * @return void
427
	 */
428
	public function update_status( Payment $payment ) {
429
		$transaction_id = $payment->get_transaction_id();
430
431
		if ( null === $transaction_id ) {
432
			return;
433
		}
434
435
		$mollie_payment = $this->client->get_payment( $transaction_id );
436
437
		if ( isset( $mollie_payment->status ) ) {
438
			$payment->set_status( Statuses::transform( $mollie_payment->status ) );
439
		}
440
441
		/**
442
		 * Mollie profile.
443
		 */
444
		$mollie_profile = new Profile();
445
		$mollie_profile->set_id( $mollie_payment->profileId );
446
447
		$profile_internal_id = $this->profile_data_store->get_or_insert_profile( $mollie_profile );
448
449
		/**
450
		 * If the Mollie payment contains a customer ID we will try to connect
451
		 * this Mollie customer ID the WordPress user and subscription.
452
		 * This can be usefull in case when a WordPress user is created after
453
		 * a succesfull payment.
454
		 *
455
		 * @link https://www.gravityforms.com/add-ons/user-registration/
456
		 */
457
		if ( isset( $mollie_payment->customerId ) ) {
458
			$mollie_customer = new Customer();
459
			$mollie_customer->set_id( $mollie_payment->customerId );
460
461
			$customer_internal_id = $this->customer_data_store->get_or_insert_customer(
0 ignored issues
show
Unused Code introduced by
The assignment to $customer_internal_id is dead and can be removed.
Loading history...
462
				$mollie_customer,
463
				array(
0 ignored issues
show
Unused Code introduced by
The call to Pronamic\WordPress\Pay\G...et_or_insert_customer() has too many arguments starting with array('profile_id' => $profile_internal_id). ( Ignorable by Annotation )

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

463
			/** @scrutinizer ignore-call */ 
464
   $customer_internal_id = $this->customer_data_store->get_or_insert_customer(

This check compares calls to functions or methods with their respective definitions. If the call has more arguments than are defined, it raises an issue.

If a function is defined several times with a different number of parameters, the check may pick up the wrong definition and report false positives. One codebase where this has been known to happen is Wordpress. Please note the @ignore annotation hint above.

Loading history...
464
					'profile_id' => $profile_internal_id,
465
				),
466
				array(
467
					'profile_id' => '%s',
468
				)
469
			);
470
471
			// Meta.
472
			$customer_id = $payment->get_meta( 'mollie_customer_id' );
473
474
			if ( empty( $customer_id ) ) {
475
				$payment->set_meta( 'mollie_customer_id', $mollie_customer->get_id() );
476
			}
477
478
			// Customer.
479
			$customer = $payment->get_customer();
480
481
			if ( null !== $customer ) {
482
				// Connect to user.
483 10
				$user = \get_user_by( 'id', $customer->get_user_id() );
484 10
485
				if ( false !== $user ) {
486
					$this->customer_data_store->connect_mollie_customer_to_wp_user( $mollie_customer, $user );
487 10
				}
488
			}
489
490 10
			// Subscription.
491
			$subscription = $payment->get_subscription();
492 10
493
			if ( null !== $subscription ) {
494
				$customer_id = $subscription->get_meta( 'mollie_customer_id' );
495 10
496 10
				if ( empty( $customer_id ) ) {
497
					$subscription->set_meta( 'mollie_customer_id', $mollie_customer->get_id() );
498
				}
499 10
			}
500 7
		}
501
502 7
		if ( isset( $mollie_payment->details ) ) {
503
			$consumer_bank_details = $payment->get_consumer_bank_details();
504
505 10
			if ( null === $consumer_bank_details ) {
506 4
				$consumer_bank_details = new BankAccountDetails();
507
508
				$payment->set_consumer_bank_details( $consumer_bank_details );
509
			}
510
511 10
			$details = $mollie_payment->details;
512
513
			/*
514
			 * @codingStandardsIgnoreStart
515
			 *
516
			 * Ignore coding standards because of sniff WordPress.NamingConventions.ValidVariableName.NotSnakeCaseMemberVar
517
			 */
518
			if ( isset( $details->consumerName ) ) {
519
				$consumer_bank_details->set_name( $details->consumerName );
520
			}
521
522
			if ( isset( $details->cardHolder ) ) {
523
				$consumer_bank_details->set_name( $details->cardHolder );
524 10
			}
525
526
			if ( isset( $details->cardNumber ) ) {
527
				// The last four digits of the card number.
528
				$consumer_bank_details->set_account_number( $details->cardNumber );
529 10
			}
530
531 10
			if ( isset( $details->cardCountryCode ) ) {
532
				// The ISO 3166-1 alpha-2 country code of the country the card was issued in.
533
				$consumer_bank_details->set_country( $details->cardCountryCode );
534
			}
535
536
			if ( isset( $details->consumerAccount ) ) {
537
				switch ( $mollie_payment->method ) {
538
					case Methods::BELFIUS:
539
					case Methods::DIRECT_DEBIT:
540 27
					case Methods::IDEAL:
541 27
					case Methods::KBC:
542 11
					case Methods::SOFORT:
543
						$consumer_bank_details->set_iban( $details->consumerAccount );
544
545 16
						break;
546
					case Methods::BANCONTACT:
547
					case Methods::BANKTRANSFER:
548
					case Methods::PAYPAL:
549
					default:
550
						$consumer_bank_details->set_account_number( $details->consumerAccount );
551
552
						break;
553
				}
554
			}
555 15
556 15
			if ( isset( $details->consumerBic ) ) {
557 3
				$consumer_bank_details->set_bic( $details->consumerBic );
558
			}
559
560 12
			/*
561 11
			 * Failure reason.
562
			 */
563
			$failure_reason = $payment->get_failure_reason();
0 ignored issues
show
Bug introduced by
The method get_failure_reason() does not exist on Pronamic\WordPress\Pay\Payments\Payment. ( Ignorable by Annotation )

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

563
			/** @scrutinizer ignore-call */ 
564
   $failure_reason = $payment->get_failure_reason();

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...
564 4
565 4
			if ( null === $failure_reason ) {
566
				$failure_reason = new FailureReason();
567
568
				$payment->set_failure_reason( $failure_reason );
0 ignored issues
show
Bug introduced by
The method set_failure_reason() does not exist on Pronamic\WordPress\Pay\Payments\Payment. ( Ignorable by Annotation )

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

568
				$payment->/** @scrutinizer ignore-call */ 
569
              set_failure_reason( $failure_reason );

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...
569
			}
570
571
			// SEPA Direct Debit.
572
			if ( isset( $details->bankReasonCode ) ) {
573 27
				$failure_reason->set_code( $details->bankReasonCode );
574 27
			}
575 1
576
			if ( isset( $details->bankReasonCode ) ) {
577
				$failure_reason->set_message( $details->bankReason );
578 26
			}
579
580 26
			// Credit card.
581
			if ( isset( $details->failureReason ) ) {
582
				$failure_reason->set_code( $details->failureReason );
583
			}
584 26
585
			if ( isset( $details->failureMessage ) ) {
586 26
				$failure_reason->set_message( $details->failureMessage );
587 1
			}
588
			// @codingStandardsIgnoreEnd
589
		}
590 25
	}
591
592 25
	/**
593 10
	 * Get Mollie customer ID for payment.
594
	 *
595
	 * @param Payment $payment Payment.
596
	 * @return string|null
597 15
	 */
598
	public function get_customer_id_for_payment( Payment $payment ) {
599 15
		$customer_ids = $this->get_customer_ids_for_payment( $payment );
600
601 15
		$customer_id = $this->get_first_existing_customer_id( $customer_ids );
602
603 15
		return $customer_id;
604
	}
605 15
606
	/**
607
	 * Get Mollie customers for the specified payment.
608
	 *
609
	 * @param Payment $payment Payment.
610
	 * @return array<string>
611
	 */
612
	private function get_customer_ids_for_payment( Payment $payment ) {
613
		$customer_ids = array();
614
615
		// Customer ID from subscription meta.
616
		$subscription = $payment->get_subscription();
617
618
		if ( null !== $subscription ) {
619
			$customer_id = $this->get_customer_id_for_subscription( $payment->get_subscription() );
0 ignored issues
show
Bug introduced by
It seems like $payment->get_subscription() can also be of type null; however, parameter $subscription of Pronamic\WordPress\Pay\G...r_id_for_subscription() does only seem to accept Pronamic\WordPress\Pay\Subscriptions\Subscription, 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

619
			$customer_id = $this->get_customer_id_for_subscription( /** @scrutinizer ignore-type */ $payment->get_subscription() );
Loading history...
620
621
			if ( null !== $customer_id ) {
622
				$customer_ids[] = $customer_id;
623
			}
624
		}
625
626
		// Customer ID from WordPress user.
627
		$customer = $payment->get_customer();
628
629
		if ( null !== $customer ) {
630
			$user_id = $customer->get_user_id();
631
632
			if ( ! empty( $user_id ) ) {
633
				$user_customer_ids = $this->get_customer_ids_for_user( $user_id );
634
635
				$customer_ids = \array_merge( $customer_ids, $user_customer_ids );
636
			}
637
		}
638
639
		return $customer_ids;
640
	}
641
642
	/**
643
	 * Get Mollie customers for the specified WordPress user ID.
644
	 *
645
	 * @param int $user_id WordPress user ID.
646
	 * @return array<string>
647
	 */
648
	private function get_customer_ids_for_user( $user_id ) {
649
		$customer_query = new CustomerQuery(
650
			array(
651
				'user_id' => $user_id,
652
			)
653
		);
654
655
		$customers = $customer_query->get_customers();
656
657
		$customer_ids = wp_list_pluck( $customers, 'mollie_id' );
658
659
		return $customer_ids;
660
	}
661
662
	/**
663
	 * Get customer ID for subscription.
664
	 *
665
	 * @param Subscription $subscription Subscription.
666
	 * @return string|null
667
	 */
668
	private function get_customer_id_for_subscription( Subscription $subscription ) {
669
		$customer_id = $subscription->get_meta( 'mollie_customer_id' );
670
671
		if ( empty( $customer_id ) ) {
672
			// Try to get (legacy) customer ID from first payment.
673
			$first_payment = $subscription->get_first_payment();
674
675
			if ( null !== $first_payment ) {
676
				$customer_id = $first_payment->get_meta( 'mollie_customer_id' );
677
			}
678
		}
679
680
		if ( empty( $customer_id ) ) {
681
			return null;
682
		}
683
684
		return $customer_id;
685
	}
686
687
	/**
688
	 * Get first existing customer from customers list.
689
	 *
690
	 * @param array $customer_ids Customers.
691
	 * @return string|null
692
	 */
693
	private function get_first_existing_customer_id( $customer_ids ) {
694
		$customer_ids = \array_filter( $customer_ids );
695
696
		$customer_ids = \array_unique( $customer_ids );
697
698
		foreach ( $customer_ids as $customer_id ) {
699
			$customer = $this->client->get_customer( $customer_id );
700
701
			if ( null !== $customer ) {
702
				return $customer_id;
703
			}
704
		}
705
706
		return null;
707
	}
708
709
	/**
710
	 * Create customer for payment.
711
	 *
712
	 * @param Payment $payment Payment.
713
	 * @return string|null
714
	 * @throws Error Throws Error when Mollie error occurs.
715
	 */
716
	private function create_customer_for_payment( Payment $payment ) {
717
		$mollie_customer = new Customer();
718
		$mollie_customer->set_mode( $this->config->is_test_mode() ? 'test' : 'live' );
719
		$mollie_customer->set_email( $payment->get_email() );
720
721
		$pronamic_customer = $payment->get_customer();
722
723
		if ( null !== $pronamic_customer ) {
724
			$name = $pronamic_customer->get_name();
725
726
			if ( null !== $name ) {
727
				$mollie_customer->set_name( \strval( $name ) );
728
			}
729
		}
730
731
		// Create customer.
732
		$mollie_customer = $this->client->create_customer( $mollie_customer );
733
734
		$customer_id = $this->customer_data_store->insert_customer( $mollie_customer );
0 ignored issues
show
Unused Code introduced by
The assignment to $customer_id is dead and can be removed.
Loading history...
735
736
		// Connect to user.
737
		$user = \get_user_by( 'id', $pronamic_customer->get_user_id() );
738
739
		if ( false !== $user ) {
740
			$this->customer_data_store->connect_mollie_customer_to_wp_user( $mollie_customer, $user );
741
		}
742
743
		// Store customer ID in subscription meta.
744
		$subscription = $payment->get_subscription();
745
746
		if ( null !== $subscription ) {
747
			$subscription->set_meta( 'mollie_customer_id', $mollie_customer->get_id() );
748
		}
749
750
		return $mollie_customer->get_id();
751
	}
752
}
753