wp-pay-gateways/adyen

View on GitHub
src/WebSdkGateway.php

Summary

Maintainability
B
4 hrs
Test Coverage
<?php
/**
 * Web SDK gateway
 *
 * @author    Pronamic <info@pronamic.eu>
 * @copyright 2005-2022 Pronamic
 * @license   GPL-3.0-or-later
 * @package   Pronamic\WordPress\Pay\Gateways\Adyen
 */

namespace Pronamic\WordPress\Pay\Gateways\Adyen;

use Exception;
use InvalidArgumentException;
use Locale;
use Pronamic\WordPress\Pay\Core\Gateway as Core_Gateway;
use Pronamic\WordPress\Pay\Core\PaymentMethods;
use Pronamic\WordPress\Pay\Core\Util as Core_Util;
use Pronamic\WordPress\Pay\Payments\Payment;
use Pronamic\WordPress\Pay\Plugin;
use WP_Error;

/**
 * Web SDK gateway
 *
 * @link https://github.com/adyenpayments/php/blob/master/generatepaymentform.php
 *
 * @author  Remco Tolsma
 * @version 2.0.1
 * @since   1.0.0
 */
class WebSdkGateway extends AbstractGateway {
    /**
     * Web SDK version.
     *
     * @link https://docs.adyen.com/developers/checkout/web-sdk/release-notes-web-sdk
     *
     * @var string
     */
    const SDK_VERSION = '1.9.2';

    /**
     * Constructs and initializes an Adyen gateway.
     *
     * @param Config $config Config.
     */
    public function __construct( Config $config ) {
        parent::__construct( $config );

        // Supported features.
        $this->supports = array(
            'webhook_log',
            'webhook',
        );
    }

    /**
     * Get supported payment methods
     *
     * @see Core_Gateway::get_supported_payment_methods()
     *
     * @return array<string>
     */
    public function get_supported_payment_methods() {
        return array(
            PaymentMethods::BANCONTACT,
            PaymentMethods::CREDIT_CARD,
            PaymentMethods::DIRECT_DEBIT,
            PaymentMethods::GIROPAY,
            PaymentMethods::IDEAL,
            PaymentMethods::MAESTRO,
            PaymentMethods::SOFORT,
        );
    }

    /**
     * Start.
     *
     * @param Payment $payment Payment.
     * @return void
     * @throws \Exception Throws an exception when the shopper country cannot be determined.
     */
    public function start( Payment $payment ) {
        // Amount.
        $amount = AmountTransformer::transform( $payment->get_total_amount() );

        // Payment method type.
        $payment_method_type = PaymentMethodType::transform( $payment->get_payment_method() );

        // Country.
        $country_code = Util::get_country_code( $payment );

        /*
         * API Integration
         *
         * @link https://docs.adyen.com/api-explorer/#/PaymentSetupAndVerificationService/v41/payments
         */
        $api_integration_payment_method_types = array(
            PaymentMethodType::IDEAL,
            PaymentMethodType::DIRECT_EBANKING,
        );

        if ( in_array( $payment_method_type, $api_integration_payment_method_types, true ) ) {
            $payment_method = array(
                'type' => $payment_method_type,
            );

            if ( PaymentMethodType::IDEAL === $payment_method_type ) {
                $payment_method['issuer'] = (string) $payment->get_meta( 'issuer' );
            }

            // API integration.
            $payment_request = new PaymentRequest(
                $amount,
                $this->config->get_merchant_account(),
                (string) $payment->get_id(),
                $payment->get_return_url(),
                new PaymentMethod( (object) $payment_method )
            );

            $payment_request->set_country_code( $country_code );

            PaymentRequestHelper::complement( $payment, $payment_request );

            $payment_response = $this->client->create_payment( $payment_request );

            $payment->set_transaction_id( $payment_response->get_psp_reference() );

            $redirect = $payment_response->get_redirect();

            if ( null !== $redirect ) {
                $payment->set_action_url( $redirect->get_url() );
            }

            // Return early so SDK integration code will not be executed for API integration.
            return;
        }

        /**
         * The shopper country is required.
         * 
         * @link https://docs.adyen.com/api-explorer/#/CheckoutService/v67/post/paymentSession__reqParam_countryCode
         */
        if ( null === $country_code ) {
            throw new \Exception( 'Unable to determine shopper country.' );
        }

        /**
         * SDK Integration
         *
         * @link https://docs.adyen.com/api-explorer/#/PaymentSetupAndVerificationService/v41/paymentSession
         */
        $payment_session_request = new PaymentSessionRequest(
            $amount,
            $this->config->get_merchant_account(),
            (string) $payment->get_id(),
            $payment->get_return_url(),
            $country_code
        );

        PaymentRequestHelper::complement( $payment, $payment_session_request );

        // Origin.
        $origin = home_url();

        $origin_url = wp_parse_url( home_url() );

        if ( is_array( $origin_url ) && isset( $origin_url['scheme'], $origin_url['host'] ) ) {
            $origin = sprintf(
                '%s://%s',
                $origin_url['scheme'],
                $origin_url['host']
            );
        }

        $payment_session_request->set_origin( $origin );
        $payment_session_request->set_sdk_version( self::SDK_VERSION );

        if ( null !== $payment_method_type ) {
            $payment_session_request->set_allowed_payment_methods( array( $payment_method_type ) );
        }

        $payment_session_response = $this->client->create_payment_session( $payment_session_request );

        $payment->set_meta( 'adyen_sdk_version', self::SDK_VERSION );
        $payment->set_meta( 'adyen_payment_session', $payment_session_response->get_payment_session() );

        $payment->set_action_url( $payment->get_pay_redirect_url() );
    }

