Test Failed
Push — develop ( fcc0f9...19b05e )
by Remco
05:00
created

WebSdkGateway::update_status()   A

Complexity

Conditions 3
Paths 4

Size

Total Lines 22
Code Lines 12

Duplication

Lines 0
Ratio 0 %

Importance

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