Failed Conditions
Push — develop ( 8c1843...7824fe )
by Reüel
07:49
created

src/Gateway.php (1 issue)

Labels
Severity
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 Pronamic\WordPress\Pay\Core\Gateway as Core_Gateway;
14
use Pronamic\WordPress\Pay\Core\Statuses as Core_Statuses;
15
use Pronamic\WordPress\Pay\Core\PaymentMethods;
16
use Pronamic\WordPress\Pay\Core\Util;
17
use Pronamic\WordPress\Pay\Payments\Payment;
18
use Pronamic\WordPress\Pay\Plugin;
19
20
/**
21
 * Gateway
22
 *
23
 * @author  Remco Tolsma
24
 * @version 1.0.0
25
 * @since   1.0.0
26
 * @link    https://github.com/adyenpayments/php/blob/master/generatepaymentform.php
27
 */
28
class Gateway extends Core_Gateway {
29
	/**
30
	 * Slug of this gateway.
31
	 *
32
	 * @var string
33
	 */
34
	const SLUG = 'adyen';
35
36
	/**
37
	 * Web SDK version.
38
	 *
39
	 * @link https://docs.adyen.com/developers/checkout/web-sdk/release-notes-web-sdk
40
	 *
41
	 * @var string
42
	 */
43
	const SDK_VERSION = '1.9.2';
44
45
	/**
46
	 * Client.
47
	 *
48
	 * @var Client
49
	 */
50
	protected $client;
51
52
	/**
53
	 * Constructs and initializes an Adyen gateway.
54
	 *
55
	 * @param Config $config Config.
56
	 */
57
	public function __construct( Config $config ) {
58
		parent::__construct( $config );
59
60
		$this->set_method( self::METHOD_HTTP_REDIRECT );
61
		$this->set_slug( self::SLUG );
62
63
		$this->client = new Client( $config->api_key, $config->api_live_url_prefix );
64
		$this->client->set_merchant_account( $config->merchant_account );
65
		$this->client->set_mode( $config->mode );
66
	}
67
68
	/**
69
	 * Get supported payment methods
70
	 *
71
	 * @see Core_Gateway::get_supported_payment_methods()
72
	 */
73
	public function get_supported_payment_methods() {
74
		return array(
75
			PaymentMethods::BANCONTACT,
76
			PaymentMethods::CREDIT_CARD,
77
			PaymentMethods::DIRECT_DEBIT,
78
			PaymentMethods::GIROPAY,
79
			PaymentMethods::IDEAL,
80
			PaymentMethods::MAESTRO,
81
			PaymentMethods::SOFORT,
82
		);
83
	}
84
85
	/**
86
	 * Start.
87
	 *
88
	 * @param Payment $payment Payment.
89
	 *
90
	 * @see Plugin::start()
91
	 */
92
	public function start( Payment $payment ) {
93
		// Amount.
94
		$amount = new Amount(
95
			$payment->get_total_amount()->get_currency()->get_alphabetic_code(),
96
			$payment->get_total_amount()->get_minor_units()
0 ignored issues
show
The method get_minor_units() does not exist on Pronamic\WordPress\Money\TaxedMoney. ( Ignorable by Annotation )

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

96
			$payment->get_total_amount()->/** @scrutinizer ignore-call */ get_minor_units()

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...
97
		);
98
99
		// Payment method. Take leap of faith for unknown payment methods.
100
		$type = PaymentMethodType::transform(
101
			$payment->get_method(),
102
			$payment->get_method()
103
		);
104
105
		$payment_method = new PaymentMethod( $type );
106
107
		switch ( $payment->get_method() ) {
108
			case PaymentMethods::IDEAL:
109
				$payment_method->issuer = $payment->get_issuer();
110
111
				break;
112
		}
113
114
		// Country.
115
		$locale = get_locale();
116
117
		if ( null !== $payment->get_customer() ) {
118
			$locale = $payment->get_customer()->get_locale();
119
		}
120
121
		$locale = explode( '_', $locale );
122
123
		$country_code = strtoupper( substr( $locale[1], 0, 2 ) );
124
125
		// Create payment or payment session request.
126
		switch ( $payment->get_method() ) {
127
			case PaymentMethods::IDEAL:
128
			case PaymentMethods::SOFORT:
129
				// API integration.
130
				$request = new PaymentRequest(
131
					$amount,
132
					$this->config->merchant_account,
133
					$payment->get_id(),
134
					$payment->get_return_url(),
135
					$payment_method
136
				);
137
138
				$request->set_country_code( $country_code );
139
140
				break;
141
			default:
142
				// Web SDK integration.
143
				$request = new PaymentSessionRequest(
144
					$amount,
145
					$this->config->merchant_account,
146
					$payment->get_id(),
147
					$payment->get_return_url(),
148
					$country_code
149
				);
150
151
				$request->set_origin( home_url() );
152
				$request->set_sdk_version( self::SDK_VERSION );
153
154
				// Set allowed payment methods.
155
				$allowed_methods = array( $type );
156
157
				// Add all available payment methods if no payment method is given.
158
				if ( empty( $type ) ) {
159
					$allowed_methods = array();
160
161
					foreach ( $this->get_available_payment_methods() as $method ) {
162
						$allowed_methods[] = PaymentMethodType::transform( $method );
163
					}
164
				}
165
166
				$request->set_allowed_payment_methods( $allowed_methods );
167
		}
168
169
		$request = PaymentRequestTransformer::transform( $payment, $request );
170
171
		// Create payment or payment session.
172
		if ( $request instanceof PaymentRequest ) {
173
			$result = $this->client->create_payment( $request );
174
		} else {
175
			$result = $this->client->create_payment_session( $request );
176
		}
177
178
		// Handle errors.
179
		if ( ! $result ) {
180
			$this->error = $this->client->get_error();
181
182
			return;
183
		}
184
185
		// Set checkout meta for Web SDK redirect.
186
		if ( isset( $result->paymentSession ) ) {
187
			$payment->set_meta(
188
				'adyen_checkout',
189
				array(
190
					'sdk_version' => self::SDK_VERSION,
191
					'payload'     => $result->paymentSession,
192
				)
193
			);
194
		}
195
196
		// Set transaction ID.
197
		if ( isset( $result->pspReference ) ) {
198
			$payment->set_transaction_id( $result->pspReference );
199
		}
200
201
		// Set action URL.
202
		$action_url = $payment->get_pay_redirect_url();
203
204
		if ( isset( $result->redirect->url ) ) {
205
			$action_url = $result->redirect->url;
206
		}
207
208
		$payment->set_action_url( $action_url );
209
	}
210
211
	/**
212
	 * Payment redirect.
213
	 *
214
	 * @param Payment $payment Payment.
215
	 *
216
	 * @return void
217
	 */
218
	public function payment_redirect( Payment $payment ) {
219
		$checkout = $payment->get_meta( 'adyen_checkout' );
220
221
		if ( empty( $checkout ) ) {
222
			return;
223
		}
224
225
		$url = sprintf(
226
			'https://checkoutshopper-%s.adyen.com/checkoutshopper/assets/js/sdk/checkoutSDK.%s.min.js',
227
			( self::MODE_TEST === $payment->get_mode() ? 'test' : 'live' ),
228
			$checkout['sdk_version']
229
		);
230
231
		wp_register_script(
232
			'pronamic-pay-adyen-checkout',
233
			$url,
234
			array(),
235
			$checkout['sdk_version'],
236
			false
237
		);
238
239
		// No cache.
240
		Util::no_cache();
241
242
		$context = ( self::MODE_TEST === $payment->get_mode() ? 'test' : 'live' );
243
244
		require __DIR__ . '/../views/checkout.php';
245
246
		exit;
247
	}
248
249
	/**
250
	 * Update status of the specified payment.
251
	 *
252
	 * @param Payment $payment Payment.
253
	 *
254
	 * @return void
255
	 */
256
	public function update_status( Payment $payment ) {
257
		// Maybe process stored webhook notification.
258
		$this->maybe_handle_notification( $payment );
259
260
		// Process payload on return.
261
		if ( ! filter_has_var( INPUT_GET, 'payload' ) ) {
262
			return;
263
		}
264
265
		$status = null;
266
267
		$payload = filter_input( INPUT_GET, 'payload', FILTER_SANITIZE_STRING );
268
269
		switch ( $payment->get_method() ) {
270
			case PaymentMethods::IDEAL:
271
			case PaymentMethods::SOFORT:
272
				$result = $this->client->get_payment_details( $payload );
273
274
				break;
275
			default:
276
				$result = $this->client->get_payment_result( $payload );
277
		}
278
279
		if ( $result ) {
280
			$status = ResultCode::transform( $result->resultCode );
281
282
			$psp_reference = $result->pspReference;
283
		}
284
285
		// Handle errors.
286
		if ( empty( $status ) ) {
287
			$payment->set_status( Core_Statuses::FAILURE );
288
289
			$this->error = $this->client->get_error();
290
291
			return;
292
		}
293
294
		// Update status.
295
		$payment->set_status( $status );
296
297
		// Update transaction ID.
298
		if ( isset( $psp_reference ) ) {
299
			$payment->set_transaction_id( $psp_reference );
300
		}
301
	}
302
303
	/**
304
	 * Maybe handle notification.
305
	 *
306
	 * @param Payment $payment      Payment.
307
	 */
308
	public function maybe_handle_notification( Payment $payment ) {
309
		$notification = $payment->get_meta( 'adyen_notification' );
310
311
		if ( empty( $notification ) ) {
312
			return;
313
		}
314
315
		$notification = json_decode( $notification );
316
317
		if ( ! is_object( $notification ) ) {
318
			return;
319
		}
320
321
		switch ( $notification->eventCode ) {
322
			case EventCode::AUTHORIZATION:
323
				$this->handle_authorization_event( $payment, $notification );
324
325
				break;
326
		}
327
328
		$payment->set_meta( 'adyen_notification', null );
329
	}
330
331
	/**
332
	 * Handle authorization event.
333
	 *
334
	 * @param Payment $payment      Payment.
335
	 * @param object  $notification Notification.
336
	 */
337
	public function handle_authorization_event( Payment $payment, $notification ) {
338
		if ( ! is_object( $notification ) ) {
339
			return;
340
		}
341
342
		$success = $notification->success;
343
344
		if ( 'true' === $success ) {
345
			$status = Core_Statuses::SUCCESS;
346
		} else {
347
			$status = Core_Statuses::FAILURE;
348
349
			// Add note.
350
			$note = sprintf(
351
				/* translators: %s: failure reason message */
352
				__( 'Failure reason: %s.', 'pronamic_ideal' ),
353
				esc_html( $notification->reason )
354
			);
355
356
			$payment->add_note( $note );
357
		}
358
359
		$payment->set_status( $status );
360
	}
361
362
	/**
363
	 * Get available payment methods.
364
	 *
365
	 * @see Core_Gateway::get_available_payment_methods()
366
	 */
367
	public function get_available_payment_methods() {
368
		$payment_methods = array();
369
370
		// Get active payment methods for Adyen account.
371
		$methods = $this->client->get_payment_methods();
372
373
		if ( ! $methods ) {
374
			$this->error = $this->client->get_error();
375
376
			return $payment_methods;
377
		}
378
379
		// Transform to WordPress payment methods.
380
		foreach ( $methods as $method => $details ) {
381
			$payment_method = PaymentMethodType::transform_gateway_method( $method );
382
383
			if ( $payment_method ) {
384
				$payment_methods[] = $payment_method;
385
			}
386
		}
387
388
		$payment_methods = array_unique( $payment_methods );
389
390
		return $payment_methods;
391
	}
392
393
	/**
394
	 * Get issuers.
395
	 *
396
	 * @see Pronamic_WP_Pay_Gateway::get_issuers()
397
	 */
398
	public function get_issuers() {
399
		$groups = array();
400
401
		$payment_method = PaymentMethodType::transform( PaymentMethods::IDEAL );
402
403
		$result = $this->client->get_issuers( $payment_method );
404
405
		if ( ! $result ) {
406
			$this->error = $this->client->get_error();
407
408
			return $groups;
409
		}
410
411
		$groups[] = array(
412
			'options' => $result,
413
		);
414
415
		return $groups;
416
	}
417
}
418