    /**
     * Payment redirect.
     *
     * @param Payment $payment Payment.
     * @return void
     */
    public function payment_redirect( Payment $payment ) {
        $sdk_version     = $payment->get_meta( 'adyen_sdk_version' );
        $payment_session = $payment->get_meta( 'adyen_payment_session' );

        if ( empty( $sdk_version ) || empty( $payment_session ) ) {
            return;
        }

        if ( empty( $payment->config_id ) ) {
            return;
        }

        $url = sprintf(
            'https://checkoutshopper-%s.adyen.com/checkoutshopper/assets/js/sdk/checkoutSDK.%s.min.js',
            ( self::MODE_TEST === $payment->get_mode() ? 'test' : 'live' ),
            $sdk_version
        );

        wp_register_script(
            'pronamic-pay-adyen-checkout',
            $url,
            array(
                'jquery',
            ),
            $sdk_version,
            false
        );

        /**
         * Config object.
         *
         * @link https://docs.adyen.com/checkout/web-sdk/
         * @link https://docs.adyen.com/checkout/web-sdk/customization/settings/
         * @link https://docs.adyen.com/checkout/web-sdk/customization/styling/#styling-the-card-fields
         */
        $config_object = (object) array(
            'context' => ( self::MODE_TEST === $payment->get_mode() ? 'test' : 'live' ),
        );

        /**
         * Filters the Adyen config object.
         *
         * @link https://github.com/wp-pay-gateways/adyen#pronamic_pay_adyen_config_object
         * @link https://docs.adyen.com/checkout/web-sdk/
         * @link https://docs.adyen.com/checkout/web-sdk/customization/settings/
         * @link https://docs.adyen.com/checkout/web-sdk/customization/styling/#styling-the-card-fields
         *
         * @param object $config_object Adyen config object.
         *
         * @since 1.1 Added.
         */
        $config_object = apply_filters( 'pronamic_pay_adyen_config_object', $config_object );

        wp_localize_script(
            'pronamic-pay-adyen-checkout',
            'pronamicPayAdyenCheckout',
            array(
                'paymentsResultUrl' => rest_url( Integration::REST_ROUTE_NAMESPACE . '/payments/result/' . $payment->config_id ),
                'paymentReturnUrl'  => $payment->get_return_url(),
                'paymentSession'    => $payment_session,
                'configObject'      => $config_object,
            )
        );

        // Add checkout head action.
        add_action( 'pronamic_pay_adyen_checkout_head', array( $this, 'checkout_head' ) );

        // No cache.
        Core_Util::no_cache();

        require __DIR__ . '/../views/checkout-web-sdk.php';

        exit;
    }

    /**
     * Checkout head.
     *
     * @return void
     */
    public function checkout_head() {
        wp_print_styles( 'pronamic-pay-redirect' );

        wp_print_scripts( 'pronamic-pay-adyen-checkout' );
    }

    /**
     * Update status of the specified payment.
     *
     * @param Payment $payment Payment.
     *
     * @return void
     */
    public function update_status( Payment $payment ) {
        // Process payload on return.
        if ( ! filter_has_var( INPUT_GET, 'payload' ) ) {
            return;
        }

        $payload = filter_input( INPUT_GET, 'payload', FILTER_SANITIZE_STRING );

        $payment_result_request = new PaymentResultRequest( $payload );

        try {
            $payment_result_response = $this->client->get_payment_result( $payment_result_request );

            PaymentResultHelper::update_payment( $payment, $payment_result_response );
        } catch ( Exception $e ) {
            $note = sprintf(
                /* translators: %s: exception message */
                __( 'Error getting payment result: %s', 'pronamic_ideal' ),
                $e->getMessage()
            );

            $payment->add_note( $note );
        }
    }
}