Failed Conditions
Push — develop ( 0bf85e...ba0dec )
by Reüel
04:38
created

src/Gateway.php (2 issues)

1
<?php
2
3
namespace Pronamic\WordPress\Pay\Gateways\Buckaroo;
4
5
use Pronamic\WordPress\Money\Money;
6
use Pronamic\WordPress\Pay\Banks\BankAccountDetails;
7
use Pronamic\WordPress\Pay\Core\Gateway as Core_Gateway;
8
use Pronamic\WordPress\Pay\Core\PaymentMethods as Core_PaymentMethods;
9
use Pronamic\WordPress\Pay\Core\Server;
10
use Pronamic\WordPress\Pay\Payments\Payment;
11
use Pronamic\WordPress\Pay\Payments\PaymentStatus;
12
13
/**
14
 * Title: Buckaroo gateway
15
 * Description:
16
 * Copyright: 2005-2021 Pronamic
17
 * Company: Pronamic
18
 *
19
 * @author Remco Tolsma
20
 * @version 2.0.4
21
 * @since 1.0.0
22
 */
23
class Gateway extends Core_Gateway {
24
	/**
25
	 * Client.
0 ignored issues
show
The type Pronamic\WordPress\Pay\Gateways\Buckaroo\Client 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...
26
	 *
27
	 * @var Client
28
	 */
29
	protected $client;
30
31
	/**
32
	 * Constructs and initializes an Buckaroo gateway
33
	 *
34
	 * @param Config $config Config.
35
	 */
36
	public function __construct( Config $config ) {
37
		parent::__construct( $config );
38
39
		$this->set_method( self::METHOD_HTTP_REDIRECT );
40
41
		// Supported features.
42
		$this->supports = array(
43
			'payment_status_request',
44
			'refunds',
45
			'webhook',
46
			'webhook_log',
47
			'webhook_no_config',
48
		);
49
	}
50
51
	/**
52
	 * Get issuers.
53
	 *
54
	 * @since 1.2.4
55
	 * @see Pronamic_WP_Pay_Gateway::get_issuers()
56
	 */
57
	public function get_issuers() {
58
		$groups = array();
59
60
		$object = $this->request( 'GET', 'Transaction/Specification/ideal?serviceVersion=2' );
61
62
		foreach ( $object->Actions as $action ) {
63
			if ( 'Pay' === $action->Name ) {
64
				foreach ( $action->RequestParameters as $request_parameter ) {
65
					if ( 'issuer' === $request_parameter->Name ) {
66
						foreach ( $request_parameter->ListItemDescriptions as $item ) {
67
							if ( ! array_key_exists( $item->GroupName, $groups ) ) {
68
								$groups[ $item->GroupName ] = array(
69
									'name'    => $item->GroupName,
70
									'options' => array(),
71
								);
72
							}
73
74
							$groups[ $item->GroupName ]['options'][ $item->Value ] = $item->Description;
75
						}
76
					}
77
				}
78
			}
79
		}
80
81
		return $groups;
82
	}
83
84
	/**
85
	 * Get supported payment methods
86
	 *
87
	 * @see Pronamic_WP_Pay_Gateway::get_supported_payment_methods()
88
	 */
89
	public function get_supported_payment_methods() {
90
		return array(
91
			Core_PaymentMethods::BANK_TRANSFER,
92
			Core_PaymentMethods::BANCONTACT,
93
			Core_PaymentMethods::CREDIT_CARD,
94
			Core_PaymentMethods::GIROPAY,
95
			Core_PaymentMethods::IDEAL,
96
			Core_PaymentMethods::PAYPAL,
97
			Core_PaymentMethods::SOFORT,
98
		);
99
	}
100
101
	/**
102
	 * Start
103
	 *
104
	 * @param Payment $payment Payment.
105
	 *
106
	 * @see Core_Gateway::start()
107
	 */
108
	public function start( Payment $payment ) {
109
		/**
110
		 * Currency.
111
		 */
112
		$currency_code = $payment->get_total_amount()->get_currency()->get_alphabetic_code();
113
114
		if ( null === $currency_code ) {
115
			throw new \InvalidArgumentException( 'Can not start payment with empty currency code.' );
116
		}
117
118
		/**
119
		 * Push URL.
120
		 */
121
		$push_url = \rest_url( Integration::REST_ROUTE_NAMESPACE . '/push' );
122
123
		/**
124
		 * Filters the Buckaroo push URL.
125
		 *
126
		 * If you want to debug the Buckaroo report URL you can use this filter
127
		 * to override the push URL. You could for example use a service like
128
		 * https://webhook.site/ to inspect the push requests from Buckaroo.
129
		 *
130
		 * @param string $push_url Buckaroo push URL.
131
		 */
132
		$push_url = \apply_filters( 'pronamic_pay_buckaroo_push_url', $push_url );
133
134
		/**
135
		 * JSON Transaction.
136
		 *
137
		 * @link https://testcheckout.buckaroo.nl/json/Docs/Api/POST-json-Transaction
138
		 */
139
		$data = (object) array(
140
			'Currency'                  => $currency_code,
141
			'AmountDebit'               => $payment->get_total_amount()->get_value(),
142
			'Description'               => $payment->get_description(),
143
			'Invoice'                   => Util::get_invoice_number( (string) $this->config->get_invoice_number(), $payment ),
144
			'ReturnURL'                 => $payment->get_return_url(),
145
			'ReturnURLCancel'           => \add_query_arg(
146
				'buckaroo_return_url_cancel',
147
				true,
148
				$payment->get_return_url()
149
			),
150
			'ReturnURLError'            => \add_query_arg(
151
				'buckaroo_return_url_error',
152
				true,
153
				$payment->get_return_url()
154
			),
155
			'ReturnURLReject'           => \add_query_arg(
156
				'buckaroo_return_url_reject',
157
				true,
158
				$payment->get_return_url()
159
			),
160
			/**
161
			 * Push URL.
162
			 *
163
			 * When provided, this push URL overrides all the push URLs as configured in the payment plaza under websites for the associated website key
164
			 *
165
			 * @link https://dev.buckaroo.nl/Apis
166
			 */
167
			'PushURL'                   => $push_url,
168
			/**
169
			 * Push URL Failure.
170
			 *
171
			 * When provided, this push URL overrides the push URL for failed transactions as configured in the payment plaza under websites for the associated website key.
172
			 *
173
			 * @link https://dev.buckaroo.nl/Apis
174
			 */
175
			'PushURLFailure'            => $push_url,
176
			/**
177
			 * Services.
178
			 *
179
			 * Specifies which service (can be a payment method and/or additional service) is being called upon in the request.
180
			 *
181
			 * @link https://dev.buckaroo.nl/Apis
182
			 */
183
			'Services'                  => (object) array(
184
				'ServiceList' => array(),
185
			),
186
			/**
187
			 * Continue On Incomplete.
188
			 *
189
			 * Specifies if a redirecturl to a payment form will be returned to
190
			 * which a customer should be sent if no paymentmethod is selected
191
			 * or if any required parameter which the customer may provide is
192
			 * missing or incorrect. Possible Values:
193
			 *
194
			 * · No: This is the default. The request will fail if not all the
195
			 * needed information is provided.
196
			 *
197
			 * · RedirectToHTML: A redirect to the HTML gateway is provided if
198
			 * a recoverable problems are detected in the request. The customer
199
			 * can then provide the needed information there.
200
			 *
201
			 * @link https://dev.buckaroo.nl/Apis
202
			 * @link https://testcheckout.buckaroo.nl/json/Docs/Api/POST-json-Transaction
203
			 * @link https://testcheckout.buckaroo.nl/json/Docs/ResourceModel?modelName=ContinueOnIncomplete
204
			 */
205
			'ContinueOnIncomplete'      => 'RedirectToHTML',
206
			/**
207
			 * Services Excluded For Client.
208
			 *
209
			 * If no primary service is provided and ContinueOnIncomplete is
210
			 * set, this list of comma separated servicescodes can be used to
211
			 * limit the number of services from which the customer may choose
212
			 * once he is redirected to the payment form. Services which are
213
			 * entered in this field are not selectable.
214
			 * This field is optional.
215
			 *
216
			 * @link https://dev.buckaroo.nl/Apis
217
			 * @link https://testcheckout.buckaroo.nl/json/Docs/Api/POST-json-Transaction
218
			 */
219
			'ServicesExcludedForClient' => $this->config->get_excluded_services(),
220
			/**
221
			 * Custom parameters.
222
			 *
223
			 * @link https://testcheckout.buckaroo.nl/json/Docs/Api/POST-json-Transaction
224
			 */
225
			'CustomParameters'          => array(
226
				(object) array(
227
					'Name'  => 'pronamic_payment_id',
228
					'Value' => $payment->get_id(),
229
				),
230
			),
231
		);
232
233
		/**
234
		 * Client IP.
235
		 *
236
		 * In this field the IP address of the customer (or employee) for which
237
		 * the action is being performed can be passed. Please note, If this
238
		 * field is not sent to our gateway, your server IP address will be
239
		 * used as the clientIP. This may result in unwanted behaviour for
240
		 * anti-fraud checks. Also, certain payment methods perform checks on
241
		 * the IP address, if an IP address is overused, the request could be
242
		 * blocked. This field is sent in the following format, where
243
		 * type 0 = IPv4 and type 1 = IPv6:
244
		 * "ClientIP": { "Type": 0, "Address": "0.0.0.0" },
245
		 *
246
		 * @link https://testcheckout.buckaroo.nl/json/Docs/Api/POST-json-Transaction
247
		 * @link https://stackoverflow.com/questions/1448871/how-to-know-which-version-of-the-internet-protocol-ip-a-client-is-using-when-c/1448901
248
		 */
249
		$customer = $payment->get_customer();
250
251
		if ( null !== $customer ) {
252
			$ip_address = $customer->get_ip_address();
253
254
			if ( null !== $ip_address ) {
255
				$data->ClientIP = (object) array(
256
					'Type'    => false === \strpos( $ip_address, ':' ) ? 0 : 1,
257
					'Address' => $ip_address,
258
				);
259
			}
260
		}
261
262
		/**
263
		 * Payment method.
264
		 *
265
		 * @link https://testcheckout.buckaroo.nl/json/Docs/Api/POST-json-Transaction
266
		 * @link https://testcheckout.buckaroo.nl/json/Docs/ResourceModel?modelName=ServicesRequest
267
		 * @link https://testcheckout.buckaroo.nl/json/Docs/ResourceModel?modelName=ServiceRequest
268
		 */
269
		$payment_method = $payment->get_method();
270
271
		switch ( $payment_method ) {
272
			/**
273
			 * Payment method creditcard.
274
			 *
275
			 * @link https://dev.buckaroo.nl/PaymentMethods/Description/creditcards#pay
276
			 */
277
			case Core_PaymentMethods::CREDIT_CARD:
278
				$data->Services->ServiceList[] = (object) array(
279
					'Action' => 'Pay',
280
					'Name'   => PaymentMethods::AMERICAN_EXPRESS,
281
				);
282
283
				$data->Services->ServiceList[] = (object) array(
284
					'Action' => 'Pay',
285
					'Name'   => PaymentMethods::MAESTRO,
286
				);
287
288
				$data->Services->ServiceList[] = (object) array(
289
					'Action' => 'Pay',
290
					'Name'   => PaymentMethods::MASTERCARD,
291
				);
292
293
				$data->Services->ServiceList[] = (object) array(
294
					'Action' => 'Pay',
295
					'Name'   => PaymentMethods::VISA,
296
				);
297
298
				break;
299
			/**
300
			 * Payment method iDEAL.
301
			 *
302
			 * @link https://dev.buckaroo.nl/PaymentMethods/Description/ideal#pay
303
			 */
304
			case Core_PaymentMethods::IDEAL:
305
				$data->Services->ServiceList[] = (object) array(
306
					'Action'     => 'Pay',
307
					'Name'       => 'ideal',
308
					'Parameters' => array(
309
						array(
310
							'Name'  => 'issuer',
311
							'Value' => $payment->get_issuer(),
312
						),
313
					),
314
				);
315
316
				break;
317
			/**
318
			 * Payment method transfer.
319
			 *
320
			 * @link https://dev.buckaroo.nl/PaymentMethods/Description/transfer#pay
321
			 */
322
			case Core_PaymentMethods::BANK_TRANSFER:
323
				$data->Services->ServiceList[] = (object) array(
324
					'Action' => 'Pay',
325
					'Name'   => 'transfer',
326
				);
327
328
				break;
329
			/**
330
			 * Payment method Bancontact.
331
			 *
332
			 * @link https://dev.buckaroo.nl/PaymentMethods/Description/bancontact#pay
333
			 */
334
			case Core_PaymentMethods::BANCONTACT:
335
			case Core_PaymentMethods::MISTER_CASH:
336
				$data->Services->ServiceList[] = (object) array(
337
					'Action' => 'Pay',
338
					'Name'   => 'bancontactmrcash',
339
				);
340
341
				break;
342
			/**
343
			 * Payment method Giropay.
344
			 *
345
			 * @link https://dev.buckaroo.nl/PaymentMethods/Description/giropay#pay
346
			 */
347
			case Core_PaymentMethods::GIROPAY:
348
				$data->Services->ServiceList[] = (object) array(
349
					'Action' => 'Pay',
350
					'Name'   => 'giropay',
351
				);
352
353
				break;
354
			/**
355
			 * Payment method PayPal.
356
			 *
357
			 * @link https://dev.buckaroo.nl/PaymentMethods/Description/paypal#pay
358
			 */
359
			case Core_PaymentMethods::PAYPAL:
360
				$data->Services->ServiceList[] = (object) array(
361
					'Action' => 'Pay',
362
					'Name'   => 'paypal',
363
				);
364
365
				break;
366
			/**
367
			 * Payment method Sofort.
368
			 *
369
			 * @link https://dev.buckaroo.nl/PaymentMethods/Description/sofort#pay
370
			 */
371
			case Core_PaymentMethods::SOFORT:
372
				$data->Services->ServiceList[] = (object) array(
373
					'Action' => 'Pay',
374
					'Name'   => 'sofortueberweisung',
375
				);
376
377
				break;
378
		}
379
380
		/**
381
		 * Request.
382
		 */
383
		$object = $this->request( 'POST', 'Transaction', $data );
384
385
		/**
386
		 * Buckaroo keys.
387
		 *
388
		 * @link https://testcheckout.buckaroo.nl/json/Docs/ResourceModel?modelName=TransactionResponse
389
		 */
390
		if ( \property_exists( $object, 'Key' ) ) {
391
			$payment->set_transaction_id( $object->Key );
392
		}
393
394
		if ( \property_exists( $object, 'PaymentKey' ) ) {
395
			$payment->set_meta( 'buckaroo_transaction_payment_key', $object->PaymentKey );
396
		}
397
398
		/**
399
		 * Request Errors.
400
		 *
401
		 * @link https://testcheckout.buckaroo.nl/json/Docs/Api/POST-json-Transaction
402
		 */
403
		if ( \property_exists( $object, 'RequestErrors' ) && null !== $object->RequestErrors ) {
404
			$exception = null;
405
406
			foreach ( $object->RequestErrors as $errors ) {
407
				foreach ( $errors as $error ) {
408
					// Add exception.
409
					$exception = new \Exception( $error->ErrorMessage, 0, $exception );
410
				}
411
			}
412
413
			if ( null !== $exception ) {
414
				throw $exception;
415
			}
416
		}
417
418
		/**
419
		 * Required Action.
420
		 */
421
		if ( null !== $object->RequiredAction ) {
422
			if ( 'Redirect' !== $object->RequiredAction->Name ) {
423
				throw new \Exception(
424
					\sprintf(
425
						'Unsupported Buckaroo action: %s',
426
						$object->RequiredAction->Name
427
					)
428
				);
429
			}
430
431
			// Set action URL.
432
			if ( \property_exists( $object->RequiredAction, 'RedirectURL' ) ) {
433
				$payment->set_action_url( $object->RequiredAction->RedirectURL );
434
			}
435
		}
436
437
		// Failure.
438
		if ( \property_exists( $object, 'Status' ) && \property_exists( $object->Status, 'Code' ) ) {
439
			$status = Statuses::transform( (string) $object->Status->Code->Code );
440
441
			if ( PaymentStatus::FAILURE === $status ) {
442
				throw new \Exception(
443
					\sprintf(
444
						/* translators: 1: payment provider name, 2: status message, 3: status sub message*/
445
						__( 'Unable to create payment at gateway: %1$s%2$s', 'pronamic_ideal' ),
446
						$object->Status->Code->Description,
447
						\property_exists( $object->Status, 'SubCode' ) ? ' – ' . $object->Status->SubCode->Description : ''
448
					)
449
				);
450
			}
451
		}
452
	}
453
454
	/**
455
	 * JSON API Request.
456
	 *
457
	 * @param string      $method   HTTP request method.
458
	 * @param string      $endpoint JSON API endpoint.
459
	 * @param object|null $data     Data.
460
	 */
461
	public function request( $method, $endpoint, $data = null ) {
462
		$host = 'checkout.buckaroo.nl';
463
464
		if ( self::MODE_TEST === $this->config->mode ) {
465
			$host = 'testcheckout.buckaroo.nl';
466
		}
467
468
		/**
469
		 * Authentication.
470
		 *
471
		 * The HMAC SHA256 is calculated over a concatenated string (as raw data/binary/bytes) of the following values: WebsiteKey, requestHttpMethod, requestUri, requestTimeStamp, nonce, requestContentBase64String. See the next table for more information about these values. Please note: the Base64 hash should be a string of 44 characters. If yours is longer, it is probably in hexadecimal format.
472
		 *
473
		 * @link https://dev.buckaroo.nl/Apis/Description/json
474
		 * @link https://testcheckout.buckaroo.nl/json/Docs/Authentication
475
		 */
476
		$website_key         = $this->config->website_key;
477
		$request_http_method = $method;
478
		$request_uri         = $host . '/json/' . $endpoint;
479
		$request_timestamp   = \strval( \time() );
480
		$nonce               = \wp_generate_password( 32 );
481
		$request_content     = null === $data ? '' : \wp_json_encode( $data );
482
483
		$values = \implode(
484
			'',
485
			array(
486
				$website_key,
487
				$request_http_method,
488
				\strtolower( \rawurlencode( $request_uri ) ),
489
				$request_timestamp,
490
				$nonce,
491
				\
492
				// phpcs:ignore WordPress.PHP.DiscouragedPHPFunctions.obfuscation_base64_encode
493
				null === $data ? '' : \base64_encode( \md5( $request_content, true ) ),
0 ignored issues
show
It seems like $request_content can also be of type false; however, parameter $string of md5() 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

493
				null === $data ? '' : \base64_encode( \md5( /** @scrutinizer ignore-type */ $request_content, true ) ),
Loading history...
494
			)
495
		);
496
497
		$hash = \hash_hmac( 'sha256', $values, $this->config->secret_key, true );
498
499
		// phpcs:ignore WordPress.PHP.DiscouragedPHPFunctions.obfuscation_base64_encode
500
		$hmac = \base64_encode( $hash );
501
502
		$authorization = \sprintf(
503
			'hmac %s:%s:%s:%s',
504
			$this->config->website_key,
505
			$hmac,
506
			$nonce,
507
			$request_timestamp
508
		);
509
510
		$response = \Pronamic\WordPress\Http\Facades\Http::request(
511
			'https://' . $request_uri,
512
			array(
513
				'method'  => $request_http_method,
514
				'headers' => array(
515
					'Authorization' => $authorization,
516
					'Content-Type'  => 'application/json',
517
				),
518
				'body'    => $request_content,
519
			)
520
		);
521
522
		$object = $response->json();
523
524
		/**
525
		 * OK.
526
		 */
527
		return $object;
528
	}
529
530
	/**
531
	 * Update status of the specified payment
532
	 *
533
	 * @link https://testcheckout.buckaroo.nl/json/Docs/Api/GET-json-Transaction-Status-transactionKey
534
	 * @param Payment $payment Payment.
535
	 */
536
	public function update_status( Payment $payment ) {
537
		$transaction_key = $payment->get_transaction_id();
538
539
		if ( empty( $transaction_key ) ) {
540
			return;
541
		}
542
543
		$result = $this->request( 'GET', 'Transaction/Status/' . $transaction_key );
544
545
		$payment->set_status( Statuses::transform( \strval( $result->Status->Code->Code ) ) );
546
547
		/**
548
		 * Consumer bank details.
549
		 */
550
		$consumer_bank_details = $payment->get_consumer_bank_details();
551
552
		if ( null === $consumer_bank_details ) {
553
			$consumer_bank_details = new BankAccountDetails();
554
555
			$payment->set_consumer_bank_details( $consumer_bank_details );
556
		}
557
558
		/**
559
		 * Services.
560
		 */
561
		foreach ( $result->Services as $service ) {
562
			foreach ( $service->Parameters as $parameter ) {
563
				if ( 'consumerName' === $parameter->Name ) {
564
					$consumer_bank_details->set_name( $parameter->Value );
565
				}
566
567
				if ( 'consumerIBAN' === $parameter->Name ) {
568
					$consumer_bank_details->set_iban( $parameter->Value );
569
				}
570
571
				if ( 'consumerBIC' === $parameter->Name ) {
572
					$consumer_bank_details->set_iban( $parameter->Value );
573
				}
574
			}
575
		}
576
577
		/**
578
		 * Refunds.
579
		 *
580
		 * @link https://testcheckout.buckaroo.nl/json/Docs/Api/GET-json-Transaction-RefundInfo-transactionKey
581
		 */
582
		$result = $this->request( 'GET', 'Transaction/RefundInfo/' . $transaction_key );
583
584
		if ( \property_exists( $result, 'RefundedAmount' ) && ! empty( $result->RefundedAmount ) ) {
585
			$refunded_amount = new Money( $result->RefundedAmount, $result->RefundCurrency );
586
587
			$payment->set_refunded_amount( $refunded_amount );
588
		}
589
	}
590
591
	/**
592
	 * Create refund.
593
	 *
594
	 * @param string $transaction_id Transaction ID.
595
	 * @param Money  $amount         Amount to refund.
596
	 * @param string $description    Refund reason.
597
	 * @return string
598
	 */
599
	public function create_refund( $transaction_id, Money $amount, $description = null ) {
600
		$original_transaction = $this->request( 'GET', 'Transaction/Status/' . $transaction_id );
601
602
		if ( ! \is_object( $original_transaction ) ) {
603
			throw new \Exception(
604
				sprintf(
605
					/* translators: %s: transaction key */
606
					__( 'Unable to create refund for transaction with transaction key: %s', 'pronamic_ideal' ),
607
					$transaction_id
608
				)
609
			);
610
		}
611
612
		$service_name = Util::get_transaction_service( $original_transaction );
613
614
		if ( null === $service_name ) {
615
			throw new \Exception(
616
				sprintf(
617
					/* translators: %s: transaction key */
618
					__( 'Unable to create refund for transaction without service name. Transaction key: %s', 'pronamic_ideal' ),
619
					$transaction_id
620
				)
621
			);
622
		}
623
624
		// Invoice.
625
		$payment = \get_pronamic_payment_by_transaction_id( $transaction_id );
626
627
		$invoice = null;
628
629
		if ( null !== $payment ) {
630
			$invoice = Util::get_invoice_number( (string) $this->config->get_invoice_number(), $payment );
631
		}
632
633
		// Refund request.
634
		$data = (object) array(
635
			'Channel'                => 'Web',
636
			'Currency'               => $amount->get_currency()->get_alphabetic_code(),
637
			'AmountCredit'           => (float) $amount->get_value(),
638
			'Invoice'                => $invoice,
639
			'OriginalTransactionKey' => $transaction_id,
640
			'Services'               => array(
641
				'ServiceList' => array(
642
					array(
643
						'Name'   => $service_name,
644
						'Action' => 'Refund',
645
					),
646
				),
647
			),
648
		);
649
650
		$refund = $this->request( 'POST', 'Transaction', $data );
651
652
		// Check refund object.
653
		if ( ! \is_object( $refund ) ) {
654
			return null;
655
		}
656
657
		// Check refund status.
658
		if ( \property_exists( $refund, 'Status' ) && \property_exists( $refund->Status, 'Code' ) ) {
659
			$status = Statuses::transform( (string) $refund->Status->Code->Code );
660
661
			if ( PaymentStatus::SUCCESS !== $status ) {
662
				throw new \Exception(
663
					\sprintf(
664
						/* translators: 1: payment provider name, 2: status message, 3: status sub message*/
665
						__( 'Unable to create refund at %1$s gateway: %2$s%3$s', 'pronamic_ideal' ),
666
						__( 'Buckaroo', 'pronamic_ideal' ),
667
						$refund->Status->Code->Description,
668
						\property_exists( $refund->Status, 'SubCode' ) ? ' – ' . $refund->Status->SubCode->Description : ''
669
					)
670
				);
671
			}
672
		}
673
674
		// Update payment refunded amount.
675
		if ( null !== $payment ) {
676
			$result = $this->request( 'GET', 'Transaction/RefundInfo/' . $transaction_id );
677
678
			if ( \property_exists( $result, 'RefundedAmount' ) && ! empty( $result->RefundedAmount ) ) {
679
				$refunded_amount = new Money( $result->RefundedAmount, $result->RefundCurrency );
680
681
				$payment->set_refunded_amount( $refunded_amount );
682
			}
683
		}
684
685
		// Return.
686
		$refund_id = \property_exists( $refund, 'Key' ) ? $refund->Key : null;
687
688
		return $refund_id;
689
	}
690
}
691