Failed Conditions
Push — develop ( cca2f3...680a51 )
by Reüel
05:07
created

Gateway::request()   A

Complexity

Conditions 4
Paths 4

Size

Total Lines 67
Code Lines 36

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 20

Importance

Changes 4
Bugs 0 Features 0
Metric Value
cc 4
eloc 36
c 4
b 0
f 0
nc 4
nop 3
dl 0
loc 67
ccs 0
cts 45
cp 0
crap 20
rs 9.344

How to fix   Long Method   

Long Method

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

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

Commonly applied refactorings include:

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

334
			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...
335
				$data->Services->ServiceList[] = (object) array(
336
					'Action' => 'Pay',
337
					'Name'   => 'bancontactmrcash',
338
				);
339
340
				break;
341
			/**
342
			 * Payment method Giropay.
343
			 *
344
			 * @link https://dev.buckaroo.nl/PaymentMethods/Description/giropay#pay
345
			 */
346
			case Core_PaymentMethods::GIROPAY:
347
				$data->Services->ServiceList[] = (object) array(
348
					'Action' => 'Pay',
349
					'Name'   => 'giropay',
350
				);
351
352
				break;
353
			/**
354
			 * Payment method PayPal.
355
			 *
356
			 * @link https://dev.buckaroo.nl/PaymentMethods/Description/paypal#pay
357
			 */
358
			case Core_PaymentMethods::PAYPAL:
359
				$data->Services->ServiceList[] = (object) array(
360
					'Action' => 'Pay',
361
					'Name'   => 'paypal',
362
				);
363
364
				break;
365
			/**
366
			 * Payment method Sofort.
367
			 *
368
			 * @link https://dev.buckaroo.nl/PaymentMethods/Description/sofort#pay
369
			 */
370
			case Core_PaymentMethods::SOFORT:
371
				$data->Services->ServiceList[] = (object) array(
372
					'Action' => 'Pay',
373
					'Name'   => 'sofortueberweisung',
374
				);
375
376
				break;
377
		}
378
379
		/**
380
		 * Request.
381
		 */
382
		$object = $this->request( 'POST', 'Transaction', $data );
383
384
		/**
385
		 * Request Errors.
386
		 *
387
		 * @link https://testcheckout.buckaroo.nl/json/Docs/Api/POST-json-Transaction
388
		 */
389
		$exception = null;
390
391
		/**
392
		 * Channel errors.
393
		 *
394
		 * @link https://testcheckout.buckaroo.nl/json/Docs/ResourceModel?modelName=TransactionRequestResponseChannelError
395
		 */
396
		foreach ( $object->RequestErrors->ChannelErrors as $error ) {
397
			$exception = new \Exception( $error->ErrorMessage, 0, $exception );
398
		}
399
400
		/**
401
		 * Service errors.
402
		 *
403
		 * @link https://testcheckout.buckaroo.nl/json/Docs/ResourceModel?modelName=TransactionRequestResponseServiceError
404
		 */
405
		foreach ( $object->RequestErrors->ServiceErrors as $error ) {
406
			$exception = new \Exception( $error->ErrorMessage, 0, $exception );
407
		}
408
409
		/**
410
		 * Action errors.
411
		 *
412
		 * @link https://testcheckout.buckaroo.nl/json/Docs/ResourceModel?modelName=TransactionRequestResponseActionError
413
		 */
414
		foreach ( $object->RequestErrors->ActionErrors as $error ) {
415
			$exception = new \Exception( $error->ErrorMessage, 0, $exception );
416
		}
417
418
		/**
419
		 * Action errors.
420
		 *
421
		 * @link https://testcheckout.buckaroo.nl/json/Docs/ResourceModel?modelName=TransactionRequestResponseParameterError
422
		 */
423
		foreach ( $object->RequestErrors->ParameterErrors as $error ) {
424
			$exception = new \Exception( $error->ErrorMessage, 0, $exception );
425
		}
426
427
		/**
428
		 * Action errors.
429
		 *
430
		 * @link https://testcheckout.buckaroo.nl/json/Docs/ResourceModel?modelName=TransactionRequestResponseCustomParameterError
431
		 */
432
		foreach ( $object->RequestErrors->CustomParameterErrors as $error ) {
433
			$exception = new \Exception( $error->ErrorMessage, 0, $exception );
434
		}
435
436
		if ( null !== $exception ) {
437
			throw $exception;
438
		}
439
440
		/**
441
		 * Required Action.
442
		 */
443
		if ( 'Redirect' !== $object->RequiredAction->Name ) {
444
			throw new \Exception(
445
				\sprintf(
446
					'Unsupported Buckaroo action: %s',
447
					$object->RequiredAction->Name
448
				)
449
			);
450
		}
451
452
		$payment->set_action_url( $object->RequiredAction->RedirectURL );
453
454
		/**
455
		 * Buckaroo keys.
456
		 *
457
		 * @link https://testcheckout.buckaroo.nl/json/Docs/ResourceModel?modelName=TransactionResponse
458
		 */
459
		$payment->set_meta( 'buckaroo_transaction_key', $object->Key );
460
		$payment->set_meta( 'buckaroo_transaction_payment_key', $object->PaymentKey );
461
462
		/**
463
		 * Transaction ID.
464
		 *
465
		 * @link https://dev.buckaroo.nl/PaymentMethods/Description/ideal]
466
		 */
