1 | <?php |
||
2 | /** |
||
3 | * Mollie gateway. |
||
4 | * |
||
5 | * @author Pronamic <[email protected]> |
||
6 | * @copyright 2005-2022 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 Pronamic\WordPress\DateTime\DateTime; |
||
14 | use Pronamic\WordPress\Money\Money; |
||
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\Gateways\Mollie\Payment as MolliePayment; |
||
20 | use Pronamic\WordPress\Pay\Payments\FailureReason; |
||
21 | use Pronamic\WordPress\Pay\Payments\Payment; |
||
22 | use Pronamic\WordPress\Pay\Subscriptions\Subscription; |
||
23 | use Pronamic\WordPress\Pay\Subscriptions\SubscriptionStatus; |
||
24 | |||
25 | /** |
||
26 | * Title: Mollie |
||
27 | * Description: |
||
28 | * Copyright: 2005-2022 Pronamic |
||
29 | * Company: Pronamic |
||
30 | * |
||
31 | * @author Remco Tolsma |
||
32 | * @version 2.1.4 |
||
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 | * Config |
||
45 | * |
||
46 | * @var Config |
||
47 | */ |
||
48 | protected $config; |
||
49 | |||
50 | /** |
||
51 | * Profile data store. |
||
52 | * |
||
53 | * @var ProfileDataStore |
||
54 | */ |
||
55 | private $profile_data_store; |
||
56 | |||
57 | /** |
||
58 | * Customer data store. |
||
59 | * |
||
60 | * @var CustomerDataStore |
||
61 | */ |
||
62 | private $customer_data_store; |
||
63 | |||
64 | /** |
||
65 | * Constructs and initializes an Mollie gateway |
||
66 | * |
||
67 | * @param Config $config Config. |
||
68 | */ |
||
69 | 39 | public function __construct( Config $config ) { |
|
70 | 39 | parent::__construct( $config ); |
|
71 | |||
72 | 39 | $this->set_method( self::METHOD_HTTP_REDIRECT ); |
|
73 | |||
74 | // Supported features. |
||
75 | 39 | $this->supports = array( |
|
76 | 'payment_status_request', |
||
77 | 'recurring_apple_pay', |
||
78 | 'recurring_direct_debit', |
||
79 | 'recurring_credit_card', |
||
80 | 'recurring', |
||
81 | 'refunds', |
||
82 | 'webhook', |
||
83 | 'webhook_log', |
||
84 | 'webhook_no_config', |
||
85 | ); |
||
86 | |||
87 | 39 | // Client. |
|
88 | $this->client = new Client( (string) $config->api_key ); |
||
89 | |||
90 | 39 | // Data Stores. |
|
91 | 39 | $this->profile_data_store = new ProfileDataStore(); |
|
92 | $this->customer_data_store = new CustomerDataStore(); |
||
93 | |||
94 | 39 | // Actions. |
|
95 | 39 | add_action( 'pronamic_payment_status_update', array( $this, 'copy_customer_id_to_wp_user' ), 99, 1 ); |
|
96 | } |
||
97 | |||
98 | /** |
||
99 | * Get issuers |
||
100 | * |
||
101 | * @see Core_Gateway::get_issuers() |
||
102 | * @return array<int, array<string, array<string>>> |
||
103 | 3 | */ |
|
104 | 3 | public function get_issuers() { |
|
105 | $groups = array(); |
||
106 | |||
107 | 3 | try { |
|
108 | $result = $this->client->get_issuers(); |
||
109 | |||
110 | $groups[] = array( |
||
111 | 'options' => $result, |
||
112 | 3 | ); |
|
113 | } catch ( Error $e ) { |
||
114 | 3 | // Catch Mollie error. |
|
115 | 3 | $error = new \WP_Error( |
|
116 | 3 | 'mollie_error', |
|
117 | sprintf( '%1$s (%2$s) - %3$s', $e->get_title(), $e->getCode(), $e->get_detail() ) |
||
118 | ); |
||
119 | 3 | ||
120 | $this->set_error( $error ); |
||
121 | } catch ( \Exception $e ) { |
||
122 | // Catch exceptions. |
||
123 | $error = new \WP_Error( 'mollie_error', $e->getMessage() ); |
||
124 | |||
125 | $this->set_error( $error ); |
||
126 | } |
||
127 | 3 | ||
128 | return $groups; |
||
129 | } |
||
130 | |||
131 | /** |
||
132 | * Get available payment methods. |
||
133 | * |
||
134 | * @see Core_Gateway::get_available_payment_methods() |
||
135 | * @return array<int, string> |
||
136 | 2 | */ |
|
137 | 2 | public function get_available_payment_methods() { |
|
138 | $payment_methods = array(); |
||
139 | |||
140 | 2 | // Set sequence types to get payment methods for. |
|
141 | $sequence_types = array( Sequence::ONE_OFF, Sequence::RECURRING, Sequence::FIRST ); |
||
142 | 2 | ||
143 | $results = array(); |
||
144 | 2 | ||
145 | foreach ( $sequence_types as $sequence_type ) { |
||
146 | // Get active payment methods for Mollie account. |
||
147 | 2 | try { |
|
148 | 2 | $result = $this->client->get_payment_methods( $sequence_type ); |
|
149 | } catch ( Error $e ) { |
||
150 | // Catch Mollie error. |
||
151 | $error = new \WP_Error( |
||
152 | 'mollie_error', |
||
153 | sprintf( '%1$s (%2$s) - %3$s', $e->get_title(), $e->getCode(), $e->get_detail() ) |
||
154 | ); |
||
155 | |||
156 | $this->set_error( $error ); |
||
157 | |||
158 | 2 | break; |
|
159 | } catch ( \Exception $e ) { |
||
160 | 2 | // Catch exceptions. |
|
161 | $error = new \WP_Error( 'mollie_error', $e->getMessage() ); |
||
162 | 2 | ||
163 | $this->set_error( $error ); |
||
164 | 2 | ||
165 | break; |
||
166 | } |
||
167 | 2 | ||
168 | if ( Sequence::FIRST === $sequence_type ) { |
||
169 | foreach ( $result as $method => $title ) { |
||
170 | unset( $result[ $method ] ); |
||
171 | |||
172 | // Get WordPress payment method for direct debit method. |
||
173 | $method = Methods::transform_gateway_method( $method ); |
||
174 | $payment_method = array_search( $method, PaymentMethods::get_recurring_methods(), true ); |
||
175 | |||
176 | if ( $payment_method ) { |
||
177 | $results[ $payment_method ] = $title; |
||
178 | } |
||
179 | } |
||
180 | } |
||
181 | 2 | ||
182 | 2 | if ( is_array( $result ) ) { |
|
183 | $results = array_merge( $results, $result ); |
||
184 | } |
||
185 | } |
||
186 | |||
187 | 2 | // Transform to WordPress payment methods. |
|
188 | 2 | foreach ( $results as $method => $title ) { |
|
189 | $method = (string) $method; |
||
190 | 2 | ||
191 | $payment_method = Methods::transform_gateway_method( $method ); |
||
192 | 2 | ||
193 | if ( PaymentMethods::is_recurring_method( $method ) ) { |
||
194 | $payment_method = $method; |
||
195 | } |
||
196 | 2 | ||
197 | 2 | if ( null !== $payment_method ) { |
|
198 | $payment_methods[] = (string) $payment_method; |
||
199 | } |
||
200 | } |
||
201 | 2 | ||
202 | $payment_methods = array_unique( $payment_methods ); |
||
203 | 2 | ||
204 | return $payment_methods; |
||
205 | } |
||
206 | |||
207 | /** |
||
208 | * Get supported payment methods |
||
209 | * |
||
210 | * @see Core_Gateway::get_supported_payment_methods() |
||
211 | * @return array<string> |
||
212 | 2 | */ |
|
213 | public function get_supported_payment_methods() { |
||
214 | 2 | return array( |
|
215 | PaymentMethods::APPLE_PAY, |
||
216 | PaymentMethods::BANCONTACT, |
||
217 | PaymentMethods::BANK_TRANSFER, |
||
218 | PaymentMethods::BELFIUS, |
||
219 | PaymentMethods::CREDIT_CARD, |
||
220 | PaymentMethods::DIRECT_DEBIT, |
||
221 | PaymentMethods::DIRECT_DEBIT_BANCONTACT, |
||
222 | PaymentMethods::DIRECT_DEBIT_IDEAL, |
||
223 | PaymentMethods::DIRECT_DEBIT_SOFORT, |
||
224 | PaymentMethods::EPS, |
||
225 | PaymentMethods::GIROPAY, |
||
226 | PaymentMethods::IDEAL, |
||
227 | PaymentMethods::KBC, |
||
228 | PaymentMethods::PAYPAL, |
||
229 | PaymentMethods::PRZELEWY24, |
||
230 | PaymentMethods::SOFORT, |
||
231 | ); |
||
232 | } |
||
233 | |||
234 | /** |
||
235 | * Get webhook URL for Mollie. |
||
236 | * |
||
237 | * @param Payment $payment Payment. |
||
238 | 4 | * @return string|null |
|
239 | 4 | */ |
|
240 | public function get_webhook_url( Payment $payment ) { |
||
241 | 4 | $url = \rest_url( Integration::REST_ROUTE_NAMESPACE . '/webhook/' . (string) $payment->get_id() ); |
|
242 | |||
243 | 4 | $host = wp_parse_url( $url, PHP_URL_HOST ); |
|
244 | |||
245 | if ( is_array( $host ) ) { |
||
246 | // Parsing failure. |
||
247 | $host = ''; |
||
248 | 4 | } |
|
249 | |||
250 | 1 | if ( 'localhost' === $host ) { |
|
251 | 3 | // Mollie doesn't allow localhost. |
|
252 | return null; |
||
253 | 1 | } elseif ( '.dev' === substr( $host, -4 ) ) { |
|
254 | 2 | // Mollie doesn't allow the .dev TLD. |
|
255 | return null; |
||
256 | 1 | } elseif ( '.local' === substr( $host, -6 ) ) { |
|
257 | 1 | // Mollie doesn't allow the .local TLD. |
|
258 | return null; |
||
259 | } elseif ( '.test' === substr( $host, -5 ) ) { |
||
260 | // Mollie doesn't allow the .test TLD. |
||
261 | return null; |
||
262 | 1 | } |
|
263 | |||
264 | return $url; |
||
265 | } |
||
266 | |||
267 | /** |
||
268 | * Start |
||
269 | * |
||
270 | * @see Core_Gateway::start() |
||
271 | * @param Payment $payment Payment. |
||
272 | * @return void |
||
273 | * @throws Error Mollie error. |
||
274 | * @throws \Exception Throws exception on error creating Mollie customer for payment. |
||
275 | */ |
||
276 | public function start( Payment $payment ) { |
||
277 | $description = (string) $payment->get_description(); |
||
278 | |||
279 | /** |
||
280 | * Filters the Mollie payment description. |
||
281 | * |
||
282 | * The maximum length of the description field differs per payment |
||
283 | * method, with the absolute maximum being 255 characters. |
||
284 | * |
||
285 | * @link https://docs.mollie.com/reference/v2/payments-api/create-payment#parameters |
||
286 | * @since 3.0.1 |
||
287 | * @param string $description Description. |
||
288 | * @param Payment $payment Payment. |
||
289 | */ |
||
290 | $description = \apply_filters( 'pronamic_pay_mollie_payment_description', $description, $payment ); |
||
291 | |||
292 | $request = new PaymentRequest( |
||
293 | AmountTransformer::transform( $payment->get_total_amount() ), |
||
294 | $description |
||
295 | ); |
||
296 | |||
297 | $request->redirect_url = $payment->get_return_url(); |
||
298 | $request->webhook_url = $this->get_webhook_url( $payment ); |
||
299 | |||
300 | // Locale. |
||
301 | $customer = $payment->get_customer(); |
||
302 | |||
303 | if ( null !== $customer ) { |
||
304 | $request->locale = LocaleHelper::transform( $customer->get_locale() ); |
||
305 | } |
||
306 | |||
307 | // Customer ID. |
||
308 | $customer_id = $this->get_customer_id_for_payment( $payment ); |
||
309 | |||
310 | if ( null === $customer_id ) { |
||
311 | $sequence_type = $payment->get_meta( 'mollie_sequence_type' ); |
||
312 | |||
313 | if ( 'recurring' !== $sequence_type ) { |
||
314 | $customer_id = $this->create_customer_for_payment( $payment ); |
||
315 | } |
||
316 | } |
||
317 | |||
318 | if ( null !== $customer_id ) { |
||
319 | $request->customer_id = $customer_id; |
||
320 | |||
321 | // Set Mollie customer ID in subscription meta. |
||
322 | foreach ( $payment->get_subscriptions() as $subscription ) { |
||
323 | $mollie_customer_id = $subscription->get_meta( 'mollie_customer_id' ); |
||
324 | |||
325 | if ( empty( $mollie_customer_id ) ) { |
||
326 | $subscription->set_meta( 'mollie_customer_id', $customer_id ); |
||
327 | |||
328 | $subscription->save(); |
||
329 | } |
||
330 | } |
||
331 | } |
||
332 | |||
333 | /** |
||
334 | * Payment method. |
||
335 | * |
||
336 | * Leap of faith if the WordPress payment method could not transform to a Mollie method? |
||
337 | */ |
||
338 | $payment_method = $payment->get_payment_method(); |
||
339 | |||
340 | $request->set_method( Methods::transform( $payment_method, $payment_method ) ); |
||
341 | |||
342 | /** |
||
343 | * Sequence type. |
||
344 | * |
||
345 | * Recurring payments are created through the Payments API by providing a `sequenceType`. |
||
346 | */ |
||
347 | $subscriptions = $payment->get_subscriptions(); |
||
348 | |||
349 | if ( \count( $subscriptions ) > 0 ) { |
||
350 | $first_method = PaymentMethods::get_first_payment_method( $payment_method ); |
||
351 | |||
352 | $request->set_method( Methods::transform( $first_method, $first_method ) ); |
||
353 | |||
354 | $request->set_sequence_type( 'first' ); |
||
355 | |||
356 | foreach ( $subscriptions as $subscription ) { |
||
357 | $mandate_id = $subscription->get_meta( 'mollie_mandate_id' ); |
||
358 | |||
359 | if ( ! empty( $mandate_id ) ) { |
||
360 | $request->set_mandate_id( $mandate_id ); |
||
361 | } |
||
362 | } |
||
363 | } |
||
364 | |||
365 | $sequence_type = $payment->get_meta( 'mollie_sequence_type' ); |
||
366 | |||
367 | if ( ! empty( $sequence_type ) ) { |
||
368 | $request->set_sequence_type( $sequence_type ); |
||
369 | |||
370 | if ( 'recurring' === $sequence_type ) { |
||
371 | $request->set_method( null ); |
||
372 | } |
||
373 | } |
||
374 | |||
375 | /** |
||
376 | * Direct Debit. |
||
377 | * |
||
378 | * Check if one-off SEPA Direct Debit can be used, otherwise short circuit payment. |
||
379 | */ |
||
380 | $consumer_bank_details = $payment->get_consumer_bank_details(); |
||
381 | |||
382 | if ( PaymentMethods::DIRECT_DEBIT === $payment_method && null !== $consumer_bank_details ) { |
||
383 | $consumer_name = $consumer_bank_details->get_name(); |
||
384 | $consumer_iban = $consumer_bank_details->get_iban(); |
||
385 | |||
386 | $request->consumer_name = $consumer_name; |
||
387 | $request->consumer_account = $consumer_iban; |
||
388 | |||
389 | // Check if one-off SEPA Direct Debit can be used, otherwise short circuit payment. |
||
390 | if ( null !== $customer_id ) { |
||
391 | // Find or create mandate. |
||
392 | $mandate_id = $this->client->has_valid_mandate( $customer_id, PaymentMethods::DIRECT_DEBIT, $consumer_iban ); |
||
393 | |||
394 | if ( false === $mandate_id ) { |
||
395 | $mandate = $this->client->create_mandate( $customer_id, $consumer_bank_details ); |
||
396 | |||
397 | if ( ! \property_exists( $mandate, 'id' ) ) { |
||
398 | throw new \Exception( 'Missing mandate ID.' ); |
||
399 | } |
||
400 | |||
401 | $mandate_id = $mandate->id; |
||
402 | } |
||
403 | |||
404 | // Charge immediately on-demand. |
||
405 | $request->set_sequence_type( 'recurring' ); |
||
406 | $request->set_mandate_id( (string) $mandate_id ); |
||
407 | } |
||
408 | } |
||
409 | |||
410 | /** |
||
411 | * Metadata. |
||
412 | * |
||
413 | * Provide any data you like, for example a string or a JSON object. |
||
414 | * We will save the data alongside the payment. Whenever you fetch |
||
415 | * the payment with our API, we’ll also include the metadata. You |
||
416 | * can use up to approximately 1kB. |
||
417 | * |
||
418 | * @link https://docs.mollie.com/reference/v2/payments-api/create-payment |
||
419 | * @link https://en.wikipedia.org/wiki/Metadata |
||
420 | */ |
||
421 | $metadata = null; |
||
422 | |||
423 | /** |
||
424 | * Filters the Mollie metadata. |
||
425 | * |
||
426 | * @since 2.2.0 |
||
427 | * |
||
428 | * @param mixed $metadata Metadata. |
||
429 | * @param Payment $payment Payment. |
||
430 | */ |
||
431 | $metadata = \apply_filters( 'pronamic_pay_mollie_payment_metadata', $metadata, $payment ); |
||
432 | |||
433 | $request->set_metadata( $metadata ); |
||
434 | |||
435 | // Issuer. |
||
436 | if ( Methods::IDEAL === $request->method ) { |
||
437 | $request->issuer = $payment->get_meta( 'issuer' ); |
||
0 ignored issues
–
show
|
|||
438 | } |
||
439 | |||
440 | // Billing email. |
||
441 | $billing_email = ( null === $customer ) ? null : $customer->get_email(); |
||
442 | |||
443 | /** |
||
444 | * Filters the Mollie payment billing email used for bank transfer payment instructions. |
||
445 | * |
||
446 | * @since 2.2.0 |
||
447 | * |
||
448 | * @param string|null $billing_email Billing email. |
||
449 | * @param Payment $payment Payment. |
||
450 | */ |
||
451 | $billing_email = \apply_filters( 'pronamic_pay_mollie_payment_billing_email', $billing_email, $payment ); |
||
452 | |||
453 | $request->set_billing_email( $billing_email ); |
||
454 | |||
455 | // Due date. |
||
456 | if ( ! empty( $this->config->due_date_days ) ) { |
||
457 | try { |
||
458 | $due_date = new DateTime( sprintf( '+%s days', $this->config->due_date_days ) ); |
||
459 | } catch ( \Exception $e ) { |
||
460 | $due_date = null; |
||
461 | } |
||
462 | |||
463 | $request->set_due_date( $due_date ); |
||
464 | } |
||
465 | |||
466 | // Create payment. |
||
467 | $attempt = (int) $payment->get_meta( 'mollie_create_payment_attempt' ); |
||
468 | $attempt = empty( $attempt ) ? 1 : $attempt + 1; |
||
469 | |||
470 | $payment->set_meta( 'mollie_create_payment_attempt', $attempt ); |
||
471 | |||
472 | try { |
||
473 | $mollie_payment = $this->client->create_payment( $request ); |
||
474 | |||
475 | $payment->delete_meta( 'mollie_create_payment_attempt' ); |
||
476 | } catch ( Error $error ) { |
||
477 | if ( 'recurring' !== $request->get_sequence_type() ) { |
||
478 | throw $error; |
||
479 | } |
||
480 | |||
481 | if ( null === $request->get_mandate_id() ) { |
||
482 | throw $error; |
||
483 | } |
||
484 | |||
485 | /** |
||
486 | * Only schedule retry for specific status codes. |
||
487 | * |
||
488 | * @link https://docs.mollie.com/overview/handling-errors |
||
489 | */ |
||
490 | if ( ! \in_array( $error->get_status(), array( 429, 502, 503 ), true ) ) { |
||
491 | throw $error; |
||
492 | } |
||
493 | |||
494 | \as_schedule_single_action( |
||
495 | \time() + $this->get_retry_seconds( $attempt ), |
||
496 | 'pronamic_pay_mollie_payment_start', |
||
497 | array( |
||
498 | 'payment_id' => $payment->get_id(), |
||
499 | ), |
||
500 | 'pronamic-pay-mollie' |
||
501 | ); |
||
502 | |||
503 | // Add note. |
||
504 | $payment->add_note( |
||
505 | \sprintf( |
||
506 | '%s - %s - %s', |
||
507 | $error->get_status(), |
||
508 | $error->get_title(), |
||
509 | $error->get_detail() |
||
510 | ) |
||
511 | ); |
||
512 | |||
513 | $payment->save(); |
||
514 | |||
515 | return; |
||
516 | } |
||
517 | |||
518 | // Update payment from Mollie payment. |
||
519 | $this->update_payment_from_mollie_payment( $payment, $mollie_payment ); |
||
520 | } |
||
521 | |||
522 | /** |
||
523 | * Get retry seconds. |
||
524 | * |
||
525 | * @param int $attempt Number of attempts. |
||
526 | * @return int |
||
527 | */ |
||
528 | private function get_retry_seconds( $attempt ) { |
||
529 | switch ( $attempt ) { |
||
530 | case 1: |
||
531 | return 5 * MINUTE_IN_SECONDS; |
||
532 | case 2: |
||
533 | return HOUR_IN_SECONDS; |
||
534 | case 3: |
||
535 | return 12 * HOUR_IN_SECONDS; |
||
536 | case 4: |
||
537 | default: |
||
538 | return DAY_IN_SECONDS; |
||
539 | } |
||
540 | } |
||
541 | |||
542 | /** |
||
543 | * Update status of the specified payment |
||
544 | * |
||
545 | * @param Payment $payment Payment. |
||
546 | * @return void |
||
547 | */ |
||
548 | public function update_status( Payment $payment ) { |
||
549 | $transaction_id = $payment->get_transaction_id(); |
||
550 | |||
551 | if ( null === $transaction_id ) { |
||
552 | return; |
||
553 | } |
||
554 | |||
555 | // Update payment from Mollie payment. |
||
556 | $mollie_payment = $this->client->get_payment( $transaction_id ); |
||
557 | |||
558 | $this->update_payment_from_mollie_payment( $payment, $mollie_payment ); |
||
559 | } |
||
560 | |||
561 | /** |
||
562 | * Update payment from Mollie payment. |
||
563 | * |
||
564 | * @param Payment $payment Payment. |
||
565 | * @param MolliePayment $mollie_payment Mollie payment. |
||
566 | * @return void |
||
567 | */ |
||
568 | public function update_payment_from_mollie_payment( Payment $payment, MolliePayment $mollie_payment ) { |
||
569 | /** |
||
570 | * Transaction ID. |
||
571 | */ |
||
572 | $transaction_id = $mollie_payment->get_id(); |
||
573 | |||
574 | $payment->set_transaction_id( $transaction_id ); |
||
575 | |||
576 | /** |
||
577 | * Status. |
||
578 | */ |
||
579 | $status = Statuses::transform( $mollie_payment->get_status() ); |
||
580 | |||
581 | if ( null !== $status ) { |
||
582 | $payment->set_status( $status ); |
||
583 | } |
||
584 | |||
585 | /** |
||
586 | * Payment method. |
||
587 | */ |
||
588 | $method = $mollie_payment->get_method(); |
||
589 | |||
590 | if ( null !== $method ) { |
||
591 | $payment_method = Methods::transform_gateway_method( $method ); |
||
592 | |||
593 | // Use wallet method as payment method. |
||
594 | $mollie_payment_details = $mollie_payment->get_details(); |
||
595 | |||
596 | if ( null !== $mollie_payment_details && isset( $mollie_payment_details->wallet ) ) { |
||
597 | $wallet_method = Methods::transform_gateway_method( $mollie_payment_details->wallet ); |
||
598 | |||
599 | if ( null !== $wallet_method ) { |
||
600 | $payment_method = $wallet_method; |
||
601 | } |
||
602 | } |
||
603 | |||
604 | if ( null !== $payment_method ) { |
||
605 | $payment->set_payment_method( $payment_method ); |
||
606 | |||
607 | // Update subscription payment method. |
||
608 | foreach ( $payment->get_subscriptions() as $subscription ) { |
||
609 | if ( null === $subscription->get_payment_method() ) { |
||
610 | $subscription->set_payment_method( $payment->get_payment_method() ); |
||
611 | |||
612 | $subscription->save(); |
||
613 | } |
||
614 | } |
||
615 | } |
||
616 | } |
||
617 | |||
618 | /** |
||
619 | * Expiry date. |
||
620 | */ |
||
621 | $expires_at = $mollie_payment->get_expires_at(); |
||
622 | |||
623 | if ( null !== $expires_at ) { |
||
624 | $expiry_date = DateTime::create_from_interface( $expires_at ); |
||
625 | |||
626 | $payment->set_expiry_date( $expiry_date ); |
||
627 | } |
||
628 | |||
629 | /** |
||
630 | * Mollie profile. |
||
631 | */ |
||
632 | $mollie_profile = new Profile(); |
||
633 | |||
634 | $mollie_profile->set_id( $mollie_payment->get_profile_id() ); |
||
635 | |||
636 | $profile_internal_id = $this->profile_data_store->get_or_insert_profile( $mollie_profile ); |
||
637 | |||
638 | /** |
||
639 | * If the Mollie payment contains a customer ID we will try to connect |
||
640 | * this Mollie customer ID the WordPress user and subscription. |
||
641 | * This can be useful in case when a WordPress user is created after |
||
642 | * a successful payment. |
||
643 | * |
||
644 | * @link https://www.gravityforms.com/add-ons/user-registration/ |
||
645 | */ |
||
646 | $mollie_customer_id = $mollie_payment->get_customer_id(); |
||
647 | |||
648 | if ( null !== $mollie_customer_id ) { |
||
649 | $mollie_customer = new Customer( $mollie_customer_id ); |
||
650 | |||
651 | $customer_internal_id = $this->customer_data_store->get_or_insert_customer( |
||
652 | $mollie_customer, |
||
653 | array( |
||
654 | 'profile_id' => $profile_internal_id, |
||
655 | ), |
||
656 | array( |
||
657 | 'profile_id' => '%s', |
||
658 | ) |
||
659 | ); |
||
660 | |||
661 | // Customer. |
||
662 | $customer = $payment->get_customer(); |
||
663 | |||
664 | if ( null !== $customer ) { |
||
665 | // Connect to user. |
||
666 | $user_id = $customer->get_user_id(); |
||
667 | |||
668 | if ( null !== $user_id ) { |
||
669 | $user = \get_user_by( 'id', $user_id ); |
||
670 | |||
671 | if ( false !== $user ) { |
||
672 | $this->customer_data_store->connect_mollie_customer_to_wp_user( $mollie_customer, $user ); |
||
673 | } |
||
674 | } |
||
675 | } |
||
676 | } |
||
677 | |||
678 | /** |
||
679 | * Customer ID. |
||
680 | */ |
||
681 | $mollie_customer_id = $mollie_payment->get_customer_id(); |
||
682 | |||
683 | if ( null !== $mollie_customer_id ) { |
||
684 | $customer_id = $payment->get_meta( 'mollie_customer_id' ); |
||
685 | |||
686 | if ( empty( $customer_id ) ) { |
||
687 | $payment->set_meta( 'mollie_customer_id', $mollie_customer_id ); |
||
688 | } |
||
689 | |||
690 | foreach ( $payment->get_subscriptions() as $subscription ) { |
||
691 | $customer_id = $subscription->get_meta( 'mollie_customer_id' ); |
||
692 | |||
693 | if ( empty( $customer_id ) ) { |
||
694 | $subscription->set_meta( 'mollie_customer_id', $mollie_customer_id ); |
||
695 | } |
||
696 | } |
||
697 | } |
||
698 | |||
699 | /** |
||
700 | * Mandate ID. |
||
701 | */ |
||
702 | $mollie_mandate_id = $mollie_payment->get_mandate_id(); |
||
703 | |||
704 | if ( null !== $mollie_mandate_id ) { |
||
705 | $mandate_id = $payment->get_meta( 'mollie_mandate_id' ); |
||
706 | |||
707 | if ( empty( $mandate_id ) ) { |
||
708 | $payment->set_meta( 'mollie_mandate_id', $mollie_mandate_id ); |
||
709 | } |
||
710 | |||
711 | foreach ( $payment->get_subscriptions() as $subscription ) { |
||
712 | $mandate_id = $subscription->get_meta( 'mollie_mandate_id' ); |
||
713 | |||
714 | if ( empty( $mandate_id ) ) { |
||
715 | $subscription->set_meta( 'mollie_mandate_id', $mollie_mandate_id ); |
||
716 | } |
||
717 | } |
||
718 | } |
||
719 | |||
720 | // phpcs:disable WordPress.NamingConventions.ValidVariableName.UsedPropertyNotSnakeCase -- Mollie JSON object. |
||
721 | |||
722 | /** |
||
723 | * Details. |
||
724 | */ |
||
725 | $mollie_payment_details = $mollie_payment->get_details(); |
||
726 | |||
727 | if ( null !== $mollie_payment_details ) { |
||
728 | /** |
||
729 | * Consumer bank details. |
||
730 | */ |
||
731 | $consumer_bank_details = $payment->get_consumer_bank_details(); |
||
732 | |||
733 | if ( null === $consumer_bank_details ) { |
||
734 | $consumer_bank_details = new BankAccountDetails(); |
||
735 | |||
736 | $payment->set_consumer_bank_details( $consumer_bank_details ); |
||
737 | } |
||
738 | |||
739 | if ( isset( $mollie_payment_details->consumerName ) ) { |
||
740 | $consumer_bank_details->set_name( $mollie_payment_details->consumerName ); |
||
741 | } |
||
742 | |||
743 | if ( isset( $mollie_payment_details->cardHolder ) ) { |
||
744 | $consumer_bank_details->set_name( $mollie_payment_details->cardHolder ); |
||
745 | } |
||
746 | |||
747 | if ( isset( $mollie_payment_details->cardNumber ) ) { |
||
748 | // The last four digits of the card number. |
||
749 | $consumer_bank_details->set_account_number( $mollie_payment_details->cardNumber ); |
||
750 | } |
||
751 | |||
752 | if ( isset( $mollie_payment_details->cardCountryCode ) ) { |
||
753 | // The ISO 3166-1 alpha-2 country code of the country the card was issued in. |
||
754 | $consumer_bank_details->set_country( $mollie_payment_details->cardCountryCode ); |
||
755 | } |
||
756 | |||
757 | if ( isset( $mollie_payment_details->consumerAccount ) ) { |
||
758 | switch ( $mollie_payment->get_method() ) { |
||
759 | case Methods::BELFIUS: |
||
760 | case Methods::DIRECT_DEBIT: |
||
761 | case Methods::IDEAL: |
||
762 | case Methods::KBC: |
||
763 | case Methods::SOFORT: |
||
764 | $consumer_bank_details->set_iban( $mollie_payment_details->consumerAccount ); |
||
765 | |||
766 | break; |
||
767 | case Methods::BANCONTACT: |
||
768 | case Methods::BANKTRANSFER: |
||
769 | case Methods::PAYPAL: |
||
770 | default: |
||
771 | $consumer_bank_details->set_account_number( $mollie_payment_details->consumerAccount ); |
||
772 | |||
773 | break; |
||
774 | } |
||
775 | } |
||
776 | |||
777 | if ( isset( $mollie_payment_details->consumerBic ) ) { |
||
778 | $consumer_bank_details->set_bic( $mollie_payment_details->consumerBic ); |
||
779 | } |
||
780 | |||
781 | /** |
||
782 | * Bank transfer recipient details. |
||
783 | */ |
||
784 | $bank_transfer_recipient_details = $payment->get_bank_transfer_recipient_details(); |
||
785 | |||
786 | if ( null === $bank_transfer_recipient_details ) { |
||
787 | $bank_transfer_recipient_details = new BankTransferDetails(); |
||
788 | |||
789 | $payment->set_bank_transfer_recipient_details( $bank_transfer_recipient_details ); |
||
790 | } |
||
791 | |||
792 | $bank_details = $bank_transfer_recipient_details->get_bank_account(); |
||
793 | |||
794 | if ( null === $bank_details ) { |
||
795 | $bank_details = new BankAccountDetails(); |
||
796 | |||
797 | $bank_transfer_recipient_details->set_bank_account( $bank_details ); |
||
798 | } |
||
799 | |||
800 | if ( isset( $mollie_payment_details->bankName ) ) { |
||
801 | /** |
||
802 | * Set `bankName` as bank details name, as result "Stichting Mollie Payments" |
||
803 | * is not the name of a bank, but the account holder name. |
||
804 | */ |
||
805 | $bank_details->set_name( $mollie_payment_details->bankName ); |
||
806 | } |
||
807 | |||
808 | if ( isset( $mollie_payment_details->bankAccount ) ) { |
||
809 | $bank_details->set_iban( $mollie_payment_details->bankAccount ); |
||
810 | } |
||
811 | |||
812 | if ( isset( $mollie_payment_details->bankBic ) ) { |
||
813 | $bank_details->set_bic( $mollie_payment_details->bankBic ); |
||
814 | } |
||
815 | |||
816 | if ( isset( $mollie_payment_details->transferReference ) ) { |
||
817 | $bank_transfer_recipient_details->set_reference( $mollie_payment_details->transferReference ); |
||
818 | } |
||
819 | |||
820 | /* |
||
821 | * Failure reason. |
||
822 | */ |
||
823 | $failure_reason = $payment->get_failure_reason(); |
||
824 | |||
825 | if ( null === $failure_reason ) { |
||
826 | $failure_reason = new FailureReason(); |
||
827 | } |
||
828 | |||
829 | // SEPA Direct Debit. |
||
830 | if ( isset( $mollie_payment_details->bankReasonCode ) ) { |
||
831 | $failure_reason->set_code( $mollie_payment_details->bankReasonCode ); |
||
832 | } |
||
833 | |||
834 | if ( isset( $mollie_payment_details->bankReason ) ) { |
||
835 | $failure_reason->set_message( $mollie_payment_details->bankReason ); |
||
836 | } |
||
837 | |||
838 | // Credit card. |
||
839 | if ( isset( $mollie_payment_details->failureReason ) ) { |
||
840 | $failure_reason->set_code( $mollie_payment_details->failureReason ); |
||
841 | } |
||
842 | |||
843 | if ( isset( $mollie_payment_details->failureMessage ) ) { |
||
844 | $failure_reason->set_message( $mollie_payment_details->failureMessage ); |
||
845 | } |
||
846 | |||
847 | $failure_code = $failure_reason->get_code(); |
||
848 | $failure_message = $failure_reason->get_message(); |
||
849 | |||
850 | if ( ! empty( $failure_code ) || ! empty( $failure_message ) ) { |
||
851 | $payment->set_failure_reason( $failure_reason ); |
||
852 | } |
||
853 | } |
||
854 | |||
855 | /** |
||
856 | * Links. |
||
857 | */ |
||
858 | $links = $mollie_payment->get_links(); |
||
859 | |||
860 | // Action URL. |
||
861 | if ( \property_exists( $links, 'checkout' ) ) { |
||
862 | $payment->set_action_url( $links->checkout->href ); |
||
863 | } |
||
864 | |||
865 | // Change payment state URL. |
||
866 | if ( \property_exists( $links, 'changePaymentState' ) ) { |
||
867 | $payment->set_meta( 'mollie_change_payment_state_url', $links->changePaymentState->href ); |
||
868 | } |
||
869 | |||
870 | // phpcs:enable WordPress.NamingConventions.ValidVariableName.UsedPropertyNotSnakeCase -- Mollie JSON object. |
||
871 | |||
872 | /** |
||
873 | * Chargebacks. |
||
874 | */ |
||
875 | if ( $mollie_payment->has_chargebacks() ) { |
||
876 | $mollie_chargebacks = $this->client->get_payment_chargebacks( |
||
877 | $mollie_payment->get_id(), |
||
878 | array( 'limit' => 1 ) |
||
879 | ); |
||
880 | |||
881 | 10 | $mollie_chargeback = \reset( $mollie_chargebacks ); |
|
882 | 10 | ||
883 | if ( false !== $mollie_chargeback ) { |
||
884 | 10 | $subscriptions = array_filter( |
|
885 | $payment->get_subscriptions(), |
||
886 | 10 | function ( $subscription ) { |
|
887 | return SubscriptionStatus::ACTIVE === $subscription->get_status(); |
||
888 | } |
||
889 | ); |
||
890 | |||
891 | foreach ( $subscriptions as $subscription ) { |
||
892 | if ( $mollie_chargeback->get_created_at() > $subscription->get_activated_at() ) { |
||
893 | $subscription->set_status( SubscriptionStatus::ON_HOLD ); |
||
894 | |||
895 | 10 | $subscription->add_note( |
|
896 | 10 | \sprintf( |
|
897 | /* translators: 1: Mollie chargeback ID, 2: Mollie payment ID */ |
||
898 | \__( 'Subscription put on hold due to chargeback `%1$s` of payment `%2$s`.', 'pronamic_ideal' ), |
||
899 | 10 | \esc_html( $mollie_chargeback->get_id() ), |
|
900 | \esc_html( $mollie_payment->get_id() ) |
||
901 | 10 | ) |
|
902 | 10 | ); |
|
903 | } |
||
904 | 10 | } |
|
905 | 4 | } |
|
906 | } |
||
907 | |||
908 | /** |
||
909 | * Refunds. |
||
910 | 10 | */ |
|
911 | $amount_refunded = $mollie_payment->get_amount_refunded(); |
||
912 | 10 | ||
913 | 10 | if ( null !== $amount_refunded ) { |
|
914 | $refunded_amount = new Money( $amount_refunded->get_value(), $amount_refunded->get_currency() ); |
||
915 | 10 | ||
916 | 7 | $payment->set_refunded_amount( $refunded_amount->get_value() > 0 ? $refunded_amount : null ); |
|
917 | } |
||
918 | 7 | ||
919 | // Save. |
||
920 | $payment->save(); |
||
921 | |||
922 | 10 | foreach ( $payment->get_subscriptions() as $subscription ) { |
|
923 | $subscription->save(); |
||
924 | } |
||
925 | } |
||
926 | |||
927 | /** |
||
928 | * Update subscription mandate. |
||
929 | * |
||
930 | * @param Subscription $subscription Subscription. |
||
931 | 24 | * @param string $mandate_id Mollie mandate ID. |
|
932 | 24 | * @param string|null $payment_method Payment method. |
|
933 | * @return void |
||
934 | 24 | * @throws \Exception Throws exception if subscription note could not be added. |
|
935 | */ |
||
936 | public function update_subscription_mandate( Subscription $subscription, $mandate_id, $payment_method = null ) { |
||
937 | $customer_id = (string) $subscription->get_meta( 'mollie_customer_id' ); |
||
938 | 24 | ||
939 | $mandate = $this->client->get_mandate( $mandate_id, $customer_id ); |
||
940 | 24 | ||
941 | if ( ! \is_object( $mandate ) ) { |
||
942 | 24 | return; |
|
943 | } |
||
944 | |||
945 | // Update mandate. |
||
946 | $old_mandate_id = $subscription->get_meta( 'mollie_mandate_id' ); |
||
947 | |||
948 | $subscription->set_meta( 'mollie_mandate_id', $mandate_id ); |
||
949 | |||
950 | if ( ! empty( $old_mandate_id ) && $old_mandate_id !== $mandate_id ) { |
||
951 | 10 | $note = \sprintf( |
|
952 | 10 | /* translators: 1: old mandate ID, 2: new mandate ID */ |
|
953 | \__( 'Mandate for subscription changed from "%1$s" to "%2$s".', 'pronamic_ideal' ), |
||
954 | 10 | \esc_html( $old_mandate_id ), |
|
955 | \esc_html( $mandate_id ) |
||
956 | 7 | ); |
|
957 | |||
958 | 7 | $subscription->add_note( $note ); |
|
959 | 7 | } |
|
960 | |||
961 | // Update payment method. |
||
962 | $old_method = $subscription->get_payment_method(); |
||
963 | 10 | $new_method = ( null === $payment_method && \property_exists( $mandate, 'method' ) ? Methods::transform_gateway_method( $mandate->method ) : $payment_method ); |
|
964 | 6 | ||
965 | // `Direct Debit` is not a recurring method, use `Direct Debit (mandate via ...)` instead. |
||
966 | if ( PaymentMethods::DIRECT_DEBIT === $new_method ) { |
||
967 | 4 | $new_method = PaymentMethods::DIRECT_DEBIT_IDEAL; |
|
968 | |||
969 | // Use `Direct Debit (mandate via Bancontact)` if consumer account starts with `BE`. |
||
970 | if ( \property_exists( $mandate, 'details' ) && 'BE' === \substr( $mandate->details->consumerAccount, 0, 2 ) ) { |
||
971 | $new_method = PaymentMethods::DIRECT_DEBIT_BANCONTACT; |
||
972 | } |
||
973 | } |
||
974 | |||
975 | if ( ! empty( $old_method ) && $old_method !== $new_method ) { |
||
976 | $subscription->set_payment_method( $new_method ); |
||
977 | 10 | ||
978 | 10 | // Add note. |
|
979 | $note = \sprintf( |
||
980 | 10 | /* translators: 1: old payment method, 2: new payment method */ |
|
981 | \__( 'Payment method for subscription changed from "%1$s" to "%2$s".', 'pronamic_ideal' ), |
||
982 | 10 | \esc_html( (string) PaymentMethods::get_name( $old_method ) ), |
|
983 | \esc_html( (string) PaymentMethods::get_name( $new_method ) ) |
||
984 | 4 | ); |
|
985 | |||
986 | $subscription->add_note( $note ); |
||
987 | } |
||
988 | |||
989 | $subscription->save(); |
||
990 | } |
||
991 | |||
992 | /** |
||
993 | * Create refund. |
||
994 | 4 | * |
|
995 | 4 | * @param string $transaction_id Transaction ID. |
|
996 | * @param Money $amount Amount to refund. |
||
997 | * @param string $description Refund reason. |
||
998 | * @return string |
||
999 | 6 | */ |
|
1000 | public function create_refund( $transaction_id, Money $amount, $description = null ) { |
||
1001 | $request = new RefundRequest( AmountTransformer::transform( $amount ) ); |
||
1002 | |||
1003 | // Metadata payment ID. |
||
1004 | $payment = \get_pronamic_payment_by_transaction_id( $transaction_id ); |
||
1005 | |||
1006 | if ( null !== $payment ) { |
||
1007 | $request->set_metadata( |
||
1008 | array( |
||
1009 | 'pronamic_payment_id' => $payment->get_id(), |
||
1010 | ) |
||
1011 | ); |
||
1012 | } |
||
1013 | |||
1014 | // Description. |
||
1015 | if ( ! empty( $description ) ) { |
||
1016 | $request->set_description( $description ); |
||
1017 | } |
||
1018 | |||
1019 | $refund = $this->client->create_refund( $transaction_id, $request ); |
||
1020 | |||
1021 | return $refund->get_id(); |
||
1022 | } |
||
1023 | |||
1024 | /** |
||
1025 | * Get Mollie customer ID for payment. |
||
1026 | * |
||
1027 | * @param Payment $payment Payment. |
||
1028 | * @return string|null |
||
1029 | */ |
||
1030 | public function get_customer_id_for_payment( Payment $payment ) { |
||
1031 | $customer_ids = $this->get_customer_ids_for_payment( $payment ); |
||
1032 | |||
1033 | $customer_id = $this->get_first_existing_customer_id( $customer_ids ); |
||
1034 | |||
1035 | return $customer_id; |
||
1036 | } |
||
1037 | |||
1038 | /** |
||
1039 | * Get Mollie customers for the specified payment. |
||
1040 | * |
||
1041 | * @param Payment $payment Payment. |
||
1042 | * @return array<string> |
||
1043 | */ |
||
1044 | private function get_customer_ids_for_payment( Payment $payment ) { |
||
1045 | $customer_ids = array(); |
||
1046 | |||
1047 | // Customer ID from subscription meta. |
||
1048 | $subscriptions = $payment->get_subscriptions(); |
||
1049 | |||
1050 | foreach ( $subscriptions as $subscription ) { |
||
1051 | $customer_id = $this->get_customer_id_for_subscription( $subscription ); |
||
1052 | |||
1053 | if ( null !== $customer_id ) { |
||
1054 | $customer_ids[] = $customer_id; |
||
1055 | } |
||
1056 | } |
||
1057 | |||
1058 | // Customer ID from WordPress user. |
||
1059 | $customer = $payment->get_customer(); |
||
1060 | |||
1061 | if ( null !== $customer ) { |
||
1062 | $user_id = $customer->get_user_id(); |
||
1063 | |||
1064 | if ( ! empty( $user_id ) ) { |
||
1065 | $user_customer_ids = $this->get_customer_ids_for_user( $user_id ); |
||
1066 | |||
1067 | $customer_ids = \array_merge( $customer_ids, $user_customer_ids ); |
||
1068 | } |
||
1069 | } |
||
1070 | |||
1071 | return $customer_ids; |
||
1072 | } |
||
1073 | |||
1074 | /** |
||
1075 | * Get Mollie customers for the specified WordPress user ID. |
||
1076 | * |
||
1077 | * @param int $user_id WordPress user ID. |
||
1078 | 27 | * @return array<string> |
|
1079 | 27 | */ |
|
1080 | 1 | public function get_customer_ids_for_user( $user_id ) { |
|
1081 | $customer_query = new CustomerQuery( |
||
1082 | array( |
||
1083 | 'user_id' => $user_id, |
||
1084 | 26 | ) |
|
1085 | ); |
||
1086 | |||
1087 | 26 | $customers = $customer_query->get_customers(); |
|
1088 | |||
1089 | 26 | $customer_ids = wp_list_pluck( $customers, 'mollie_id' ); |
|
1090 | 16 | ||
1091 | return $customer_ids; |
||
1092 | } |
||
1093 | 26 | ||
1094 | /** |
||
1095 | * Get customer ID for subscription. |
||
1096 | * |
||
1097 | * @param Subscription $subscription Subscription. |
||
1098 | 26 | * @return string|null |
|
1099 | */ |
||
1100 | 26 | private function get_customer_id_for_subscription( Subscription $subscription ) { |
|
1101 | 3 | $customer_id = $subscription->get_meta( 'mollie_customer_id' ); |
|
1102 | |||
1103 | if ( empty( $customer_id ) ) { |
||
1104 | 23 | return null; |
|
1105 | } |
||
1106 | 23 | ||
1107 | 12 | return $customer_id; |
|
1108 | } |
||
1109 | |||
1110 | /** |
||
1111 | 11 | * Get first existing customer from customers list. |
|
1112 | * |
||
1113 | * @param array<string> $customer_ids Customers. |
||
1114 | 11 | * @return string|null |
|
1115 | * @throws Error Throws error on Mollie error. |
||
1116 | */ |
||
1117 | 11 | private function get_first_existing_customer_id( $customer_ids ) { |
|
1118 | 11 | $customer_ids = \array_filter( $customer_ids ); |
|
1119 | |||
1120 | $customer_ids = \array_unique( $customer_ids ); |
||
1121 | |||
1122 | 11 | foreach ( $customer_ids as $customer_id ) { |
|
1123 | 11 | try { |
|
1124 | $customer = $this->client->get_customer( $customer_id ); |
||
1125 | 11 | } catch ( Error $error ) { |
|
1126 | 2 | // Check for status 410 ("Gone - The customer is no longer available"). |
|
1127 | if ( 410 === $error->get_status() ) { |
||
1128 | 2 | continue; |
|
1129 | } |
||
1130 | 2 | ||
1131 | throw $error; |
||
1132 | 11 | } |
|
1133 | |||
1134 | if ( null !== $customer ) { |
||
1135 | return $customer_id; |
||
1136 | } |
||
1137 | } |
||
1138 | |||
1139 | return null; |
||
1140 | } |
||
1141 | |||
1142 | /** |
||
1143 | * Create customer for payment. |
||
1144 | * |
||
1145 | * @param Payment $payment Payment. |
||
1146 | * @return string|null |
||
1147 | * @throws Error Throws Error when Mollie error occurs. |
||
1148 | * @throws \Exception Throws exception when error in customer data store occurs. |
||
1149 | */ |
||
1150 | private function create_customer_for_payment( Payment $payment ) { |
||
1151 | $customer = $payment->get_customer(); |
||
1152 | |||
1153 | $mollie_customer = new Customer(); |
||
1154 | $mollie_customer->set_mode( $this->config->is_test_mode() ? 'test' : 'live' ); |
||
1155 | $mollie_customer->set_email( null === $customer ? null : $customer->get_email() ); |
||
1156 | |||
1157 | $pronamic_customer = $payment->get_customer(); |
||
1158 | |||
1159 | if ( null !== $pronamic_customer ) { |
||
1160 | // Name. |
||
1161 | $name = (string) $pronamic_customer->get_name(); |
||
1162 | |||
1163 | if ( '' !== $name ) { |
||
1164 | $mollie_customer->set_name( $name ); |
||
1165 | } |
||
1166 | |||
1167 | // Locale. |
||
1168 | $locale = $pronamic_customer->get_locale(); |
||
1169 | |||
1170 | if ( null !== $locale ) { |
||
1171 | $mollie_customer->set_locale( LocaleHelper::transform( $locale ) ); |
||
1172 | } |
||
1173 | } |
||
1174 | |||
1175 | // Try to get name from consumer bank details. |
||
1176 | $consumer_bank_details = $payment->get_consumer_bank_details(); |
||
1177 | |||
1178 | if ( null === $mollie_customer->get_name() && null !== $consumer_bank_details ) { |
||
1179 | $name = $consumer_bank_details->get_name(); |
||
1180 | |||
1181 | if ( null !== $name ) { |
||
1182 | $mollie_customer->set_name( $name ); |
||
1183 | } |
||
1184 | } |
||
1185 | |||
1186 | // Create customer. |
||
1187 | $mollie_customer = $this->client->create_customer( $mollie_customer ); |
||
1188 | |||
1189 | $customer_id = $this->customer_data_store->insert_customer( $mollie_customer ); |
||
1190 | |||
1191 | // Connect to user. |
||
1192 | if ( null !== $pronamic_customer ) { |
||
1193 | $user_id = $pronamic_customer->get_user_id(); |
||
1194 | |||
1195 | if ( null !== $user_id ) { |
||
1196 | $user = \get_user_by( 'id', $user_id ); |
||
1197 | |||
1198 | if ( false !== $user ) { |
||
1199 | $this->customer_data_store->connect_mollie_customer_to_wp_user( $mollie_customer, $user ); |
||
1200 | } |
||
1201 | } |
||
1202 | } |
||
1203 | |||
1204 | // Store customer ID in subscription meta. |
||
1205 | $subscriptions = $payment->get_subscriptions(); |
||
1206 | |||
1207 | foreach ( $subscriptions as $subscription ) { |
||
1208 | $subscription->set_meta( 'mollie_customer_id', $mollie_customer->get_id() ); |
||
1209 | |||
1210 | $subscription->save(); |
||
1211 | } |
||
1212 | |||
1213 | return $mollie_customer->get_id(); |
||
1214 | } |
||
1215 | |||
1216 | /** |
||
1217 | * Copy Mollie customer ID from subscription meta to WordPress user meta. |
||
1218 | * |
||
1219 | * @param Payment $payment Payment. |
||
1220 | * @return void |
||
1221 | */ |
||
1222 | public function copy_customer_id_to_wp_user( Payment $payment ) { |
||
1223 | if ( $this->config->id !== $payment->config_id ) { |
||
1224 | return; |
||
1225 | } |
||
1226 | |||
1227 | // Subscriptions. |
||
1228 | $subscriptions = $payment->get_subscriptions(); |
||
1229 | |||
1230 | foreach ( $subscriptions as $subscription ) { |
||
1231 | // Customer. |
||
1232 | $customer = $payment->get_customer(); |
||
1233 | |||
1234 | if ( null === $customer ) { |
||
1235 | $customer = $subscription->get_customer(); |
||
1236 | } |
||
1237 | |||
1238 | if ( null === $customer ) { |
||
1239 | continue; |
||
1240 | } |
||
1241 | |||
1242 | // WordPress user. |
||
1243 | $user_id = $customer->get_user_id(); |
||
1244 | |||
1245 | if ( null === $user_id ) { |
||
1246 | continue; |
||
1247 | } |
||
1248 | |||
1249 | $user = \get_user_by( 'id', $user_id ); |
||
1250 | |||
1251 | if ( false === $user ) { |
||
1252 | continue; |
||
1253 | } |
||
1254 | |||
1255 | // Customer IDs. |
||
1256 | $customer_ids = array( |
||
1257 | // Payment. |
||
1258 | $payment->get_meta( 'mollie_customer_id' ), |
||
1259 | |||
1260 | // Subscription. |
||
1261 | $subscription->get_meta( 'mollie_customer_id' ), |
||
1262 | ); |
||
1263 | |||
1264 | // Connect. |
||
1265 | $customer_ids = \array_filter( $customer_ids ); |
||
1266 | $customer_ids = \array_unique( $customer_ids ); |
||
1267 | |||
1268 | foreach ( $customer_ids as $customer_id ) { |
||
1269 | $customer = new Customer( $customer_id ); |
||
1270 | |||
1271 | $this->customer_data_store->get_or_insert_customer( $customer ); |
||
1272 | |||
1273 | $this->customer_data_store->connect_mollie_customer_to_wp_user( $customer, $user ); |
||
1274 | } |
||
1275 | } |
||
1276 | |||
1277 | } |
||
1278 | } |
||
1279 |
Our type inference engine has found a suspicous assignment of a value to a property. This check raises an issue when a value that can be of a mixed type is assigned to a property that is type hinted more strictly.
For example, imagine you have a variable
$accountId
that can either hold an Id object or false (if there is no account id yet). Your code now assigns that value to theid
property of an instance of theAccount
class. This class holds a proper account, so the id value must no longer be false.Either this assignment is in error or a type check should be added for that assignment.