Failed Conditions
Push — develop ( d9bf11...21613b )
by Reüel
04:11
created

Gateway   F

Complexity

Total Complexity 73

Size/Duplication

Total Lines 805
Duplicated Lines 0 %

Test Coverage

Coverage 0%

Importance

Changes 30
Bugs 0 Features 0
Metric Value
eloc 303
c 30
b 0
f 0
dl 0
loc 805
ccs 0
cts 408
cp 0
rs 2.56
wmc 73

7 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 12 1
B update_status() 0 86 10
B request() 0 79 7
B get_issuers() 0 45 10
C create_refund() 0 100 13
F start() 0 404 31
A get_supported_payment_methods() 0 14 1

How to fix   Complexity   

Complex Class

Complex classes like Gateway often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

While breaking up the class, it is a good idea to analyze how other classes use Gateway, and based on these observations, apply Extract Interface, too.

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\Payments\Payment;
10
use Pronamic\WordPress\Pay\Payments\PaymentStatus;
11
use WP_Error;
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
	 * Constructs and initializes an Buckaroo gateway
26
	 *
27
	 * @param Config $config Config.
28
	 */
29
	public function __construct( Config $config ) {
30
		parent::__construct( $config );
31
32
		$this->set_method( self::METHOD_HTTP_REDIRECT );
33
34
		// Supported features.
35
		$this->supports = array(
36
			'payment_status_request',
37
			'refunds',
38
			'webhook',
39
			'webhook_log',
40
			'webhook_no_config',
41
		);
42
	}
43
44
	/**
45
	 * Get issuers.
46
	 *
47
	 * @since 1.2.4
48
	 * @see Core_Gateway::get_issuers()
49
	 */
50
	public function get_issuers() {
51
		$groups = array();
52
53
		// Check non-empty keys in configuration.
54
		if ( empty( $this->config->website_key ) || empty( $this->config->secret_key ) ) {
55
			return $groups;
56
		}
57
58
		// Get iDEAL issuers.
59
		try {
60
			$object = $this->request( 'GET', 'Transaction/Specification/ideal?serviceVersion=2' );
61
		} catch ( \Exception $e ) {
62
			$this->set_error( new WP_Error( 'buckaroo_error', $e->getMessage() ) );
63
64
			return $groups;
65
		}
66
67
		foreach ( $object->Actions as $action ) {
68
			// Check action name.
69
			if ( 'Pay' !== $action->Name ) {
70
				continue;
71
			}
72
73
			foreach ( $action->RequestParameters as $request_parameter ) {
74
				// Check request parameter name.
75
				if ( 'issuer' !== $request_parameter->Name ) {
76
					continue;
77
				}
78
79
				foreach ( $request_parameter->ListItemDescriptions as $item ) {
80
					// Make sure to add group.
81
					if ( ! array_key_exists( $item->GroupName, $groups ) ) {
82
						$groups[ $item->GroupName ] = array(
83
							'name'    => $item->GroupName,
84
							'options' => array(),
85
						);
86
					}
87
88
					// Add issuer to group.
89
					$groups[ $item->GroupName ]['options'][ $item->Value ] = $item->Description;
90
				}
91
			}
92
		}
93
94
		return $groups;
95
	}
96
97
	/**
98
	 * Get supported payment methods
99
	 *
100
	 * @see Core_Gateway::get_supported_payment_methods()
101
	 */
102
	public function get_supported_payment_methods() {
103
		return array(
104
			Core_PaymentMethods::AMERICAN_EXPRESS,
105
			Core_PaymentMethods::BANK_TRANSFER,
106
			Core_PaymentMethods::BANCONTACT,
107
			Core_PaymentMethods::CREDIT_CARD,
108
			Core_PaymentMethods::GIROPAY,
109
			Core_PaymentMethods::IDEAL,
110
			Core_PaymentMethods::MAESTRO,
111
			Core_PaymentMethods::MASTERCARD,
112
			Core_PaymentMethods::PAYPAL,
113
			Core_PaymentMethods::SOFORT,
114
			Core_PaymentMethods::V_PAY,
115
			Core_PaymentMethods::VISA,
116
		);
117
	}