467
		foreach ( $object->Services as $service ) {
468
			foreach ( $service->Parameters as $parameter ) {
469
				if ( 'transactionId' === $parameter->Name ) {
470
					$payment->set_transaction_id( $parameter->Value );
471
				}
472
			}
473
		}
474
	}
475
476
	/**
477
	 * JSON API Request.
478
	 *
479
	 * @param string      $method   HTTP request method.
480
	 * @param string      $endpoint JSON API endpoint.
481
	 * @param object|null $data     Data.
482
	 */
483
	public function request( $method, $endpoint, $data = null ) {
484
		$host = 'checkout.buckaroo.nl';
485
486
		if ( self::MODE_TEST === $this->config->mode ) {
487
			$host = 'testcheckout.buckaroo.nl';
488
		}
489
490
		/**
491
		 * Authentication.
492
		 *
493
		 * 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.
494
		 *
495
		 * @link https://dev.buckaroo.nl/Apis/Description/json
496
		 * @link https://testcheckout.buckaroo.nl/json/Docs/Authentication
497
		 */
498
		$website_key         = $this->config->website_key;
499
		$request_http_method = $method;
500
		$request_uri         = $host . '/json/' . $endpoint;
501
		$request_timestamp   = \strval( \time() );
502
		$nonce               = \wp_generate_password( 32 );
503
		$request_content     = null === $data ? '' : \wp_json_encode( $data );
504
505
		$values = \implode(
506
			'',
507
			array(
508
				$website_key,
509
				$request_http_method,
510
				\strtolower( \rawurlencode( $request_uri ) ),
511
				$request_timestamp,
512
				$nonce,
513
				\
514
				// phpcs:ignore WordPress.PHP.DiscouragedPHPFunctions.obfuscation_base64_encode
515
				null === $data ? '' : \base64_encode( \md5( $request_content, true ) ),
0 ignored issues
show
Bug introduced by
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

515
				null === $data ? '' : \base64_encode( \md5( /** @scrutinizer ignore-type */ $request_content, true ) ),
Loading history...
516
			)
517
		);
518
519
		$hash = \hash_hmac( 'sha256', $values, $this->config->secret_key, true );
520
521
		// phpcs:ignore WordPress.PHP.DiscouragedPHPFunctions.obfuscation_base64_encode
522
		$hmac = \base64_encode( $hash );
523
524
		$authorization = \sprintf(
525
			'hmac %s:%s:%s:%s',
526
			$this->config->website_key,
527
			$hmac,
528
			$nonce,
529
			$request_timestamp
530
		);
531
532
		$response = \Pronamic\WordPress\Http\Facades\Http::request(
533
			'https://' . $request_uri,
534
			array(
535
				'method'  => $request_http_method,
536
				'headers' => array(
537
					'Authorization' => $authorization,
538
					'Content-Type'  => 'application/json',
539
				),
540
				'body'    => $request_content,
541
			)
542
		);
543
544
		$object = $response->json();
545
546
		/**
547
		 * OK.
548
		 */
549
		return $object;
550
	}
551
552
	/**
553
	 * Update status of the specified payment
554
	 *
555
	 * @link https://testcheckout.buckaroo.nl/json/Docs/Api/GET-json-Transaction-Status-transactionKey
556
	 * @param Payment $payment Payment.
557
	 */
558
	public function update_status( Payment $payment ) {
559
		$transaction_key = $payment->get_meta( 'buckaroo_transaction_key' );
560
561
		if ( empty( $transaction_key ) ) {
562
			return;
563
		}
564
565
		$result = $this->request( 'GET', 'Transaction/Status/' . $transaction_key );
566
567
		$payment->set_status( Statuses::transform( \strval( $result->Status->Code->Code ) ) );
568
569
		/**
570
		 * Consumer bank details.
571
		 */
572
		$consumer_bank_details = $payment->get_consumer_bank_details();
573
574
		if ( null === $consumer_bank_details ) {
575
			$consumer_bank_details = new BankAccountDetails();
576
577
			$payment->set_consumer_bank_details( $consumer_bank_details );
578
		}
579
580
		/**
581
		 * Services.
582
		 */
583
		foreach ( $result->Services as $service ) {
584
			foreach ( $service->Parameters as $parameter ) {
585
				if ( 'transactionId' === $parameter->Name ) {
586
					$payment->set_transaction_id( $parameter->Value );
587
				}
588
589
				if ( 'consumerName' === $parameter->Name ) {
590
					$consumer_bank_details->set_name( $parameter->Value );
591
				}
592
593
				if ( 'consumerIBAN' === $parameter->Name ) {
594
					$consumer_bank_details->set_iban( $parameter->Value );
595
				}
596
597
				if ( 'consumerBIC' === $parameter->Name ) {
598
					$consumer_bank_details->set_iban( $parameter->Value );
599
				}
600
			}
601
		}
602
603
		/**
604
		 * Refunds.
605
		 *
606
		 * @link https://testcheckout.buckaroo.nl/json/Docs/Api/GET-json-Transaction-RefundInfo-transactionKey
607
		 */
608
		$result = $this->request( 'GET', 'Transaction/RefundInfo/' . $transaction_key );
609
610
		$refunded_amount = new Money( $result->RefundedAmount, $result->RefundCurrency );
611
612
		$payment->set_refunded_amount( $refunded_amount );
613
	}
614
}
615