Passed
Push — develop ( c2f1df...779f55 )
by Reüel
05:07
created

Gateway   A

Complexity

Total Complexity 36

Size/Duplication

Total Lines 398
Duplicated Lines 0 %

Test Coverage

Coverage 5.84%

Importance

Changes 27
Bugs 1 Features 0
Metric Value
eloc 162
c 27
b 1
f 0
dl 0
loc 398
ccs 8
cts 137
cp 0.0584
rs 9.52
wmc 36

8 Methods

Rating   Name   Duplication   Size   Complexity  
A checkout_head() 0 4 1
A payment_redirect() 0 69 5
A get_available_payment_methods() 0 21 3
A get_supported_payment_methods() 0 9 1
B get_issuers() 0 48 9
A __construct() 0 10 1
A update_status() 0 22 3
C start() 0 134 13
1
<?php
2
/**
3
 * Gateway
4
 *
5
 * @author    Pronamic <[email protected]>
6
 * @copyright 2005-2019 Pronamic
7
 * @license   GPL-3.0-or-later
8
 * @package   Pronamic\WordPress\Pay\Gateways\Adyen
9
 */
10
11
namespace Pronamic\WordPress\Pay\Gateways\Adyen;
12
13
use Exception;
14
use InvalidArgumentException;
15
use Locale;
16
use Pronamic\WordPress\Pay\Core\Gateway as Core_Gateway;
17
use Pronamic\WordPress\Pay\Core\PaymentMethods;
18
use Pronamic\WordPress\Pay\Core\Util as Core_Util;
19
use Pronamic\WordPress\Pay\Payments\Payment;
20
use Pronamic\WordPress\Pay\Plugin;
21
use WP_Error;
22
23
/**
24
 * Gateway
25
 *
26
 * @link https://github.com/adyenpayments/php/blob/master/generatepaymentform.php
27
 *
28
 * @author  Remco Tolsma
29
 * @version 1.0.0
30
 * @since   1.0.0
31
 */