118
119
	/**
120
	 * Start
121
	 *
122
	 * @param Payment $payment Payment.
123
	 *
124
	 * @see Core_Gateway::start()
125
	 */
126
	public function start( Payment $payment ) {
127
		/**
128
		 * Currency.
129
		 */
130
		$currency_code = $payment->get_total_amount()->get_currency()->get_alphabetic_code();
131
132
		/**
133
		 * Push URL.
134
		 */
135
		$push_url = \rest_url( Integration::REST_ROUTE_NAMESPACE . '/push' );
136
137
		/**
138
		 * Filters the Buckaroo push URL.
139
		 *
140
		 * If you want to debug the Buckaroo report URL you can use this filter
141
		 * to override the push URL. You could for example use a service like
142
		 * https://webhook.site/ to inspect the push requests from Buckaroo.
143
		 *
144
		 * @param string $push_url Buckaroo push URL.
145
		 */
146
		$push_url = \apply_filters( 'pronamic_pay_buckaroo_push_url', $push_url );
147
148
		/**
149
		 * JSON Transaction.
150
		 *
151
		 * @link https://testcheckout.buckaroo.nl/json/Docs/Api/POST-json-Transaction
152
		 */
153
		$data = (object) array(
154
			'Currency'                  => $currency_code,
155
			/**
156
			 * The debit amount for the request. This is in decimal format,
157
			 * with a point as the decimal separator. For example, if the
158
			 * currency is specified as EUR, sending “1” will mean that 1 euro
159
			 * will be paid. “1.00” is also 1 euro. “0.01” means 1 cent.
160
			 * Please note, a transaction must have either a debit amount or a
161
			 * credit amount and it cannot have both.
162
			 *
163
			 * @link https://dev.buckaroo.nl/Apis
164
			 */
165
			'AmountDebit'               => $payment->get_total_amount()->number_format( null, '.', '' ),
166
			'Description'               => $payment->get_description(),
167
			'Invoice'                   => Util::get_invoice_number( (string) $this->config->get_invoice_number(), $payment ),
168
			'ReturnURL'                 => $payment->get_return_url(),
169
			'ReturnURLCancel'           => \add_query_arg(
170
				'buckaroo_return_url_cancel',
171
				true,
172
				$payment->get_return_url()
173
			),
174
			'ReturnURLError'            => \add_query_arg(
175
				'buckaroo_return_url_error',
176
				true,
177
				$payment->get_return_url()
178
			),
179
			'ReturnURLReject'           => \add_query_arg(
180
				'buckaroo_return_url_reject',
181
				true,
182
				$payment->get_return_url()
183
			),
184
			/**
185
			 * Push URL.
186
			 *
187
			 * When provided, this push URL overrides all the push URLs as configured in the payment plaza under websites for the associated website key
188
			 *
189
			 * @link https://dev.buckaroo.nl/Apis
190
			 */
191
			'PushURL'                   => $push_url,
192
			/**
193
			 * Push URL Failure.
194
			 *
195
			 * 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.
196
			 *
197
			 * @link https://dev.buckaroo.nl/Apis
198
			 */
199
			'PushURLFailure'            => $push_url,
200
			/**
201
			 * Services.
202
			 *
203
			 * Specifies which service (can be a payment method and/or additional service) is being called upon in the request.
204
			 *
205
			 * @link https://dev.buckaroo.nl/Apis
206
			 */
207
			'Services'                  => (object) array(
208
				'ServiceList' => array(),
209
			),
210
			/**
211
			 * Continue On Incomplete.
212
			 *
213
			 * Specifies if a redirecturl to a payment form will be returned to
214
			 * which a customer should be sent if no paymentmethod is selected
215
			 * or if any required parameter which the customer may provide is
216
			 * missing or incorrect. Possible Values:
217
			 *
218
			 * · No: This is the default. The request will fail if not all the
219
			 * needed information is provided.
220
			 *
221
			 * · RedirectToHTML: A redirect to the HTML gateway is provided if
222
			 * a recoverable problems are detected in the request. The customer
223
			 * can then provide the needed information there.
224
			 *
225
			 * @link https://dev.buckaroo.nl/Apis
226
			 * @link https://testcheckout.buckaroo.nl/json/Docs/Api/POST-json-Transaction
227
			 * @link https://testcheckout.buckaroo.nl/json/Docs/ResourceModel?modelName=ContinueOnIncomplete
228
			 */
229
			'ContinueOnIncomplete'      => 'RedirectToHTML',
230
			/**
231
			 * Services Excluded For Client.
232
			 *
233
			 * If no primary service is provided and ContinueOnIncomplete is
234
			 * set, this list of comma separated servicescodes can be used to
235
			 * limit the number of services from which the customer may choose
236
			 * once he is redirected to the payment form. Services which are
237
			 * entered in this field are not selectable.
238
			 * This field is optional.
239
			 *
240
			 * @link https://dev.buckaroo.nl/Apis
241
			 * @link https://testcheckout.buckaroo.nl/json/Docs/Api/POST-json-Transaction
242
			 */
243
			'ServicesExcludedForClient' => $this->config->get_excluded_services(),
244
			/**
245
			 * Custom parameters.
246
			 *
247
			 * @link https://testcheckout.buckaroo.nl/json/Docs/Api/POST-json-Transaction
248
			 */
249
			'CustomParameters'          => array(
250
				(object) array(
251
					'Name'  => 'pronamic_payment_id',
252
					'Value' => $payment->get_id(),
253
				),
254
			),
255
		);
256
257
		/**
258
		 * Client IP.
259
		 *
260
		 * In this field the IP address of the customer (or employee) for which
261
		 * the action is being performed can be passed. Please note, If this
262
		 * field is not sent to our gateway, your server IP address will be
263
		 * used as the clientIP. This may result in unwanted behaviour for
264
		 * anti-fraud checks. Also, certain payment methods perform checks on
265
		 * the IP address, if an IP address is overused, the request could be
266
		 * blocked. This field is sent in the following format, where
267
		 * type 0 = IPv4 and type 1 = IPv6:
268
		 * "ClientIP": { "Type": 0, "Address": "0.0.0.0" },
269
		 *
270
		 * @link https://testcheckout.buckaroo.nl/json/Docs/Api/POST-json-Transaction
271
		 * @link https://stackoverflow.com/questions/1448871/how-to-know-which-version-of-the-internet-protocol-ip-a-client-is-using-when-c/1448901
272
		 */
273
		$customer = $payment->get_customer();
274
275
		if ( null !== $customer ) {
276
			$ip_address = $customer->get_ip_address();
277
278
			if ( null !== $ip_address ) {
279
				$data->ClientIP = (object) array(
280
					'Type'    => false === \strpos( $ip_address, ':' ) ? 0 : 1,
281
					'Address' => $ip_address,
282
				);
283
			}
284
		}
285
286
		/**
287
		 * Payment method.
288
		 *
289
		 * @link https://testcheckout.buckaroo.nl/json/Docs/Api/POST-json-Transaction
290
		 * @link https://testcheckout.buckaroo.nl/json/Docs/ResourceModel?modelName=ServicesRequest
291
		 * @link https://testcheckout.buckaroo.nl/json/Docs/ResourceModel?modelName=ServiceRequest
292
		 */
293
		switch ( $payment->get_payment_method() ) {
0 ignored issues
show
Bug introduced by
The method get_payment_method() 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

293
		switch ( $payment->/** @scrutinizer ignore-call */ get_payment_method() ) {

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...
294
			/**
295
			 * Payment method American Express.
296
			 * 
297
			 * @link 
298
			 */
299
			case Core_PaymentMethods::AMERICAN_EXPRESS:
300
				$data->Services->ServiceList[] = (object) array(
301
					'Action' => 'Pay',
302
					'Name'   => PaymentMethods::AMERICAN_EXPRESS,
303
				);
304
305
				break;
306
			/**
307
			 * Payment method creditcard.
308
			 *
309
			 * @link https://dev.buckaroo.nl/PaymentMethods/Description/creditcards#pay
310
			 */
311
			case Core_PaymentMethods::CREDIT_CARD:
312
				$data->Services->ServiceList[] = (object) array(
313
					'Action' => 'Pay',
314
					'Name'   => PaymentMethods::AMERICAN_EXPRESS,
315
				);
316
317
				$data->Services->ServiceList[] = (object) array(
318
					'Action' => 'Pay',
319
					'Name'   => PaymentMethods::MAESTRO,
320
				);
321
322
				$data->Services->ServiceList[] = (object) array(
323
					'Action' => 'Pay',
324
					'Name'   => PaymentMethods::MASTERCARD,
325
				);
326
327
				$data->Services->ServiceList[] = (object) array(
328
					'Action' => 'Pay',
329
					'Name'   => PaymentMethods::VISA,
330
				);
331
332
				break;
333
			/**
334
			 * Payment method iDEAL.
335
			 *
336
			 * @link https://dev.buckaroo.nl/PaymentMethods/Description/ideal#pay
337
			 */
338
			case Core_PaymentMethods::IDEAL:
339
				$data->Services->ServiceList[] = (object) array(
340
					'Action'     => 'Pay',
341
					'Name'       => 'ideal',
342
					'Parameters' => array(
343
						array(
344
							'Name'  => 'issuer',
345
							'Value' => $payment->get_meta( 'issuer' ),
346
						),
347
					),
348
				);
349
350
				break;
351
			/**
352
			 * Payment method transfer.
353
			 *
354
			 * @link https://dev.buckaroo.nl/PaymentMethods/Description/transfer#pay
355
			 */
356
			case Core_PaymentMethods::BANK_TRANSFER:
357
				$data->Services->ServiceList[] = (object) array(
358
					'Action' => 'Pay',
359
					'Name'   => 'transfer',
360
				);
361
362
				break;
363
			/**
364
			 * Payment method Bancontact.
365
			 *
366
			 * @link https://dev.buckaroo.nl/PaymentMethods/Description/bancontact#pay
367
			 */
368
			case Core_PaymentMethods::BANCONTACT:
369
			case Core_PaymentMethods::MISTER_CASH:
0 ignored issues
show
Deprecated Code introduced by
The constant Pronamic\WordPress\Pay\C...entMethods::MISTER_CASH has been deprecated: "Bancontact/Mister Cash" was renamed to just "Bancontact". ( Ignorable by Annotation )

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

369
			case /** @scrutinizer ignore-deprecated */ Core_PaymentMethods::MISTER_CASH:

This class constant has been deprecated. The supplier of the class has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the constant will be removed from the class and what other constant to use instead.

Loading history...
370
				$data->Services->ServiceList[] = (object) array(
371
					'Action' => 'Pay',
372
					'Name'   => 'bancontactmrcash',
373
				);
374
375
				break;
376
			/**
377
			 * Payment method Maestro.
378
			 * 
379
			 * @link 
380
			 */
381
			case Core_PaymentMethods::MAESTRO:
382
				$data->Services->ServiceList[] = (object) array(
383
					'Action' => 'Pay',
384
					'Name'   => PaymentMethods::MAESTRO,
385
				);
386
387
				break;
388
			/**
389
			 * Payment method Mastercard.
390
			 * 
391
			 * @link 
392
			 */
393
			case Core_PaymentMethods::MASTERCARD:
394
				$data->Services->ServiceList[] = (object) array(
395
					'Action' => 'Pay',
396
					'Name'   => PaymentMethods::MASTERCARD,
397
				);
398
399
				break;
400
			/**
401
			 * Payment method Giropay.
402
			 *
403
			 * @link https://dev.buckaroo.nl/PaymentMethods/Description/giropay#pay
404
			 */
405
			case Core_PaymentMethods::GIROPAY:
406
				$data->Services->ServiceList[] = (object) array(
407
					'Action' => 'Pay',
408
					'Name'   => 'giropay',
409
				);
410
411
				break;
412
			/**
413
			 * Payment method PayPal.
414
			 *
415
			 * @link https://dev.buckaroo.nl/PaymentMethods/Description/paypal#pay
416
			 */
417
			case Core_PaymentMethods::PAYPAL:
418
				$data->Services->ServiceList[] = (object) array(
419
					'Action' => 'Pay',
420
					'Name'   => 'paypal',
421
				);
422
423
				break;
424
			/**
425
			 * Payment method Sofort.
426
			 *
427
			 * @link https://dev.buckaroo.nl/PaymentMethods/Description/sofort#pay
428
			 */
429
			case Core_PaymentMethods::SOFORT:
430
				$data->Services->ServiceList[] = (object) array(
431
					'Action' => 'Pay',
432
					'Name'   => 'sofortueberweisung',
433
				);
434
435
				break;
436
			/**
437
			 * Payment method V PAY.
438
			 * 
439
			 * @link https://dev.buckaroo.nl/PaymentMethods/Description/creditcards#top
440
			 */
441
			case Core_PaymentMethods::V_PAY:
442
				$data->Services->ServiceList[] = (object) array(
443
					'Action' => 'Pay',
444
					'Name'   => PaymentMethods::V_PAY,
445
				);
446
447
				break;
448
			/**
449
			 * Payment method Visa.
450
			 * 
451
			 * @link https://dev.buckaroo.nl/PaymentMethods/Description/creditcards#top
452
			 */
453
			case Core_PaymentMethods::VISA:
454
				$data->Services->ServiceList[] = (object) array(
455
					'Action' => 'Pay',
456
					'Name'   => PaymentMethods::VISA,
457
				);
458
459
				break;
460
		}
461
462
		/**
463
		 * Request.
464
		 */
465
		$object = $this->request( 'POST', 'Transaction', $data );
466
467
		/**
468
		 * Buckaroo keys.
469
		 *
470
		 * @link https://testcheckout.buckaroo.nl/json/Docs/ResourceModel?modelName=TransactionResponse
471
		 */
472
		if ( \property_exists( $object, 'Key' ) ) {
473
			$payment->set_transaction_id( $object->Key );
474
		}
475
476
		if ( \property_exists( $object, 'PaymentKey' ) ) {
477
			$payment->set_meta( 'buckaroo_transaction_payment_key', $object->PaymentKey );
478
		}
479
480
		/**
481
		 * Request Errors.
482
		 *
483
		 * @link https://testcheckout.buckaroo.nl/json/Docs/Api/POST-json-Transaction
484
		 */
485
		if ( \property_exists( $object, 'RequestErrors' ) && null !== $object->RequestErrors ) {
486
			$exception = null;
487
488
			foreach ( $object->RequestErrors as $errors ) {
489
				foreach ( $errors as $error ) {
490
					// Add exception.
491
					$exception = new \Exception( $error->ErrorMessage, 0, $exception );
492
				}
493
			}
494
495
			if ( null !== $exception ) {
496
				throw $exception;
497
			}
498
		}
499
500
		/**
501
		 * Required Action.
502
		 */
503
		if ( null !== $object->RequiredAction ) {
504
			if ( 'Redirect' !== $object->RequiredAction->Name ) {
505
				throw new \Exception(
506
					\sprintf(
507
						'Unsupported Buckaroo action: %s',
508
						$object->RequiredAction->Name
509
					)
510
				);
511
			}
512
513
			// Set action URL.
514
			if ( \property_exists( $object->RequiredAction, 'RedirectURL' ) ) {
515
				$payment->set_action_url( $object->RequiredAction->RedirectURL );
516
			}
517
		}
518
519
		// Failure.
520
		if ( \property_exists( $object, 'Status' ) && \property_exists( $object->Status, 'Code' ) ) {
521
			$status = Statuses::transform( (string) $object->Status->Code->Code );
522
523
			if ( PaymentStatus::FAILURE === $status ) {
524
				throw new \Exception(
525
					\sprintf(
526
						/* translators: 1: payment provider name, 2: status message, 3: status sub message*/
527
						__( 'Unable to create payment at gateway: %1$s%2$s', 'pronamic_ideal' ),
528
						$object->Status->Code->Description,
529
						\property_exists( $object->Status, 'SubCode' ) ? ' – ' . $object->Status->SubCode->Description : ''
530
					)
531
				);
532
			}
533
		}
534
	}
535
536
	/**
537
	 * JSON API Request.
538
	 *
539
	 * @param string      $method   HTTP request method.
540
	 * @param string      $endpoint JSON API endpoint.
541
	 * @param object|null $data     Data.
542
	 * @return object
543
	 */
544
	public function request( $method, $endpoint, $data = null ) {
545
		$host = 'checkout.buckaroo.nl';
546
547
		if ( self::MODE_TEST === $this->config->mode ) {
548
			$host = 'testcheckout.buckaroo.nl';
549
		}
550
551
		/**
552
		 * Authentication.
553
		 *
554
		 * 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.
555
		 *
556
		 * @link https://dev.buckaroo.nl/Apis/Description/json
557
		 * @link https://testcheckout.buckaroo.nl/json/Docs/Authentication
558
		 */
559
		$website_key         = $this->config->website_key;
560
		$request_http_method = $method;
561
		$request_uri         = $host . '/json/' . $endpoint;
562
		$request_timestamp   = \strval( \time() );
563
		$nonce               = \wp_generate_password( 32 );
564
		$request_content     = null === $data ? '' : \wp_json_encode( $data );
565
566
		$values = \implode(
567
			'',
568
			array(
569
				$website_key,
570
				$request_http_method,
571
				\strtolower( \rawurlencode( $request_uri ) ),
572
				$request_timestamp,
573
				$nonce,
574
				// phpcs:ignore WordPress.PHP.DiscouragedPHPFunctions.obfuscation_base64_encode
575
				null === $data ? '' : \base64_encode( \md5( (string) $request_content, true ) ),
576
			)
577
		);
578
579
		$hash = \hash_hmac( 'sha256', $values, $this->config->secret_key, true );
580
581
		// phpcs:ignore WordPress.PHP.DiscouragedPHPFunctions.obfuscation_base64_encode
582
		$hmac = \base64_encode( $hash );
583
584
		$authorization = \sprintf(
585
			'hmac %s:%s:%s:%s',
586
			$this->config->website_key,
587
			$hmac,
588
			$nonce,
589
			$request_timestamp
590
		);
591
592
		$response = \Pronamic\WordPress\Http\Facades\Http::request(
593
			'https://' . $request_uri,
594
			array(
595
				'method'  => $request_http_method,
596
				'headers' => array(
597
					'Authorization' => $authorization,
598
					'Content-Type'  => 'application/json',
599
				),
600
				'body'    => $request_content,
601
			)
602
		);
603
604
		try {
605
			$object = $response->json();
606
		} catch ( \Exception $e ) {
607
			// JSON error.
608
			$json_error = \json_last_error();
609
610
			// Check authorization error.
611
			if ( \JSON_ERROR_NONE !== $json_error && 400 === $response->status() ) {
612
				throw new \Exception( $response->body() );
613
			}
614
615
			// Re-throw original response exception.
616
			throw $e;
617
		}
618
619
		/**
620
		 * OK.
621
		 */
622
		return $object;
623
	}
624
625
	/**
626
	 * Update status of the specified payment
627
	 *
628
	 * @link https://testcheckout.buckaroo.nl/json/Docs/Api/GET-json-Transaction-Status-transactionKey
629
	 * @param Payment $payment Payment.
630
	 */
631
	public function update_status( Payment $payment ) {
632
		$transaction_key = $payment->get_transaction_id();
633
634
		if ( empty( $transaction_key ) ) {
635
			return;
636
		}
637
638
		$result = $this->request( 'GET', 'Transaction/Status/' . $transaction_key );
639
640
		$payment->set_status( Statuses::transform( \strval( $result->Status->Code->Code ) ) );
641
642
		/**
643
		 * Consumer bank details.
644
		 */
645
		$consumer_bank_details = $payment->get_consumer_bank_details();
646
647
		if ( null === $consumer_bank_details ) {
648
			$consumer_bank_details = new BankAccountDetails();
649
650
			$payment->set_consumer_bank_details( $consumer_bank_details );
651
		}
652
653
		/**
654
		 * Services.
655
		 */
656
		foreach ( $result->Services as $service ) {
657
			foreach ( $service->Parameters as $parameter ) {
658
				if ( 'consumerName' === $parameter->Name ) {
659
					$consumer_bank_details->set_name( $parameter->Value );
660
				}
661
662
				if ( \in_array(
663
					$parameter->Name,
664
					array(
665
						/**
666
						 * Payment method iDEAL.
667
						 * 
668
						 * @link https://dev.buckaroo.nl/PaymentMethods/Description/ideal
669
						 */
670
						'consumerIBAN',
671
						/**
672
						 * Payment method Sofort.
673
						 * 
674
						 * @link https://dev.buckaroo.nl/PaymentMethods/Description/sofort
675
						 */
676
						'CustomerIBAN',
677
					),
678
					true
679
				) ) {
680
					$consumer_bank_details->set_iban( $parameter->Value );
681
				}
682
683
				if ( \in_array(
684
					$parameter->Name,
685
					array(
686
						/**
687
						 * Payment method iDEAL.
688
						 * 
689
						 * @link https://dev.buckaroo.nl/PaymentMethods/Description/ideal
690
						 */
691
						'consumerName',
692
						/**
693
						 * Payment method Sofort.
694
						 * 
695
						 * @link https://dev.buckaroo.nl/PaymentMethods/Description/sofort
696
						 */
697
						'CustomerBIC',
698
					),
699
					true
700
				) ) {
701
					$consumer_bank_details->set_bic( $parameter->Value );
702
				}
703
			}
704
		}
705
706
		/**
707
		 * Refunds.
708
		 *
709
		 * @link https://testcheckout.buckaroo.nl/json/Docs/Api/GET-json-Transaction-RefundInfo-transactionKey
710
		 */
711
		$result = $this->request( 'GET', 'Transaction/RefundInfo/' . $transaction_key );
712
713
		if ( \property_exists( $result, 'RefundedAmount' ) && ! empty( $result->RefundedAmount ) ) {
714
			$refunded_amount = new Money( $result->RefundedAmount, $result->RefundCurrency );
715
716
			$payment->set_refunded_amount( $refunded_amount );
717
		}
718
	}
719
720
	/**
721
	 * Create refund.
722
	 *
723
	 * @param string $transaction_id Transaction ID.
724
	 * @param Money  $amount         Amount to refund.
725
	 * @param string $description    Refund reason.
726
	 * @return null|string
727
	 */
728
	public function create_refund( $transaction_id, Money $amount, $description = null ) {
0 ignored issues
show
Unused Code introduced by
The parameter $description is not used and could be removed. ( Ignorable by Annotation )

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

728
	public function create_refund( $transaction_id, Money $amount, /** @scrutinizer ignore-unused */ $description = null ) {

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

Loading history...
729
		$original_transaction = $this->request( 'GET', 'Transaction/Status/' . $transaction_id );
730
731
		if ( ! \is_object( $original_transaction ) ) {
732
			throw new \Exception(
733
				sprintf(
734
					/* translators: %s: transaction key */
735
					__( 'Unable to create refund for transaction with transaction key: %s', 'pronamic_ideal' ),
736
					$transaction_id
737
				)
738
			);
739
		}
740
741
		$service_name = Util::get_transaction_service( $original_transaction );
742
743
		if ( null === $service_name ) {
744
			throw new \Exception(
745
				sprintf(
746
					/* translators: %s: transaction key */
747
					__( 'Unable to create refund for transaction without service name. Transaction key: %s', 'pronamic_ideal' ),
748
					$transaction_id
749
				)
750
			);
751
		}
752
753
		// Invoice.
754
		$payment = \get_pronamic_payment_by_transaction_id( $transaction_id );
755
756
		$invoice = null;
757
758
		if ( null !== $payment ) {
759
			$invoice = Util::get_invoice_number( (string) $this->config->get_invoice_number(), $payment );
760
		}
761
762
		// Refund request.
763
		$data = (object) array(
764
			'Channel'                => 'Web',
765
			'Currency'               => $amount->get_currency()->get_alphabetic_code(),
766
			/**
767
			 * The credit amount for the request. This is in decimal format,
768
			 * with a point as the decimal separator. For example, if the
769
			 * currency is specified as EUR, sending “1” will mean that 1 euro
770
			 * will be paid. “1.00” is also 1 euro. “0.01” means 1 cent.
771
			 * Please note, a transaction must have either a debit amount or a
772
			 * credit amount and it cannot have both.
773
			 *
774
			 * @link https://dev.buckaroo.nl/Apis
775
			 */
776
			'AmountCredit'           => $amount->format( null, '.', '' ),
0 ignored issues
show
Unused Code introduced by
The call to Pronamic\WordPress\Money\Money::format() has too many arguments starting with '.'. ( Ignorable by Annotation )

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

776
			'AmountCredit'           => $amount->/** @scrutinizer ignore-call */ format( null, '.', '' ),

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...
777
			'Invoice'                => $invoice,
778
			'OriginalTransactionKey' => $transaction_id,
779
			'Services'               => array(
780
				'ServiceList' => array(
781
					array(
782
						'Name'   => $service_name,
783
						'Action' => 'Refund',
784
					),
785
				),
786
			),
787
		);
788
789
		$refund = $this->request( 'POST', 'Transaction', $data );
790
791
		// Check refund object.
792
		if ( ! \is_object( $refund ) ) {
793
			return null;
794
		}
795
796
		// Check refund status.
797
		if ( \property_exists( $refund, 'Status' ) && \property_exists( $refund->Status, 'Code' ) ) {
798
			$status = Statuses::transform( (string) $refund->Status->Code->Code );
799
800
			if ( PaymentStatus::SUCCESS !== $status ) {
801
				throw new \Exception(
802
					\sprintf(
803
						/* translators: 1: payment provider name, 2: status message, 3: status sub message*/
804
						__( 'Unable to create refund at %1$s gateway: %2$s%3$s', 'pronamic_ideal' ),
805
						__( 'Buckaroo', 'pronamic_ideal' ),
806
						$refund->Status->Code->Description,
807
						\property_exists( $refund->Status, 'SubCode' ) ? ' – ' . $refund->Status->SubCode->Description : ''
808
					)
809
				);
810
			}
811
		}
812
813
		// Update payment refunded amount.
814
		if ( null !== $payment ) {
815
			$result = $this->request( 'GET', 'Transaction/RefundInfo/' . $transaction_id );
816
817
			if ( \property_exists( $result, 'RefundedAmount' ) && ! empty( $result->RefundedAmount ) ) {
818
				$refunded_amount = new Money( $result->RefundedAmount, $result->RefundCurrency );
819
820
				$payment->set_refunded_amount( $refunded_amount );
821
			}
822
		}
823
824
		// Return.
825
		$refund_id = \property_exists( $refund, 'Key' ) ? $refund->Key : null;
826
827
		return $refund_id;
828
	}
829
}
830