1368 lines
45 KiB
PHP
1368 lines
45 KiB
PHP
<?php
|
||
/**
|
||
* WC_Payment_Gateway_Revolut
|
||
*
|
||
* Abstract Revolut Payment Gateway
|
||
*
|
||
* @package WooCommerce
|
||
* @category Payment Gateways
|
||
* @author Revolut
|
||
* @since 2.0.0
|
||
*/
|
||
|
||
defined( 'ABSPATH' ) || exit();
|
||
|
||
if ( ! class_exists( 'WC_Payment_Gateway' ) ) {
|
||
return;
|
||
}
|
||
|
||
define( 'FAILED_CARD', 2005 );
|
||
|
||
/**
|
||
* WC_Payment_Gateway_Revolut class.
|
||
*/
|
||
abstract class WC_Payment_Gateway_Revolut extends WC_Payment_Gateway_CC {
|
||
|
||
|
||
use WC_Gateway_Revolut_Helper_Trait;
|
||
use WC_Gateway_Revolut_Express_Checkout_Helper_Trait;
|
||
|
||
/**
|
||
* API client
|
||
*
|
||
* @var WC_Revolut_API_Client
|
||
*/
|
||
public $api_client;
|
||
|
||
/**
|
||
* Revolut saved cards
|
||
*
|
||
* @var bool
|
||
*/
|
||
public $revolut_saved_cards = false;
|
||
|
||
/**
|
||
* Default payment gateway title
|
||
*
|
||
* @var string
|
||
*/
|
||
protected $default_title;
|
||
|
||
/**
|
||
* User friendly error message code
|
||
*
|
||
* @var int
|
||
*/
|
||
protected $user_friendly_error_message_code = 1000;
|
||
|
||
/**
|
||
* Available currency list
|
||
*
|
||
* @var array
|
||
*/
|
||
public $available_currency_list = array( 'AED', 'AUD', 'BGN', 'CAD', 'CHF', 'CZK', 'DKK', 'EUR', 'GBP', 'HKD', 'HUF', 'ILS', 'ISK', 'JPY', 'MXN', 'NOK', 'NZD', 'PLN', 'QAR', 'RON', 'SAR', 'SEK', 'SGD', 'THB', 'TRY', 'USD', 'ZAR' );
|
||
|
||
/**
|
||
* Card Payments available currency list
|
||
*
|
||
* @var array
|
||
*/
|
||
public $card_payments_currency_list = array( 'AUD', 'CAD', 'CHF', 'CZK', 'DKK', 'EUR', 'GBP', 'HKD', 'HUF', 'JPY', 'NOK', 'NZD', 'PLN', 'RON', 'SEK', 'SGD', 'USD', 'ZAR' );
|
||
|
||
/**
|
||
* Constructor
|
||
*/
|
||
public function __construct() {
|
||
$this->api_settings = revolut_wc()->api_settings;
|
||
$this->has_fields = true;
|
||
$this->icon = $this->get_icon();
|
||
|
||
$this->init_supports();
|
||
$this->init_form_fields();
|
||
$this->init_settings();
|
||
|
||
$this->api_client = new WC_Revolut_API_Client( $this->api_settings );
|
||
|
||
add_filter( 'wc_revolut_settings_nav_tabs', array( $this, 'admin_nav_tab' ) );
|
||
add_action( 'woocommerce_update_options_payment_gateways_' . $this->id, array( $this, 'process_admin_options' ) );
|
||
add_action( 'woocommerce_checkout_order_processed', array( $this, 'woocommerce_checkout_revolut_order_processed' ), 300, 3 );
|
||
add_action( 'woocommerce_order_status_changed', array( $this, 'order_action_from_woocommerce' ), 300, 3 );
|
||
}
|
||
|
||
/**
|
||
* Init required js and css assets
|
||
*/
|
||
protected function init_scripts() {
|
||
add_action( 'wp_enqueue_scripts', array( $this, 'wc_revolut_enqueue_scripts' ) );
|
||
}
|
||
|
||
/**
|
||
* Validates if the WooCommerce order created successfully.
|
||
*
|
||
* @since 2.0.0
|
||
*
|
||
* @param int $order_id The ID of the order.
|
||
* @param array $posted_data The ID of the order.
|
||
* @param WC_Order $order Created WC order.
|
||
*/
|
||
public function woocommerce_checkout_revolut_order_processed( $order_id, $posted_data, $order ) {
|
||
if ( ! $this->check_is_post_data_submitted( 'revolut_create_wc_order' ) || $posted_data['payment_method'] !== $this->id ) {
|
||
return;
|
||
}
|
||
|
||
try {
|
||
$billing_phone = $this->get_post_request_data( 'billing_phone' );
|
||
$billing_email = $this->get_post_request_data( 'billing_email' );
|
||
$revolut_customer_id = $this->get_or_create_revolut_customer( $billing_phone, $billing_email );
|
||
$this->update_revolut_customer( $revolut_customer_id, $billing_phone );
|
||
} catch ( Exception $e ) {
|
||
$this->log_error( 'creating revolut customer failed error : ' . $e->getMessage() );
|
||
}
|
||
|
||
WC()->session->set( 'order_awaiting_payment', $order_id );
|
||
|
||
$order_total = $order->get_total();
|
||
$order_currency = $order->get_currency();
|
||
$public_id = $this->get_post_request_data( 'revolut_public_id' );
|
||
$is_express_checkout = (bool) $this->get_post_request_data( 'is_express_checkout' );
|
||
$revolut_pay_redirected = (bool) $this->get_post_request_data( 'revolut_pay_redirected' );
|
||
|
||
if ( ! $is_express_checkout ) {
|
||
// update payment amount and currency after order creation in order to be sure that the payment will be exactly same with order.
|
||
$update_revolut_order_result = false;
|
||
try {
|
||
$update_revolut_order_result = $this->update_revolut_order_total( $order_total, $order_currency, $public_id );
|
||
} catch ( Exception $e ) {
|
||
$this->log_error( $e->getMessage() );
|
||
}
|
||
|
||
if ( ! $update_revolut_order_result ) {
|
||
wc_add_notice( __( 'Something went wrong while checking out. Payment was not taken. Please try again', 'revolut-gateway-for-woocommerce' ), 'error' );
|
||
|
||
wp_send_json(
|
||
array(
|
||
'refresh-checkout' => true,
|
||
'wc_order_id' => $order_id,
|
||
'result' => 'revolut_wc_order_created',
|
||
)
|
||
);
|
||
}
|
||
}
|
||
|
||
$this->maybe_cancel_previous_wc_order( $public_id, $order_id );
|
||
$revolut_order_id = $this->get_revolut_order_by_public_id( $public_id );
|
||
$this->save_wc_order_id( $public_id, $revolut_order_id, $order_id );
|
||
if ( ! $revolut_pay_redirected ) {
|
||
wp_send_json(
|
||
array(
|
||
'wc_order_id' => $order_id,
|
||
'reload' => isset( WC()->session->reload_checkout ),
|
||
'result' => 'revolut_wc_order_created',
|
||
)
|
||
);
|
||
}
|
||
}
|
||
|
||
/**
|
||
* Supported functionality
|
||
*/
|
||
public function init_supports() {
|
||
$this->supports = array(
|
||
'products',
|
||
);
|
||
}
|
||
|
||
/**
|
||
* Add default options
|
||
*/
|
||
public function add_default_options() {
|
||
try {
|
||
$this->update_option( 'title', $this->default_title );
|
||
$this->update_option( 'enabled', 'yes' );
|
||
} catch ( Exception $e ) {
|
||
$this->log_error( $e );
|
||
}
|
||
}
|
||
|
||
/**
|
||
* Display icon in checkout
|
||
*
|
||
* @abstract
|
||
*/
|
||
public function get_icon() {
|
||
}
|
||
|
||
/**
|
||
* Crate html widget for reward banner
|
||
*
|
||
* @return string
|
||
*/
|
||
public function get_upsell_banner_html() {
|
||
try {
|
||
$wc_order_id = (int) get_query_var( 'order-received' );
|
||
|
||
if ( $this->api_settings->get_option( 'disable_banner' ) !== 'yes' || ! $wc_order_id ) {
|
||
return '';
|
||
}
|
||
|
||
$wc_order = wc_get_order( $wc_order_id );
|
||
|
||
$transaction_id = $wc_order->get_transaction_id() ? $wc_order->get_transaction_id() : $wc_order_id;
|
||
$payment_method = $wc_order->get_payment_method();
|
||
$customer_phone = $wc_order->get_billing_phone();
|
||
$customer_email = $wc_order->get_billing_email();
|
||
$order_currency = $wc_order->get_currency();
|
||
$revolut_payment_public_id = $wc_order->get_meta( 'revolut_payment_public_id', true );
|
||
$public_key = $this->get_merchant_public_api_key();
|
||
$locale = $this->get_lang_iso_code();
|
||
|
||
$enrollment_confirmation_banner = "<div id='upsellEnrollmentConfirmationBanner'
|
||
data-banner-locale='" . $locale . "'
|
||
data-banner-phone='" . $customer_phone . "'
|
||
data-banner-email='" . $customer_email . "'
|
||
data-banner-order-public-id='" . $revolut_payment_public_id . "'
|
||
data-banner-merchant-public-key='" . $public_key . "'></div>";
|
||
|
||
$promotional_banner = "<div id='upsellPromotionalBanner'
|
||
data-banner-transaction-id='" . $transaction_id . "'
|
||
data-banner-phone='" . $customer_phone . "'
|
||
data-banner-currency='" . $order_currency . "'
|
||
data-banner-merchant-public-key='" . $public_key . "'
|
||
data-banner-locale='" . $locale . "'
|
||
data-banner-email='" . $customer_email . "' ></div>";
|
||
|
||
switch ( $payment_method ) {
|
||
case WC_Gateway_Revolut_Pay::GATEWAY_ID:
|
||
case WC_Gateway_Revolut_Payment_Request::GATEWAY_ID:
|
||
return '';
|
||
case WC_Gateway_Revolut_CC::GATEWAY_ID:
|
||
return $enrollment_confirmation_banner;
|
||
default:
|
||
return $promotional_banner;
|
||
}
|
||
} catch ( Exception $e ) {
|
||
$this->log_error( 'get_upsell_banner_html : ', $e->getMessage() );
|
||
}
|
||
|
||
return '';
|
||
}
|
||
|
||
/**
|
||
* Add script to load card form
|
||
*/
|
||
public function wc_revolut_enqueue_scripts() {
|
||
wp_register_style( 'revolut-custom-style', plugins_url( 'assets/css/style.css', WC_REVOLUT_MAIN_FILE ), array(), WC_GATEWAY_REVOLUT_VERSION );
|
||
wp_enqueue_style( 'revolut-custom-style' );
|
||
|
||
wp_enqueue_script( 'revolut-core', $this->api_client->base_url . '/embed.js', false, WC_GATEWAY_REVOLUT_VERSION, true );
|
||
wp_enqueue_script( 'revolut-upsell', $this->api_client->base_url . '/upsell/embed.js', false, WC_GATEWAY_REVOLUT_VERSION, true );
|
||
|
||
wp_enqueue_script( 'jquery' );
|
||
wp_enqueue_script(
|
||
'revolut-woocommerce',
|
||
plugins_url( 'assets/js/revolut.js', WC_REVOLUT_MAIN_FILE ),
|
||
array(
|
||
'revolut-core',
|
||
'revolut-upsell',
|
||
'jquery',
|
||
),
|
||
WC_GATEWAY_REVOLUT_VERSION,
|
||
true
|
||
);
|
||
|
||
wp_localize_script(
|
||
'revolut-woocommerce',
|
||
'wc_revolut',
|
||
array(
|
||
'ajax_url' => WC_AJAX::get_endpoint( '%%wc_revolut_gateway_ajax_endpoint%%' ),
|
||
'page' => $this->wc_revolut_get_current_page(),
|
||
'order_id' => $this->wc_revolut_get_current_order_id(),
|
||
'order_key' => $this->wc_revolut_get_current_order_key(),
|
||
'promotion_banner_html' => $this->get_upsell_banner_html(),
|
||
'nonce' => array(
|
||
'billing_info' => wp_create_nonce( 'wc-revolut-get-billing-info' ),
|
||
'customer_info' => wp_create_nonce( 'wc-revolut-get-customer-info' ),
|
||
'get_order_public_id' => wp_create_nonce( 'wc-revolut-get-order-public-id' ),
|
||
),
|
||
)
|
||
);
|
||
}
|
||
|
||
/**
|
||
* Check the current page
|
||
*/
|
||
public function wc_revolut_get_current_page() {
|
||
global $wp;
|
||
if ( is_product() ) {
|
||
return 'product';
|
||
}
|
||
if ( is_cart() ) {
|
||
return 'cart';
|
||
}
|
||
if ( is_checkout() ) {
|
||
if ( ! empty( $wp->query_vars['order-pay'] ) ) {
|
||
return 'order_pay';
|
||
}
|
||
|
||
return 'checkout';
|
||
}
|
||
if ( is_add_payment_method_page() ) {
|
||
return 'add_payment_method';
|
||
}
|
||
|
||
return '';
|
||
}
|
||
|
||
/**
|
||
* Get current order id on 'order_pay' page
|
||
*/
|
||
public function wc_revolut_get_current_order_id() {
|
||
global $wp;
|
||
if ( is_checkout() ) {
|
||
if ( ! empty( $wp->query_vars['order-pay'] ) && absint( $wp->query_vars['order-pay'] ) > 0 ) {
|
||
return absint( $wp->query_vars['order-pay'] );
|
||
|
||
}
|
||
}
|
||
return '';
|
||
}
|
||
|
||
/**
|
||
* Get current order key
|
||
*/
|
||
public function wc_revolut_get_current_order_key() {
|
||
$order_id = $this->wc_revolut_get_current_order_id();
|
||
if ( $order_id ) {
|
||
$order = wc_get_order( $order_id );
|
||
return $order->get_order_key();
|
||
}
|
||
return '';
|
||
}
|
||
|
||
/**
|
||
* Send order action request from Woocommerce to API.
|
||
*
|
||
* @param String $revolut_order_id Revolut order id.
|
||
* @param String $action Api action.
|
||
* @param array|object|null $body Request body.
|
||
*
|
||
* @return mixed
|
||
* @throws Exception Exception.
|
||
*/
|
||
public function action_revolut_order( $revolut_order_id, $action, $body = null ) {
|
||
if ( empty( $revolut_order_id ) ) {
|
||
return array();
|
||
}
|
||
|
||
$json = $this->api_client->post( "/orders/$revolut_order_id/$action", $body );
|
||
|
||
if ( ! empty( $json ) && ! isset( $json['id'] ) && isset( $json['code'] ) ) {
|
||
if ( ! empty( $json['code'] ) && FAILED_CARD === $json['code'] ) {
|
||
/* translators: %s: Order Action. */
|
||
throw new Exception( sprintf( __( 'Customer will not be able to get a %s using this card!', 'revolut-gateway-for-woocommerce' ), $action ) );
|
||
}
|
||
|
||
/* translators:%1s: Order Action. %$2s: Order Action.*/
|
||
throw new Exception( sprintf( __( 'Cannot %1$s Order - Error Id: %2$s.', 'revolut-gateway-for-woocommerce' ), $action, $json['code'] ) );
|
||
}
|
||
|
||
return $json;
|
||
}
|
||
|
||
/**
|
||
* Add public_id field and logo on card form.
|
||
*
|
||
* @abstract
|
||
* @param String $public_id Revolut public id.
|
||
* @param String $merchant_public_key Revolut public key.
|
||
* @param String $display_tokenization Available saved card tokens.
|
||
*
|
||
* @return string
|
||
*/
|
||
public function generate_inline_revolut_form( $public_id, $merchant_public_key, $display_tokenization ) {
|
||
return '';
|
||
}
|
||
/**
|
||
* Add save checkbox on payment form
|
||
*
|
||
* @abstract
|
||
*
|
||
* @return string
|
||
*/
|
||
public function save_payment_method_checkbox() {
|
||
return '';
|
||
}
|
||
|
||
/**
|
||
* Check if save action requested for the payment method.
|
||
*
|
||
* @abstract
|
||
*
|
||
* @return bool
|
||
*/
|
||
public function save_payment_method_requested() {
|
||
return false;
|
||
}
|
||
|
||
/**
|
||
* Check if saved payment method requested for making the payment.
|
||
*
|
||
* @abstract
|
||
*
|
||
* @return bool
|
||
*/
|
||
public function is_using_saved_payment_method() {
|
||
return false;
|
||
}
|
||
|
||
/**
|
||
* Add update checkbox on payment form
|
||
*
|
||
* @abstract
|
||
*
|
||
* @return string
|
||
*/
|
||
public function display_update_subs_payment_checkout() {
|
||
return '';
|
||
}
|
||
|
||
/**
|
||
* Save Payment method
|
||
*
|
||
* @param int $order_id The ID of the order.
|
||
*
|
||
* @return WC_Payment_Token_CC
|
||
* @throws Exception Exception.
|
||
*/
|
||
public function save_payment_method( $order_id ) {
|
||
// get revolut customer ID from Revolut order.
|
||
$revolut_order = null;
|
||
for ( $i = 0; $i <= 9; $i++ ) {
|
||
$revolut_order = $this->api_client->get( '/orders/' . $order_id );
|
||
if ( isset( $revolut_order['customer_id'] ) && ! empty( $revolut_order['customer_id'] ) && 'PROCESSING' !== $revolut_order['state'] ) {
|
||
$revolut_customer_id = $revolut_order['customer_id'];
|
||
break;
|
||
}
|
||
sleep( 2 );
|
||
}
|
||
|
||
if ( empty( $revolut_customer_id ) ) {
|
||
throw new Exception( 'An error occurred while saving the card' );
|
||
}
|
||
|
||
if ( ! $this->get_revolut_customer_id() ) {
|
||
$this->insert_revolut_customer_id( $revolut_customer_id );
|
||
}
|
||
|
||
$revolut_customer = $this->api_client->get( '/customers/' . $revolut_customer_id );
|
||
|
||
if ( empty( $revolut_customer['payment_methods'] ) || 0 === count( $revolut_customer['payment_methods'] ) ) {
|
||
throw new Exception( 'Can not save Payment Methods through API' );
|
||
}
|
||
|
||
$payment_methods = $revolut_customer['payment_methods'];
|
||
$exist_tokens = WC_Payment_Tokens::get_customer_tokens( get_current_user_id(), $this->id );
|
||
$stored_tokens = array();
|
||
|
||
foreach ( $exist_tokens as $token ) {
|
||
$stored_tokens[ $token->get_token() ] = $token;
|
||
}
|
||
|
||
if ( empty( $revolut_order ) ) {
|
||
$revolut_order = $this->api_client->get( '/orders/' . $order_id );
|
||
}
|
||
|
||
$current_payment_list = isset( $revolut_order['payments'] ) && ! empty( $revolut_order['payments'] ) ? $revolut_order['payments'] : array();
|
||
$current_token = null;
|
||
|
||
foreach ( $payment_methods as $payment_method ) {
|
||
|
||
if ( in_array( $payment_method['id'], array_keys( $stored_tokens ), true ) ) {
|
||
continue;
|
||
}
|
||
|
||
$token = new WC_Payment_Token_CC();
|
||
$token->set_token( $payment_method['id'] );
|
||
$token->set_gateway_id( $this->id );
|
||
$method_details = $payment_method['method_details'];
|
||
$card_type = $payment_method['type'];
|
||
$current_payment = self::searchListKeyValue( $current_payment_list, 'id', $payment_method['id'] );
|
||
|
||
if ( isset( $current_payment['payment_method'] )
|
||
&& isset( $current_payment['payment_method']['card'] )
|
||
&& isset( $current_payment['payment_method']['card']['card_brand'] ) ) {
|
||
$card_type = $current_payment['payment_method']['card']['card_brand'];
|
||
}
|
||
|
||
$token->set_card_type( $card_type );
|
||
$token->set_last4( $method_details['last4'] );
|
||
$token->set_expiry_month( $method_details['expiry_month'] );
|
||
$token->set_expiry_year( $method_details['expiry_year'] );
|
||
$token->set_user_id( get_current_user_id() );
|
||
$token->save();
|
||
$current_token = $token;
|
||
}
|
||
|
||
return $current_token;
|
||
}
|
||
|
||
/**
|
||
* Add new Payment method
|
||
*
|
||
* @throws Exception Exception.
|
||
*/
|
||
public function add_payment_method() {
|
||
try {
|
||
// find public_id.
|
||
$revolut_payment_public_id = $this->get_post_request_data( 'revolut_public_id' );
|
||
if ( empty( $revolut_payment_public_id ) ) {
|
||
throw new Exception( 'Missing revolut_public_id parameter' );
|
||
}
|
||
|
||
// resolve revolut_public_id into revolut_order_id.
|
||
$revolut_order_id = $this->get_revolut_order_by_public_id( $revolut_payment_public_id );
|
||
if ( empty( $revolut_order_id ) ) {
|
||
throw new Exception( 'Missing revolut order id parameter' );
|
||
}
|
||
|
||
$wc_token = $this->save_payment_method( $revolut_order_id );
|
||
if ( null === $wc_token ) {
|
||
throw new Exception( 'An error occurred while saving payment method' );
|
||
}
|
||
|
||
$this->handle_add_payment_method( null, $wc_token, get_current_user_id() );
|
||
|
||
return array(
|
||
'result' => 'success',
|
||
'redirect' => wc_get_endpoint_url( 'payment-methods' ),
|
||
);
|
||
|
||
} catch ( Exception $e ) {
|
||
$this->log_error( $e );
|
||
|
||
wc_add_notice( $e->getMessage(), 'error' );
|
||
return false;
|
||
}
|
||
}
|
||
|
||
/**
|
||
* Process the payment and return the result.
|
||
*
|
||
* @param int $wc_order_id WooCommerce order id.
|
||
*
|
||
* @return array
|
||
*
|
||
* @throws Exception Exception.
|
||
*/
|
||
public function process_payment( $wc_order_id ) {
|
||
$wc_order = wc_get_order( $wc_order_id );
|
||
|
||
try {
|
||
// find public_id.
|
||
$is_express_checkout = (bool) $this->get_posted_integer_data( 'is_express_checkout' );
|
||
$revolut_payment_public_id = $this->get_post_request_data( 'revolut_public_id' );
|
||
if ( empty( $revolut_payment_public_id ) ) {
|
||
throw new Exception( 'Missing revolut_public_id parameter' );
|
||
}
|
||
|
||
$revolut_payment_error = $this->get_post_request_data( 'revolut_payment_error' );
|
||
|
||
if ( empty( $revolut_payment_error ) ) {
|
||
$revolut_payment_error = $this->get_request_data( '_rp_fr' );
|
||
}
|
||
|
||
if ( ! empty( $revolut_payment_error ) ) {
|
||
throw new Exception( $revolut_payment_error, $this->user_friendly_error_message_code );
|
||
}
|
||
|
||
// resolve revolut_public_id into revolut_order_id.
|
||
$revolut_order_id = $this->get_revolut_order_by_public_id( $revolut_payment_public_id );
|
||
if ( empty( $revolut_order_id ) ) {
|
||
throw new Exception( 'Can not find Revolut order ID' );
|
||
}
|
||
|
||
// express checkout are the manual orders needs to be captured during processing.
|
||
if ( $is_express_checkout && 'authorize_and_capture' === $this->api_settings->get_option( 'payment_action' ) ) {
|
||
$this->action_revolut_order( $revolut_order_id, 'capture' );
|
||
}
|
||
|
||
// check if it needs to process payment with previously saved method.
|
||
$previously_saved_wc_token = $this->maybe_pay_by_saved_method( $revolut_order_id );
|
||
|
||
$this->save_wc_order_id( $revolut_payment_public_id, $revolut_order_id, $wc_order_id );
|
||
|
||
// payment should be processed until this point, if not throw an error.
|
||
$this->check_payment_processed( $revolut_order_id );
|
||
// payment process began...
|
||
$wc_order->update_status( 'on-hold' );
|
||
$wc_order->add_order_note( 'Payment has been successfully authorized (Order ID: ' . $revolut_order_id . ').' );
|
||
|
||
// check payment result and update order status.
|
||
$this->handle_revolut_order_result( $wc_order, $revolut_order_id );
|
||
// check save method requested.
|
||
$newly_saved_wc_token = $this->maybe_save_payment_method( $revolut_order_id, $wc_order );
|
||
// check if there is any saved or used payment token.
|
||
$wc_token = null;
|
||
if ( $previously_saved_wc_token ) {
|
||
$wc_token = $previously_saved_wc_token;
|
||
} else {
|
||
$wc_token = $newly_saved_wc_token;
|
||
}
|
||
|
||
update_post_meta( $wc_order_id, 'revolut_payment_public_id', $revolut_payment_public_id );
|
||
$this->save_payment_token_to_order( $wc_order, $wc_token, get_current_user_id() );
|
||
$this->verify_order_total( $revolut_order_id, $wc_order );
|
||
$this->update_payment_method_title( $revolut_order_id, $wc_order );
|
||
|
||
return $this->checkout_return( $wc_order, $revolut_order_id );
|
||
} catch ( Exception $e ) {
|
||
$this->log_error( $e->getMessage() );
|
||
$wc_order->update_status( 'failed' );
|
||
$wc_order->add_order_note( 'Customer attempted to pay, but the payment failed or got declined. (Error: ' . $e->getMessage() . ')' );
|
||
$error_message_for_user = 'Something went wrong';
|
||
if ( $e->getCode() === $this->user_friendly_error_message_code ) {
|
||
$error_message_for_user = $e->getMessage();
|
||
}
|
||
|
||
// if page will be reloaded add the error message as notice, otherwise they're lost in the page reload.
|
||
if ( $this->get_posted_integer_data( 'reload_checkout' ) || $this->get_posted_integer_data( 'revolut_pay_redirected' ) ) {
|
||
unset( WC()->session->reload_checkout );
|
||
wc_add_notice( $error_message_for_user, 'error' );
|
||
}
|
||
|
||
return array(
|
||
'messages' => $error_message_for_user,
|
||
'result' => 'fail',
|
||
'redirect' => '',
|
||
);
|
||
}
|
||
}
|
||
|
||
/**
|
||
* Process the payment and return the result.
|
||
*
|
||
* @param string $revolut_order_id Revolut order id.
|
||
* @param WC_Order $wc_order WooCommerce order.
|
||
*/
|
||
protected function update_payment_method_title( $revolut_order_id, $wc_order ) {
|
||
try {
|
||
if ( 'revolut_payment_request' !== $this->id ) {
|
||
return;
|
||
}
|
||
$revolut_order = $this->api_client->get( '/orders/' . $revolut_order_id );
|
||
$revolut_order_total = $this->get_revolut_order_amount( $revolut_order );
|
||
$revolut_order_currency = $this->get_revolut_order_currency( $revolut_order );
|
||
|
||
if ( empty( $revolut_order_total ) || empty( $revolut_order_currency ) ) {
|
||
/* translators: %s: Revolut order id. */
|
||
$wc_order->add_order_note( sprintf( __( 'Can\'t retrieve payment amount for this order. Please check your Revolut Business account (Order ID: %s)', 'revolut-gateway-for-woocommerce' ), $revolut_order_id ) );
|
||
return;
|
||
}
|
||
|
||
if ( ! isset( $revolut_order['payments'][0]['payment_method']['type'] ) || empty( $revolut_order['payments'][0]['payment_method']['type'] ) ) {
|
||
return;
|
||
}
|
||
|
||
$payment_method = $revolut_order['payments'][0]['payment_method']['type'];
|
||
|
||
if ( 'APPLE_PAY' === $payment_method ) {
|
||
$payment_method_title = 'Apple Pay (via Revolut)';
|
||
} elseif ( 'GOOGLE_PAY' === $payment_method ) {
|
||
$payment_method_title = 'Google Pay (via Revolut)';
|
||
} else {
|
||
$payment_method_title = $this->title;
|
||
}
|
||
|
||
$wc_order->set_payment_method_title( $payment_method_title );
|
||
$wc_order->save();
|
||
} catch ( Exception $e ) {
|
||
$this->log_error( $e->getMessage() );
|
||
}
|
||
}
|
||
|
||
/**
|
||
* Verify is paid amount and order total are equal
|
||
*
|
||
* @param string $revolut_order_id Revolut order id.
|
||
* @param WC_Order $wc_order WooCommerce order.
|
||
*
|
||
* @throws Exception Exception.
|
||
*/
|
||
protected function verify_order_total( $revolut_order_id, $wc_order ) {
|
||
$revolut_order = $this->api_client->get( '/orders/' . $revolut_order_id );
|
||
$revolut_order_total = $this->get_revolut_order_amount( $revolut_order );
|
||
$revolut_order_currency = $this->get_revolut_order_currency( $revolut_order );
|
||
|
||
if ( empty( $revolut_order_total ) || empty( $revolut_order_currency ) ) {
|
||
/* translators: %s: Revolut order id. */
|
||
$wc_order->add_order_note( sprintf( __( 'Can\'t retrieve payment amount for this order. Please check your Revolut Business account (Order ID: %s)', 'revolut-gateway-for-woocommerce' ), $revolut_order_id ) );
|
||
return;
|
||
}
|
||
|
||
$wc_order_currency = $wc_order->get_currency();
|
||
$wc_order_total = $this->get_revolut_order_total( $wc_order->get_total(), $wc_order_currency );
|
||
|
||
if ( $wc_order_total !== $revolut_order_total || strtolower( $revolut_order_currency ) !== strtolower( $wc_order_currency ) ) {
|
||
if ( abs( $wc_order_total - $revolut_order_total ) < 50 ) {
|
||
return;
|
||
}
|
||
|
||
$wc_order_total = $this->get_wc_order_total( $wc_order_total, $wc_order_currency );
|
||
$revolut_order_total = $this->get_wc_order_total( $revolut_order_total, $revolut_order_currency );
|
||
|
||
$order_message = '<b>Difference detected between order and payment total.</b> Please verify order with the customer. (Order ID: ' . $revolut_order_id . ').';
|
||
$order_message .= ' Order Total: ' . $wc_order_total . strtoupper( $wc_order_currency );
|
||
$order_message .= ' Paid amount: ' . $revolut_order_total . strtoupper( $revolut_order_currency );
|
||
|
||
$wc_order->update_status( 'on-hold' );
|
||
$wc_order->add_order_note( wp_kses_post( $order_message ) );
|
||
}
|
||
}
|
||
|
||
/**
|
||
* Update internal table to avoid piggybacking on already paid order.
|
||
*
|
||
* @param string $public_id Revolut public id.
|
||
* @param string $revolut_order_id Revolut order id.
|
||
* @param int $wc_order_id WooCommerce order id.
|
||
*
|
||
* @throws Exception Exception.
|
||
*/
|
||
protected function save_wc_order_id( $public_id, $revolut_order_id, $wc_order_id ) {
|
||
try {
|
||
global $wpdb;
|
||
|
||
$exist_wc_order_id = $wpdb->get_row( $wpdb->prepare( 'SELECT wc_order_id FROM ' . $wpdb->prefix . 'wc_revolut_orders WHERE wc_order_id=%d', array( $wc_order_id ) ), ARRAY_A ); // db call ok; no-cache ok.
|
||
|
||
if ( ! empty( $exist_wc_order_id ) && ! empty( $exist_wc_order_id['wc_order_id'] ) ) {
|
||
$updated_rows = $wpdb->query(
|
||
$wpdb->prepare(
|
||
'UPDATE ' . $wpdb->prefix . "wc_revolut_orders
|
||
SET order_id=UNHEX(REPLACE(%s, '-', '')), public_id=UNHEX(REPLACE(%s, '-', ''))
|
||
WHERE wc_order_id=%d",
|
||
array( $revolut_order_id, $public_id, $wc_order_id )
|
||
)
|
||
); // db call ok; no-cache ok.
|
||
} else {
|
||
$updated_rows = $wpdb->query(
|
||
$wpdb->prepare(
|
||
'UPDATE ' . $wpdb->prefix . 'wc_revolut_orders
|
||
SET wc_order_id=%d
|
||
WHERE public_id=UNHEX(REPLACE(%s, "-", ""))',
|
||
array( $wc_order_id, $public_id )
|
||
)
|
||
); // db call ok; no-cache ok.
|
||
}
|
||
|
||
if ( 1 !== $updated_rows && ! empty( $wpdb->last_error ) ) {
|
||
$this->log_error( 'Can not update wc_order_id for Revolut order record on DB: ' . $wpdb->last_error );
|
||
return false;
|
||
}
|
||
|
||
$body = array(
|
||
'merchant_order_ext_ref' => $wc_order_id,
|
||
);
|
||
|
||
$this->api_client->patch( "/orders/$revolut_order_id", $body );
|
||
} catch ( Exception $e ) {
|
||
$this->log_error( $e->getMessage() );
|
||
}
|
||
}
|
||
|
||
/**
|
||
* Cancel previous WC order if there is a new one
|
||
*
|
||
* @param string $public_id Revolut public id.
|
||
* @param int $new_wc_order_id WooCommerce order id.
|
||
*
|
||
* @throws Exception Exception.
|
||
*/
|
||
protected function maybe_cancel_previous_wc_order( $public_id, $new_wc_order_id ) {
|
||
try {
|
||
global $wpdb;
|
||
$current_wc_order = $wpdb->get_row( $wpdb->prepare( 'SELECT wc_order_id FROM ' . $wpdb->prefix . 'wc_revolut_orders WHERE public_id=UNHEX(REPLACE(%s, "-", ""))', array( $public_id ) ), ARRAY_A ); // db call ok; no-cache ok.
|
||
|
||
if ( empty( $current_wc_order ) || empty( (int) $current_wc_order['wc_order_id'] ) ) {
|
||
return true;
|
||
}
|
||
|
||
$current_wc_order_id = (int) $current_wc_order['wc_order_id'];
|
||
|
||
if ( empty( $current_wc_order_id ) || $current_wc_order_id === $new_wc_order_id ) {
|
||
return true;
|
||
}
|
||
|
||
$wc_order = wc_get_order( $current_wc_order_id );
|
||
|
||
if ( ! $wc_order->get_id() ) {
|
||
return true;
|
||
}
|
||
|
||
$wc_order->update_status( 'cancelled' );
|
||
|
||
} catch ( Exception $e ) {
|
||
$this->log_error( $e->getMessage() );
|
||
}
|
||
}
|
||
|
||
/**
|
||
* Update WooCommerce Order status based on payment result.
|
||
*
|
||
* @param WC_Order $wc_order WooCommerce order.
|
||
* @param string $revolut_order_id Revolut order id.
|
||
*
|
||
* @throws Exception Exception.
|
||
*/
|
||
protected function handle_revolut_order_result( $wc_order, $revolut_order_id ) {
|
||
$wc_order_id = $wc_order->get_id();
|
||
|
||
// verify that the order was paid.
|
||
$mode = $this->api_settings->get_option( 'payment_action' );
|
||
|
||
for ( $i = 0; $i < WC_REVOLUT_FETCH_API_ORDER_ATTEMPTS; $i++ ) {
|
||
if ( isset( $revolut_order_id ) && ! empty( $revolut_order_id ) ) {
|
||
$order = $this->api_client->get( '/orders/' . $revolut_order_id );
|
||
$wc_order_status = empty( $wc_order->get_status() ) ? '' : $wc_order->get_status();
|
||
$check_wc_status = 'processing' === $wc_order_status || 'completed' === $wc_order_status;
|
||
if ( isset( $order['state'] ) && ! $check_wc_status ) {
|
||
if ( 'COMPLETED' === $order['state'] && 'authorize_and_capture' === $mode ) {
|
||
update_post_meta( $wc_order_id, 'revolut_capture', 'yes' );
|
||
$wc_order->payment_complete( $revolut_order_id );
|
||
$wc_order->add_order_note( 'Payment has been successfully captured (Order ID: ' . $revolut_order_id . ').' );
|
||
return true;
|
||
} elseif ( 'AUTHORISED' === $order['state'] && 'authorize' === $mode ) {
|
||
return true;
|
||
} elseif ( 'PENDING' === $order['state'] ) {
|
||
$wc_order->add_order_note( 'Something went wrong while completing this payment. Please reach out to your customer and ask them to try again.' );
|
||
throw new Exception( 'Something went wrong while completing this payment.' );
|
||
} elseif ( 9 === $i && ( 'AUTHORISED' === $order['state'] || 'PROCESSING' === $order['state'] || 'IN_SETTLEMENT' === $order['state'] ) ) {
|
||
if ( 'authorize_and_capture' === $mode ) {
|
||
$wc_order->add_order_note(
|
||
'Payment is taking a bit longer than expected to be completed.
|
||
If the order is not moved to the “Processing” state after 24h, please check your Revolut account to verify that this payment was taken.
|
||
You might need to contact your customer if it wasn’t.'
|
||
);
|
||
}
|
||
|
||
return true;
|
||
}
|
||
|
||
sleep( WC_REVOLUT_WAIT_FOR_ORDER_TIME );
|
||
} elseif ( $check_wc_status ) {
|
||
return true;
|
||
}
|
||
} else {
|
||
throw new Exception( 'Revolut order ID is missing' );
|
||
}
|
||
}
|
||
|
||
return true;
|
||
}
|
||
|
||
/**
|
||
* Check is Payment processed.
|
||
*
|
||
* @param string $revolut_order_id Revolut order id.
|
||
*
|
||
* @throws Exception Exception.
|
||
*/
|
||
protected function check_payment_processed( $revolut_order_id ) {
|
||
if ( $this->is_pending_payment( $revolut_order_id ) ) {
|
||
throw new Exception( 'Something went wrong while completing this payment. Please try again.' );
|
||
}
|
||
}
|
||
|
||
/**
|
||
* Build payment fields area - including fields for logged-in users, and the payment fields.
|
||
*/
|
||
public function payment_fields() {
|
||
if ( 'sandbox' === $this->api_settings->get_option( 'mode' ) ) {
|
||
if ( 'revolut_cc' === $this->id ) {
|
||
echo wp_kses_post( "<p style='color:red'>The payment gateway is in Sandbox Mode. You can use our <a href='https://developer.revolut.com/docs/guides/accept-payments/get-started/test-in-the-sandbox-environment/test-cards' target='_blank'>test cards</a> to simulate different payment scenarios." );
|
||
} elseif ( 'revolut_pay' === $this->id ) {
|
||
echo wp_kses_post( "<p style='color:red'>The payment gateway is in Sandbox Mode." );
|
||
}
|
||
}
|
||
|
||
if ( ! $this->check_currency_support() ) {
|
||
$this->currency_support_error();
|
||
return false;
|
||
}
|
||
|
||
$public_id = $this->get_revolut_public_id();
|
||
$revolut_customer_id = $this->get_or_create_revolut_customer();
|
||
$descriptor = new WC_Revolut_Order_Descriptor( WC()->cart->get_total( '' ), get_woocommerce_currency(), $revolut_customer_id );
|
||
$display_tokenization = ! empty( $revolut_customer_id ) && $this->supports( 'tokenization' ) && ( is_checkout() || $this->get_request_data( 'pay_for_order' ) ) && $this->revolut_saved_cards;
|
||
|
||
if ( $display_tokenization ) {
|
||
try {
|
||
$this->normalize_payment_methods( $revolut_customer_id );
|
||
} catch ( Exception $e ) {
|
||
$display_tokenization = false;
|
||
$this->log_error( $e->getMessage() );
|
||
}
|
||
}
|
||
|
||
$merchant_public_key = $this->get_merchant_public_api_key();
|
||
|
||
try {
|
||
if ( empty( $public_id ) || is_add_payment_method_page() ) {
|
||
$public_id = $this->create_revolut_order( $descriptor );
|
||
} else {
|
||
$public_id = $this->update_revolut_order( $descriptor, $public_id );
|
||
}
|
||
|
||
$this->set_revolut_public_id( $public_id );
|
||
|
||
if ( $display_tokenization ) {
|
||
$this->tokenization_script();
|
||
$this->saved_payment_methods();
|
||
}
|
||
|
||
echo wp_kses(
|
||
$this->generate_inline_revolut_form( $public_id, $merchant_public_key, $display_tokenization ),
|
||
array_merge(
|
||
array(
|
||
'input' => array(
|
||
'id' => array(),
|
||
'type' => array(),
|
||
'name' => array(),
|
||
'value' => array(),
|
||
'checked' => array(),
|
||
'class' => array(),
|
||
'placeholder' => array(),
|
||
'style' => array(),
|
||
),
|
||
),
|
||
wp_kses_allowed_html( 'post' )
|
||
)
|
||
);
|
||
echo wp_kses(
|
||
$this->save_payment_method_checkbox(),
|
||
array(
|
||
'label' => array(
|
||
'style' => array(),
|
||
'for' => array(),
|
||
),
|
||
'input' => array(
|
||
'id' => array(),
|
||
'type' => array(),
|
||
'name' => array(),
|
||
'value' => array(),
|
||
'checked' => array(),
|
||
'style' => array(),
|
||
),
|
||
'p' => array(
|
||
'class' => array(),
|
||
),
|
||
)
|
||
);
|
||
echo wp_kses_post( $this->display_update_subs_payment_checkout() );
|
||
} catch ( Exception $e ) {
|
||
$this->log_error( $e->getMessage() );
|
||
echo wp_kses_post( 'To receive payments using the Revolut Gateway for WooCommerce plugin, please <a href="https://developer.revolut.com/docs/accept-payments/#plugins-plugins-woocommerce-configure-the-woocommerce-plugin" target="_blank">configure your API key</a>.<br><br>If you are still seeing this message after the configuration of your API key, please reach out via the support chat in your Revolut Business account.' );
|
||
}
|
||
}
|
||
|
||
/**
|
||
* Remove Payment Tokens which are not available in the API.
|
||
*
|
||
* @param string $revolut_customer_id Revolut customer id.
|
||
*
|
||
* @throws Exception Exception.
|
||
*/
|
||
protected function normalize_payment_methods( $revolut_customer_id ) {
|
||
$exist_tokens = WC_Payment_Tokens::get_customer_tokens( get_current_user_id(), $this->id );
|
||
|
||
if ( empty( $exist_tokens ) ) {
|
||
return array();
|
||
}
|
||
|
||
$revolut_customer = $this->api_client->get( '/customers/' . $revolut_customer_id );
|
||
|
||
if ( ! isset( $revolut_customer['id'] ) || empty( $revolut_customer['id'] ) ) {
|
||
$this->remove_all_payment_tokens( $exist_tokens );
|
||
throw new Exception( 'Can not find Revolut Customer' );
|
||
}
|
||
|
||
if ( ! isset( $revolut_customer['payment_methods'] ) || empty( $revolut_customer['payment_methods'] ) ) {
|
||
$this->remove_all_payment_tokens( $exist_tokens );
|
||
throw new Exception( 'Revolut Customer does not have any saved payment methods' );
|
||
}
|
||
|
||
$saved_revolut_payment_tokens = array_column( $revolut_customer['payment_methods'], 'id' );
|
||
|
||
foreach ( $exist_tokens as $wc_token ) {
|
||
$wc_token_id = $wc_token->get_id();
|
||
$wc_payment_token = $wc_token->get_token();
|
||
if ( ! in_array( $wc_payment_token, $saved_revolut_payment_tokens, true ) ) {
|
||
WC_Payment_Tokens::delete( $wc_token_id );
|
||
}
|
||
}
|
||
}
|
||
|
||
/**
|
||
* Clear all saved payment tokens.
|
||
*
|
||
* @param array $exist_tokens list of payment tokens.
|
||
*/
|
||
public function remove_all_payment_tokens( $exist_tokens ) {
|
||
if ( empty( $exist_tokens ) ) {
|
||
return;
|
||
}
|
||
|
||
foreach ( $exist_tokens as $wc_token ) {
|
||
$wc_token_id = $wc_token->get_id();
|
||
WC_Payment_Tokens::delete( $wc_token_id );
|
||
}
|
||
}
|
||
|
||
/**
|
||
* Check is order needs to paid with the saved payment method.
|
||
*
|
||
* @param string $revolut_order_id Revolut order id.
|
||
*/
|
||
protected function maybe_pay_by_saved_method( $revolut_order_id ) {
|
||
if ( $this->is_using_saved_payment_method() ) {
|
||
$wc_token = $this->get_selected_payment_token();
|
||
return $this->pay_by_saved_method( $revolut_order_id, $wc_token );
|
||
}
|
||
|
||
return null;
|
||
}
|
||
|
||
/**
|
||
* Charge customer with previously saved payment method.
|
||
*
|
||
* @param string $revolut_order_id Revolut order id.
|
||
* @param WC_Payment_Token_CC $wc_token WooCommerce payment token.
|
||
*/
|
||
protected function pay_by_saved_method( $revolut_order_id, $wc_token ) {
|
||
$payment_method_id = $wc_token->get_token();
|
||
|
||
$body = array(
|
||
'payment_method_id' => $payment_method_id,
|
||
);
|
||
|
||
$this->action_revolut_order( $revolut_order_id, 'confirm', $body );
|
||
return $wc_token;
|
||
}
|
||
|
||
/**
|
||
* Check if the payment methods should be saved.
|
||
*
|
||
* @param string $revolut_order_id Revolut order id.
|
||
* @param WC_Order $wc_order WooCommerce order.
|
||
*/
|
||
protected function maybe_save_payment_method( $revolut_order_id, $wc_order ) {
|
||
if ( $this->save_payment_method_requested() && ! $this->is_using_saved_payment_method() ) {
|
||
try {
|
||
return $this->save_payment_method( $revolut_order_id );
|
||
} catch ( Exception $e ) {
|
||
$wc_order->add_order_note( 'Card save process failed. (Error: ' . $e->getMessage() . ')' );
|
||
}
|
||
}
|
||
return null;
|
||
}
|
||
|
||
/**
|
||
* Check if the payment methods should be saved.
|
||
*
|
||
* @param WC_Order $order WooCommerce order.
|
||
* @param WC_Payment_Token_CC $wc_token WooCommerce payment token.
|
||
* @param int $wc_customer_id WooCommerce customer id.
|
||
*
|
||
* @throws Exception Exception.
|
||
*/
|
||
protected function save_payment_token_to_order( $order, $wc_token, $wc_customer_id ) {
|
||
if ( null !== $wc_token && ! empty( $wc_token->get_id() ) ) {
|
||
$id_payment_token = $wc_token->get_id();
|
||
$order_id = $order->get_id();
|
||
|
||
if ( empty( $id_payment_token ) || empty( $order_id ) ) {
|
||
throw new Exception( 'Can not save payment into order meta' );
|
||
}
|
||
|
||
$order->update_meta_data( '_payment_token', $wc_token->get_token() );
|
||
$order->update_meta_data( '_payment_token_id', $id_payment_token );
|
||
$order->update_meta_data( '_wc_customer_id', $wc_customer_id );
|
||
|
||
if ( is_callable( array( $order, 'save' ) ) ) {
|
||
$order->save();
|
||
}
|
||
|
||
// Also store it on the subscriptions being purchased or paid for in the order.
|
||
if ( function_exists( 'wcs_order_contains_subscription' ) && wcs_order_contains_subscription( $order_id ) ) {
|
||
$subscriptions = wcs_get_subscriptions_for_order( $order_id );
|
||
} elseif ( function_exists( 'wcs_order_contains_renewal' ) && wcs_order_contains_renewal( $order_id ) ) {
|
||
$subscriptions = wcs_get_subscriptions_for_renewal_order( $order_id );
|
||
} else {
|
||
$subscriptions = array();
|
||
}
|
||
|
||
foreach ( $subscriptions as $subscription ) {
|
||
$subscription_id = $subscription->get_id();
|
||
update_post_meta( $subscription_id, '_payment_token', $wc_token->get_token() );
|
||
update_post_meta( $subscription_id, '_payment_token_id', $id_payment_token );
|
||
update_post_meta( $subscription_id, '_wc_customer_id', $wc_customer_id );
|
||
}
|
||
}
|
||
}
|
||
|
||
/**
|
||
* Updates all active subscriptions payment method.
|
||
*
|
||
* @abstract
|
||
*
|
||
* @param WC_Subscription $current_subscription WooCommerce Subscription.
|
||
* @param object $wc_token WooCommerce Payment Token.
|
||
* @param int $wc_customer_id WooCommerce Customer id.
|
||
* @return bool
|
||
*/
|
||
public function handle_add_payment_method( $current_subscription, $wc_token, $wc_customer_id ) {
|
||
return false;
|
||
}
|
||
|
||
/**
|
||
* Grab selected payment token from Request
|
||
*
|
||
* @abstract
|
||
*
|
||
* @return String
|
||
*/
|
||
public function get_selected_payment_token() {
|
||
return '';
|
||
}
|
||
|
||
/**
|
||
* Return after checkout successfully.
|
||
*
|
||
* @param int $wc_order WooCommerce order id.
|
||
* @param String $revolut_order_id Revolut order id.
|
||
*
|
||
* @return array
|
||
*/
|
||
public function checkout_return( $wc_order, $revolut_order_id ) {
|
||
$this->clear_temp_session( $revolut_order_id );
|
||
$this->unset_revolut_public_id();
|
||
$this->unset_revolut_express_checkout_public_id();
|
||
if ( isset( WC()->cart ) ) {
|
||
WC()->cart->empty_cart();
|
||
}
|
||
|
||
if ( $this->get_posted_integer_data( 'revolut_pay_redirected' ) ) {
|
||
wp_safe_redirect( $this->get_return_url( $wc_order ) );
|
||
exit;
|
||
}
|
||
|
||
return array(
|
||
'result' => 'success',
|
||
'redirect' => $this->get_return_url( $wc_order ),
|
||
);
|
||
}
|
||
|
||
/**
|
||
* Clear temporary payment session.
|
||
*
|
||
* @param String $revolut_order_id Revolut order id.
|
||
*
|
||
* @return void
|
||
*/
|
||
public function clear_temp_session( $revolut_order_id ) {
|
||
global $wpdb;
|
||
$wpdb->delete( $wpdb->prefix . 'wc_revolut_temp_session', array( 'order_id' => $revolut_order_id ) ); // db call ok; no-cache ok.
|
||
}
|
||
|
||
/**
|
||
* Add admin notice when use revolut payment without API key
|
||
*/
|
||
public function admin_notices() {
|
||
if ( 'yes' !== $this->get_option( 'enabled' )
|
||
|| ! empty( $this->api_client->api_key ) ) {
|
||
return;
|
||
}
|
||
|
||
if ( empty( $this->api_client->api_key ) ) {
|
||
echo wp_kses_post(
|
||
'<div class="error revolut-passphrase-message"><p>'
|
||
. __( 'Revolut requires an API Key to work.', 'revolut-gateway-for-woocommerce' )
|
||
. '</p></div>'
|
||
);
|
||
}
|
||
}
|
||
|
||
/**
|
||
* Handle Order action from Woocommerce to API.
|
||
*
|
||
* @param int $order_id WooCommerce Order Id.
|
||
* @param String $old_status WooCommerce Order Status.
|
||
* @param String $new_status WooCommerce Order Status.
|
||
*
|
||
* @throws Exception Exception.
|
||
*/
|
||
public function order_action_from_woocommerce( $order_id, $old_status, $new_status ) {
|
||
$wc_order = wc_get_order( $order_id );
|
||
$revolut_order_id = $this->get_revolut_order( $order_id );
|
||
|
||
if ( ! empty( $revolut_order_id ) && in_array( $wc_order->get_payment_method(), WC_REVOLUT_GATEWAYS, true ) && $this->check_is_order_has_capture_status( $new_status ) ) {
|
||
$order = $this->api_client->get( '/orders/' . $revolut_order_id );
|
||
$state = isset( $order['state'] ) ? $order['state'] : '';
|
||
|
||
// check fraud order.
|
||
$order_amount = $this->get_revolut_order_amount( $order );
|
||
$currency = $this->get_revolut_order_currency( $order );
|
||
$total = $this->get_revolut_order_total( $wc_order->get_total(), $currency );
|
||
|
||
if ( $total !== $order_amount ) {
|
||
$wc_order->add_order_note( __( 'Order amount can\'t be partially captured. Please try again or capture this payment from your Revolut Business web portal.', 'revolut-gateway-for-woocommerce' ) );
|
||
}
|
||
|
||
if ( 'AUTHORISED' === $state ) {
|
||
$this->action_revolut_order( $revolut_order_id, 'capture' );
|
||
$order_response = $this->api_client->get( '/orders/' . $revolut_order_id );
|
||
|
||
if ( 'COMPLETED' === $order_response['state'] || 'IN_SETTLEMENT' === $order_response['state'] ) {
|
||
$wc_order->payment_complete( $revolut_order_id );
|
||
$wc_order->add_order_note( __( 'Payment amount has been captured successfully.', 'revolut-gateway-for-woocommerce' ) );
|
||
update_post_meta( $order_id, 'revolut_capture', 'yes' );
|
||
} else {
|
||
$wc_order->add_order_note( __( 'Order capture wasn\'t successful. Please try again or check your Revolut Business web portal for more information', 'revolut-gateway-for-woocommerce' ) );
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
/**
|
||
* Get Revolut Order from database
|
||
*
|
||
* @param String $order_id Revolut Order Id.
|
||
*
|
||
* @return string|string[]|null
|
||
*/
|
||
public function get_revolut_order( $order_id ) {
|
||
global $wpdb;
|
||
|
||
$revolut_order_id = $this->uuid_dashes(
|
||
$wpdb->get_col(
|
||
$wpdb->prepare(
|
||
'SELECT HEX(order_id) FROM ' . $wpdb->prefix . 'wc_revolut_orders
|
||
WHERE wc_order_id=%s',
|
||
array( $order_id )
|
||
)
|
||
)
|
||
); // db call ok; no-cache ok.
|
||
|
||
return $revolut_order_id;
|
||
}
|
||
|
||
/**
|
||
* Process a refund if supported.
|
||
*
|
||
* @param int $order_id Order ID.
|
||
* @param float $amount Refund amount.
|
||
* @param string $reason Refund reason.
|
||
*
|
||
* @return bool|WP_Error
|
||
* @throws Exception Exception.
|
||
*/
|
||
public function process_refund( $order_id, $amount = null, $reason = '' ) {
|
||
$wc_order = wc_get_order( $order_id );
|
||
|
||
if ( ! $this->can_refund_order( $wc_order ) ) {
|
||
return new WP_Error( 'error', __( 'Order can\'t be refunded.', 'woocommerce' ) );
|
||
}
|
||
|
||
$revolut_order_id = $this->get_revolut_order( $order_id );
|
||
|
||
if ( ! isset( $revolut_order_id ) ) {
|
||
throw new Exception( __( 'Can\'t retrieve order information right now. Please try again later or process the refund via your Revolut Business account.', 'revolut-gateway-for-woocommerce' ) );
|
||
} else {
|
||
$order = $this->api_client->get( '/orders/' . $revolut_order_id );
|
||
if ( 'PAYMENT' === $order['type'] && 'COMPLETED' === $order['state'] || 'IN_SETTLEMENT' === $order['state'] ) {
|
||
if ( $order['refunded_amount']['value'] === $order['order_amount']['value'] ) {
|
||
throw new Exception( __( 'The amount remaining for this order is less than the amount being refunded. Please check your Revolut Business account.', 'revolut-gateway-for-woocommerce' ) );
|
||
}
|
||
|
||
$amount = round( $amount, 2 );
|
||
$currency = $this->get_revolut_order_currency( $order );
|
||
if ( $this->is_zero_decimal( $currency ) && ( $amount - floor( $amount ) ) > 0 ) {
|
||
throw new Exception( __( 'Revolut: Can\'t refund this amount for this order. Please check your Revolut Business account.', 'revolut-gateway-for-woocommerce' ) );
|
||
}
|
||
$refund_amount = $this->get_revolut_order_total( $amount, $currency );
|
||
$refund_amount_api = (float) $order['refunded_amount']['value'];
|
||
$order_amount_api = $this->get_revolut_order_amount( $order );
|
||
|
||
if ( $refund_amount_api < $order_amount_api && $refund_amount <= $order_amount_api - $refund_amount_api ) {
|
||
$body = array(
|
||
'amount' => $refund_amount,
|
||
'currency' => $wc_order->get_currency(),
|
||
'description' => $reason,
|
||
);
|
||
$response = $this->action_revolut_order( $revolut_order_id, 'refund', $body );
|
||
if ( isset( $response['id'] ) && ! empty( $response['id'] ) ) {
|
||
/* translators: %s: Revolut refund id. */
|
||
$wc_order->add_order_note( sprintf( __( 'Order has been successfully refunded (Refund ID: %s).', 'revolut-gateway-for-woocommerce' ), $response['id'] ) );
|
||
|
||
return true;
|
||
}
|
||
} else {
|
||
throw new Exception( __( 'Revolut: This amount can\'t be refunded for this order. Please check your Revolut Business account.', 'revolut-gateway-for-woocommerce' ) );
|
||
}
|
||
} else {
|
||
throw new Exception( __( 'Revolut: Incomplete order can\'t be refunded', 'revolut-gateway-for-woocommerce' ) );
|
||
}
|
||
}
|
||
|
||
return false;
|
||
}
|
||
|
||
/**
|
||
* Add setting tab to admin configuration.
|
||
*
|
||
* @param array $tabs setting tabs.
|
||
*/
|
||
public function admin_nav_tab( $tabs ) {
|
||
$tabs[ $this->id ] = $this->tab_title;
|
||
|
||
return $tabs;
|
||
}
|
||
|
||
/**
|
||
* Check is currency supported.
|
||
*/
|
||
public function check_currency_support() {
|
||
if ( ! in_array( get_woocommerce_currency(), $this->available_currency_list, true ) ) {
|
||
return false;
|
||
}
|
||
return true;
|
||
}
|
||
|
||
/**
|
||
* Add currency not supported error.
|
||
*/
|
||
public function currency_support_error() {
|
||
echo wp_kses_post( get_woocommerce_currency() . ' currency is not supported, please use a different currency to check out. You can check the supported currencies in the <a href="https://www.revolut.com/en-HR/business/help/merchant-accounts/payments/in-which-currencies-can-i-accept-payments" target="_blank">[following link]</a>' );
|
||
}
|
||
|
||
/**
|
||
* Search in multidimensional array by key and value pair.
|
||
*
|
||
* @param array $list list for search.
|
||
* @param string $skey search key.
|
||
* @param mixed $svalue search value.
|
||
*/
|
||
public function searchListKeyValue( $list, $skey, $svalue ) {
|
||
foreach ( $list as $element ) {
|
||
if ( isset( $element['payment_method'] ) ) {
|
||
foreach ( $element['payment_method'] as $key => $value ) {
|
||
if ( $key === $skey && $svalue === $value ) {
|
||
return $element;
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
return null;
|
||
}
|
||
}
|