32
class Gateway extends Core_Gateway {
33
	/**
34
	 * Web SDK version.
35
	 *
36
	 * @link https://docs.adyen.com/developers/checkout/web-sdk/release-notes-web-sdk
37
	 *
38
	 * @var string
39
	 */
40
	const SDK_VERSION = '1.9.2';
41
42
	/**
43
	 * Client.
44
	 *
45
	 * @var Client
46
	 */
47
	public $client;
48
49
	/**
50
	 * Constructs and initializes an Adyen gateway.
51
	 *
52
	 * @param Config $config Config.
53
	 */
54 2
	public function __construct( Config $config ) {
55 2
		parent::__construct( $config );
56
57 2
		$this->set_method( self::METHOD_HTTP_REDIRECT );
58
59
		// Supported features.
60 2
		$this->supports = array();
61
62
		// Client.
63 2
		$this->client = new Client( $config );
64 2
	}
65
66
	/**
67
	 * Get supported payment methods
68
	 *
69
	 * @see Core_Gateway::get_supported_payment_methods()
70
	 */
71 1
	public function get_supported_payment_methods() {
72
		return array(
73 1
			PaymentMethods::BANCONTACT,
74
			PaymentMethods::CREDIT_CARD,
75
			PaymentMethods::DIRECT_DEBIT,
76
			PaymentMethods::GIROPAY,
77
			PaymentMethods::IDEAL,
78
			PaymentMethods::MAESTRO,
79
			PaymentMethods::SOFORT,
80
		);
81
	}
82
83
	/**
84
	 * Start.
85
	 *
86
	 * @see Plugin::start()
87
	 *
88
	 * @param Payment $payment Payment.
89
	 * @return void
90
	 */
91
	public function start( Payment $payment ) {
92
		// Amount.
93
		try {
94
			$amount = AmountTransformer::transform( $payment->get_total_amount() );
95
		} catch ( InvalidArgumentException $e ) {
96
			$this->error = new WP_Error( 'adyen_error', $e->getMessage() );
97
98
			return;
99
		}
100
101
		// Payment method type.
102
		$payment_method_type = PaymentMethodType::transform( $payment->get_method() );
103
104
		// Country.
105
		$locale = get_locale();
106
107
		$customer = $payment->get_customer();
108
109
		if ( null !== $customer ) {
110
			$locale = $customer->get_locale();
111
		}
112
113
		$locale = strval( $locale );
114
115
		$country_code = Locale::getRegion( $locale );
116
117
		// Set country from billing address.
118
		$billing_address = $payment->get_billing_address();
119
120
		if ( null !== $billing_address ) {
121
			$country = $billing_address->get_country_code();
122
123
			if ( ! empty( $country ) ) {
124
				$country_code = $country;
125
			}
126
		}
127
128
		/*
129
		 * API Integration
130
		 *
131
		 * @link https://docs.adyen.com/api-explorer/#/PaymentSetupAndVerificationService/v41/payments
132
		 */
133
		$api_integration_payment_method_types = array(
134
			PaymentMethodType::IDEAL,
135
			PaymentMethodType::DIRECT_EBANKING,
136
		);
137
138
		if ( in_array( $payment_method_type, $api_integration_payment_method_types, true ) ) {
139
			$payment_method = new PaymentMethod( $payment_method_type );
140
141
			if ( PaymentMethodType::IDEAL === $payment_method_type ) {
142
				$payment_method = new PaymentMethodIDeal( $payment_method_type, (string) $payment->get_issuer() );
143
			}
144
145
			// API integration.
146
			$payment_request = new PaymentRequest(
147
				$amount,
148
				$this->config->get_merchant_account(),
149
				strval( $payment->get_id() ),
150
				$payment->get_return_url(),
151
				$payment_method
152
			);
153
154
			$payment_request->set_country_code( $country_code );
155
156
			PaymentRequestHelper::complement( $payment, $payment_request );
157
158
			try {
159
				$payment_response = $this->client->create_payment( $payment_request );
160
			} catch ( Exception $e ) {
161
				$this->error = new WP_Error( 'adyen_error', $e->getMessage() );
162
163
				return;
164
			}
165
166
			$payment->set_transaction_id( $payment_response->get_psp_reference() );
167
168
			$redirect = $payment_response->get_redirect();
169
170
			if ( null !== $redirect ) {
171
				$payment->set_action_url( $redirect->get_url() );
172
			}
173
174
			// Return early so SDK integration code will not be executed for API integration.
175
			return;
176
		}
177
178
		/*
179
		 * SDK Integration
180
		 *
181
		 * @link https://docs.adyen.com/api-explorer/#/PaymentSetupAndVerificationService/v41/paymentSession
182
		 */
183
		$payment_session_request = new PaymentSessionRequest(
184
			$amount,
185
			$this->config->get_merchant_account(),
186
			strval( $payment->get_id() ),
187
			$payment->get_return_url(),
188
			$country_code
189
		);
190
191
		PaymentRequestHelper::complement( $payment, $payment_session_request );
192
193
		// Origin.
194
		$origin = home_url();
195
196
		$origin_url = wp_parse_url( home_url() );
197
198
		if ( is_array( $origin_url ) && isset( $origin_url['scheme'], $origin_url['host'] ) ) {
199
			$origin = sprintf(
200
				'%s://%s',
201
				$origin_url['scheme'],
202
				$origin_url['host']
203
			);
204
		}
205
206
		$payment_session_request->set_origin( $origin );
207
		$payment_session_request->set_sdk_version( self::SDK_VERSION );
208
209
		if ( null !== $payment_method_type ) {
210
			$payment_session_request->set_allowed_payment_methods( array( $payment_method_type ) );
211
		}
212
213
		try {
214
			$payment_session_response = $this->client->create_payment_session( $payment_session_request );
215
		} catch ( Exception $e ) {
216
			$this->error = new WP_Error( 'adyen_error', $e->getMessage() );
217
218
			return;
219
		}
220
221
		$payment->set_meta( 'adyen_sdk_version', self::SDK_VERSION );
222
		$payment->set_meta( 'adyen_payment_session', $payment_session_response->get_payment_session() );
223
224
		$payment->set_action_url( $payment->get_pay_redirect_url() );
225
	}
226
227
	/**
228
	 * Payment redirect.
229
	 *
230
	 * @param Payment $payment Payment.
231
	 *
232
	 * @return void
233
	 */
234
	public function payment_redirect( Payment $payment ) {
235
		$sdk_version     = $payment->get_meta( 'adyen_sdk_version' );
236
		$payment_session = $payment->get_meta( 'adyen_payment_session' );
237
238
		if ( empty( $sdk_version ) || empty( $payment_session ) ) {
239
			return;
240
		}
241
242
		$url = sprintf(
243
			'https://checkoutshopper-%s.adyen.com/checkoutshopper/assets/js/sdk/checkoutSDK.%s.min.js',
244
			( self::MODE_TEST === $payment->get_mode() ? 'test' : 'live' ),
245
			$sdk_version
246
		);
247
248
		wp_register_script(
249
			'pronamic-pay-adyen-checkout',
250
			$url,
251
			array(
252
				'jquery',
253
			),
254
			$sdk_version,
255
			false
256
		);
257
258
		/**
259
		 * Config object.
260
		 *
261
		 * @link https://docs.adyen.com/checkout/web-sdk/
262
		 * @link https://docs.adyen.com/checkout/web-sdk/customization/settings/
263
		 * @link https://docs.adyen.com/checkout/web-sdk/customization/styling/#styling-the-card-fields
264
		 */
265
		$config_object = (object) array(
266
			'context' => ( self::MODE_TEST === $payment->get_mode() ? 'test' : 'live' ),
267
		);
268
269
		/**
270
		 * Filters the Adyen config object.
271
		 *
272
		 * @link https://github.com/wp-pay-gateways/adyen#pronamic_pay_adyen_config_object
273
		 * @link https://docs.adyen.com/checkout/web-sdk/
274
		 * @link https://docs.adyen.com/checkout/web-sdk/customization/settings/
275
		 * @link https://docs.adyen.com/checkout/web-sdk/customization/styling/#styling-the-card-fields
276
		 *
277
		 * @param object $config_object Adyen config object.
278
		 *
279
		 * @since 1.1
280
		 */
281
		$config_object = apply_filters( 'pronamic_pay_adyen_config_object', $config_object );
282
283
		wp_localize_script(
284
			'pronamic-pay-adyen-checkout',
285
			'pronamicPayAdyenCheckout',
286
			array(
287
				'paymentsResultUrl' => rest_url( Integration::REST_ROUTE_NAMESPACE . '/payments/result/' . $payment->config_id ),
288
				'paymentReturnUrl'  => $payment->get_return_url(),
289
				'paymentSession'    => $payment_session,
290
				'configObject'      => $config_object,
291
			)
292
		);
293
294
		// Add checkout head action.
295
		add_action( 'pronamic_pay_adyen_checkout_head', array( $this, 'checkout_head' ) );
296
297
		// No cache.
298
		Core_Util::no_cache();
299
300
		require __DIR__ . '/../views/checkout.php';
301
302
		exit;
303
	}
304
305
	/**
306
	 * Checkout head.
307
	 *
308
	 * @return void
309
	 */
310
	public function checkout_head() {
311
		wp_print_styles( 'pronamic-pay-redirect' );
312
313
		wp_print_scripts( 'pronamic-pay-adyen-checkout' );
314
	}
315
316
	/**
317
	 * Update status of the specified payment.
318
	 *
319
	 * @param Payment $payment Payment.
320
	 *
321
	 * @return void
322
	 */
323
	public function update_status( Payment $payment ) {
324
		// Process payload on return.
325
		if ( ! filter_has_var( INPUT_GET, 'payload' ) ) {
326
			return;
327
		}
328
329
		$payload = filter_input( INPUT_GET, 'payload', FILTER_SANITIZE_STRING );
330
331
		$payment_result_request = new PaymentResultRequest( $payload );
332
333
		try {
334
			$payment_result_response = $this->client->get_payment_result( $payment_result_request );
335
336
			PaymentResultHelper::update_payment( $payment, $payment_result_response );
337
		} catch ( Exception $e ) {
338
			$note = sprintf(
339
				/* translators: %s: exception message */
340
				__( 'Error getting payment result: %s', 'pronamic_ideal' ),
341
				$e->getMessage()
342
			);
343
344
			$payment->add_note( $note );
345
		}
346
	}
347
348
	/**
349
	 * Get available payment methods.
350
	 *
351
	 * @see Core_Gateway::get_available_payment_methods()
352
	 */
353
	public function get_available_payment_methods() {
354
		$core_payment_methods = array();
355
356
		try {
357
			$payment_methods_response = $this->client->get_payment_methods();
358
		} catch ( Exception $e ) {
359
			$this->error = new WP_Error( 'adyen_error', $e->getMessage() );
360
361
			return $core_payment_methods;
362
		}
363
364
		foreach ( $payment_methods_response->get_payment_methods() as $payment_method ) {
365
			$core_payment_method = PaymentMethodType::to_wp( $payment_method->get_type() );
366
367
			$core_payment_methods[] = $core_payment_method;
368
		}
369
370
		$core_payment_methods = array_filter( $core_payment_methods );
371
		$core_payment_methods = array_unique( $core_payment_methods );
372
373
		return $core_payment_methods;
374
	}
375
376
	/**
377
	 * Get issuers.
378
	 *
379
	 * @see Pronamic_WP_Pay_Gateway::get_issuers()
380
	 * @return array
381
	 */
382
	public function get_issuers() {
383
		$issuers = array();
384
385
		try {
386
			$payment_methods_response = $this->client->get_payment_methods();
387
		} catch ( Exception $e ) {
388
			$this->error = new WP_Error( 'adyen_error', $e->getMessage() );
389
390
			return $issuers;
391
		}
392
393
		$payment_methods = $payment_methods_response->get_payment_methods();
394
395
		// Limit to iDEAL payment methods.
396
		$payment_methods = array_filter(
397
			$payment_methods,
398
			/**
399
			 * Check if payment method is iDEAL.
400
			 *
401
			 * @param PaymentMethod $payment_method Payment method.
402
			 * @return boolean True if payment method is iDEAL, false otherwise.
403
			 */
404
			function( $payment_method ) {
405
				return ( PaymentMethodType::IDEAL === $payment_method->get_type() );
406
			}
407
		);
408
409
		foreach ( $payment_methods as $payment_method ) {
410
			$details = $payment_method->get_details();
411
412
			if ( is_array( $details ) ) {
413
				foreach ( $details as $detail ) {
414
					if ( 'issuer' === $detail->key && 'select' === $detail->type ) {
415
						foreach ( $detail->items as $item ) {
416
							$issuers[ $item->id ] = $item->name;
417
						}
418
					}
419
				}
420
			}
421
		}
422
423
		if ( empty( $issuers ) ) {
424
			return $issuers;
425
		}
426
427
		return array(
428
			array(
429
				'options' => $issuers,
430
			),
431
		);
432
	}
433
}
434