first commit

This commit is contained in:
2026-03-05 13:07:40 +01:00
commit 64ba0721ee
25709 changed files with 4691006 additions and 0 deletions

View File

@@ -0,0 +1,13 @@
Copyright 2020 Revolut Ltd
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.

View File

@@ -0,0 +1,208 @@
<?php
/**
* Revolut_Webhook_Controller
*
* Controller for handling Revolut webhook callbacks
*
* @package WooCommerce
* @category Payment Gateways
* @author Revolut
* @since 2.0.0
*/
/**
* Revolut_Webhook_Controller class
*/
class Revolut_Webhook_Controller extends \WC_REST_Data_Controller {
use WC_Gateway_Revolut_Helper_Trait;
use WC_Gateway_Revolut_Express_Checkout_Helper_Trait;
/**
* Endpoint namespace.
*
* @var string
*/
protected $namespace = 'wc/v3';
/**
* Route base.
*
* @var string
*/
protected $rest_base = 'revolut';
/**
* Constructor
*/
public function __construct() {
$this->api_settings = revolut_wc()->api_settings;
$this->api_client = new WC_Revolut_API_Client( $this->api_settings );
}
/**
* Register routes.
*
* @since 3.5.0
*/
public function register_routes() {
register_rest_route(
$this->namespace,
'/' . $this->rest_base,
array(
'methods' => \WP_REST_Server::ALLMETHODS,
'callback' => array( $this, 'handle_revolut_webhook_callbacks' ),
'permission_callback' => array( $this, 'handle_revolut_webhook_callbacks_permissions_check' ),
)
);
}
/**
* Revolut webhook callback request
*
* @param WP_REST_Request $request WP REST Request.
*
* @return WP_Error|WP_REST_Response
*/
public function handle_revolut_webhook_callbacks( $request ) {
$parameters = $request->get_params();
$order_id = '';
$event = '';
$this->log_info( 'start handle_revolut_webhook_callbacks' );
$this->log_info( $parameters );
if ( in_array( 'shipping_address', array_keys( $parameters ), true ) ) {
$this->convert_revolut_order_metadata_into_wc_session( $parameters['order_id'] );
$requested_address = $parameters['shipping_address'];
$requested_address['address'] = $requested_address['street_line_1'];
$requested_address['address_2'] = '';
$requested_address['state'] = ! empty( $requested_address['region'] ) ? $requested_address['region'] : '';
$country = $requested_address['country'];
$postcode = $requested_address['postcode'];
$postcode = wc_format_postcode( $postcode, $country );
$is_valid_postcode = WC_Validation::is_postcode( $postcode, $country );
if ( ! $is_valid_postcode ) {
$this->log_info( 'Invalid postcode info: ' . $postcode );
return new WP_REST_Response(
array(
'valid' => false,
'delivery_methods' => array(),
),
200
);
}
$shipping_options = $this->get_shipping_options( $requested_address );
$this->log_info(
array(
'wc_order_total' => WC()->cart->get_total( '' ),
'get_current_user_id' => get_current_user_id(),
'valid' => (bool) count( $shipping_options ),
'delivery_methods' => $shipping_options,
)
);
return new WP_REST_Response(
array(
'valid' => (bool) count( $shipping_options ),
'delivery_methods' => $shipping_options,
),
200
);
}
if ( isset( $parameters['order_id'] ) && isset( $parameters['event'] ) ) {
$order_id = $parameters['order_id'];
$event = $parameters['event'];
}
if ( empty( $order_id ) ) {
$parameters = $request->get_body();
$parameters = json_decode( $parameters, true );
if ( isset( $parameters['order_id'] ) && isset( $parameters['event'] ) ) {
$order_id = $parameters['order_id'];
$event = $parameters['event'];
}
}
if ( empty( $order_id ) ) {
return new WP_REST_Response( array( 'status' => 'Failed' ), 400 );
}
$wc_order_id = $this->get_wc_order_id( $order_id );
if ( empty( $wc_order_id ) || empty( $wc_order_id['wc_order_id'] ) ) {
return new WP_REST_Response( array( 'status' => 'Failed' ), 404 );
}
// force webhook callback to wait, in order to be sure that the main payment process has ended.
$wait_for_main_process_time = ( WC_REVOLUT_WAIT_FOR_ORDER_TIME * 4 );
sleep( $wait_for_main_process_time );
$wc_order = wc_get_order( $wc_order_id['wc_order_id'] );
if ( ! $wc_order ) {
return new WP_REST_Response( array( 'status' => 'Failed' ), 422 );
}
$wc_order_status = empty( $wc_order->get_status() ) ? '' : $wc_order->get_status();
$check_wc_status = 'processing' === $wc_order_status || 'completed' === $wc_order_status;
$check_capture = isset( get_post_meta( $wc_order_id['wc_order_id'], 'revolut_capture' )[0] ) ? get_post_meta( $wc_order_id['wc_order_id'], 'revolut_capture' )[0] : '';
$data = array();
if ( 'yes' !== $check_capture ) {
if ( ! empty( $wc_order ) && empty( $wc_order->get_transaction_id() ) && ! $check_wc_status ) {
if ( 'ORDER_COMPLETED' === $event ) {
/* translators: %s: Revolut Order ID. */
$wc_order->add_order_note( sprintf( __( 'Payment has been successfully captured (Order ID: %s)', 'revolut-gateway-for-woocommerce' ), $order_id ) );
$wc_order->payment_complete( $order_id );
update_post_meta( $wc_order_id['wc_order_id'], 'revolut_capture', 'yes' );
$data = array(
'status' => 'OK',
'response' => 'Completed',
);
} else {
$data = array(
'status' => 'Failed',
);
}
}
} else {
$data = array(
'status' => 'Failed',
);
}
return new WP_REST_Response( $data, 200 );
}
/**
* Permissions check
*
* @param WP_REST_Request $request Full details about the request.
*
* @return bool
*/
public function handle_revolut_webhook_callbacks_permissions_check( $request = null ) {
return true;
}
/**
* Get Woocommerce Order ID
*
* @param String $order_id Revolut order id.
*
* @return array|object|void|null
*/
public function get_wc_order_id( $order_id ) {
global $wpdb;
return $wpdb->get_row( $wpdb->prepare( 'SELECT wc_order_id FROM ' . $wpdb->prefix . "wc_revolut_orders WHERE order_id=UNHEX(REPLACE(%s, '-', ''))", array( $order_id ) ), ARRAY_A ); // db call ok; no-cache ok.
}
}

View File

@@ -0,0 +1,26 @@
#woocommerce-revolut-card-element{
border-radius: 3px;
padding: 5px 5px;
}
#revolut-upsell-banner {
margin-top: 5px;
}
.hidden_by_revolut {
display: none !important;
}
.revolut-payment-method-save label {
display: inline !important;
}
.revolut-error {
margin-top: 5px;
}
.revolut-pay {
height: auto;
}
.revolut-card-gateway-icon-amex {
display: none;
}

View File

@@ -0,0 +1,12 @@
<svg width="94" height="17" viewBox="0 0 94 17" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M1.68302 12V9.714H3.22202C4.49102 9.714 5.30102 8.895 5.30102 7.689C5.30102 6.519 4.50902 5.7 3.22202 5.7H0.900024V12H1.68302ZM1.68302 6.411H3.12302C3.96902 6.411 4.49102 6.879 4.49102 7.689C4.49102 8.535 3.99602 8.994 3.12302 8.994H1.68302V6.411Z" fill="#8B959E"/>
<path d="M7.92129 12.081C9.36129 12.081 10.0003 11.019 10.0003 9.705C10.0003 8.382 9.34329 7.32 7.92129 7.32C6.49929 7.32 5.84229 8.382 5.84229 9.705C5.84229 11.028 6.48129 12.081 7.92129 12.081ZM7.92129 11.406C6.99429 11.406 6.60729 10.695 6.60729 9.705C6.60729 8.724 6.98529 7.995 7.92129 7.995C8.85729 7.995 9.23529 8.715 9.23529 9.705C9.23529 10.695 8.85729 11.406 7.92129 11.406Z" fill="#8B959E"/>
<path d="M12.534 12L13.641 8.427H13.677L14.757 12H15.54L16.836 7.491V7.401H16.071L15.153 10.974H15.117L14.037 7.401H13.263L12.183 10.974H12.147L11.229 7.401H10.446V7.491L11.751 12H12.534Z" fill="#8B959E"/>
<path d="M19.374 12.081C20.355 12.081 21.165 11.514 21.291 10.668H20.535C20.409 11.154 19.977 11.406 19.374 11.406C18.519 11.406 18.078 10.803 18.078 9.93H21.354V9.561C21.354 8.283 20.661 7.32 19.365 7.32C17.943 7.32 17.286 8.373 17.286 9.705C17.286 11.055 18.015 12.081 19.374 12.081ZM18.087 9.3C18.114 8.58 18.501 7.995 19.365 7.995C20.184 7.995 20.571 8.571 20.571 9.3H18.087Z" fill="#8B959E"/>
<path d="M23.1878 12V9.768C23.1878 8.688 23.5838 8.076 24.4568 8.076H24.8168V7.347H24.4028C23.8358 7.347 23.3768 7.662 23.1878 8.175H23.1518L23.0888 7.401H22.4318V12H23.1878Z" fill="#8B959E"/>
<path d="M27.3109 12.081C28.2919 12.081 29.1019 11.514 29.2279 10.668H28.4719C28.3459 11.154 27.9139 11.406 27.3109 11.406C26.4559 11.406 26.0149 10.803 26.0149 9.93H29.2909V9.561C29.2909 8.283 28.5979 7.32 27.3019 7.32C25.8799 7.32 25.2229 8.373 25.2229 9.705C25.2229 11.055 25.9519 12.081 27.3109 12.081ZM26.0239 9.3C26.0509 8.58 26.4379 7.995 27.3019 7.995C28.1209 7.995 28.5079 8.571 28.5079 9.3H26.0239Z" fill="#8B959E"/>
<path d="M31.9617 12.081C32.6457 12.081 33.1047 11.766 33.3477 11.361H33.3837L33.4827 12H34.1397V5.34H33.3837V8.04H33.3477C33.1047 7.635 32.6457 7.32 31.9617 7.32C30.6657 7.32 30.0177 8.337 30.0087 9.696C30.0177 11.181 30.7557 12.081 31.9617 12.081ZM32.0877 11.406C31.1337 11.406 30.7737 10.623 30.7737 9.696C30.7737 8.778 31.1337 7.995 32.0877 7.995C33.0057 7.995 33.4017 8.787 33.4017 9.696C33.4017 10.614 33.0057 11.406 32.0877 11.406Z" fill="#8B959E"/>
<path d="M40.1847 12.081C41.3907 12.081 42.1287 11.181 42.1377 9.696C42.1287 8.337 41.4807 7.32 40.1847 7.32C39.5007 7.32 39.0417 7.635 38.7987 8.04H38.7627V5.34H38.0067V12H38.6637L38.7627 11.361H38.7987C39.0417 11.766 39.5007 12.081 40.1847 12.081ZM40.0587 11.406C39.1407 11.406 38.7447 10.614 38.7447 9.696C38.7447 8.787 39.1407 7.995 40.0587 7.995C41.0127 7.995 41.3727 8.778 41.3727 9.696C41.3727 10.623 41.0127 11.406 40.0587 11.406Z" fill="#8B959E"/>
<path d="M44.3326 14.061L46.8796 7.491V7.401H46.0875L44.7375 11.01H44.7015L43.3065 7.401H42.4965V7.491L44.3415 11.946L44.3505 11.964L43.5676 13.971V14.061H44.3326Z" fill="#8B959E"/>
<path fill-rule="evenodd" clip-rule="evenodd" d="M59.0134 13.0369L56.793 9.12191C58.1976 8.60604 58.8939 7.70677 58.8939 6.39711C58.8954 4.79652 57.6336 3.77778 55.6244 3.77778H51.6981V13.0369H53.4318V9.28037H54.9032L57.0304 13.0369H59.0134ZM55.6244 5.31189C56.6488 5.31189 57.1613 5.72178 57.1613 6.52858C57.1613 7.33537 56.6483 7.74526 55.6244 7.74526H53.4318V5.31189H55.6244ZM82.044 13.0371V3.9604H80.3892V13.0371H82.044ZM78.5549 7.06465C77.8585 6.44281 77.018 6.13889 76.0461 6.13889C75.0876 6.13889 74.247 6.44331 73.5502 7.06465C72.8538 7.673 72.5 8.51977 72.5 9.60449C72.5 10.6892 72.8538 11.5355 73.5502 12.1574C74.2465 12.7657 75.0876 13.0701 76.0461 13.0701C77.018 13.0701 77.8585 12.7657 78.5549 12.1574C79.2646 11.5355 79.6185 10.6892 79.6185 9.60449C79.6185 8.51977 79.2641 7.673 78.5549 7.06465ZM74.7332 10.9931C74.366 10.6362 74.1811 10.1729 74.1811 9.60449C74.1811 9.03565 74.3645 8.57276 74.7332 8.22885C75.1005 7.87195 75.5346 7.69998 76.0456 7.69998C76.557 7.69998 77.0041 7.87195 77.3719 8.22885C77.752 8.57276 77.9368 9.03565 77.9368 9.60449C77.9368 10.1733 77.7535 10.6362 77.3719 10.9931C77.0046 11.3371 76.5576 11.509 76.0456 11.509C75.5346 11.509 75.1015 11.3371 74.7332 10.9931ZM87.3855 10.0976V6.47599H89.0443V10.3755C89.0443 11.8566 88.1001 13.2218 86.0384 13.2218H86.0255C83.9509 13.2218 83.0052 11.8861 83.0052 10.3755V6.47599H84.6631V10.0976C84.6631 10.9708 85.1191 11.5487 86.0255 11.5487C86.9172 11.5487 87.3855 10.9703 87.3855 10.0976ZM70.6804 6.47599L69.0255 10.9204L67.3707 6.47599H65.6107L68.2514 13.0368H69.8017L72.4418 6.47599H70.6804ZM64.7265 7.2166C65.3177 7.83844 65.6196 8.61874 65.6196 9.571H65.6191V10.1533H60.603C60.708 11.1586 61.4044 11.7934 62.3891 11.7934C63.1901 11.7934 63.7818 11.3965 64.1883 10.5897L65.4223 11.3041C64.8063 12.5872 63.7952 13.2221 62.3629 13.2221C61.4306 13.2221 60.6426 12.9046 59.9855 12.2563C59.3417 11.6085 59.0135 10.7752 59.0135 9.75644C59.0135 8.73771 59.3411 7.91792 59.9984 7.26959C60.6684 6.62175 61.4832 6.29084 62.4417 6.29084C63.3745 6.29084 64.1352 6.59476 64.7265 7.2166ZM64.0956 8.93616C63.9385 8.08937 63.3204 7.56051 62.3882 7.56051C61.5342 7.56051 60.8522 8.15586 60.602 8.93616H64.0956ZM89.9207 11.2769C89.9207 12.3511 90.7845 13.2214 91.8496 13.2214H92.9945V11.7398H92.142C91.8288 11.7398 91.5755 11.4848 91.5755 11.1699V7.82728H92.9945V6.47813H91.5755V4.70308H89.9207V11.2769Z" fill="#8B959E"/>
</svg>

After

Width:  |  Height:  |  Size: 5.4 KiB

View File

@@ -0,0 +1 @@
<svg id="Revolut_Logos" data-name="Revolut Logos" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1200 1200"><defs><style>.cls-1,.cls-2{fill:#191c1f;}.cls-2{fill-rule:evenodd;}</style></defs><g id="Symbol"><path class="cls-1" d="M564.35,590c36,.72,98.91,1.8,109-89.92,9.71-85.6-44.24-92.43-93.15-89.2-1.8,11.51-3.24,22.3-5,33.45-6.47,43.52-12.59,86.32-21.94,145.66Z"/><path class="cls-2" d="M657.5,273.46c108.26,2.16,161.85,51.43,187.74,92.79a209.05,209.05,0,0,1,30.93,111.14v9.35h0c-1.8,34.89-5,101.06-83.08,165.8,48.91,114.73,59,136,68.7,154.29,14.75,28.77,7.55,64-17.62,84.16-30.21,24.1-59.7,33.81-112.93,37.4-4.32.36-9,.36-13.31.36a155.88,155.88,0,0,1-130.2-65.1,66.75,66.75,0,0,1-21.58,29.13c-30.93,23.74-59.7,32.37-112.93,34.17-4.68.36-9.35.36-13.67.36-48.55,0-75.53-21.22-90.28-38.84-36.69-44.6-25.54-105.38-16.54-153.93v-.36c2.52-13.67,4.68-28,6.11-42.44v-1.8c1.08-11.15,4.68-32,10.79-70.49l.72-4.68c9.71-59.34,34.53-212.92,32-247.09a67.69,67.69,0,0,1,8.27-51.43,65.57,65.57,0,0,1,42.44-29.85,603.62,603.62,0,0,1,143.86-15.11C600,270.94,626.21,271.66,657.5,273.46ZM447.1,352.22C500,340.71,540.61,335,655.34,340.71,806.4,343.59,810,456.88,810,478.1c0,1.8-.36,3.6-.36,5.39-1.8,34.17-4.32,89.56-99.27,145.3,73.37,201.77,80.2,204.65,91.71,209.68.36,0,.36.36.72.36-5.75,6.83-25.54,16.54-79.13,19.78-76.61,5.39-94.95-57.91-94.95-57.91L583.75,664H541c-2.16,14.75-4.68,29.13-6.83,42.8C523,776.24,515.06,826.6,525.49,839.54c-17.62,9-29.49,10.79-66.18,16.18-3.24.36-6.83,1.08-10.43,1.44-73,10.43-62.22-50-51.43-110.06,3.24-17.26,6.11-34.53,7.19-50,1.08-10.07,5.39-36.33,10.79-70.49,10.07-61.5,24.1-147.46,30.21-207.88C449.26,386.75,450.34,362.29,447.1,352.22Z"/></g></svg>

After

Width:  |  Height:  |  Size: 1.6 KiB

View File

@@ -0,0 +1,7 @@
<svg width="36" height="24" xmlns="http://www.w3.org/2000/svg" version="1.1">
<g id="Layer_1">
<path id="svg_1" fill="#1977C6" d="m32.98707,0.01321l-30,0c-1.65685,0 -3,1.34315 -3,3l0,18c0,1.6569 1.34315,3 3,3l30,0c1.6569,0 3,-1.3431 3,-3l0,-18c0,-1.65685 -1.3431,-3 -3,-3z"/>
<path id="svg_2" fill="white" d="m33.09357,20.17891l2.8935,0l0,-0.9618l0,-6.7165l0,-0.9747l-1.8124,0l0,-4.7113l-1.726,4.7113l-1.6109,0l-1.726,-4.7016l0,4.7016l-1.8123,0l0,-6.7165l2.867,0l1.4958,4.1832l1.5056,-4.1832l2.8192,0l0,-0.9619l-3.5344,0l-0.7968,2.2329l-0.7917,-2.2329l-4.5594,0l0,2.963l-1.3149,-2.963l-3.6834,0l-3.8194,8.6492l3.0792,0l0,7.6822l9.5402,0l1.4973,-1.6483l1.4898,1.6483zm-5.7941,-8.653l-2.9628,-6.7165l-2.3589,0l-2.9631,6.7165l2.0137,0l0.5562,-1.3433l3.0875,0l0.5658,1.3433l2.0616,0zm8.6876,0.9747l-3.183,3.3391l3.183,3.3774l-2.4062,0l-1.9657,-2.1685l-1.9753,2.1685l-2.3398,0l3.1644,-3.3583l-3.1644,-3.3582l2.4068,0l1.9467,2.1493l1.9656,-2.1493l2.3679,0zm-8.687,0l-5.7149,0l0,6.7165l5.7149,0l0,-1.5543l-3.8834,0l0,-1.046l3.7874,0l0,-1.516l-3.7874,0l0,-1.0458l3.8834,0l0,-1.5544zm6.8437,3.342l1.8433,1.9621l0,-3.908l-1.8433,1.9459zm-11.0154,-9.3638l-0.911,2.1973l1.822,0l-0.911,-2.1973z" clip-rule="evenodd" fill-rule="evenodd"/>
<path id="svg_3" fill-opacity="0.07" fill="black" d="m32.98707,1.01321l-30,0c-1.10457,0 -2,0.89543 -2,2l0,18c0,1.1046 0.89543,2 2,2l30,0c1.1046,0 2,-0.8954 2,-2l0,-18c0,-1.10457 -0.8954,-2 -2,-2zm-30,-1l30,0c1.6569,0 3,1.34315 3,3l0,18c0,1.6569 -1.3431,3 -3,3l-30,0c-1.65685,0 -3,-1.3431 -3,-3l0,-18c0,-1.65685 1.34315,-3 3,-3z" clip-rule="evenodd" fill-rule="evenodd"/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 1.6 KiB

View File

@@ -0,0 +1,84 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Generator: Adobe Illustrator 21.1.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
<svg version="1.1" id="Artwork" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
width="165.52107px" height="105.9651px" viewBox="0 0 165.52107 105.9651" enable-background="new 0 0 165.52107 105.9651"
xml:space="preserve">
<g>
<path id="XMLID_4_" d="M150.69807,0H14.82318c-0.5659,0-1.1328,0-1.69769,0.0033c-0.47751,0.0034-0.95391,0.0087-1.43031,0.0217
c-1.039,0.0281-2.0869,0.0894-3.1129,0.2738c-1.0424,0.1876-2.0124,0.4936-2.9587,0.9754
c-0.9303,0.4731-1.782,1.0919-2.52009,1.8303c-0.73841,0.7384-1.35721,1.5887-1.83021,2.52
c-0.4819,0.9463-0.7881,1.9166-0.9744,2.9598c-0.18539,1.0263-0.2471,2.074-0.2751,3.1119
c-0.0128,0.4764-0.01829,0.9528-0.0214,1.4291c-0.0033,0.5661-0.0022,1.1318-0.0022,1.6989V91.142
c0,0.5671-0.0011,1.13181,0.0022,1.69901c0.00311,0.4763,0.0086,0.9527,0.0214,1.4291
c0.028,1.03699,0.08971,2.08469,0.2751,3.11069c0.1863,1.0436,0.4925,2.0135,0.9744,2.9599
c0.473,0.9313,1.0918,1.7827,1.83021,2.52c0.73809,0.7396,1.58979,1.3583,2.52009,1.8302
c0.9463,0.4831,1.9163,0.7892,2.9587,0.9767c1.026,0.1832,2.0739,0.2456,3.1129,0.2737c0.4764,0.0108,0.9528,0.0172,1.43031,0.0194
c0.56489,0.0044,1.13179,0.0044,1.69769,0.0044h135.87489c0.5649,0,1.13181,0,1.69659-0.0044
c0.47641-0.0022,0.95282-0.0086,1.4314-0.0194c1.0368-0.0281,2.0845-0.0905,3.11301-0.2737
c1.041-0.1875,2.0112-0.4936,2.9576-0.9767c0.9313-0.4719,1.7805-1.0906,2.52011-1.8302c0.7372-0.7373,1.35599-1.5887,1.8302-2.52
c0.48299-0.9464,0.78889-1.9163,0.97429-2.9599c0.1855-1.026,0.2457-2.0737,0.2738-3.11069
c0.013-0.4764,0.01941-0.9528,0.02161-1.4291c0.00439-0.5672,0.00439-1.1319,0.00439-1.69901V14.8242
c0-0.5671,0-1.1328-0.00439-1.6989c-0.0022-0.4763-0.00861-0.9527-0.02161-1.4291c-0.02811-1.0379-0.0883-2.0856-0.2738-3.1119
c-0.18539-1.0432-0.4913-2.0135-0.97429-2.9598c-0.47421-0.9313-1.093-1.7816-1.8302-2.52
c-0.73961-0.7384-1.58881-1.3572-2.52011-1.8303c-0.9464-0.4818-1.9166-0.7878-2.9576-0.9754
c-1.0285-0.1844-2.0762-0.2457-3.11301-0.2738c-0.47858-0.013-0.95499-0.0183-1.4314-0.0217C151.82988,0,151.26297,0,150.69807,0
L150.69807,0z"/>
<path id="XMLID_3_" fill="#FFFFFF" d="M150.69807,3.532l1.67149,0.0032c0.4528,0.0032,0.90561,0.0081,1.36092,0.0205
c0.79201,0.0214,1.71849,0.0643,2.58209,0.2191c0.7507,0.1352,1.38029,0.3408,1.9845,0.6484
c0.5965,0.3031,1.14301,0.7003,1.62019,1.1768c0.479,0.4797,0.87671,1.0271,1.18381,1.6302
c0.30589,0.5995,0.51019,1.2261,0.64459,1.9823c0.1544,0.8542,0.1971,1.7832,0.21881,2.5801
c0.01219,0.4498,0.01819,0.8996,0.0204,1.3601c0.00429,0.5569,0.0042,1.1135,0.0042,1.6715V91.142
c0,0.558,0.00009,1.1136-0.0043,1.6824c-0.00211,0.4497-0.0081,0.8995-0.0204,1.3501c-0.02161,0.7957-0.0643,1.7242-0.2206,2.5885
c-0.13251,0.7458-0.3367,1.3725-0.64429,1.975c-0.30621,0.6016-0.70331,1.1484-1.18022,1.6251
c-0.47989,0.48-1.0246,0.876-1.62819,1.1819c-0.5997,0.3061-1.22821,0.51151-1.97151,0.6453
c-0.88109,0.157-1.84639,0.2002-2.57339,0.2199c-0.4574,0.0103-0.9126,0.01649-1.37889,0.0187
c-0.55571,0.0043-1.1134,0.0042-1.6692,0.0042H14.82318c-0.0074,0-0.0146,0-0.0221,0c-0.5494,0-1.0999,0-1.6593-0.0043
c-0.4561-0.00211-0.9112-0.0082-1.3512-0.0182c-0.7436-0.0201-1.7095-0.0632-2.5834-0.2193
c-0.74969-0.1348-1.3782-0.3402-1.9858-0.6503c-0.59789-0.3032-1.1422-0.6988-1.6223-1.1797
c-0.4764-0.4756-0.8723-1.0207-1.1784-1.6232c-0.3064-0.6019-0.5114-1.2305-0.64619-1.9852
c-0.15581-0.8626-0.19861-1.7874-0.22-2.5777c-0.01221-0.4525-0.01731-0.9049-0.02021-1.3547l-0.0022-1.3279l0.0001-0.3506V14.8242
l-0.0001-0.3506l0.0021-1.3251c0.003-0.4525,0.0081-0.9049,0.02031-1.357c0.02139-0.7911,0.06419-1.7163,0.22129-2.5861
c0.1336-0.7479,0.3385-1.3765,0.6465-1.9814c0.3037-0.5979,0.7003-1.1437,1.17921-1.6225
c0.477-0.4772,1.02309-0.8739,1.62479-1.1799c0.6011-0.3061,1.2308-0.5116,1.9805-0.6465c0.8638-0.1552,1.7909-0.198,2.5849-0.2195
c0.4526-0.0123,0.9052-0.0172,1.3544-0.0203l1.6771-0.0033H150.69807"/>
<g>
<g>
<path d="M45.1862,35.64053c1.41724-1.77266,2.37897-4.15282,2.12532-6.58506c-2.07464,0.10316-4.60634,1.36871-6.07207,3.14276
c-1.31607,1.5192-2.4809,3.99902-2.17723,6.3293C41.39111,38.72954,43.71785,37.36345,45.1862,35.64053"/>
<path d="M47.28506,38.98252c-3.38211-0.20146-6.25773,1.91951-7.87286,1.91951c-1.61602,0-4.08931-1.81799-6.76438-1.76899
c-3.48177,0.05114-6.71245,2.01976-8.4793,5.15079c-3.63411,6.2636-0.95904,15.55471,2.57494,20.65606
c1.71618,2.5238,3.78447,5.30269,6.50976,5.20287c2.57494-0.10104,3.58421-1.66732,6.71416-1.66732
c3.12765,0,4.03679,1.66732,6.76252,1.61681c2.82665-0.05054,4.59381-2.52506,6.30997-5.05132
c1.96878-2.877,2.77473-5.65498,2.82542-5.80748c-0.0507-0.05051-5.45058-2.12204-5.50065-8.33358
c-0.05098-5.20101,4.23951-7.6749,4.44144-7.82832C52.3832,39.4881,48.5975,39.08404,47.28506,38.98252"/>
</g>
<g>
<path d="M76.73385,31.94381c7.35096,0,12.4697,5.06708,12.4697,12.44437c0,7.40363-5.22407,12.49704-12.65403,12.49704h-8.13892
v12.94318h-5.88037v-37.8846H76.73385z M68.41059,51.9493h6.74732c5.11975,0,8.0336-2.75636,8.0336-7.53479
c0-4.77792-2.91385-7.50845-8.00727-7.50845h-6.77365V51.9493z"/>
<path d="M90.73997,61.97864c0-4.8311,3.70182-7.79761,10.26583-8.16526l7.56061-0.44614v-2.12639
c0-3.07185-2.07423-4.90959-5.53905-4.90959c-3.28251,0-5.33041,1.57492-5.82871,4.04313h-5.35574
c0.31499-4.98859,4.56777-8.66407,11.3941-8.66407c6.69466,0,10.97377,3.54432,10.97377,9.08388v19.03421h-5.43472v-4.54194
h-0.13065c-1.60125,3.07185-5.09341,5.01441-8.71623,5.01441C94.52078,70.30088,90.73997,66.94038,90.73997,61.97864z
M108.56641,59.4846v-2.17905l-6.8,0.41981c-3.38683,0.23649-5.30306,1.73291-5.30306,4.09579
c0,2.41504,1.99523,3.99046,5.04075,3.99046C105.46823,65.81161,108.56641,63.08108,108.56641,59.4846z"/>
<path d="M119.34167,79.9889v-4.5946c0.4193,0.10483,1.36425,0.10483,1.83723,0.10483c2.6252,0,4.04313-1.10245,4.90908-3.9378
c0-0.05267,0.49931-1.68025,0.49931-1.70658l-9.97616-27.64562h6.14268l6.98432,22.47371h0.10432l6.98433-22.47371h5.9857
l-10.34483,29.06304c-2.36186,6.69517-5.0924,8.84789-10.81577,8.84789C121.17891,80.12006,119.76098,80.06739,119.34167,79.9889
z"/>
</g>
</g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 6.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 33 KiB

View File

@@ -0,0 +1,9 @@
<svg width="36" height="24" viewBox="0 0 36 24" fill="none" xmlns="http://www.w3.org/2000/svg">
<rect width="36" height="24" rx="3" fill="white"/>
<path d="M33 0H3C1.34315 0 0 1.34315 0 3V21C0 22.6569 1.34315 24 3 24H33C34.6569 24 36 22.6569 36 21V3C36 1.34315 34.6569 0 33 0Z" fill="white"/>
<path fill-rule="evenodd" clip-rule="evenodd" d="M15.1603 17.0447H20.8385V6.9554H15.1603V17.0447Z" fill="#FF5F00"/>
<path fill-rule="evenodd" clip-rule="evenodd" d="M15.5208 12.0001C15.5214 11.0257 15.7451 10.0644 16.1749 9.18997C16.6046 8.3155 17.229 7.5511 18 6.9554C17.0448 6.21204 15.9011 5.74992 14.6976 5.621C13.4941 5.49207 12.2785 5.70147 11.1875 6.22563C10.0965 6.74979 9.17342 7.56794 8.52198 8.58805C7.87053 9.60817 7.51661 10.7898 7.5 12.0001C7.51661 13.2103 7.87053 14.392 8.52198 15.4121C9.17342 16.4322 10.0965 17.2503 11.1875 17.7745C12.2785 18.2987 13.4941 18.5081 14.6976 18.3791C15.9011 18.2502 17.0448 17.7881 18 17.0447C17.229 16.449 16.6046 15.6846 16.1749 14.8102C15.7451 13.9357 15.5214 12.9744 15.5208 12.0001Z" fill="#EB001B"/>
<path fill-rule="evenodd" clip-rule="evenodd" d="M28.297 15.9761V15.7276H28.227L28.1512 15.8991L28.0753 15.7276H28.01V15.9761H28.0567V15.7882L28.1278 15.9504H28.1757L28.2468 15.7882V15.9761H28.297ZM27.8805 15.9761V15.7696H27.9645V15.7276H27.7498V15.7696H27.8338V15.9761H27.8805ZM28.5 12.0001C28.4834 13.2103 28.1295 14.392 27.478 15.4121C26.8266 16.4322 25.9035 17.2503 24.8125 17.7745C23.7215 18.2987 22.5059 18.5081 21.3024 18.3791C20.0989 18.2502 18.9552 17.7881 18 17.0447C18.7714 16.4494 19.396 15.685 19.8258 14.8105C20.2555 13.936 20.479 12.9745 20.479 12.0001C20.479 11.0256 20.2555 10.0642 19.8258 9.18964C19.396 8.31509 18.7714 7.55076 18 6.9554C18.9552 6.21204 20.0989 5.74992 21.3024 5.621C22.5059 5.49207 23.7215 5.70147 24.8125 6.22563C25.9035 6.74979 26.8266 7.56794 27.478 8.58805C28.1295 9.60817 28.4834 10.7898 28.5 12.0001Z" fill="#F79E1B"/>
<path fill-rule="evenodd" clip-rule="evenodd" d="M33 1H3C1.89543 1 1 1.89543 1 3V21C1 22.1046 1.89543 23 3 23H33C34.1046 23 35 22.1046 35 21V3C35 1.89543 34.1046 1 33 1ZM3 0H33C34.6569 0 36 1.34315 36 3V21C36 22.6569 34.6569 24 33 24H3C1.34315 24 0 22.6569 0 21V3C0 1.34315 1.34315 0 3 0Z" fill="black" fill-opacity="0.07"/>
<rect x="0.5" y="0.5" width="35" height="23" rx="2.5" stroke="black" stroke-opacity="0.07"/>
</svg>

After

Width:  |  Height:  |  Size: 2.3 KiB

View File

@@ -0,0 +1,6 @@
<svg width="52" height="32" viewBox="0 0 52 32" fill="none" xmlns="http://www.w3.org/2000/svg">
<rect width="52" height="32" fill="white"/>
<path d="M6.5 12.1111C6.5 10.3929 7.89289 9 9.61111 9H17.3889C19.1071 9 20.5 10.3929 20.5 12.1111V19.8889C20.5 21.6071 19.1071 23 17.3889 23H9.61111C7.89289 23 6.5 21.6071 6.5 19.8889V12.1111Z" fill="#191C1F"/>
<path fill-rule="evenodd" clip-rule="evenodd" d="M14.1055 10.8093C15.1321 10.8632 15.779 10.9855 16.4563 11.3666C16.9818 11.662 17.3827 12.1108 17.6667 12.6605C17.817 12.9528 17.8929 13.2467 17.9491 13.6134C17.9947 13.9126 18.0053 14.2163 17.978 14.5155C17.9628 14.7068 17.9355 14.8807 17.8929 15.0523C17.8064 15.3993 17.656 15.7281 17.4541 16.0295C17.2551 16.3249 17.0122 16.5876 16.7282 16.8306L16.6264 16.9133L16.6963 17.1153C16.9545 17.8442 17.1944 18.3834 17.4814 18.8625L17.5923 19.0394L17.6849 19.1814C17.978 19.6111 18.0266 20.028 17.6849 20.419C17.4298 20.7121 16.9134 21.1115 15.1898 21.2034C14.4776 21.2414 13.9051 20.9202 13.5133 20.419C13.4505 20.3297 13.3134 20.3369 13.2456 20.4225C13.0798 20.6317 12.8445 20.8104 12.5672 20.9217L12.4275 20.9726L12.2787 21.0189C12.0099 21.0948 11.6805 21.1775 11.2749 21.192C8.72282 21.2836 9.01758 19.2467 9.01758 19.2467H9.01303L9.46925 16.5792C9.46925 16.5792 9.56615 15.9774 9.62567 15.5914C9.68662 15.1961 9.77753 14.5785 9.77753 14.5785L9.85498 14.0432L9.94609 13.2687L9.99469 12.7744C10.0053 12.5519 10.0053 12.3704 9.99469 12.2034L10.0615 11.8693L10.0964 11.7159C10.1374 11.5618 10.1784 11.4881 10.2604 11.4L10.3424 11.3188L10.3926 11.2717C10.5748 11.113 10.7084 11.0606 10.8998 11.0098C10.9636 10.9931 11.0273 10.9794 11.0987 10.9672L11.3113 10.9369L11.776 10.8875C12.5368 10.7987 13.3645 10.7698 14.1055 10.8093ZM11.8711 12.0277L11.8711 12.0277L11.9081 12.0242C12.5929 11.9444 13.3568 11.9148 14.0447 11.952C14.6795 11.9854 15.331 12.0462 15.8959 12.3636C16.2315 12.5526 16.476 12.8472 16.6507 13.1851C16.7433 13.3658 16.7888 13.5883 16.8192 13.7888C16.8511 13.9968 16.8587 14.2087 16.8405 14.419L16.8253 14.5557C16.8162 14.6301 16.8025 14.7037 16.7843 14.7759C16.7296 14.9968 16.6324 15.2041 16.5064 15.3932C16.3287 15.6559 16.0994 15.8791 15.8504 16.0728C15.6696 16.214 15.4768 16.3408 15.2778 16.4562C15.6879 17.7812 16.1189 18.6212 16.6962 19.7273C16.6051 19.8313 15.9855 20.0181 15.129 20.0637C14.8997 20.0758 14.722 19.9976 14.5854 19.8898C14.3242 19.6832 14.2209 19.3666 14.2209 19.3666L13.4669 17.1832C13.4301 17.0767 13.3298 17.0052 13.2171 17.0052H12.6248C12.432 18.2421 12.3515 18.9484 12.3515 19.7273C12.3515 19.7273 12.2604 19.9482 11.1639 20.0561C10.8617 20.0857 10.4305 20.05 10.2619 19.7546C10.1024 19.476 10.1753 19.1176 10.2391 18.804L10.2771 18.6111L10.3168 18.3876C10.4343 17.7274 10.5516 17.0679 10.6567 16.4053C10.7691 15.6954 10.886 14.9103 10.9893 14.1988C10.9935 14.1614 11.0001 14.1056 11.0081 14.0374L11.0139 13.9883C11.0562 13.6297 11.1293 13.0103 11.1366 12.826C11.1472 12.6005 11.1503 12.3689 11.1366 12.1441C11.1352 12.0981 11.6371 12.0501 11.8711 12.0277ZM12.804 15.8542C12.804 15.8542 13.0219 14.817 13.2198 13.1048C14.0447 12.9696 14.9407 13.1328 14.7296 14.4525C14.5005 15.8797 13.5374 15.864 12.9754 15.8549L12.9741 15.8549L12.804 15.8542Z" fill="white"/>
<path d="M25.118 20.5V16.944H27.512C29.486 16.944 30.746 15.67 30.746 13.794C30.746 11.974 29.514 10.7 27.512 10.7H23.9V20.5H25.118ZM25.118 11.806H27.358C28.674 11.806 29.486 12.534 29.486 13.794C29.486 15.11 28.716 15.824 27.358 15.824H25.118V11.806ZM34.1604 20.626C35.1684 20.626 35.9664 20.22 36.4004 19.492H36.4564L36.5404 20.5H37.5344V15.684C37.5344 14.326 36.5684 13.22 34.7344 13.22C33.1664 13.22 32.0184 14.13 32.0184 15.502H33.1524C33.1664 14.816 33.6844 14.228 34.7344 14.228C35.8964 14.228 36.3864 14.914 36.3864 15.712V16.426C35.9384 16.3 35.3784 16.174 34.6224 16.174C32.5224 16.174 31.6684 17.21 31.6684 18.414C31.6684 19.66 32.6064 20.626 34.1604 20.626ZM34.3704 19.646C33.3344 19.646 32.8584 19.114 32.8584 18.4C32.8584 17.56 33.4604 17.112 34.6224 17.112C35.2524 17.112 35.7984 17.182 36.3864 17.364V17.728C36.3864 18.764 35.5884 19.646 34.3704 19.646ZM41.3012 23.706L45.2632 13.486V13.346H44.0312L41.9312 18.96H41.8752L39.7052 13.346H38.4452V13.486L41.3152 20.416L41.3292 20.444L40.1112 23.566V23.706H41.3012Z" fill="#191C1F"/>
</svg>

After

Width:  |  Height:  |  Size: 4.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 291 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.1 KiB

View File

@@ -0,0 +1,13 @@
<svg width="36" height="24" viewBox="0 0 36 24" fill="none" xmlns="http://www.w3.org/2000/svg">
<rect width="36" height="24" rx="3" fill="white"/>
<path d="M33 0H3C1.34315 0 0 1.34315 0 3V21C0 22.6569 1.34315 24 3 24H33C34.6569 24 36 22.6569 36 21V3C36 1.34315 34.6569 0 33 0Z" fill="white"/>
<g clip-path="url(#clip0_601_24744)">
<path fill-rule="evenodd" clip-rule="evenodd" d="M24.1966 9H23.0973V14.9496H24.1966V9ZM31.9994 10.5833V11.5066H30.8628V13.5831C30.8628 13.7563 30.901 13.9067 30.9599 13.9662C31.024 14.0312 31.1349 14.0642 31.2893 14.0642H31.9994V14.9874H31.029C30.6016 14.9874 30.2804 14.8845 30.0742 14.6815C29.868 14.4786 29.7635 14.1713 29.7635 13.7681V9.37959H30.8628V10.5833H31.9994ZM15.6303 13.7916L16.7669 10.5832H17.9217L16.2809 14.9496H14.9796L13.3388 10.5832H14.4937L15.6303 13.7916ZM27.8434 13.4854C27.9285 13.2875 27.9717 13.047 27.9717 12.7706V10.5833H29.071V14.9496H28.1062L28.0077 14.4406C27.8777 14.5836 27.7119 14.7112 27.5138 14.8203C27.2968 14.9395 27.0123 15 26.6686 15C26.4301 15 26.2014 14.9671 25.9887 14.9022C25.7749 14.8369 25.5833 14.726 25.4193 14.5725C25.2551 14.4189 25.1231 14.2118 25.0271 13.9573C24.9311 13.7036 24.8825 13.3836 24.8825 13.0063V10.5833H25.9818V12.8885C25.9818 13.2855 26.0603 13.588 26.2153 13.7876C26.3687 13.9851 26.6059 14.0853 26.9202 14.0853C27.1398 14.0853 27.3294 14.0343 27.4836 13.9336C27.6379 13.833 27.7589 13.6822 27.8434 13.4854ZM21.4169 10.8136C21.0705 10.6273 20.6591 10.5329 20.1944 10.5329C19.7354 10.5329 19.3255 10.6273 18.9762 10.8135C18.6265 11.0003 18.3518 11.264 18.1595 11.5973C17.9676 11.9304 17.8703 12.3252 17.8703 12.7706C17.8703 13.2106 17.9676 13.6026 18.1595 13.9357C18.3516 14.2689 18.6265 14.5326 18.9762 14.7193C19.3255 14.9055 19.7354 14.9999 20.1944 14.9999C20.6591 14.9999 21.0704 14.9055 21.4169 14.7192C21.7637 14.5326 22.037 14.2689 22.2292 13.9356C22.4212 13.6024 22.5186 13.2104 22.5186 12.7706C22.5186 12.3253 22.4212 11.9306 22.2292 11.5973C22.0369 11.2639 21.7636 11.0002 21.4169 10.8136ZM20.8361 13.9334C20.659 14.0453 20.4431 14.102 20.1944 14.102C19.9514 14.102 19.7369 14.0453 19.5569 13.9334C19.3765 13.8213 19.235 13.6632 19.1363 13.4633C19.0372 13.2632 18.9869 13.0302 18.9869 12.7706C18.9869 12.5057 19.0372 12.2713 19.1363 12.074C19.235 11.8768 19.3766 11.7186 19.5571 11.6037C19.7371 11.489 19.9516 11.4308 20.1944 11.4308C20.443 11.4308 20.6588 11.489 20.8359 11.6036C21.0136 11.7185 21.1537 11.8768 21.2526 12.074C21.3517 12.2719 21.402 12.5063 21.402 12.7706C21.402 13.0296 21.3517 13.2627 21.2526 13.4633C21.1538 13.6632 21.0136 13.8214 20.8361 13.9334ZM4 10.4683H5.14242V14.9496H4V10.4683ZM8.725 10.7246C8.725 9.7737 7.92677 9.00006 6.94556 9.00006H4V9.95708H6.80551C7.24956 9.95708 7.61739 10.2955 7.62551 10.7114C7.62957 10.9197 7.549 11.1162 7.39864 11.2649C7.24822 11.4135 7.04724 11.4955 6.83273 11.4955H5.73985C5.70104 11.4955 5.66946 11.5261 5.66946 11.5637V12.4143C5.66946 12.4287 5.67407 12.4426 5.68274 12.4542L7.53699 14.9497H8.89434L7.03578 12.4474C7.97175 12.4018 8.725 11.6389 8.725 10.7246ZM11.0765 10.5329C11.518 10.5329 11.9088 10.6187 12.2379 10.7882C12.5669 10.9576 12.8286 11.2014 13.0156 11.5127C13.2019 11.8237 13.2994 12.1958 13.3053 12.6188C13.3053 12.6814 13.3037 12.7434 13.301 12.8054C13.2977 12.8691 13.2903 12.9325 13.2788 12.9939L13.2751 13.0135H9.97302V13.0486C9.98435 13.2728 10.0373 13.4704 10.1305 13.6346C10.2232 13.7982 10.3572 13.9267 10.5284 14.0165C10.7006 14.1068 10.8996 14.1526 11.12 14.1526C11.38 14.1526 11.6045 14.0917 11.7872 13.9716C11.9574 13.8599 12.0742 13.702 12.1344 13.5021L12.1396 13.485H13.2328L13.2268 13.5135C13.171 13.7815 13.057 14.0278 12.888 14.2456C12.7101 14.4747 12.4722 14.6598 12.1807 14.7957C11.8892 14.9313 11.5498 15 11.1719 15C10.6955 15 10.2769 14.907 9.92803 14.7236C9.57845 14.5401 9.30501 14.2778 9.11543 13.9439C8.92627 13.6108 8.83042 13.2189 8.83042 12.7791C8.83042 12.3279 8.92482 11.9303 9.11107 11.5976C9.2975 11.264 9.56348 11.0003 9.90154 10.8137C10.2391 10.6273 10.6344 10.5329 11.0765 10.5329ZM12.1848 12.2585C12.1419 11.9817 12.0251 11.7638 11.8373 11.6105C11.6432 11.4521 11.3901 11.3718 11.0851 11.3718C10.9047 11.3718 10.7346 11.4093 10.5797 11.4831C10.425 11.5567 10.2952 11.6619 10.1939 11.7957C10.0973 11.9233 10.0358 12.0789 10.011 12.2585H12.1848Z" fill="#191C1F"/>
</g>
<path fill-rule="evenodd" clip-rule="evenodd" d="M33 1H3C1.89543 1 1 1.89543 1 3V21C1 22.1046 1.89543 23 3 23H33C34.1046 23 35 22.1046 35 21V3C35 1.89543 34.1046 1 33 1ZM3 0H33C34.6569 0 36 1.34315 36 3V21C36 22.6569 34.6569 24 33 24H3C1.34315 24 0 22.6569 0 21V3C0 1.34315 1.34315 0 3 0Z" fill="black" fill-opacity="0.07"/>
<defs>
<clipPath id="clip0_601_24744">
<rect width="28" height="6" fill="white" transform="translate(4 9)"/>
</clipPath>
</defs>
</svg>

After

Width:  |  Height:  |  Size: 4.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 25 KiB

View File

@@ -0,0 +1,6 @@
<svg width="36" height="24" viewBox="0 0 36 24" fill="none" xmlns="http://www.w3.org/2000/svg">
<rect width="36" height="24" rx="3" fill="white"/>
<path d="M33 0H3C1.34315 0 0 1.34315 0 3V21C0 22.6569 1.34315 24 3 24H33C34.6569 24 36 22.6569 36 21V3C36 1.34315 34.6569 0 33 0Z" fill="white"/>
<path d="M17.2985 7.65897L15.4366 16.3633H13.1846L15.0466 7.65897H17.2985ZM26.7724 13.2795L27.9577 10.0106L28.6397 13.2795H26.7724ZM29.286 16.3633H31.3681L29.5489 7.65897H27.6284C27.1953 7.65897 26.8304 7.90995 26.6689 8.297L23.29 16.3633H25.6549L26.1244 15.0634H29.0131L29.286 16.3633ZM23.4072 13.5215C23.417 11.2244 20.2316 11.0972 20.2529 10.0707C20.2598 9.75886 20.5573 9.42663 21.2077 9.34166C21.5301 9.29996 22.4199 9.26648 23.4286 9.73125L23.8231 7.8845C23.2814 7.68873 22.5842 7.5 21.7167 7.5C19.4906 7.5 17.9246 8.68248 17.912 10.3771C17.8977 11.6303 19.0309 12.329 19.8825 12.7462C20.7608 13.1728 21.055 13.4465 21.0507 13.8277C21.0446 14.4117 20.3504 14.6703 19.7042 14.6799C18.5712 14.6977 17.9146 14.3739 17.3913 14.1297L16.9825 16.038C17.5095 16.2792 18.4806 16.4892 19.4861 16.5C21.8528 16.5 23.4002 15.3312 23.4072 13.5215ZM14.0807 7.65897L10.432 16.3633H8.05198L6.25632 9.41664C6.14747 8.98946 6.05252 8.83245 5.72147 8.65194C5.17995 8.35769 4.28604 8.08263 3.5 7.91152L3.55325 7.65897H7.38497C7.87304 7.65897 8.31216 7.98376 8.42395 8.54583L9.37248 13.5831L11.7149 7.65897H14.0807Z" fill="#1434CB"/>
<path fill-rule="evenodd" clip-rule="evenodd" d="M33 1H3C1.89543 1 1 1.89543 1 3V21C1 22.1046 1.89543 23 3 23H33C34.1046 23 35 22.1046 35 21V3C35 1.89543 34.1046 1 33 1ZM3 0H33C34.6569 0 36 1.34315 36 3V21C36 22.6569 34.6569 24 33 24H3C1.34315 24 0 22.6569 0 21V3C0 1.34315 1.34315 0 3 0Z" fill="black" fill-opacity="0.07"/>
</svg>

After

Width:  |  Height:  |  Size: 1.7 KiB

View File

@@ -0,0 +1,560 @@
jQuery(function ($) {
let wcAddToCartButton = $('.single_add_to_cart_button')
let orderSelectedShippingOption = null
let paymentRequestType = null
let paymentRequest = null
let address_info = null
let wc_order_id = null
function handleError(message) {
$.blockUI({ message: null, overlayCSS: { background: '#fff', opacity: 0.6 } })
if (paymentRequest) {
paymentRequest.destroy()
}
sendRequest(getAjaxURL('set_error_message'), {
revolut_payment_request_error: message,
})
.then(response => {
window.location.reload()
})
.catch(error => {
window.location.reload()
})
}
function logError(message) {
sendRequest(
getAjaxURL('log_error'),
{
revolut_payment_request_error: message,
},
false,
)
}
function getAjaxURL(endpoint, controller = 'revolut_payment_request_') {
return wc_revolut_payment_request_params.ajax_url
.toString()
.replace('%%wc_revolut_gateway_ajax_endpoint%%', `${controller}${endpoint}`)
}
function getProductAttributes() {
const select = $('.variations_form').find('.variations select'),
data = {}
select.each(function () {
const attribute_name = $(this).data('attribute_name') || $(this).attr('name')
data[attribute_name] = $(this).val() || ''
})
return data
}
function checkCartCreateErrors() {
if (!wcAddToCartButton.is('.disabled')) {
return false
}
if (wcAddToCartButton.is('.wc-variation-is-unavailable')) {
return wc_add_to_cart_variation_params.i18n_unavailable_text
}
if (wcAddToCartButton.is('.wc-variation-selection-needed')) {
return wc_add_to_cart_variation_params.i18n_make_a_selection_text
}
return wc_revolut_payment_request_params.error_messages.cart_create_failed
}
function createCart(add_to_cart = 0, revpay = false) {
return new Promise((resolve, reject) => {
if (checkCartCreateErrors()) {
let errorMsg = checkCartCreateErrors()
if (revpay) {
return reject(errorMsg)
}
handleError(errorMsg)
return resolve(false)
}
if (wc_revolut_payment_request_params.is_cart_page) {
return resolve({ success: true })
}
let product_data = {}
product_data['add_to_cart'] = add_to_cart
product_data['is_revolut_pay'] = revpay ? 1 : 0
product_data['security'] = wc_revolut_payment_request_params.nonce.add_to_cart
product_data['revolut_public_id'] =
wc_revolut_payment_request_params.revolut_public_id
product_data['product_id'] = $('.single_add_to_cart_button').val()
product_data['qty'] = $('.quantity .qty').val()
product_data['attributes'] = []
if ($('.single_variation_wrap').length) {
product_data['product_id'] = $('.single_variation_wrap')
.find('input[name="product_id"]')
.val()
}
if ($('.variations_form').length) {
product_data['attributes'] = getProductAttributes()
}
sendRequest(getAjaxURL('add_to_cart'), product_data).then(response => {
if (!response.success) {
if (revpay) {
displayErrorMessage(
wc_revolut_payment_request_params.error_messages.cart_create_failed,
)
return resolve(false)
}
handleError(wc_revolut_payment_request_params.error_messages.cart_create_failed)
return resolve(false)
}
wc_revolut_payment_request_params.total = response.total.amount
wc_revolut_payment_request_params.nonce.checkout = response.checkout_nonce
resolve(response)
})
})
}
function getShippingOptions(address) {
let address_data = {
security: wc_revolut_payment_request_params.nonce.shipping,
revolut_public_id: wc_revolut_payment_request_params.revolut_public_id,
country: address.country,
state: address.region,
postcode: address.postalCode,
city: address.city,
address: '',
address_2: '',
is_product_page: wc_revolut_payment_request_params.is_product_page,
require_shipping: wc_revolut_payment_request_params.shipping_required,
}
return new Promise((resolve, reject) => {
sendRequest(getAjaxURL('get_shipping_options'), address_data)
.then(response => {
if (response['shippingOptions'] && response['shippingOptions'].length !== 0) {
orderSelectedShippingOption = response['shippingOptions'][0]['id']
}
resolve(response)
})
.catch(error => {
reject(error)
})
})
}
function updateShippingOptions(shippingOption) {
let shipping_option_data = {
revolut_public_id: wc_revolut_payment_request_params.revolut_public_id,
security: wc_revolut_payment_request_params.nonce.update_shipping,
shipping_method: [shippingOption.id],
is_product_page: wc_revolut_payment_request_params.is_product_page,
}
return new Promise((resolve, reject) => {
sendRequest(getAjaxURL('update_shipping_method'), shipping_option_data)
.then(response => {
resolve(response)
})
.catch(error => {
reject(error)
})
})
}
function updatePaymentTotal() {
let shipping_option_data = {
revolut_public_id: wc_revolut_payment_request_params.revolut_public_id,
security: wc_revolut_payment_request_params.nonce.update_order_total,
}
return new Promise((resolve, reject) => {
sendRequest(getAjaxURL('update_payment_total'), shipping_option_data)
.then(response => {
resolve(response)
})
.catch(error => {
reject(error)
})
})
}
function udpateExpressCheckoutParams(revpay = false) {
return new Promise((resolve, reject) => {
sendRequest(
getAjaxURL(revpay ? 'get_express_checkout_params' : 'get_payment_request_params'),
{
security: revpay
? wc_revolut_payment_request_params.nonce.get_express_checkout_params
: wc_revolut_payment_request_params.nonce.get_payment_request_params,
},
)
.then(response => {
if (response.success) {
wc_revolut_payment_request_params.revolut_public_id =
response.revolut_public_id
wc_revolut_payment_request_params.nonce.checkout = response.checkout_nonce
return resolve()
}
reject('')
})
.catch(error => {
reject(error)
})
})
}
function loadOrderData() {
return new Promise((resolve, reject) => {
sendRequest(getAjaxURL('load_order_data'), {
revolut_public_id: wc_revolut_payment_request_params.revolut_public_id,
security: wc_revolut_payment_request_params.nonce.load_order_data,
})
.then(response => {
resolve(response)
})
.catch(error => {
reject(error)
})
})
}
function cancelOrder(messages) {
$.blockUI({ message: null, overlayCSS: { background: '#fff', opacity: 0.6 } })
return new Promise((resolve, reject) => {
sendRequest(getAjaxURL('cancel_order'), {
revolut_public_id: wc_revolut_payment_request_params.revolut_public_id,
security: wc_revolut_payment_request_params.nonce.cancel_order,
}).then(response => {
handleError(messages)
})
})
}
function submitOrder(errorMessage = '', revolut_gateway = 'revolut_payment_request') {
$.blockUI({ message: null, overlayCSS: { background: '#fff', opacity: 0.6 } })
let data = {}
data['is_express_checkout'] = 1
data['revolut_gateway'] = revolut_gateway
data['revolut_public_id'] = wc_revolut_payment_request_params.revolut_public_id
data['revolut_payment_error'] = errorMessage
data['wc_order_id'] = wc_order_id
data['reload_checkout'] = 0
data['revolut_save_payment_method'] = 0
data['wc-revolut_cc-payment-token'] = ''
sendRequest(getAjaxURL('process_payment_result', 'wc_revolut_'), data).then(
response => {
if (response.result === 'success') {
window.location.href = response.redirect
return
}
$.unblockUI()
$('.blockUI.blockOverlay').hide()
if (!response.messages || typeof response.messages == 'undefined') {
response.messages = `<div class="woocommerce-error">${wc_revolut_payment_request_params.error_messages.checkout_general}</div>`
}
cancelOrder(response.messages)
},
)
}
function submitWooCommerceOrder(payment_method = 'revolut_payment_request') {
return new Promise((resolve, reject) => {
sendRequest(getAjaxURL('create_order'), {
payment_method: payment_method,
_wpnonce: wc_revolut_payment_request_params.nonce.checkout,
shipping_method: [orderSelectedShippingOption],
payment_request_type: paymentRequestType,
revolut_public_id: wc_revolut_payment_request_params.revolut_public_id,
shipping_required: wc_revolut_payment_request_params.shipping_required ? 1 : 0,
address_info: address_info,
revolut_create_wc_order: 1,
is_express_checkout: 1,
})
.then(response => {
if (true === response.reload) {
window.location.reload()
return
}
if (response.result === 'revolut_wc_order_created') {
wc_order_id = response['wc_order_id']
return resolve(true)
}
if (typeof response.messages == 'undefined') {
response.messages = `<div class="woocommerce-error">${wc_revolut_payment_request_params.error_messages.checkout_general}</div>`
}
logError('submitWooCommerceOrder failed: ' + JSON.stringify(response))
return cancelOrder($(response.messages).text())
})
.catch(error => {
cancelOrder(error)
})
})
}
function displayErrorMessage(message) {
if (message && !message.includes('woocommerce-error')) {
message = `<div class="woocommerce-error">${message}</div>`
}
$('.woocommerce-error').remove()
if (wc_revolut_payment_request_params.is_product_page) {
var element = $('.product').first()
element.before(message)
$('html, body').animate(
{
scrollTop: element.prev('.woocommerce-error').offset().top,
},
600,
)
} else {
var $form = $('.shop_table.cart').closest('form')
$form.before(message)
$('html, body').animate(
{
scrollTop: $form.prev('.woocommerce-error').offset().top,
},
600,
)
}
}
function initPaymentRequestButton() {
if ($('#revolut-payment-request-button').length < 1) {
return false
}
// remove duplicated instances
if ($('.wc-revolut-payment-request-instance').length > 1) {
$('.wc-revolut-payment-request-instance').not(':last').remove()
}
udpateExpressCheckoutParams().then(function () {
const RC = RevolutCheckout(wc_revolut_payment_request_params.revolut_public_id)
const revolutPaymentReuqestButton = document.getElementById(
'revolut-payment-request-button',
)
paymentRequest = RC.paymentRequest({
target: revolutPaymentReuqestButton,
requestShipping: wc_revolut_payment_request_params.shipping_required,
shippingOptions: wc_revolut_payment_request_params.free_shipping_option,
onClick() {
if (!wc_revolut_payment_request_params.shipping_required) {
return createCart(1)
}
},
onShippingOptionChange: selectedShippingOption => {
orderSelectedShippingOption = selectedShippingOption['id']
return updateShippingOptions(selectedShippingOption)
},
onShippingAddressChange: selectedShippingAddress => {
return createCart(1).then(function () {
return getShippingOptions(selectedShippingAddress)
})
},
onSuccess() {
submitOrder()
},
validate(address) {
address_info = address
return submitWooCommerceOrder()
},
onError(error) {
let errorMessage = error
if (error['message']) {
errorMessage = error['message']
}
if (errorMessage == 'Unknown') {
errorMessage =
wc_revolut_payment_request_params.error_messages.checkout_general
}
if (wc_order_id) {
return submitOrder(errorMessage)
}
displayErrorMessage(errorMessage)
},
buttonStyle: {
action: wc_revolut_payment_request_params.payment_request_button_type,
size: wc_revolut_payment_request_params.payment_request_button_size,
variant: wc_revolut_payment_request_params.payment_request_button_theme,
radius: wc_revolut_payment_request_params.payment_request_button_radius,
},
})
paymentRequest.canMakePayment().then(result => {
if (result) {
paymentRequest.render()
} else {
paymentRequest.destroy()
}
})
})
}
function initRevolutPayExpressCheckoutButton() {
if ($('#revolut-pay-express-checkout-button').length < 1) {
return false
}
// remove duplicated instances
if ($('.wc-revolut-pay-express-checkout-instance').length > 1) {
$('.wc-revolut-pay-express-checkout-instance').not(':last').remove()
}
udpateExpressCheckoutParams(true).then(function () {
instance = RevolutCheckout.payments({
locale: wc_revolut_payment_request_params.locale,
publicToken: wc_revolut_payment_request_params.publicToken,
})
instance.revolutPay.mount('#revolut-pay-express-checkout-button', {
currency: wc_revolut_payment_request_params.currency,
totalAmount: parseInt(wc_revolut_payment_request_params.total),
requestShipping: true,
validate() {
return createCart(1, true).then(function (result) {
if (result && result.success) {
if (wc_revolut_payment_request_params.is_cart_page) {
return updatePaymentTotal()
}
return Promise.resolve(true)
}
})
},
createOrder: () => {
return { publicId: wc_revolut_payment_request_params.revolut_public_id }
},
buttonStyle: {
cashbackCurrency: wc_revolut_payment_request_params.currency,
variant: wc_revolut_payment_request_params.revolut_pay_button_theme,
size: wc_revolut_payment_request_params.revolut_pay_button_size,
radius: wc_revolut_payment_request_params.revolut_pay_button_radius,
},
mobileRedirectUrls: {
success: wc_revolut_payment_request_params.redirect_url,
failure: wc_revolut_payment_request_params.redirect_url,
cancel: wc_revolut_payment_request_params.redirect_url,
},
__metadata: {
environment: 'woocommerce',
context: wc_revolut_payment_request_params.is_cart_page ? 'cart' : 'product',
origin_url: wc_revolut_payment_request_params.revolut_pay_origin_url,
},
})
instance.revolutPay.on('payment', function (event) {
switch (event.type) {
case 'success':
$.blockUI({ message: null, overlayCSS: { background: '#fff', opacity: 0.6 } })
loadOrderData()
.then(function (order_data) {
address_info = order_data.address_info
orderSelectedShippingOption = order_data.selected_shipping_option
submitWooCommerceOrder('revolut_pay')
.then(function () {
submitOrder('', 'revolut_pay')
})
.catch(error => {
displayErrorMessage([error])
$.unblockUI()
$('.blockUI.blockOverlay').hide()
})
})
.catch(error => {
displayErrorMessage([error])
$.unblockUI()
$('.blockUI.blockOverlay').hide()
})
break
case 'error':
displayErrorMessage(event.error.message)
break
}
})
})
}
$('.quantity').on('input', '.qty', function () {
if (
!paymentRequest ||
wcAddToCartButton.is('.disabled') ||
wc_revolut_payment_request_params.is_cart_page
) {
return
}
paymentRequest.updateWith(createCart())
})
$(document.body).on('woocommerce_variation_has_changed', function () {
if (
!paymentRequest ||
wcAddToCartButton.is('.disabled') ||
wc_revolut_payment_request_params.is_cart_page
) {
return
}
paymentRequest.updateWith(createCart())
})
$(document.body).on('updated_cart_totals', function () {
initPaymentRequestButton()
initRevolutPayExpressCheckoutButton()
})
initPaymentRequestButton()
initRevolutPayExpressCheckoutButton()
function buildFormData(formData, data, parentKey) {
if (data && typeof data === 'object') {
Object.keys(data).forEach(key => {
buildFormData(formData, data[key], parentKey ? `${parentKey}[${key}]` : key)
})
} else {
const value = data == null ? '' : data
formData.append(parentKey, value)
}
}
function sendRequest(url, data, shouldLogError = true) {
const requestData = new FormData()
buildFormData(requestData, data)
return fetch(url, {
method: 'POST',
body: requestData,
})
.then(response => response.json())
.catch(error => {
if (shouldLogError) {
logError(error)
}
throw error
})
}
})

View File

@@ -0,0 +1,249 @@
jQuery(document).ready(function ($) {
$('#woocommerce_revolut_cc_restore_button').hide()
const revolutMode = $('#woocommerce_revolut_mode')
const apiDevKey = $('#woocommerce_revolut_api_key_dev').parents().closest('tr')
const apiSandboxKey = $('#woocommerce_revolut_api_key_sandbox').parents().closest('tr')
const apiLiveKey = $('#woocommerce_revolut_api_key').parents().closest('tr')
const payment_action = $('#woocommerce_revolut_payment_action')
const capture_checkbox = $('#woocommerce_revolut_accept_capture')
const capture_checkbox_container = capture_checkbox.parents().closest('tr')
const customize_capture_status_checkbox = $(
'#woocommerce_revolut_customise_capture_status',
)
const customize_capture_status_checkbox_container = customize_capture_status_checkbox
.parents()
.closest('tr')
const capture_status = $('#woocommerce_revolut_selected_capture_status_list')
.parents()
.closest('tr')
$('#woocommerce_revolut_payment_request_onboard_applepay').hide()
if (!capture_checkbox.is(':checked')) {
customize_capture_status_checkbox_container.hide()
capture_status.hide()
} else {
customize_capture_status_checkbox_container.show()
}
if (!customize_capture_status_checkbox.is(':checked')) {
capture_status.hide()
}
if (revolutMode.val() == 'sandbox') {
change('sandbox')
} else if (revolutMode.val() == 'dev') {
change('dev')
} else {
change('live')
}
if (payment_action.val() == 'authorize') {
capture_checkbox_container.show()
} else {
capture_checkbox_container.hide()
customize_capture_status_checkbox_container.hide()
capture_status.hide()
}
customize_capture_status_checkbox.on('change', function () {
capture_status.toggle($(this).is(':checked'))
if (!$(this).is(':checked')) {
$('#woocommerce_revolut_selected_capture_status_list').val(null).trigger('change')
}
})
capture_checkbox.on('change', function () {
customize_capture_status_checkbox_container.toggle($(this).is(':checked'))
customize_capture_status_checkbox.change()
if (!$(this).is(':checked')) {
capture_status.hide()
}
})
revolutMode.on('change', function () {
var mode = $(this).val()
if (mode == 'sandbox') {
change('sandbox')
} else if (mode == 'dev') {
change('dev')
} else {
change('live')
}
})
// change payment action
payment_action.on('change', function () {
if (payment_action.val() == 'authorize') {
capture_checkbox_container.show()
capture_checkbox.change()
} else {
capture_checkbox_container.hide()
customize_capture_status_checkbox_container.hide()
capture_status.hide()
}
})
// change API mode
function change(mode) {
if (mode == 'sandbox') {
apiSandboxKey.show()
apiLiveKey.hide()
apiDevKey.hide()
} else if (mode == 'dev') {
apiSandboxKey.hide()
apiLiveKey.hide()
apiDevKey.show()
apiLiveKey.hide()
} else {
apiSandboxKey.hide()
apiDevKey.hide()
apiLiveKey.show()
}
}
// onboard apple pay domain
$('.setup-applepay-domain').click(function (event) {
event.preventDefault()
$.ajax({
type: 'POST',
url: ajaxurl,
data: {
action: 'wc_revolut_onboard_applepay_domain',
},
success: function (response) {
let message = ''
const setup_button = $('.setup-applepay-domain')
if (!response.success && response.message) {
message = response.message
}
if (response.success) {
setup_button.text('Success')
setup_button.prop('disabled', true)
return true
}
$('.setup-applepay-domain-error')
.show()
.text('Setup Failed: ' + message)
},
})
})
$(document).on('change', '.revolut_styling_option_enable', function () {
if (!$('.revolut_styling_option_enable').is(':checked')) {
$('.revolut_styling_option').parents('tr').hide()
restoreStylinOptions()
} else {
$('.revolut_styling_option').parents('tr').show()
}
})
$(document).on('click', '.revolut_style_restore', function () {
restoreStylinOptions()
})
if (!$('.revolut_styling_option_enable').is(':checked')) {
$('.revolut_styling_option').parents('tr').hide()
}
function restoreStylinOptions() {
$('#woocommerce_revolut_cc_widget_background_color')
.val(default_options.default_bg_color)
.trigger('change')
$('#woocommerce_revolut_cc_widget_text_color')
.val(default_options.default_text_color)
.trigger('change')
$('#woocommerce_revolut_cc_revolut_logo_color').prop('selectedIndex', 0).val()
}
adjustCardWidgetStylingOptions()
$(document).on('change', '#woocommerce_revolut_cc_card_widget_type', function () {
adjustCardWidgetStylingOptions()
})
function adjustCardWidgetStylingOptions() {
if ($('#woocommerce_revolut_cc_card_widget_type').val() === 'popup') {
$('#woocommerce_revolut_cc_styling_title').hide()
$('#woocommerce_revolut_cc_widget_styling').parents('table').hide()
$('#woocommerce_revolut_cc_enable_cardholder_name').parents('tr').hide()
} else {
$('#woocommerce_revolut_cc_styling_title').show()
$('#woocommerce_revolut_cc_widget_styling').parents('table').show()
$('#woocommerce_revolut_cc_enable_cardholder_name').parents('tr').show()
}
}
$('#woocommerce_revolut_advanced_settings_clear_unused_order_records').hide()
const consent_clear_unused_order_records = $(
'#woocommerce_revolut_advanced_settings_consent_clear_unused_order_records',
)
consent_clear_unused_order_records.change(function () {
if ($(this).is(':checked')) {
consent_clear_unused_order_records.removeAttr('style')
} else {
consent_clear_unused_order_records.css({ borderColor: 'red' })
}
})
$('.revolut_clear_unused_order_records').click(function (e) {
e.preventDefault()
self = $(this)
if (!consent_clear_unused_order_records.is(':checked')) {
consent_clear_unused_order_records.css({ borderColor: 'red' })
alert(
'Please indicate that you have read and agree to the consequences of this operation.',
)
return false
}
$.blockUI({
message: null,
overlayCSS: { background: '#fff', opacity: 0.6 },
})
$.ajax({
type: 'POST',
url: ajaxurl,
data: {
action: 'wc_revolut_clear_records',
},
success: function (response) {
$.unblockUI()
if (response && !response.success) {
return alert(response.message)
}
alert('Operation completed successfully.')
},
error: function (jqXHR, textStatus, errorThrown) {
$.unblockUI()
if (jqXHR && jqXHR.responseText) {
let response = jqXHR.responseText.match(/{(.*?)}/)
if (response.length > 0 && response[0]) {
try {
response = JSON.parse(response[0])
if (response.message) {
alert(response.message)
return false
}
} catch (e) {
// swallow error and handle in generic block below
}
}
}
alert(errorThrown)
},
})
})
})

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,230 @@
<?php
/**
* Plugin Name: Revolut Gateway for WooCommerce
* Plugin URI: https://wordpress.org/plugins/revolut-gateway-for-woocommerce/
* Description: Accept card payments easily and securely via Revolut.
* Author: Revolut
* Author URI: https://www.revolut.com/business/online-payments
* Text Domain: revolut-gateway-for-woocommerce
* Version: 4.9.5
* Requires at least: 4.4
* Tested up to: 6.1
* WC tested up to: 6.5
* WC requires at least: 2.6
*/
defined( 'ABSPATH' ) || exit;
define( 'REVOLUT_PATH', plugin_dir_path( __FILE__ ) );
define( 'WC_GATEWAY_REVOLUT_VERSION', '4.9.5' );
define( 'WC_GATEWAY_PUBLIC_KEY_ENDPOINT', '/public-key/latest' );
define( 'WC_GATEWAY_REVPAY_INDEX', 'USE_REVOLUT_PAY_2_0' );
define( 'WC_REVOLUT_WAIT_FOR_ORDER_TIME', 2 );
define( 'WC_REVOLUT_FETCH_API_ORDER_ATTEMPTS', 10 );
define( 'WC_REVOLUT_AUTO_CANCEL_TIMEOUT', 'PT2M' );
define( 'WC_REVOLUT_GATEWAYS', array( 'revolut', 'revolut_cc', 'revolut_pay', 'revolut_payment_request' ) );
/**
* Manage all dependencies
*/
require_once REVOLUT_PATH . 'includes/class-wc-revolut-manager.php';
/**
* Init revolut
*/
function woocommerce_revolut_init() {
if ( ! class_exists( 'WC_Payment_Gateway' ) ) {
return;
}
// be sure that plugin activation hook gets triggered.
if ( WC_GATEWAY_REVOLUT_VERSION !== get_option( 'WC_GATEWAY_REVOLUT_VERSION' ) ) {
woocommerce_revolut_install( is_network_admin() );
}
define( 'WC_REVOLUT_MAIN_FILE', __FILE__ );
define( 'WC_REVOLUT_CARD_WIDGET_BG_COLOR', '#ffffff' );
define( 'WC_REVOLUT_CARD_WIDGET_TEXT_COLOR', '#848484' );
define( 'WC_REVOLUT_PLUGIN_URL', untrailingslashit( plugins_url( basename( plugin_dir_path( __FILE__ ) ), basename( __FILE__ ) ) ) );
add_action( 'admin_enqueue_scripts', 'woocommerce_revolut_load_admin_scripts' );
load_plugin_textdomain( 'revolut-gateway-for-woocommerce', false, dirname( plugin_basename( __FILE__ ) ) . '/languages' );
add_filter( 'woocommerce_payment_gateways', 'woocommerce_revolut_add_gateways' );
add_action( 'init', 'woocommerce_revolut_load_rest_api' );
add_action( 'wp_loaded', 'rest_api_includes' );
}
/**
* Include required env methods for webhook callbacks
*/
function rest_api_includes() {
require_once WC_ABSPATH . 'includes/wc-cart-functions.php';
require_once WC_ABSPATH . 'includes/wc-notice-functions.php';
}
/**
* Load API function
*/
function woocommerce_revolut_load_rest_api() {
add_action( 'rest_api_init', 'woocommerce_revolut_create_callback_api', 99 );
}
/**
* Create API to accept setup Webhook
*/
function woocommerce_revolut_create_callback_api() {
$api = new Revolut_Webhook_Controller();
$api->register_routes();
}
add_action( 'plugins_loaded', 'woocommerce_revolut_init', 0 );
/**
* Set up Revolut plugin links
*
* @param array $links Revolut plugin link.
*
* @return array
*/
function woocommerce_revolut_plugin_links( $links ) {
$settings_url = add_query_arg(
array(
'page' => 'wc-settings',
'tab' => 'checkout',
'section' => 'revolut',
),
admin_url( 'admin.php' )
);
$plugin_links = array(
'<a href="' . esc_url( $settings_url ) . '">' . __( 'Settings', 'revolut-gateway-for-woocommerce' ) . '</a>',
'<a href="https://business.revolut.com/help-centre">' . __( 'Support', 'revolut-gateway-for-woocommerce' ) . '</a>',
'<a href="https://developer.revolut.com/docs/accept-payments/plugins/woocommerce/configuration">' . __( 'Docs', 'revolut-gateway-for-woocommerce' ) . '</a>',
);
return array_merge( $plugin_links, $links );
}
add_filter( 'plugin_action_links_' . plugin_basename( __FILE__ ), 'woocommerce_revolut_plugin_links' );
/**
* Add Revolut payment gateways
*
* @param String $gateways Revolut Payment Gateways.
*
* @return mixed
*/
function woocommerce_revolut_add_gateways( $gateways ) {
return array_merge( $gateways, woocommerce_revolut_payment_gateways() );
}
/**
* Get Revolut payment gateway list.
*/
function woocommerce_revolut_payment_gateways() {
return array(
'WC_Gateway_Revolut_CC',
'WC_Gateway_Revolut_Pay',
'WC_Gateway_Revolut_Payment_Request',
);
}
/**
* Create table to save Revolut Order
*/
register_activation_hook( __FILE__, 'woocommerce_revolut_install' );
/**
* Install plugin tables.
*
* @param bool $network_wide if the plugin is being network-activated.
*/
function woocommerce_revolut_install( $network_wide ) {
global $wpdb;
// Check if the plugin is being network-activated or not.
if ( $network_wide ) {
// Retrieve all site IDs from this network (WordPress >= 4.6 provides easy to use functions for that).
if ( function_exists( 'get_sites' ) && function_exists( 'get_current_network_id' ) ) {
$site_ids = get_sites(
array(
'fields' => 'ids',
'network_id' => get_current_network_id(),
)
);
} else {
$site_ids = $wpdb->get_col( $wpdb->prepare( "SELECT blog_id FROM $wpdb->blogs WHERE site_id = %s;", array( $wpdb->siteid ) ) ); // db call ok; no-cache ok.
}
// Install the plugin for all these sites.
foreach ( $site_ids as $site_id ) {
switch_to_blog( $site_id );
woocommerce_revolut_install_single_site();
restore_current_blog();
}
} else {
woocommerce_revolut_install_single_site();
}
}
/**
* Install plugin tables for single site.
*/
function woocommerce_revolut_install_single_site() {
global $wpdb;
$charset_collate = $wpdb->get_charset_collate();
$orders_table_name = $wpdb->prefix . 'wc_revolut_orders';
$temp_session_name = $wpdb->prefix . 'wc_revolut_temp_session';
$customer_table_name = $wpdb->prefix . 'wc_revolut_customer';
try {
$orders_table_sql = "CREATE TABLE IF NOT EXISTS $orders_table_name (
order_id BINARY(16) NOT NULL,
public_id BINARY(16) NOT NULL UNIQUE,
wc_order_id INTEGER NULL UNIQUE,
PRIMARY KEY (order_id)
) $charset_collate;";
$temp_session_table_sql = "CREATE TABLE IF NOT EXISTS $temp_session_name (
order_id VARCHAR (150) NOT NULL UNIQUE,
temp_session TEXT,
INDEX (order_id)
) $charset_collate;";
$customers_table_sql = "CREATE TABLE IF NOT EXISTS $customer_table_name (
wc_customer_id INTEGER NOT NULL UNIQUE,
revolut_customer_id VARCHAR (50) NOT NULL UNIQUE,
PRIMARY KEY (wc_customer_id)
) $charset_collate;";
require_once ABSPATH . 'wp-admin/includes/upgrade.php';
dbDelta( $orders_table_sql );
dbDelta( $temp_session_table_sql );
dbDelta( $customers_table_sql );
// update plugin version on DB.
update_option( 'WC_GATEWAY_REVOLUT_VERSION', WC_GATEWAY_REVOLUT_VERSION );
} catch ( Exception $exception ) {
if ( defined( 'WP_DEBUG' ) && WP_DEBUG === true ) {
// phpcs:disable WordPress.PHP.DevelopmentFunctions
error_log( $exception->getMessage() );
// phpcs:enable
}
}
}
/**
* Add script to setup Webhook using ajax
*/
function woocommerce_revolut_load_admin_scripts() {
wp_register_script( 'revolut-settings', plugins_url( 'assets/js/revolut-setting.js', WC_REVOLUT_MAIN_FILE ), array(), WC_GATEWAY_REVOLUT_VERSION, false );
wp_localize_script(
'revolut-settings',
'default_options',
array(
'default_bg_color' => WC_REVOLUT_CARD_WIDGET_BG_COLOR,
'default_text_color' => WC_REVOLUT_CARD_WIDGET_TEXT_COLOR,
)
);
wp_enqueue_script( 'revolut-settings' );
}

View File

@@ -0,0 +1,306 @@
<?php
/**
* Revolut API Client
*
* @package WooCommerce
* @since 2.0
* @author Revolut
*/
defined( 'ABSPATH' ) || exit();
/**
* WC_Revolut_API_Client class.
*/
class WC_Revolut_API_Client {
use WC_Revolut_Logger_Trait;
/**
* Revolut Api Version
*
* @var string
*/
public $api_version = '2023-09-01';
/**
* Api url live mode
*
* @var string
*/
public $api_url_live = 'https://merchant.revolut.com';
/**
* Api url sandbox mode
*
* @var string
*/
public $api_url_sandbox = 'https://sandbox-merchant.revolut.com';
/**
* Api url dev mode
*
* @var string
*/
public $api_url_dev = 'https://merchant.revolut.codes';
/**
* Merchant management Api urls
*
* @var array
*/
public $mgmt_api_urls = array(
'live' => 'https://merchant-mgmt.revolut.com',
'dev' => 'https://merchant-mgmt.revolut.codes',
'sandbox' => 'https://sandbox-merchant-mgmt.revolut.com',
);
/**
* Api mode live|sandbox|develop
*
* @var string
*/
public $mode;
/**
* Api key
*
* @var string
*/
public $api_key;
/**
* Public key
*
* @var string
*/
public $public_key;
/**
* Api base url
*
* @var string
*/
public $base_url;
/**
* Api url
*
* @var string
*/
public $api_url;
/**
* Public Api url
*
* @var string
*/
public $mgmt_api_url;
/**
* API settings
*
* @var WC_Revolut_Settings_API
*/
private $api_settings;
/**
* Constructor
*
* @param WC_Revolut_Settings_API $api_settings Api settings.
* @param bool $new_api api version.
*/
public function __construct( WC_Revolut_Settings_API $api_settings, $new_api = false ) {
$this->api_settings = $api_settings;
$this->mode = $this->api_settings->get_option( 'mode' );
if ( 'live' === $this->mode ) {
$this->base_url = $this->api_url_live;
$this->api_key = $this->api_settings->get_option( 'api_key' );
} elseif ( 'sandbox' === $this->mode ) {
$this->base_url = $this->api_url_sandbox;
$this->api_key = $this->api_settings->get_option( 'api_key_sandbox' );
} elseif ( 'dev' === $this->mode ) {
$this->base_url = $this->api_url_dev;
$this->api_key = $this->api_settings->get_option( 'api_key_dev' );
}
// switch to the new api if required.
$this->api_url = $new_api ? $this->base_url . '/api' : $this->base_url . '/api/1.0';
$this->mgmt_api_url = $this->mgmt_api_urls[ $this->mode ];
}
/**
* Send post to API.
*
* @param String $path Api path.
* @param array|null $body Request body.
* @param bool $is_mgmt_endpoint Management API indicator.
* @param bool $new_api New API indicator.
*
* @return mixed
* @throws Exception Exception.
*/
public function post( $path, $body = null, $is_mgmt_endpoint = false, $new_api = false ) {
return $this->request( $path, 'POST', $body, $is_mgmt_endpoint, $new_api );
}
/**
* Send request to API
*
* @param String $path Api path.
* @param String $method Request method.
* @param array|null $body Request body.
* @param bool $is_mgmt_api_endpoint Management API endpoint indicator.
* @param bool $new_api New API indicator.
* @param bool $is_mgmt_endpoint Management endpoint indicator.
*
* @return mixed
* @throws Exception Exception.
*/
private function request( $path, $method, $body = null, $is_mgmt_api_endpoint = false, $new_api = false, $is_mgmt_endpoint = false ) {
global $wp_version;
global $woocommerce;
if ( empty( $this->api_key ) ) {
return array();
}
$api_key = $this->api_key;
if ( $is_mgmt_api_endpoint && WC_GATEWAY_PUBLIC_KEY_ENDPOINT !== $path ) {
$api_key = $this->public_key;
}
$request = array(
'headers' => array(
'Revolut-Api-Version' => $this->api_version,
'Authorization' => 'Bearer ' . $api_key,
'User-Agent' => 'Revolut Payment Gateway/' . WC_GATEWAY_REVOLUT_VERSION . ' WooCommerce/' . $woocommerce->version . ' Wordpress/' . $wp_version . ' PHP/' . PHP_VERSION,
'Content-Type' => 'application/json',
),
'method' => $method,
);
if ( null !== $body ) {
$request['body'] = wp_json_encode( $body );
}
$url = $this->api_url . $path;
if ( $new_api ) {
$url = $this->base_url . '/api' . $path;
}
if ( $is_mgmt_api_endpoint ) {
$url = $this->mgmt_api_url . '/api' . $path;
}
if ( $is_mgmt_endpoint ) {
$url = $this->mgmt_api_url . $path;
}
$response = wp_remote_request( $url, $request );
$response_body = wp_remote_retrieve_body( $response );
if ( wp_remote_retrieve_response_code( $response ) >= 400 && wp_remote_retrieve_response_code( $response ) < 500 && 'GET' !== $method ) {
$this->log_error( "Failed request to URL $method $url" );
$this->log_error( $response_body );
throw new Exception( "Something went wrong: $method $url\n" . $response_body );
}
return json_decode( $response_body, true );
}
/**
* Send request to public API
*
* @param String $path Api path.
* @param array $headers Request method.
* @param String $method Request method.
* @param array|null $body Request body.
*
* @return mixed
* @throws Exception Exception.
*/
public function public_request( $path, $headers, $method = 'POST', $body = null ) {
global $wp_version;
global $woocommerce;
$headers['User-Agent'] = 'Revolut Payment Gateway/' . WC_GATEWAY_REVOLUT_VERSION . ' WooCommerce/' . $woocommerce->version . ' Wordpress/' . $wp_version . ' PHP/' . PHP_VERSION;
$headers['Content-Type'] = 'application/json';
$request = array(
'headers' => $headers,
'method' => $method,
);
if ( null !== $body ) {
$request['body'] = wp_json_encode( $body );
}
$url = $this->mgmt_api_url . '/public/' . $path;
$response = wp_remote_request( $url, $request );
$response_body = wp_remote_retrieve_body( $response );
if ( wp_remote_retrieve_response_code( $response ) >= 400 && wp_remote_retrieve_response_code( $response ) < 500 && 'GET' !== $method ) {
$this->log_error( "Failed request to URL $method $url" );
$this->log_error( $response_body );
throw new Exception( "Something went wrong: $method $url\n" . $response_body );
}
return json_decode( $response_body, true );
}
/**
* Send GET request to API
*
* @param String $path Request path.
* @param Boolean $is_mgmt_api Management API endpoint indicator.
* @param Boolean $is_mgmt Management API indicator.
*
* @return mixed
* @throws Exception Exception.
*/
public function get( $path, $is_mgmt_api = false, $is_mgmt = false ) {
return $this->request( $path, 'GET', null, $is_mgmt_api, false, $is_mgmt );
}
/**
* Revolut API patch
*
* @param String $path Request path.
* @param array|null $body Request body.
*
* @return mixed
* @throws Exception Exception.
*/
public function patch( $path, $body ) {
return $this->request( $path, 'PATCH', $body );
}
/**
* Revolut API delete
*
* @param String $path Request path.
*
* @return mixed
* @throws Exception Exception.
*/
public function delete( $path ) {
return $this->request( $path, 'DELETE' );
}
/**
* Set Revolut Merchant Public Key
*
* @param String $public_key public key.
*
* @return void
*/
public function set_public_key( $public_key ) {
$this->public_key = $public_key;
}
}

View File

@@ -0,0 +1,421 @@
<?php
/**
* Revolut Apple Pay Merchant On-boarding Class.
*
* @package WooCommerce
* @category Payment Gateways
* @author Revolut
* @since 3.0.0
*/
if ( ! defined( 'ABSPATH' ) ) {
exit;
}
/**
* WC_Revolut_Apple_Pay_OnBoarding class.
*/
class WC_Revolut_Apple_Pay_OnBoarding {
use WC_Revolut_Logger_Trait;
/**
* Onboarding file name.
*
* @var string
*/
public $domain_onboarding_file_name;
/**
* Onboarding file directory.
*
* @var string
*/
public $domain_onboarding_file_directory;
/**
* Domain name.
*
* @var string
*/
private $domain_name;
/**
* Error message.
*
* @var string
*/
public $error_messages;
/**
* Success message.
*
* @var string
*/
public $success_messages;
/**
* API settings
*
* @var WC_Revolut_Settings_API
*/
public $api_settings;
/**
* Revolut payment request setting.
*
* @var array
*/
public $revolut_payment_request_settings;
/**
* API client
*
* @var WC_Revolut_API_Client
*/
public $api_client;
/**
* Constructor
*/
public function __construct() {
$this->api_settings = revolut_wc()->api_settings;
$this->api_client = new WC_Revolut_API_Client( $this->api_settings, true );
add_action( 'admin_init', array( $this, 'maybe_onboard_apple_pay_merchant' ) );
add_action( 'admin_notices', array( $this, 'admin_notices' ) );
add_action( 'add_option_woocommerce_revolut_settings', array( $this, 'on_revolut_options_update' ), 10, 2 );
add_action( 'update_option_woocommerce_revolut_settings', array( $this, 'on_revolut_options_update' ), 10, 2 );
add_action(
'add_option_woocommerce_revolut_payment_request_settings',
array( $this, 'maybe_onboard_apple_pay_merchant' ),
10,
2
);
add_action(
'update_option_woocommerce_revolut_payment_request_settings',
array( $this, 'on_revolut_payment_request_options_update' ),
10,
2
);
$this->domain_onboarding_file_name = 'apple-developer-merchantid-domain-association';
$this->domain_onboarding_file_directory = '.well-known';
$this->onboarding_file_dir = untrailingslashit( ABSPATH ) . '/' . $this->domain_onboarding_file_directory;
$this->onboarding_file_path = $this->onboarding_file_dir . '/' . $this->domain_onboarding_file_name;
$this->domain_onboarding_file_remote_link = 'https://assets.revolut.com/api-docs/merchant-api/files/apple-developer-merchantid-domain-association';
$this->revolut_payment_request_settings = get_option( 'woocommerce_revolut_payment_request_settings', array() );
$this->domain_name = isset( $_SERVER['HTTP_HOST'] ) ? sanitize_text_field( wp_unslash( $_SERVER['HTTP_HOST'] ) ) : str_replace(
array(
'https://',
'http://',
),
'',
get_site_url()
); // phpcs:ignore
$this->error_messages = array();
$this->success_messages = array();
}
/**
* Try to onboard after Revolut API settings updated.
*
* @param array $old_options old options.
* @param array $new_options new options.
*/
public function on_revolut_options_update( $old_options, $new_options ) {
$this->api_settings = revolut_wc()->api_settings;
$this->api_client = new WC_Revolut_API_Client( $this->api_settings, true );
$this->maybe_onboard_apple_pay_merchant();
}
/**
* Try to onboard after payment request settings updated.
*
* @param array $old_options old options.
* @param array $new_options new options.
*/
public function on_revolut_payment_request_options_update( $old_options, $new_options ) {
$this->revolut_payment_request_settings = $new_options;
$this->maybe_onboard_apple_pay_merchant();
}
/**
* Display messages.
*/
public function admin_notices() {
$page = $this->get_request_data( 'page' );
$section = $this->get_request_data( 'section' );
if ( ! empty( $page ) && ! empty( $section ) ) {
$is_revolut_section = 'wc-settings' === $page && in_array( $section, WC_REVOLUT_GATEWAYS, true );
if ( $is_revolut_section ) {
if ( ! empty( $this->error_messages ) ) {
$this->error_messages = array_unique( $this->error_messages );
foreach ( $this->error_messages as $message ) {
echo wp_kses_post( '<div class="error revolut-passphrase-message"><p>' . $message . '</p></div>' );
}
}
if ( ! empty( $this->success_messages ) ) {
foreach ( $this->success_messages as $message ) {
echo wp_kses_post( '<div style="border-left-color: green" class="error revolut-passphrase-message"><p>' . $message . '</p></div>' );
}
}
}
}
}
/**
* Check is shop needs onboarding.
*/
public function check_is_shop_needs_onboarding() {
if ( $this->check_is_already_onboarded() ) {
return false;
}
if ( ! $this->is_revolut_payment_request_enabled() ) {
return false;
}
if ( ! $this->check_is_api_key_configured() ) {
return false;
}
return true;
}
/**
* Check is api key configured.
*/
public function check_is_api_key_configured() {
return ! empty( $this->api_client->api_key ) && 'sandbox' !== $this->api_settings->get_option( 'mode' );
}
/**
* Check is already onboarded.
*/
public function check_is_already_onboarded() {
return $this->get_option( 'apple_pay_merchant_onboarded' ) === 'yes'
&& $this->get_option( 'apple_pay_merchant_onboarded_api_key' ) === $this->api_client->api_key
&& $this->domain_name === $this->get_option( 'apple_pay_merchant_onboarded_domain' );
}
/**
* Check is payment request enabled.
*/
public function is_revolut_payment_request_enabled() {
return 'yes' === $this->get_option( 'enabled', 'yes' );
}
/**
* Get configuration options.
*
* @param string $option option key.
* @param mixed $default default value.
*/
public function get_option( $option, $default = '' ) {
if ( isset( $this->revolut_payment_request_settings[ $option ] ) && ! empty( $this->revolut_payment_request_settings[ $option ] ) ) {
return $this->revolut_payment_request_settings[ $option ];
}
return $default;
}
/**
* Onboard Apple Pay merchant if required.
*/
public function maybe_onboard_apple_pay_merchant() {
$action = $this->get_post_request_data( 'action' );
if ( ! empty( $action ) && 'wc_revolut_onboard_applepay_domain' === $action ) {
return false; // skip for manual on-boarding.
}
if ( ! $this->check_is_shop_needs_onboarding() ) {
return false;
}
flush_rewrite_rules();
if ( ! $this->download_onboarding_file() ) {
$this->revolut_payment_request_settings['apple_pay_merchant_onboarded_domain'] = '';
$this->revolut_payment_request_settings['apple_pay_merchant_onboarded'] = 'no';
update_option(
'woocommerce_revolut_payment_request_settings',
$this->revolut_payment_request_settings
);
return false;
}
if ( ! $this->register_domain() ) {
$this->add_onboarding_error_message(
__(
'Can not on-boarding Apple Pay merchant',
'revolut-gateway-for-woocommerce'
)
);
$this->revolut_payment_request_settings['apple_pay_merchant_onboarded_domain'] = '';
$this->revolut_payment_request_settings['apple_pay_merchant_onboarded'] = 'no';
update_option(
'woocommerce_revolut_payment_request_settings',
$this->revolut_payment_request_settings
);
return false;
}
$this->remove_onboarding_file();
$this->revolut_payment_request_settings['apple_pay_merchant_onboarded_domain'] = $this->domain_name;
$this->revolut_payment_request_settings['apple_pay_merchant_onboarded_api_key'] = $this->api_client->api_key;
$this->revolut_payment_request_settings['apple_pay_merchant_onboarded'] = 'yes';
update_option( 'woocommerce_revolut_payment_request_settings', $this->revolut_payment_request_settings );
$this->add_onboarding_success_message(
__(
'Apple Pay merchant on-boarded successfully',
'revolut-gateway-for-woocommerce'
)
);
}
/**
* Register domain.
*/
public function register_domain() {
try {
$request_body = array(
'domain' => $this->domain_name,
);
$res = $this->api_client->post( '/apple-pay/domains/register', $request_body );
} catch ( Exception $e ) {
$this->log_error( $e->getMessage() );
return false;
}
return true;
}
/**
* Download onboarding file.
*/
public function download_onboarding_file() {
try {
if ( ! file_exists( $this->onboarding_file_dir ) && ! mkdir( $this->onboarding_file_dir, 0755 ) ) {
$this->add_onboarding_error_message(
__(
'Can not on-boarding Apple Pay merchant: Can not create directory',
'woocommerce-gateway-revolut'
)
);
return false;
}
global $wp_filesystem;
if ( empty( $wp_filesystem ) ) {
require_once ABSPATH . '/wp-admin/includes/file.php';
WP_Filesystem();
}
if ( ! file_put_contents( $this->onboarding_file_path, file_get_contents( $this->domain_onboarding_file_remote_link )) ) // phpcs:ignore
{
$this->add_onboarding_error_message(
__(
'Can not on-boarding Apple Pay merchant: Can not locate on-boarding file',
'revolut-gateway-for-woocommerce'
)
);
return false;
}
return true;
} catch ( Exception $e ) {
$this->log_error( $e->getMessage() );
return false;
}
}
/**
* Remove onboarding file.
*/
public function remove_onboarding_file() {
if ( ! unlink( $this->onboarding_file_path ) ) {
$this->add_onboarding_error_message(
__(
'Can not remove on-boarding file',
'revolut-gateway-for-woocommerce'
)
);
}
}
/**
* Add error message.
*
* @param string $message message.
*/
public function add_onboarding_error_message( $message ) {
$this->error_messages[] = $message;
}
/**
* Add success message.
*
* @param string $message message.
*/
public function add_onboarding_success_message( $message ) {
$this->success_messages[] = $message;
}
/**
* Safe get posted data
*
* @param string $post_key request key.
*/
public function get_post_request_data( $post_key ) {
if ( ! isset( $_POST[ $post_key ] ) ) { // phpcs:ignore
return null;
}
return $this->recursive_sanitize_text_field( $_POST[ $post_key ]); // phpcs:ignore
}
/**
* Safe get request data
*
* @param string $get_key request key.
*/
public function get_request_data( $get_key ) {
if ( ! isset( $_GET[ $get_key ] ) ) { // phpcs:ignore
return null;
}
return $this->recursive_sanitize_text_field( $_GET[ $get_key ] ); // phpcs:ignore
}
/**
* Clear data.
*
* @param mixed $var data for cleaning.
*/
public function recursive_sanitize_text_field( $var ) {
if ( is_array( $var ) ) {
return array_map( array( $this, 'recursive_sanitize_text_field' ), $var );
} else {
return sanitize_text_field( wp_unslash( $var ) );
}
}
}

View File

@@ -0,0 +1,107 @@
<?php
/**
* Singleton class that handles class loading.
*
* @package WooCommerce
* @category Payment Gateways
* @author Revolut
* @since 2.0.0
*/
defined( 'ABSPATH' ) || exit();
/**
* WC_Revolut_Manager class.
*/
class WC_Revolut_Manager {
/**
* Class instance.
*
* @var object
*/
public static $instance;
/**
* Get singleton class instance.
*/
public static function instance() {
if ( null === self::$instance ) {
self::$instance = new self();
}
return self::$instance;
}
/**
* Constructor
*/
public function __construct() {
add_action( 'woocommerce_init', array( $this, 'woocommerce_dependencies' ) );
}
/**
* Include plugin dependencies.
*/
public function woocommerce_dependencies() {
// traits.
include_once REVOLUT_PATH . 'includes/traits/wc-revolut-settings-trait.php';
include_once REVOLUT_PATH . 'includes/traits/wc-revolut-logger-trait.php';
include_once REVOLUT_PATH . 'includes/traits/wc-revolut-helper-trait.php';
include_once REVOLUT_PATH . 'includes/traits/wc-revolut-express-checkout-helper-trait.php';
// load gateways.
include_once REVOLUT_PATH . 'includes/abstract/class-wc-payment-gateway-revolut.php';
include_once REVOLUT_PATH . 'includes/gateways/class-wc-gateway-revolut-cc.php';
include_once REVOLUT_PATH . 'includes/gateways/class-wc-gateway-revolut-pay.php';
require_once REVOLUT_PATH . 'includes/gateways/class-wc-gateway-revolut-payment-request.php';
// main classes.
include_once REVOLUT_PATH . 'includes/class-wc-revolut-privacy.php';
include_once REVOLUT_PATH . 'includes/class-wc-revolut-validate-checkout.php';
include_once REVOLUT_PATH . 'includes/class-wc-revolut-order-descriptor.php';
include_once REVOLUT_PATH . 'includes/class-wc-revolut-payment-ajax-controller.php';
include_once REVOLUT_PATH . 'includes/class-wc-revolut-apple-pay-onboarding.php';
include_once REVOLUT_PATH . 'includes/api/class-wc-revolut-api-client.php';
include_once REVOLUT_PATH . '/api/class-revolut-webhook-controller.php';
// settings.
include_once REVOLUT_PATH . 'includes/settings/class-wc-revolut-settings-api.php';
include_once REVOLUT_PATH . 'includes/settings/class-wc-revolut-advanced-settings.php';
include_once REVOLUT_PATH . '/includes/class-wc-revolut-payment-tokens.php';
// allow other plugins to provide their own settings class.
$setting_classes = apply_filters(
'wc_revolut_setting_classes',
array(
'api_settings' => 'WC_Revolut_Settings_API',
)
);
foreach ( $setting_classes as $id => $class_name ) {
if ( class_exists( $class_name ) ) {
$this->{$id} = new $class_name();
}
}
new WC_Revolut_Apple_Pay_OnBoarding();
new WC_Revolut_Payment_Ajax_Controller();
new WC_Gateway_Revolut_Payment_Request();
new WC_Gateway_Revolut_Pay();
new WC_Revolut_Advanced_Settings();
}
}
/**
* Returns the global instance of the WC_Revolut_Manager.
*
* @return WC_Revolut_Manager
* @since 2.0.0
*/
function revolut_wc() {
return WC_Revolut_Manager::instance();
}
// load singleton.
revolut_wc();

View File

@@ -0,0 +1,61 @@
<?php
/**
* Revolut order Descriptor.
*
* @package WooCommerce
* @category Payment Gateways
* @author Revolut
* @since 2.0.0
*/
/**
* WC_Revolut_Order_Descriptor class.
*/
class WC_Revolut_Order_Descriptor {
use WC_Gateway_Revolut_Helper_Trait;
/**
* Order total amount.
*
* @var float
*/
public $amount;
/**
* Order currency.
*
* @var string
*/
public $currency;
/**
* Revolut customer id.
*
* @var string
*/
public $revolut_customer_id;
/**
* OrderDescriptor constructor.
*
* @param float $amount payment amount.
* @param string $currency currency.
* @param string $revolut_customer_id Revolut customer id.
*/
public function __construct( $amount, $currency, $revolut_customer_id ) {
if ( $this->check_is_get_data_submitted( 'pay_for_order' ) && ! empty( $this->get_request_data( 'key' ) ) ) {
global $wp;
$order = wc_get_order( wc_clean( $wp->query_vars['order-pay'] ) );
$amount = $order->get_total();
}
if ( is_add_payment_method_page() || $this->is_subs_change_payment() ) {
$amount = 0;
}
$this->amount = $this->get_revolut_order_total( $amount, $currency );
$this->currency = $currency;
$this->revolut_customer_id = $revolut_customer_id;
}
}

View File

@@ -0,0 +1,471 @@
<?php
/**
* Handles AJAX calls, related to Revolut Payment.
*
* @package WooCommerce
* @category Payment Gateways
* @author Revolut
* @since 3.0.0
*/
if ( ! defined( 'ABSPATH' ) ) {
exit;
}
/**
* WC_Revolut_Payment_Ajax_Controller class.
*/
class WC_Revolut_Payment_Ajax_Controller {
use WC_Gateway_Revolut_Helper_Trait;
/**
* API client
*
* @var WC_Revolut_API_Client
*/
public $api_client;
/**
* Constructor
*/
public function __construct() {
$this->api_settings = revolut_wc()->api_settings;
$this->api_client = new WC_Revolut_API_Client( $this->api_settings );
add_action( 'wc_ajax_wc_revolut_validate_checkout_fields', array( $this, 'wc_revolut_validate_checkout_fields' ) );
add_action( 'wc_ajax_wc_revolut_validate_order_pay_form', array( $this, 'wc_revolut_validate_order_pay_form' ) );
add_action( 'wc_ajax_wc_revolut_get_order_pay_billing_info', array( $this, 'wc_revolut_get_order_pay_billing_info' ) );
add_action( 'wc_ajax_wc_revolut_get_customer_info', array( $this, 'wc_revolut_get_customer_info' ) );
add_action( 'wc_ajax_wc_revolut_process_payment_result', array( $this, 'wc_revolut_process_payment_result' ) );
add_action( 'wc_ajax_revolut_payment_request_cancel_order', array( $this, 'revolut_payment_request_ajax_cancel_order' ) );
add_action( 'wc_ajax_revolut_payment_request_set_error_message', array( $this, 'revolut_payment_request_ajax_set_error_message' ) );
add_action( 'wc_ajax_revolut_payment_request_log_error', array( $this, 'revolut_payment_request_ajax_log_error' ) );
add_action( 'wc_ajax_revolut_payment_request_log_error', array( $this, 'revolut_payment_request_ajax_log_error' ) );
if ( is_admin() ) {
add_action( 'wp_ajax_wc_revolut_set_webhook', array( $this, 'wc_revolut_set_webhook' ) );
add_action( 'wp_ajax_wc_revolut_clear_records', array( $this, 'wc_revolut_clear_records' ) );
add_action(
'wp_ajax_wc_revolut_onboard_applepay_domain',
array( $this, 'wc_revolut_onboard_applepay_domain' )
);
}
}
/**
* Process Revolut Order
*
* @throws Exception Exception.
*/
public function wc_revolut_process_payment_result() {
try {
$wc_order_id = $this->get_posted_integer_data( 'wc_order_id' );
$selected_gateway = $this->get_post_request_data( 'revolut_gateway' );
if ( empty( $wc_order_id ) || empty( $selected_gateway ) || empty( $this->get_post_request_data( 'revolut_public_id' ) ) ) {
$this->log_error(
array(
'wc_order_id' => $wc_order_id,
'selected_gateway' => $selected_gateway,
'revolut_public_id' => $this->get_post_request_data( 'revolut_public_id' ),
)
);
$revolut_payment_error = $this->get_post_request_data( 'revolut_payment_error' );
if ( empty( $revolut_payment_error ) ) {
$revolut_payment_error = __( 'We are unable to process your order, please try again.', 'woocommerce' );
}
throw new Exception( $revolut_payment_error );
}
$revolut_gateway = new WC_Gateway_Revolut_CC();
if ( 'revolut_pay' === $selected_gateway ) {
$revolut_gateway = new WC_Gateway_Revolut_Pay();
} elseif ( 'revolut_payment_request' === $selected_gateway ) {
$revolut_gateway = new WC_Gateway_Revolut_Payment_Request();
}
$result = $revolut_gateway->process_payment( $wc_order_id );
} catch ( Exception $e ) {
$result = array(
'messages' => $e->getMessage(),
'result' => 'fail',
'redirect' => '',
);
}
try {
if ( ! empty( $wc_order_id ) && isset( $result['result'] ) && 'success' === $result['result'] ) {
$result['order_id'] = $wc_order_id;
apply_filters( 'woocommerce_payment_successful_result', $result, $wc_order_id );
}
} catch ( Exception $e ) {
// if hook was unsuccessful do not prevent order process.
$this->log_error( $e->getMessage() );
}
wp_send_json( $result );
}
/**
* Setup webhook
*
* @throws Exception Exception.
*/
public function wc_revolut_set_webhook() {
try {
if ( $this->check_is_post_data_submitted( 'apiKey' ) || empty( $this->get_post_request_data( 'apiKey' ) ) ) {
wp_die( false );
}
if ( ! $this->check_is_post_data_submitted( 'mode' ) || empty( $this->get_post_request_data( 'mode' ) ) ) {
wp_die( false );
}
$web_hook_url = get_site_url( null, '/wp-json/wc/v3/revolut', 'https' );
$body = array(
'url' => $web_hook_url,
'events' => array(
'ORDER_COMPLETED',
'ORDER_AUTHORISED',
),
);
$mode = $this->get_post_request_data( 'mode' );
if ( 'live' === $mode ) {
$this->api_client->api_url = $this->api_client->api_url_live;
} elseif ( 'sandbox' === $mode ) {
$this->api_client->api_url = $this->api_client->api_url_sandbox;
} elseif ( 'dev' === $mode ) {
$this->api_client->api_url = $this->api_client->api_url_dev;
}
$this->api_client->api_url .= '/api/1.0';
$this->api_client->api_key = $this->get_post_request_data( 'apiKey' );
$web_hook_url_list = $this->api_client->get( '/webhooks' );
if ( ! empty( $web_hook_url_list ) ) {
$web_hook_url_list = array_column( $web_hook_url_list, 'url' );
if ( in_array( $web_hook_url, $web_hook_url_list, true ) ) {
wp_send_json(
array(
'success' => true,
)
);
}
}
$response = $this->api_client->post( '/webhooks', $body );
if ( isset( $response['id'] ) && ! empty( $response['id'] ) ) {
wp_send_json(
array(
'success' => true,
)
);
}
} catch ( Exception $e ) {
$this->log_error( $e->getMessage() );
wp_send_json(
array(
'success' => false,
'message' => $e->getMessage(),
)
);
}
wp_send_json(
array(
'success' => true,
)
);
}
/**
* Onboard Apple Pay domain
*
* @throws Exception Exception.
*/
public function wc_revolut_onboard_applepay_domain() {
try {
$domain_name = str_replace( array( 'https://', 'http://' ), '', get_site_url() );
$onboarding_file = untrailingslashit( ABSPATH ) . '/.well-known/apple-developer-merchantid-domain-association';
$is_exist = fopen( $onboarding_file, 'r' ); // phpcs:ignore WordPress.WP.AlternativeFunctions.file_system_read_fopen
if ( ! $is_exist ) {
wp_send_json(
array(
'success' => false,
'message' => 'Can not find Apple Pay on-boarding file: ' . $onboarding_file,
)
);
}
$request_body = array(
'domain' => $domain_name,
);
$this->api_settings = revolut_wc()->api_settings;
$this->api_client = new WC_Revolut_API_Client( $this->api_settings, true );
$response = $this->api_client->post( '/apple-pay/domains/register', $request_body );
$revolut_payment_request_settings = get_option( 'woocommerce_revolut_payment_request_settings', array() );
$revolut_payment_request_settings['apple_pay_merchant_onboarded_domain'] = $domain_name;
$revolut_payment_request_settings['apple_pay_merchant_onboarded_api_key'] = $this->api_client->api_key;
$revolut_payment_request_settings['apple_pay_merchant_onboarded'] = 'yes';
update_option( 'woocommerce_revolut_payment_request_settings', $revolut_payment_request_settings );
wp_send_json(
array(
'success' => true,
'response' => $response,
)
);
} catch ( Exception $e ) {
$this->log_error( $e->getMessage() );
wp_send_json(
array(
'success' => false,
'message' => $e->getMessage(),
)
);
}
wp_send_json(
array(
'success' => false,
'message' => 'Something went wrong.',
)
);
}
/**
* Clear unused order records
*
* @throws Exception Exception.
*/
public function wc_revolut_clear_records() {
try {
global $wpdb;
$result = $wpdb->query( $wpdb->prepare( 'DELETE FROM `' . $wpdb->prefix . 'wc_revolut_orders` WHERE wc_order_id is NUll or wc_order_id = "";' ) ); // phpcs:ignore
if ( ! $result && ! empty( $wpdb->last_error ) ) {
throw new Exception( $wpdb->last_error );
}
wp_send_json(
array(
'success' => true,
'result' => $result,
)
);
} catch ( Exception $e ) {
$this->log_error( $e->getMessage() );
wp_send_json(
array(
'success' => false,
'message' => $e->getMessage(),
)
);
}
}
/**
* Validate checkout fields
*
* @throws Exception Exception.
*/
public function wc_revolut_validate_checkout_fields() {
try {
wc_maybe_define_constant( 'WOOCOMMERCE_CHECKOUT', true );
if ( WC()->cart->is_empty() ) {
/* translators: %s: shop cart url */
throw new Exception( sprintf( __( 'Sorry, your session has expired. <a href="%s" class="wc-backward">Return to shop</a>', 'woocommerce' ), esc_url( wc_get_page_permalink( 'shop' ) ) ) );
}
$validate_checkout = new WC_Revolut_Validate_Checkout();
$validate_checkout->validate_checkout_fields();
if ( 0 === wc_notice_count( 'error' ) ) {
wp_send_json(
array(
'result' => 'success',
)
);
}
$validate_checkout->return_ajax_failure_response();
} catch ( Exception $e ) {
wc_add_notice( $e->getMessage(), 'error' );
$messages = wc_print_notices( true );
$response = array(
'result' => 'failure',
'messages' => isset( $messages ) ? $messages : '',
);
wp_send_json( $response );
}
}
/**
* Validate checkout fields
*
* @throws Exception Exception.
*/
public function wc_revolut_validate_order_pay_form() {
try {
$nonce_value = wc_get_var( $this->get_post_request_data( 'woocommerce-pay-nonce' ), $this->get_post_request_data( '_wpnonce' ) );
if ( ! wp_verify_nonce( $nonce_value, 'woocommerce-pay' ) ) {
throw new Exception( __( 'Something went wrong.', 'woocommerce' ) );
}
$order_key = $this->get_post_request_data( 'wc_order_key' );
$order_id = $this->get_posted_integer_data( 'wc_order_id' );
$order = wc_get_order( $order_id );
if ( $order_id === $order->get_id() && hash_equals( $order->get_order_key(), $order_key ) && $order->needs_payment() ) {
do_action( 'woocommerce_before_pay_action', $order );
if ( ! empty( $this->get_posted_integer_data( 'terms-field' ) && empty( $this->get_post_request_data( 'terms' ) ) ) ) {
throw new Exception( __( 'Please read and accept the terms and conditions to proceed with your order.', 'woocommerce' ) );
}
} else {
throw new Exception( __( 'Something went wrong.', 'woocommerce' ) );
}
wp_send_json(
array(
'result' => 'success',
)
);
} catch ( Exception $e ) {
$this->log_error( 'wc_revolut_validate_order_pay_form: ' . $e->getMessage() );
wc_add_notice( $e->getMessage(), 'error' );
wp_send_json(
array(
'result' => 'failure',
'messages' => wc_print_notices( true ),
)
);
}
}
/**
* Get billing info for manual order payments
*/
public function wc_revolut_get_order_pay_billing_info() {
check_ajax_referer( 'wc-revolut-get-billing-info', 'security' );
$order_id = $this->get_posted_integer_data( 'order_id' );
$order_key = $this->get_post_request_data( 'order_key' );
$order = wc_get_order( $order_id );
// validate order key.
if ( $order && $order_key === $order->get_order_key() ) {
$billing_address = $order->get_address( 'billing' );
$billing_info = array(
'name' => $billing_address['first_name'] . ' ' . $billing_address['last_name'],
'email' => $billing_address['email'],
'phone' => $billing_address['phone'],
'billingAddress' => array(
'countryCode' => $billing_address['country'],
'region' => $billing_address['state'],
'city' => $billing_address['city'],
'streetLine1' => $billing_address['address_1'],
'streetLine2' => $billing_address['address_2'],
'postcode' => $billing_address['postcode'],
),
);
wp_send_json( $billing_info );
}
wp_send_json( array() );
}
/**
* Get billing info for payment method save
*/
public function wc_revolut_get_customer_info() {
check_ajax_referer( 'wc-revolut-get-customer-info', 'security' );
$customer_id = get_current_user_id();
$customer = new WC_Customer( $customer_id );
// validate order key.
if ( $customer_id ) {
$billing_info = array(
'name' => $customer->get_first_name() . ' ' . $customer->get_last_name(),
'email' => $customer->get_email(),
'phone' => $customer->get_billing_phone(),
);
wp_send_json( $billing_info );
} else {
wp_send_json(
array(
'error' => true,
'msg' => 'Can not find customer address',
)
);
}
wp_die();
}
/**
* Cancel api order
*/
public function revolut_payment_request_ajax_cancel_order() {
check_ajax_referer( 'wc-revolut-cancel-order', 'security' );
$revolut_public_id = $this->get_post_request_data( 'revolut_public_id' );
$revolut_order_id = $this->get_revolut_order_by_public_id( $revolut_public_id );
try {
$revolut_gateway = new WC_Gateway_Revolut_CC();
$revolut_gateway->action_revolut_order( $revolut_order_id, 'cancel' );
$revolut_gateway->clear_temp_session( $revolut_order_id );
$revolut_public_id = $this->create_revolut_order( $revolut_gateway->get_revolut_order_descriptor(), true );
$revolut_gateway->set_revolut_express_checkout_public_id( $revolut_public_id );
wp_send_json(
array(
'success' => true,
'revolut_public_id' => $revolut_public_id,
)
);
} catch ( Exception $e ) {
wp_send_json( array( 'success' => false ) );
$this->log_error( $e );
}
}
/**
* Set error message
*/
public function revolut_payment_request_ajax_set_error_message() {
$error_message = $this->get_post_request_data( 'revolut_payment_request_error' );
if ( empty( $error_message ) ) {
$error_message = __( 'Something went wrong', 'revolut-gateway-for-woocommerce' );
}
wc_add_notice( $error_message, 'error' );
}
/**
* Log error message
*/
public function revolut_payment_request_ajax_log_error() {
$error_message = $this->get_post_request_data( 'revolut_payment_request_error' );
$this->log_error( $error_message );
}
}

View File

@@ -0,0 +1,68 @@
<?php
/**
* Handles and process WC payment tokens API.
* Seen in checkout page and my account->add payment method page.
*
* @package WooCommerce
* @category Payment Gateways
* @author Revolut
* @since 2.0.0
*/
if ( ! defined( 'ABSPATH' ) ) {
exit;
}
/**
* WC_Revolut_Payment_Tokens class.
*/
class WC_Revolut_Payment_Tokens {
/**
* Constructor
*/
public function __construct() {
add_action( 'woocommerce_payment_token_deleted', array( $this, 'woocommerce_payment_token_deleted' ), 10, 2 );
add_filter( 'woocommerce_payment_methods_list_item', array( $this, 'get_account_saved_payment_methods_list_item' ), 10, 2 );
}
/**
* Get saved payment method item.
*
* @param array $item list item.
* @param WC_Payment_Token $payment_token payment token.
*/
public function get_account_saved_payment_methods_list_item( $item, $payment_token ) {
return $item;
}
/**
* Delete payment token on API
*
* @param int $token_id id token.
* @param WC_Payment_Token $token payment token.
*/
public function woocommerce_payment_token_deleted( $token_id, $token ) {
$gateway_revolut = new WC_Gateway_Revolut_CC();
if ( $token->get_gateway_id() === $gateway_revolut->id ) {
$revolut_customer_id = $gateway_revolut->get_revolut_customer_id( get_current_user_id() );
if ( empty( $revolut_customer_id ) ) {
if ( is_account_page() ) {
wc_add_notice( 'Can not find customer ID', 'error' );
}
}
$payment_method_id = $token->get_token();
try {
$gateway_revolut->api_client->delete( "/customers/$revolut_customer_id/payment-methods/$payment_method_id" );
} catch ( Exception $e ) {
if ( is_account_page() ) {
wc_add_notice( $e->getMessage(), 'error' );
}
}
}
}
}
new WC_Revolut_Payment_Tokens();

View File

@@ -0,0 +1,177 @@
<?php
/**
* Revolut privacy class.
*
* @package WooCommerce
* @category Payment Gateways
* @author Revolut
* @since 2.0.0
*/
if ( ! class_exists( 'WC_Abstract_Privacy' ) ) {
return;
}
/**
* WC_Gateway_Revolut_Privacy class.
*/
class WC_Revolut_Privacy extends WC_Abstract_Privacy {
/**
* Constructor
*/
public function __construct() {
parent::__construct( __( 'Revolut', 'revolut-gateway-for-woocommerce' ) );
$this->add_exporter(
'revolut-gateway-for-woocommerce-order-data',
__( 'WooCommerce Revolut Order Data', 'revolut-gateway-for-woocommerce' ),
array(
$this,
'order_data_exporter',
)
);
$this->add_eraser(
'revolut-gateway-for-woocommerce-order-data',
__( 'WooCommerce Revolut Data', 'revolut-gateway-for-woocommerce' ),
array(
$this,
'order_data_eraser',
)
);
}
/**
* Returns a list of orders that are using one of Revolut's payment methods.
*
* @param string $email_address Email address.
* @param int $page page.
*
* @return array WP_Post
*/
protected function get_revolut_orders( $email_address, $page ) {
$user = get_user_by( 'email', $email_address ); // Check if user has an ID in the DB to load stored personal data.
$order_query = array(
'payment_method' => 'revolut',
'limit' => 10,
'page' => $page,
);
if ( $user instanceof WP_User ) {
$order_query['customer_id'] = (int) $user->ID;
} else {
$order_query['billing_email'] = $email_address;
}
return wc_get_orders( $order_query );
}
/**
* Get privacy message
*
* @return string
*/
public function get_privacy_message() {
/* translators:%1s: %$2s: */
return wpautop( sprintf( __( 'By using this extension, you may be storing personal data or sharing data with an external service. %1$sLearn more about how this works, including what you may want to include in your privacy policy.%2$s', 'revolut-gateway-for-woocommerce' ), '<a href="https://docs.woocommerce.com/document/privacy-payments/#revolut-gateway-for-woocommerce" target="_blank">', '</a>' ) );
}
/**
* Handle exporting data for Orders.
*
* @param string $email_address E-mail address to export.
* @param int $page Pagination of data.
*
* @return array
*/
public function order_data_exporter( $email_address, $page = 1 ) {
$done = false;
$data_to_export = array();
$orders = $this->get_revolut_orders( $email_address, (int) $page );
$done = true;
if ( 0 < count( $orders ) ) {
foreach ( $orders as $order ) {
$data_to_export[] = array(
'group_id' => 'woocommerce_orders',
'group_label' => __( 'Orders', 'revolut-gateway-for-woocommerce' ),
'item_id' => 'order-' . $order->get_id(),
'data' => array(
array(
'name' => __( 'Revolut token', 'revolut-gateway-for-woocommerce' ),
'value' => get_post_meta( $order->get_id(), '_revolut_pre_order_token', true ),
),
),
);
}
$done = 10 > count( $orders );
}
return array(
'data' => $data_to_export,
'done' => $done,
);
}
/**
* Finds and erases order data by email address.
*
* @param string $email_address The user email address.
* @param int $page Page.
*
* @return array An array of personal data in name value pairs
*/
public function order_data_eraser( $email_address, $page ) {
$orders = $this->get_revolut_orders( $email_address, (int) $page );
$items_removed = false;
$items_retained = false;
$messages = array();
foreach ( (array) $orders as $order ) {
$order = wc_get_order( $order->get_id() );
list($removed, $retained, $msgs) = $this->maybe_handle_order( $order );
$items_removed |= $removed;
$items_retained |= $retained;
$messages = array_merge( $messages, $msgs );
}
// Tell core if we have more orders to work on still.
$done = count( $orders ) < 10;
return array(
'items_removed' => $items_removed,
'items_retained' => $items_retained,
'messages' => $messages,
'done' => $done,
);
}
/**
* Handle eraser of data tied to Orders
*
* @param WC_Order $order WooCommerce Order.
*
* @return array
*/
protected function maybe_handle_order( $order ) {
$order_id = $order->get_id();
$revolut_token = get_post_meta( $order_id, '_revolut_pre_order_token', true );
if ( empty( $revolut_token ) ) {
return array( false, false, array() );
}
delete_post_meta( $order_id, '_revolut_pre_order_token' );
return array( true, false, array( __( 'Revolut Order Data Erased.', 'revolut-gateway-for-woocommerce' ) ) );
}
}
new WC_Revolut_Privacy();

View File

@@ -0,0 +1,47 @@
<?php
/**
* Validate checkout fields.
*
* @package WooCommerce
* @category Payment Gateways
* @author Revolut
* @since 2.0.0
*/
if ( ! defined( 'ABSPATH' ) ) {
exit;
}
/**
* WC_Revolut_Validate_Checkout class.
*/
class WC_Revolut_Validate_Checkout extends WC_Checkout {
/**
* Validate Checkout fields.
*/
public function validate_checkout_fields() {
$errors = new WP_Error();
$posted_data = $this->get_posted_data();
// Update session for customer and totals.
$this->update_session( $posted_data );
// Validate posted data and cart items before proceeding.
$this->validate_checkout( $posted_data, $errors );
foreach ( $errors->errors as $code => $messages ) {
$data = $errors->get_error_data( $code );
foreach ( $messages as $message ) {
wc_add_notice( $message, 'error', $data );
}
}
}
/**
* Return failure response.
*/
public function return_ajax_failure_response() {
$this->send_ajax_failure_response();
}
}

View File

@@ -0,0 +1,676 @@
<?php
/**
* Revolut Credit Card Gateway
*
* Provides a Revolut Payment Gateway to accept credit card payments.
*
* @package WooCommerce
* @category Payment Gateways
* @author Revolut
*/
/**
* WC_Gateway_Revolut_CC class.
*/
class WC_Gateway_Revolut_CC extends WC_Payment_Gateway_Revolut {
const GATEWAY_ID = 'revolut_cc';
/**
* Constructor
*/
public function __construct() {
$this->id = self::GATEWAY_ID;
$this->method_title = __( 'Revolut Gateway - Credit/Debit Cards', 'revolut-gateway-for-woocommerce' );
$this->tab_title = __( 'Credit/Debit Cards', 'revolut-gateway-for-woocommerce' );
$this->default_title = __( 'Pay with card', 'revolut-gateway-for-woocommerce' );
/* translators:%1s: %$2s: */
$this->method_description = sprintf( __( 'Accept card payments easily and securely via %1$sRevolut%2$s.', 'revolut-gateway-for-woocommerce' ), '<a href="https://www.revolut.com/business/online-payments">', '</a>' );
$this->title = $this->get_option( 'title' );
$this->description = $this->get_option( 'description' );
$this->save_payment_method_for = 'merchant';
parent::__construct();
if ( get_option( 'woocommerce_revolut_cc_settings' ) === false ) {
$this->add_default_options();
}
$this->init_scripts();
$this->revolut_saved_cards = 'yes' === $this->get_option( 'revolut_saved_cards' );
add_action( 'wp_enqueue_scripts', array( $this, 'load_payment_scripts' ) );
add_filter( 'wc_revolut_settings_nav_tabs', array( $this, 'admin_nav_tab' ), 4 );
if ( class_exists( 'WC_Subscriptions_Order' ) ) {
add_action( 'woocommerce_scheduled_subscription_payment_' . $this->id, array( $this, 'scheduled_subscription_payment' ), 10, 2 );
add_action( 'woocommerce_subscriptions_change_payment_before_submit', array( $this, 'differentiate_change_payment_method_form' ) );
add_action( 'wcs_resubscribe_order_created', array( $this, 'delete_resubscribe_meta' ), 10 );
// display the credit card used for a subscription in the "My Subscriptions" table.
add_filter( 'woocommerce_my_subscriptions_payment_method', array( $this, 'maybe_render_subscription_payment_method' ), 10, 2 );
add_action( 'woocommerce_subscription_failing_payment_method_updated_' . $this->id, array( $this, 'update_failing_payment_method' ), 10, 2 );
add_action( 'woocommerce_subscription_token_changed', array( $this, 'update_changed_subscription_token' ), 10, 2 );
}
}
/**
* Load required payment scripts.
*/
public function load_payment_scripts() {
$this->tokenization_script();
}
/**
* Supported functionality
*/
public function init_supports() {
parent::init_supports();
$this->supports = array(
'refunds',
'tokenization',
'add_payment_method',
'subscriptions',
'subscription_cancellation',
'subscription_suspension',
'subscription_reactivation',
'subscription_amount_changes',
'subscription_date_changes',
'subscription_payment_method_change',
'subscription_payment_method_change_customer',
'subscription_payment_method_change_admin',
'multiple_subscriptions',
'pre-orders',
);
}
/**
* Initialize Gateway Settings Form Fields
*/
public function init_form_fields() {
$this->form_fields = array(
'enabled' => array(
'title' => __( 'Enable/Disable', 'revolut-gateway-for-woocommerce' ),
'label' => __( 'Enable ', 'revolut-gateway-for-woocommerce' ) . $this->method_title,
'type' => 'checkbox',
'description' => __( 'This controls whether or not this gateway is enabled within WooCommerce.', 'revolut-gateway-for-woocommerce' ),
'default' => 'yes',
'desc_tip' => true,
),
'title' => array(
'title' => __( 'Title', 'revolut-gateway-for-woocommerce' ),
'type' => 'text',
'description' => __( 'This controls the title that the user sees during checkout.', 'revolut-gateway-for-woocommerce' ),
'default' => $this->default_title,
'desc_tip' => true,
),
'card_widget_type' => array(
'title' => __( 'Card widget type', 'revolut-gateway-for-woocommerce' ),
'type' => 'select',
'description' => __( 'Select the card widget type.', 'revolut-gateway-for-woocommerce' ),
'default' => 'card_field',
'desc_tip' => true,
'options' => array(
'card_field' => __( 'Card field', 'revolut-gateway-for-woocommerce' ),
'popup' => __( 'Popup', 'revolut-gateway-for-woocommerce' ),
),
),
'revolut_saved_cards' => array(
'title' => __( 'Save Cards', 'revolut-gateway-for-woocommerce' ),
'label' => __( 'Enable Payment with Saved Cards', 'revolut-gateway-for-woocommerce' ),
'type' => 'checkbox',
'description' => __( 'If enabled, users will be able to save their cards and use them to checkout in subsequent purchases. Card details are stored securely on Revolut servers', 'revolut-gateway-for-woocommerce' ),
'default' => 'yes',
'desc_tip' => true,
),
'enable_cardholder_name' => array(
'title' => __( 'Cardholder\'s Name Field', 'revolut-gateway-for-woocommerce' ),
'label' => __( 'Enable', 'revolut-gateway-for-woocommerce' ),
'type' => 'checkbox',
'default' => 'no',
'description' => __( 'When enabled, input for Cardholder\'s Name will be activated.', 'revolut-gateway-for-woocommerce' ),
'desc_tip' => true,
),
'styling_title' => array(
'title' => __( 'Card widget style', 'revolut-gateway-for-woocommerce' ),
'type' => 'title',
),
'widget_styling' => array(
'title' => __( 'Customize card widget style', 'revolut-gateway-for-woocommerce' ),
'label' => __( 'Enable', 'revolut-gateway-for-woocommerce' ),
'type' => 'checkbox',
'description' => __( 'By enabling this option you can customize the style of the Revolut card widget', 'revolut-gateway-for-woocommerce' ),
'default' => 'no',
'class' => 'revolut_styling_option_enable',
'desc_tip' => true,
),
'widget_background_color' => array(
'title' => __( 'Card widget background color', 'revolut-gateway-for-woocommerce' ),
'type' => 'color',
'description' => __( 'This controls the background color of the Revolut card widget', 'revolut-gateway-for-woocommerce' ),
'default' => WC_REVOLUT_CARD_WIDGET_BG_COLOR,
'class' => 'revolut_styling_option',
'desc_tip' => true,
),
'widget_text_color' => array(
'title' => __( 'Card widget font color', 'revolut-gateway-for-woocommerce' ),
'type' => 'color',
'description' => __( 'This controls the text color of the Revolut Card widget', 'revolut-gateway-for-woocommerce' ),
'default' => WC_REVOLUT_CARD_WIDGET_TEXT_COLOR,
'class' => 'revolut_styling_option',
'desc_tip' => true,
),
'revolut_logo_color' => array(
'title' => __( 'Revolut logo theme', 'revolut-gateway-for-woocommerce' ),
'type' => 'select',
'default' => '#7a7a7a',
'class' => 'revolut_styling_option',
'options' => array(
'#7a7a7a' => __( 'Dark', 'revolut-gateway-for-woocommerce' ),
'#cccccc' => __( 'Light', 'revolut-gateway-for-woocommerce' ),
),
'description' => __( 'This controls the color of the Revolut', 'revolut-gateway-for-woocommerce' ),
'desc_tip' => true,
),
'restore_button' => array(
'title' => '',
'type' => 'text',
'description' => '<button class="revolut_style_restore revolut_styling_option setup-webhook" style="min-height: 30px;"><span id="span-for-active-button-sandbox">Restore defaults</span></button>',
),
);
}
/**
* Scheduled_subscription_payment function.
*
* @param float $amount_to_charge The amount to charge.
* @param WC_Order $renewal_order WC_Order order.
*
* @throws Exception Exception.
*/
public function scheduled_subscription_payment( $amount_to_charge, $renewal_order ) {
try {
$wc_order_id = $renewal_order->get_id();
$payment_token_id = $renewal_order->get_meta( '_payment_token_id', true );
if ( empty( $payment_token_id ) ) {
throw new Exception( "Subscription order payment token is missing: $payment_token_id" );
}
$wc_customer_id = $renewal_order->get_meta( '_wc_customer_id', true );
if ( empty( $wc_customer_id ) ) {
throw new Exception( "Subscription customer ID is missing: $payment_token_id" );
}
$revolut_customer_id = $this->get_revolut_customer_id( $wc_customer_id );
if ( empty( $revolut_customer_id ) ) {
throw new Exception( "Can not find Subscription Revolut customer ID: $revolut_customer_id" );
}
$descriptor = new WC_Revolut_Order_Descriptor( $amount_to_charge, $renewal_order->get_currency(), $revolut_customer_id );
$revolut_payment_public_id = $this->create_revolut_order( $descriptor );
// 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' );
}
// update internal table to avoid piggybacking on already paid order.
$this->save_wc_order_id( $revolut_payment_public_id, $revolut_order_id, $wc_order_id );
// make the payment with saved card $payment_method_id.
$wc_token = WC_Payment_Tokens::get( $payment_token_id );
$this->pay_by_saved_method( $revolut_order_id, $wc_token );
// payment should be processed until this point, if not throw an error.
$this->check_payment_processed( $revolut_order_id );
// payment process began...
$renewal_order->update_status( 'on-hold' );
$renewal_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( $renewal_order, $revolut_order_id );
$message = sprintf( 'Subscription charge successfully completed by Revolut (Order ID: %s)', $revolut_order_id );
$renewal_order->add_order_note( $message );
$renewal_order->set_transaction_id( $revolut_order_id );
WC_Subscriptions_Manager::process_subscription_payments_on_order( $renewal_order );
} catch ( Exception $e ) {
WC_Subscriptions_Manager::process_subscription_payment_failure_on_order( $renewal_order );
$renewal_order->update_status( 'failed', 'An error occurred while Payment processing: ' . $e->getMessage() );
$this->log_error( $e->getMessage() );
return false;
}
return true;
}
/**
* Process the payment and return the result.
*
* @param int $wc_order_id WooCommerce Order order id.
*
* @throws Exception Exception.
*/
public function process_payment( $wc_order_id ) {
if ( $this->has_subscription( $wc_order_id ) ) {
if ( $this->is_subs_change_payment() ) {
return $this->change_subs_payment_method( $wc_order_id );
}
// Regular payment with force customer enabled.
return parent::process_payment( $wc_order_id );
} else {
return parent::process_payment( $wc_order_id );
}
}
/**
* Render an input in the "Change payment method" form which does not appear in the "Pay for order" page
*/
public function differentiate_change_payment_method_form() {
echo wp_kses(
'<input type="hidden" id="wc-revolut-change-payment-method" />',
array(
'input' => array(
'id' => array(),
'type' => array(),
'name' => array(),
'value' => array(),
'checked' => array(),
'class' => array(),
'placeholder' => array(),
'style' => array(),
),
),
);
}
/**
* Process the payment method change for subscriptions.
*
* @param int $wc_order_id WooCommerce order id.
*
* @throws Exception Exception.
*/
public function change_subs_payment_method( $wc_order_id ) {
try {
$subscription = wc_get_order( $wc_order_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( 'Can not find Revolut order ID' );
}
if ( $this->is_using_saved_payment_method() ) {
$wc_token = $this->get_selected_payment_token();
} else {
$wc_token = $this->save_payment_method( $revolut_order_id );
if ( null === $wc_token ) {
throw new Exception( 'An error occurred while saving payment method' );
}
}
$this->save_payment_token_to_order( $subscription, $wc_token, get_current_user_id() );
$this->handle_add_payment_method( $subscription, $wc_token, get_current_user_id() );
return array(
'result' => 'success',
'redirect' => $this->get_return_url( $subscription ),
);
} catch ( Exception $e ) {
$this->log_error( $e->getMessage() );
wc_add_notice( $e->getMessage(), 'error' );
return false;
}
}
/**
* Updates all active subscriptions payment method.
*
* @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 ) {
// remove public ID after saving the card.
$this->unset_revolut_public_id();
if ( $this->update_all_subscriptions_payment_method() ) {
$all_subs = wcs_get_users_subscriptions();
if ( ! empty( $all_subs ) ) {
foreach ( $all_subs as $sub ) {
$this->update_payment_subscription_method( $sub, $wc_token, $wc_customer_id );
}
}
return true;
}
if ( null !== $current_subscription ) {
return $this->update_payment_subscription_method( $current_subscription, $wc_token, $wc_customer_id );
}
return true;
}
/**
* Updates active subscription payment method.
*
* @param WC_Subscription $subscription WooCommerce Subscription.
* @param object $wc_token WooCommerce Payment Token id.
* @param int $wc_customer_id WooCommerce Customer id.
* @return bool
*/
public function update_payment_subscription_method( $subscription, $wc_token, $wc_customer_id ) {
if ( $subscription->has_status( 'active' ) ) {
WC_Subscriptions_Change_Payment_Gateway::update_payment_method(
$subscription,
$this->id,
array(
'post_meta' => array(
'_payment_token' => array( 'value' => $wc_token->get_token() ),
'_payment_token_id' => array( 'value' => $wc_token->get_id() ),
'_wc_customer_id' => array( 'value' => $wc_customer_id ),
),
)
);
}
return true;
}
/**
* Check is $order_id a subscription.
*
* @param int $order_id WooCommerce Order id.
* @return boolean
*/
public function has_subscription( $order_id ) {
return ( function_exists( 'wcs_order_contains_subscription' ) && ( wcs_order_contains_subscription( $order_id ) || wcs_is_subscription( $order_id ) || wcs_order_contains_renewal( $order_id ) ) );
}
/**
* Remove previous subscription information from resubscribe orders.
*
* @param WC_Order $resubscribe_order instance of a order object.
* @return void
*/
public function delete_resubscribe_meta( $resubscribe_order ) {
delete_post_meta( $resubscribe_order->get_id(), '_payment_token' );
delete_post_meta( $resubscribe_order->get_id(), '_payment_token_id' );
delete_post_meta( $resubscribe_order->get_id(), '_wc_customer_id' );
}
/**
* Render the payment method used for a subscription in the "My Subscriptions" table
*
* @param string $payment_method_to_display the default payment method text to display.
* @param WC_Subscription $subscription the subscription details.
* @return string the subscription payment method.
*/
public function maybe_render_subscription_payment_method( $payment_method_to_display, $subscription ) {
$customer_user = $subscription->get_customer_id();
// fail for other payment methods.
if ( $subscription->get_payment_method() !== $this->id || ! $customer_user ) {
return $payment_method_to_display;
}
$revolut_payment_token_id = get_post_meta( $subscription->get_id(), '_payment_token_id', true );
$payment_method_to_display = __( 'N/A', 'revolut-gateway-for-woocommerce' );
$wc_token = WC_Payment_Tokens::get( $revolut_payment_token_id );
if ( $wc_token ) {
/* translators:%1s: Card type %$2s: Card last four digits */
$payment_method_to_display = sprintf( __( 'Via %1$s card ending in %2$s', 'revolut-gateway-for-woocommerce' ), $wc_token->get_card_type(), $wc_token->get_last4() );
}
return $payment_method_to_display;
}
/**
* Update the customer_id for a subscription after using Revolut to complete a payment to make up for
* an automatic renewal payment which previously failed.
*
* @param WC_Subscription $subscription The subscription for which the failing payment method relates.
* @param WC_Order $renewal_order The order which recorded the successful payment (to make up for the failed automatic payment).
* @return void
*/
public function update_failing_payment_method( $subscription, $renewal_order ) {
update_post_meta( $subscription->get_id(), '_payment_token', $renewal_order->get_meta( '_payment_token' ) );
update_post_meta( $subscription->get_id(), '_payment_token_id', $renewal_order->get_meta( '_payment_token_id' ) );
update_post_meta( $subscription->get_id(), '_wc_customer_id', $renewal_order->get_meta( '_wc_customer_id' ) );
}
/**
* Update the subscription payment meta to change from an old payment token to a new one.
*
* @param WC_Subscription $subscription The subscription to update.
* @param WC_Payment_Token $new_token The new payment token.
* @return void
*/
public function update_changed_subscription_token( $subscription, $new_token ) {
if ( $new_token->get_gateway_id() === $this->id ) {
update_post_meta( $subscription->get_id(), '_payment_token', $new_token->get_token() );
update_post_meta( $subscription->get_id(), '_payment_token_id', $new_token->get_id() );
}
}
/**
* Display payment icons
*/
public function get_icon() {
$icons_str = '';
$icons_str .= '<img class="revolut-card-gateway-icon-amex" src="' . WC_REVOLUT_PLUGIN_URL . '/assets/images/amex.svg" style="margin-left:2px" alt="Amex" />';
$icons_str .= '<img class="revolut-card-gateway-icon-visa" src="' . WC_REVOLUT_PLUGIN_URL . '/assets/images/visa.svg" style="margin-left:2px" alt="Visa" />';
$icons_str .= '<img class="revolut-card-gateway-icon-mastercard" src="' . WC_REVOLUT_PLUGIN_URL . '/assets/images/mastercard.svg" alt="MasterCard" />';
return apply_filters( 'woocommerce_gateway_icon', $icons_str, $this->id );
}
/**
* Update all subscriptions payment methods
*
* @return bool
*/
public function update_all_subscriptions_payment_method() {
return $this->check_is_post_data_submitted( 'wc-' . $this->id . '-update-subs-payment-method-card' ) || $this->check_is_post_data_submitted( 'update_all_subscriptions_payment_method' );
}
/**
* Check if it is using saved payment method
*
* @return bool
*/
public function is_using_saved_payment_method() {
return ( $this->check_is_post_data_submitted( 'wc-' . $this->id . '-payment-token' ) && ! empty( $this->get_post_request_data( 'wc-' . $this->id . '-payment-token' ) && 'new' !== $this->get_post_request_data( 'wc-' . $this->id . '-payment-token' ) ) );
}
/**
* Grab selected payment token from Request
*
* @return string
* @throws Exception Exception.
*/
public function get_selected_payment_token() {
$wc_token_id = $this->get_posted_integer_data( 'wc-' . $this->id . '-payment-token' );
$wc_token = WC_Payment_Tokens::get( $wc_token_id );
$payment_method_id = $wc_token->get_token();
if ( empty( $payment_method_id ) || $wc_token->get_user_id() !== get_current_user_id() ) {
throw new Exception( 'Can not process payment token' );
}
return $wc_token;
}
/**
* Check if save payment method requested
*/
public function save_payment_method_requested() {
return $this->get_posted_integer_data( 'revolut_save_payment_method' );
}
/**
* Add public_id field and logo on card form
*
* @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 ) {
if ( ! in_array( get_woocommerce_currency(), $this->card_payments_currency_list, true ) ) {
return get_woocommerce_currency() . ' currency is not available for card payments';
}
$total = WC()->cart->get_total( '' );
$currency = get_woocommerce_currency();
$total = $this->get_revolut_order_total( $total, $currency );
$mode = $this->api_settings->get_option( 'mode' );
$hide_fieldset = $this->get_option( 'card_widget_type' ) === 'popup' || $this->get_request_data( 'pay_for_order' ) ? 'height:0px;padding:0' : '';
$shipping_total = $this->get_cart_total_shipping();
$hide_payment_method = ! empty( $hide_fieldset ) && ! $display_tokenization ? true : false;
$available_card_brands = $this->get_available_card_brands( $this->get_revolut_public_id() );
$display_banner = $this->api_settings->get_option( 'disable_banner' ) === 'yes' ? '<div id="revolut-upsell-banner"></div>' : '';
$cardholder_name_field = '';
if ( 'yes' === $this->get_option( 'enable_cardholder_name', 'yes' ) && ! $hide_fieldset ) {
$cardholder_name_field .= '<p class="form-row form-row-first validate-required" id="cardholder-name" data-priority="10" style="display: block;width:100%;float:none">';
$cardholder_name_field .= '<span class="woocommerce-input-wrapper"><input type="text" class="input-text" name="wc-revolut-cardholder-name" id="wc-revolut-cardholder-name" placeholder="Cardholder name" autocomplete="cardholder" required></span>';
$cardholder_name_field .= '</p>';
}
return '<fieldset id="wc-' . $this->id . '-cc-form" class="wc-credit-card-form wc-payment-form" style="background:transparent;' . $hide_fieldset . '"> ' . $cardholder_name_field . '
<div style="background: ' . $this->get_option( 'widget_background_color' ) . ';' . $hide_fieldset . '" id="woocommerce-revolut-card-element" data-available-card-brands="' . $available_card_brands . '" data-mode="' . $mode . '" data-shipping-total="' . $shipping_total . '" data-currency="' . $currency . '" data-total="' . $total . '" data-textcolor="' . $this->get_option( 'widget_text_color' ) . '" data-widget-type="' . $this->get_option( 'card_widget_type' ) . '" data-hide-payment-method="' . $hide_payment_method . '" data-locale="' . $this->get_lang_iso_code() . '" data-public-id="' . $public_id . '" data-merchant-public-key="' . $merchant_public_key . '" data-save-payment-for="' . $this->save_payment_method_for . '" data-payment-method-save-is-mandatory="' . $this->is_save_payment_method_mandatory() . '"></div>' . $this->getSvgImage() . $display_banner . '</fieldset>';
}
/**
* Check if cart contains subscription.
*/
public function cart_contains_subscription() {
try {
$cart_contains_subscription = WC_Subscriptions_Cart::cart_contains_subscription();
} catch ( Exception $e ) {
$cart_contains_subscription = false;
}
return $cart_contains_subscription;
}
/**
* Check is payment method available.
*/
public function is_available() {
if ( is_add_payment_method_page() && ! $this->revolut_saved_cards ) {
return false;
}
return 'yes' === $this->enabled;
}
/**
* Check currency support for card payments
*/
public function check_currency_support() {
if ( ! in_array( get_woocommerce_currency(), $this->card_payments_currency_list, true ) ) {
return false;
}
return true;
}
/**
* Check if saving payment method is mandatory
*/
public function is_save_payment_method_mandatory() {
if ( is_add_payment_method_page() ) {
return true;
}
if ( ! class_exists( 'WC_Subscriptions_Order' ) ) {
return false;
}
return $this->check_is_get_data_submitted( 'change_payment_method' ) || $this->cart_contains_subscription();
}
/**
* Displays a checkbox to allow users to save payment methods.
*/
public function save_payment_method_checkbox() {
if ( $this->get_option( 'card_widget_type' ) !== 'popup' && ! $this->is_save_payment_method_mandatory() && $this->revolut_saved_cards && $this->check_currency_support() && get_current_user_id() ) {
return '<p class="form-row woocommerce-SavedPaymentMethods-saveNew revolut-payment-method-save">
<input id="wc-' . $this->id . '-new-payment-method" name="wc-' . $this->id . '-new-payment-method" type="checkbox" value="' . $this->save_payment_method_for . '" style="width:auto;" />
<label for="wc-' . $this->id . '-new-payment-method">' . __( 'Save payment information to my account for future purchases.', 'revolut-gateway-for-woocommerce' ) . '</label>
</p>';
}
return '';
}
/**
* Displays a checkbox to allow users to update all subs payments with new payment.
*/
public function display_update_subs_payment_checkout() {
if ( ! class_exists( 'WC_Subscriptions_Order' ) ) {
return false;
}
if (
wcs_user_has_subscription( get_current_user_id(), '', array( 'active' ) ) &&
is_add_payment_method_page()
) {
$label = wp_kses_post( __( 'Update the Payment Method used for all of my active subscriptions.', 'revolut-gateway-for-woocommerce' ) );
$id = sprintf( 'wc-%1$s-update-subs-payment-method-card', $this->id );
woocommerce_form_field(
$id,
array(
'type' => 'checkbox',
'label' => $label,
'default' => false,
)
);
}
}
/**
* Revolut logo in SVG format.
*/
public function getSvgImage() {
return '<svg width="94" height="17" viewBox="0 0 94 17" fill="' . $this->get_option( 'revolut_logo_color' ) . '" xmlns="http://www.w3.org/2000/svg">
<path d="M1.68302 12V9.714H3.22202C4.49102 9.714 5.30102 8.895 5.30102 7.689C5.30102 6.519 4.50902 5.7 3.22202 5.7H0.900024V12H1.68302ZM1.68302 6.411H3.12302C3.96902 6.411 4.49102 6.879 4.49102 7.689C4.49102 8.535 3.99602 8.994 3.12302 8.994H1.68302V6.411Z" />
<path d="M7.92129 12.081C9.36129 12.081 10.0003 11.019 10.0003 9.705C10.0003 8.382 9.34329 7.32 7.92129 7.32C6.49929 7.32 5.84229 8.382 5.84229 9.705C5.84229 11.028 6.48129 12.081 7.92129 12.081ZM7.92129 11.406C6.99429 11.406 6.60729 10.695 6.60729 9.705C6.60729 8.724 6.98529 7.995 7.92129 7.995C8.85729 7.995 9.23529 8.715 9.23529 9.705C9.23529 10.695 8.85729 11.406 7.92129 11.406Z" />
<path d="M12.534 12L13.641 8.427H13.677L14.757 12H15.54L16.836 7.491V7.401H16.071L15.153 10.974H15.117L14.037 7.401H13.263L12.183 10.974H12.147L11.229 7.401H10.446V7.491L11.751 12H12.534Z" />
<path d="M19.374 12.081C20.355 12.081 21.165 11.514 21.291 10.668H20.535C20.409 11.154 19.977 11.406 19.374 11.406C18.519 11.406 18.078 10.803 18.078 9.93H21.354V9.561C21.354 8.283 20.661 7.32 19.365 7.32C17.943 7.32 17.286 8.373 17.286 9.705C17.286 11.055 18.015 12.081 19.374 12.081ZM18.087 9.3C18.114 8.58 18.501 7.995 19.365 7.995C20.184 7.995 20.571 8.571 20.571 9.3H18.087Z" />
<path d="M23.1878 12V9.768C23.1878 8.688 23.5838 8.076 24.4568 8.076H24.8168V7.347H24.4028C23.8358 7.347 23.3768 7.662 23.1878 8.175H23.1518L23.0888 7.401H22.4318V12H23.1878Z" />
<path d="M27.3109 12.081C28.2919 12.081 29.1019 11.514 29.2279 10.668H28.4719C28.3459 11.154 27.9139 11.406 27.3109 11.406C26.4559 11.406 26.0149 10.803 26.0149 9.93H29.2909V9.561C29.2909 8.283 28.5979 7.32 27.3019 7.32C25.8799 7.32 25.2229 8.373 25.2229 9.705C25.2229 11.055 25.9519 12.081 27.3109 12.081ZM26.0239 9.3C26.0509 8.58 26.4379 7.995 27.3019 7.995C28.1209 7.995 28.5079 8.571 28.5079 9.3H26.0239Z" />
<path d="M31.9617 12.081C32.6457 12.081 33.1047 11.766 33.3477 11.361H33.3837L33.4827 12H34.1397V5.34H33.3837V8.04H33.3477C33.1047 7.635 32.6457 7.32 31.9617 7.32C30.6657 7.32 30.0177 8.337 30.0087 9.696C30.0177 11.181 30.7557 12.081 31.9617 12.081ZM32.0877 11.406C31.1337 11.406 30.7737 10.623 30.7737 9.696C30.7737 8.778 31.1337 7.995 32.0877 7.995C33.0057 7.995 33.4017 8.787 33.4017 9.696C33.4017 10.614 33.0057 11.406 32.0877 11.406Z" />
<path d="M40.1847 12.081C41.3907 12.081 42.1287 11.181 42.1377 9.696C42.1287 8.337 41.4807 7.32 40.1847 7.32C39.5007 7.32 39.0417 7.635 38.7987 8.04H38.7627V5.34H38.0067V12H38.6637L38.7627 11.361H38.7987C39.0417 11.766 39.5007 12.081 40.1847 12.081ZM40.0587 11.406C39.1407 11.406 38.7447 10.614 38.7447 9.696C38.7447 8.787 39.1407 7.995 40.0587 7.995C41.0127 7.995 41.3727 8.778 41.3727 9.696C41.3727 10.623 41.0127 11.406 40.0587 11.406Z" />
<path d="M44.3326 14.061L46.8796 7.491V7.401H46.0875L44.7375 11.01H44.7015L43.3065 7.401H42.4965V7.491L44.3415 11.946L44.3505 11.964L43.5676 13.971V14.061H44.3326Z" />
<path fill-rule="evenodd" clip-rule="evenodd" d="M59.0134 13.0369L56.793 9.12191C58.1976 8.60604 58.8939 7.70677 58.8939 6.39711C58.8954 4.79652 57.6336 3.77778 55.6244 3.77778H51.6981V13.0369H53.4318V9.28037H54.9032L57.0304 13.0369H59.0134ZM55.6244 5.31189C56.6488 5.31189 57.1613 5.72178 57.1613 6.52858C57.1613 7.33537 56.6483 7.74526 55.6244 7.74526H53.4318V5.31189H55.6244ZM82.044 13.0371V3.9604H80.3892V13.0371H82.044ZM78.5549 7.06465C77.8585 6.44281 77.018 6.13889 76.0461 6.13889C75.0876 6.13889 74.247 6.44331 73.5502 7.06465C72.8538 7.673 72.5 8.51977 72.5 9.60449C72.5 10.6892 72.8538 11.5355 73.5502 12.1574C74.2465 12.7657 75.0876 13.0701 76.0461 13.0701C77.018 13.0701 77.8585 12.7657 78.5549 12.1574C79.2646 11.5355 79.6185 10.6892 79.6185 9.60449C79.6185 8.51977 79.2641 7.673 78.5549 7.06465ZM74.7332 10.9931C74.366 10.6362 74.1811 10.1729 74.1811 9.60449C74.1811 9.03565 74.3645 8.57276 74.7332 8.22885C75.1005 7.87195 75.5346 7.69998 76.0456 7.69998C76.557 7.69998 77.0041 7.87195 77.3719 8.22885C77.752 8.57276 77.9368 9.03565 77.9368 9.60449C77.9368 10.1733 77.7535 10.6362 77.3719 10.9931C77.0046 11.3371 76.5576 11.509 76.0456 11.509C75.5346 11.509 75.1015 11.3371 74.7332 10.9931ZM87.3855 10.0976V6.47599H89.0443V10.3755C89.0443 11.8566 88.1001 13.2218 86.0384 13.2218H86.0255C83.9509 13.2218 83.0052 11.8861 83.0052 10.3755V6.47599H84.6631V10.0976C84.6631 10.9708 85.1191 11.5487 86.0255 11.5487C86.9172 11.5487 87.3855 10.9703 87.3855 10.0976ZM70.6804 6.47599L69.0255 10.9204L67.3707 6.47599H65.6107L68.2514 13.0368H69.8017L72.4418 6.47599H70.6804ZM64.7265 7.2166C65.3177 7.83844 65.6196 8.61874 65.6196 9.571H65.6191V10.1533H60.603C60.708 11.1586 61.4044 11.7934 62.3891 11.7934C63.1901 11.7934 63.7818 11.3965 64.1883 10.5897L65.4223 11.3041C64.8063 12.5872 63.7952 13.2221 62.3629 13.2221C61.4306 13.2221 60.6426 12.9046 59.9855 12.2563C59.3417 11.6085 59.0135 10.7752 59.0135 9.75644C59.0135 8.73771 59.3411 7.91792 59.9984 7.26959C60.6684 6.62175 61.4832 6.29084 62.4417 6.29084C63.3745 6.29084 64.1352 6.59476 64.7265 7.2166ZM64.0956 8.93616C63.9385 8.08937 63.3204 7.56051 62.3882 7.56051C61.5342 7.56051 60.8522 8.15586 60.602 8.93616H64.0956ZM89.9207 11.2769C89.9207 12.3511 90.7845 13.2214 91.8496 13.2214H92.9945V11.7398H92.142C91.8288 11.7398 91.5755 11.4848 91.5755 11.1699V7.82728H92.9945V6.47813H91.5755V4.70308H89.9207V11.2769Z" />
</svg>';
}
}

View File

@@ -0,0 +1,465 @@
<?php
/**
* Revolut Pay
*
* Provides a gateway to accept payments through Revolut Pay.
*
* @package WooCommerce
* @category Payment Gateways
* @author Revolut
* @since 2.0
*/
/**
* WC_Gateway_Revolut_Pay class
*/
class WC_Gateway_Revolut_Pay extends WC_Payment_Gateway_Revolut {
const GATEWAY_ID = 'revolut_pay';
/**
* Constructor
*/
public function __construct() {
$this->id = self::GATEWAY_ID;
$this->method_title = __( 'Revolut Gateway - Revolut Pay', 'revolut-gateway-for-woocommerce' );
$this->tab_title = __( 'Revolut Pay', 'revolut-gateway-for-woocommerce' );
$this->default_title = __( 'Revolut Pay', 'revolut-gateway-for-woocommerce' );
/* translators:%1s: %$2s: */
$this->method_description = sprintf( __( 'Accept payments easily and securely via %1$sRevolut%2$s.', 'revolut-gateway-for-woocommerce' ), '<a href="https://www.revolut.com/business/online-payments">', '</a>' );
$this->title = __( 'Revolut Pay', 'revolut-gateway-for-woocommerce' );
$this->description = $this->get_option( 'description' );
parent::__construct();
if ( get_option( 'woocommerce_revolut_pay_settings' ) === false ) {
$this->add_default_options();
}
$this->activate_default_express_checkout();
if ( ! $this->is_revolut_cc_gateway_active() ) {
$this->init_scripts();
}
add_action( 'wp_loaded', array( $this, 'check_revolut_pay_payment_result' ) );
add_filter( 'wc_revolut_settings_nav_tabs', array( $this, 'admin_nav_tab' ), 3 );
add_action( 'wp_enqueue_scripts', array( $this, 'wc_revolut_pay_enqueue_scripts' ) );
add_action( 'woocommerce_after_add_to_cart_quantity', array( $this, 'display_payment_request_button_html' ), 1 );
add_action( 'woocommerce_proceed_to_checkout', array( $this, 'display_payment_request_button_html' ), 1 );
add_action( 'wc_ajax_revolut_payment_request_load_order_data', array( $this, 'revolut_payment_request_ajax_load_order_data' ) );
add_action( 'wc_ajax_revolut_payment_request_get_express_checkout_params', array( $this, 'revolut_payment_request_ajax_get_express_checkout_params' ) );
}
/**
* Get express checkout params
*/
public function check_revolut_pay_payment_result() {
if ( empty( $this->get_request_data( '_rp_oid' ) ) ) {
return;
}
$public_id = $this->get_request_data( '_rp_oid' );
global $wpdb;
$wc_order_id = $wpdb->get_row( $wpdb->prepare( 'SELECT wc_order_id, HEX(order_id) as 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.
$revolut_order_id = $this->uuid_dashes( $wc_order_id['order_id'] );
if ( empty( $revolut_order_id ) || $this->is_pending_payment( $revolut_order_id ) ) {
return;
}
if ( empty( $wc_order_id ) || empty( $wc_order_id['wc_order_id'] ) ) {
// check if fast checkout.
if ( ! empty( $wc_order_id['order_id'] ) ) {
$temp_session = $wpdb->get_row( $wpdb->prepare( 'SELECT temp_session FROM ' . $wpdb->prefix . 'wc_revolut_temp_session WHERE order_id=%s', array( $this->uuid_dashes( $wc_order_id['order_id'] ) ) ), ARRAY_A ); // db call ok; no-cache ok.
if ( ! empty( $temp_session ) ) {
$this->log_error( 'order processing FC - public_id: ' . $public_id );
return $this->process_revolut_pay_fc_payment( $public_id );
}
}
return;
}
$wc_order_id = $wc_order_id['wc_order_id'];
$wc_order = wc_get_order( $wc_order_id );
if ( empty( $wc_order->get_id() ) ) {
return;
}
$this->log_error( 'order processing - public_id: ' . $public_id . ' - wc_order_id: ' . $wc_order_id );
$_POST['revolut_public_id'] = $public_id;
$_POST['revolut_pay_redirected'] = 1;
$this->process_payment( $wc_order_id );
}
/**
* Process Revolut Pay Fast Checkout payment
*
* @param string $revolut_public_id Revolut order public id.
* @throws Exception Exception.
*/
public function process_revolut_pay_fc_payment( $revolut_public_id ) {
try {
if ( ! empty( $this->get_request_data( '_rp_fr' ) ) ) {
wc_add_notice( $this->get_request_data( '_rp_fr' ), 'error' );
return;
}
$order_data = $this->load_order_data( $revolut_public_id );
$revolut_order_id = $this->get_revolut_order_by_public_id( $revolut_public_id );
if ( empty( $order_data ) ) {
return;
}
$address = $order_data['address_info'];
$selected_shipping_option = $order_data['selected_shipping_option'];
if ( WC()->cart->is_empty() ) {
$this->convert_revolut_order_metadata_into_wc_session( $revolut_order_id );
}
if ( WC()->cart->is_empty() ) {
throw new Exception( 'Cannot initialize cart' );
}
if ( ! defined( 'WOOCOMMERCE_CHECKOUT' ) ) {
define( 'WOOCOMMERCE_CHECKOUT', true );
}
$wc_order_data = $this->format_wc_order_details(
$address,
WC()->cart->needs_shipping(),
self::GATEWAY_ID
);
$wc_order_data['shipping_method'] = array( $selected_shipping_option );
$wc_order_data['revolut_create_wc_order'] = 1;
$wc_order_data['revolut_pay_redirected'] = 1;
$wc_order_data['is_express_checkout'] = 1;
$wc_order_data['payment_method'] = self::GATEWAY_ID;
$wc_order_data['revolut_public_id'] = $revolut_public_id;
$_POST = $wc_order_data;
$_POST['_wpnonce'] = wp_create_nonce( 'woocommerce-process_checkout' );
$_REQUEST['_wpnonce'] = $_POST['_wpnonce']; // phpcs:ignore
WC()->checkout()->process_checkout();
} catch ( Exception $e ) {
wc_add_notice( $e->getMessage(), 'error' );
}
}
/**
* Get express checkout params
*/
public function revolut_payment_request_ajax_get_express_checkout_params() {
check_ajax_referer( 'wc-revolut-get-express-checkout-params', 'security' );
try {
wp_send_json(
array(
'success' => true,
'revolut_public_id' => $this->create_express_checkout_public_id(),
'checkout_nonce' => wp_create_nonce( 'woocommerce-process_checkout' ),
)
);
} catch ( Exception $e ) {
wp_send_json( array( 'success' => false ) );
$this->log_error( $e );
}
}
/**
* Load express checkout information from api
*/
public function activate_default_express_checkout() {
try {
if ( 'yes' !== $this->get_option( 'revolut_pay_express_checkout_activate_default' ) && 'yes' === $this->get_option( 'enabled' ) && empty( $this->get_option( 'revolut_pay_button_locations' ) ) && $this->is_revolut_payment_request_gateway_active() ) {
$this->update_option( 'revolut_pay_button_locations', array( 'product', 'cart' ) );
}
$this->update_option( 'revolut_pay_express_checkout_activate_default', 'yes' );
} catch ( Exception $e ) {
$this->log_error( $e->getMessage() );
}
}
/**
* Load express checkout information from api
*
* @param string $revolut_public_id Revolut order public id.
*/
public function load_order_data( $revolut_public_id ) {
try {
$order_id = $this->get_revolut_order_by_public_id( $revolut_public_id );
$revolut_order = $this->api_client->get( "/orders/{$order_id }" );
$customer_id = $revolut_order['customer_id'];
$shipping_address = $revolut_order['shipping_address'];
$customer = $this->api_client->get( '/customers/' . $customer_id );
$this->log_info( 'load_order_data' );
$this->log_info( $customer );
$this->log_info( $shipping_address );
$address_info['fullname'] = ! empty( $customer['full_name'] ) ? $customer['full_name'] : '';
$address_info['email'] = ! empty( $customer['email'] ) ? $customer['email'] : '';
$address_info['phone'] = ! empty( $customer['phone'] ) ? $customer['phone'] : '';
$shipping_address['recipient'] = $address_info['fullname'];
$shipping_address['phone'] = $address_info['phone'];
$shipping_address = $this->convert_revolut_address_to_express_checkout_address( $shipping_address );
$address_info['shippingAddress'] = $shipping_address;
$address_info['billingAddress'] = $address_info['shippingAddress'];
$selected_shipping_option = 0;
if ( ! empty( $revolut_order['delivery_method'] ) ) {
$selected_shipping_option = $revolut_order['delivery_method']['ref'];
$this->get_shipping_options( $shipping_address );
$this->update_shipping_method( array( $selected_shipping_option ) );
}
return array(
'address_info' => $address_info,
'selected_shipping_option' => $selected_shipping_option,
);
} catch ( Exception $e ) {
return array();
}
}
/**
* Load express checkout information from api
*/
public function revolut_payment_request_ajax_load_order_data() {
try {
check_ajax_referer( 'wc-revolut-load-order-data', 'security' );
$revolut_public_id = $this->get_post_request_data( 'revolut_public_id' );
wp_send_json(
$this->load_order_data( $revolut_public_id )
);
} catch ( Exception $e ) {
wp_send_json( array( 'success' => false ) );
$this->log_info( 'load_order_data_error:' );
$this->log_error( $e );
}
}
/**
* Display payment request button html
*/
public function display_payment_request_button_html() {
if ( 'yes' !== $this->enabled || ! $this->page_supports_payment_request_button( $this->get_option( 'revolut_pay_button_locations' ) ) || ! $this->is_shipping_required() ) {
return false;
}
if ( ! $this->is_revolut_payment_request_gateway_active() ) {
?>
<div class="wc-revolut-pay-express-checkout-instance" id="wc-revolut-pay-express-checkout-container" style="clear:both;padding-top:1.5em;">
<div id="revolut-pay-express-checkout-button"></div>
<p id="wc-revolut-pay-express-checkout-button-separator" style="text-align:center;margin-bottom:1.5em;">&mdash;&nbsp;<?php echo esc_html( __( 'OR', 'revolut-gateway-for-woocommerce' ) ); ?>
&nbsp;&mdash;</p>
</div>
<?php
return;
}
?>
<div class="wc-revolut-pay-express-checkout-instance" id="wc-revolut-pay-express-checkout-container" style="clear:both;padding-top:1.5em;">
<div id="revolut-pay-express-checkout-button"></div>
</div>
<?php
}
/**
* Add script to load card form
*/
public function wc_revolut_pay_enqueue_scripts() {
wp_localize_script(
'revolut-woocommerce',
'revolut_pay_button_style',
array(
'revolut_pay_button_theme' => $this->get_option( 'revolut_pay_button_theme' ),
'revolut_pay_button_size' => $this->get_option( 'revolut_pay_button_size' ),
'revolut_pay_button_radius' => $this->get_option( 'revolut_pay_button_radius' ),
'revolut_pay_origin_url' => str_replace( array( 'https://', 'http://' ), '', get_site_url() ),
)
);
if ( 'yes' !== $this->enabled || ! $this->page_supports_payment_request_button( $this->get_option( 'revolut_pay_button_locations' ) ) || ! $this->is_shipping_required() ) {
return false;
}
wp_register_script( 'revolut-core', $this->api_client->base_url . '/embed.js', false, WC_GATEWAY_REVOLUT_VERSION, true );
wp_register_script(
'revolut-woocommerce-payment-request',
plugins_url( 'assets/js/revolut-payment-request.js', WC_REVOLUT_MAIN_FILE ),
array(
'revolut-core',
'jquery',
),
WC_GATEWAY_REVOLUT_VERSION,
true
);
wp_localize_script(
'revolut-woocommerce-payment-request',
'wc_revolut_payment_request_params',
$this->get_wc_revolut_payment_request_params()
);
wp_enqueue_script( 'revolut-woocommerce-payment-request' );
}
/**
* Check if card payments is active.
*/
public function is_revolut_cc_gateway_active() {
$revolut_cc_gateway_options = get_option( 'woocommerce_revolut_cc_settings' );
return isset( $revolut_cc_gateway_options['enabled'] ) && 'yes' === $revolut_cc_gateway_options['enabled'];
}
/**
* Check if the request payments active.
*/
public function is_revolut_payment_request_gateway_active() {
$woocommerce_revolut_payment_request_settings = get_option( 'woocommerce_revolut_payment_request_settings' );
return isset( $woocommerce_revolut_payment_request_settings['enabled'] ) && 'yes' === $woocommerce_revolut_payment_request_settings['enabled'] && $this->api_settings->get_option( 'mode' ) !== 'sandbox';
}
/**
* Supported functionality
*/
public function init_supports() {
parent::init_supports();
$this->supports[] = 'refunds';
}
/**
* Initialize Gateway Settings Form Fields
*/
public function init_form_fields() {
$this->form_fields = array(
'enabled' => array(
'title' => __( 'Enable/Disable', 'revolut-gateway-for-woocommerce' ),
'label' => __( 'Enable ', 'revolut-gateway-for-woocommerce' ) . $this->method_title,
'type' => 'checkbox',
'description' => __( 'This controls whether or not this gateway is enabled within WooCommerce.', 'revolut-gateway-for-woocommerce' ),
'default' => 'yes',
'desc_tip' => true,
),
'revolut_pay_button_locations' => array(
'title' => __( 'Revolut Pay Express Checkout', 'revolut-gateway-for-woocommerce' ),
'type' => 'multiselect',
'description' => __( 'Select where you would like Revolut Pay Button to be displayed as express checkout button', 'revolut-gateway-for-woocommerce' ),
'desc_tip' => true,
'class' => 'wc-enhanced-select',
'options' => array(
'product' => __( 'Product', 'revolut-gateway-for-woocommerce' ),
'cart' => __( 'Cart', 'revolut-gateway-for-woocommerce' ),
),
'default' => array(),
'custom_attributes' => array(
'data-placeholder' => __( 'Select pages', 'revolut-gateway-for-woocommerce' ),
),
),
'revolut_pay_button_theme' => array(
'title' => __( 'Revolut Pay Button Theme', 'revolut-gateway-for-woocommerce' ),
'label' => __( 'Button Theme', 'revolut-gateway-for-woocommerce' ),
'type' => 'select',
'description' => __( 'Select the button theme you would like to show.', 'revolut-gateway-for-woocommerce' ),
'default' => 'dark',
'desc_tip' => true,
'options' => array(
'dark' => __( 'Dark', 'revolut-gateway-for-woocommerce' ),
'light' => __( 'Light', 'revolut-gateway-for-woocommerce' ),
'light-outlined' => __( 'Light-Outline', 'revolut-gateway-for-woocommerce' ),
),
),
'revolut_pay_button_size' => array(
'title' => __( 'Revolut Pay Button Size', 'revolut-gateway-for-woocommerce' ),
'label' => __( 'Button Size', 'revolut-gateway-for-woocommerce' ),
'type' => 'select',
'description' => __( 'Select the button size you would like to show.', 'revolut-gateway-for-woocommerce' ),
'default' => 'large',
'desc_tip' => true,
'options' => array(
'large' => __( 'Large', 'revolut-gateway-for-woocommerce' ),
'small' => __( 'Small', 'revolut-gateway-for-woocommerce' ),
),
),
'revolut_pay_button_radius' => array(
'title' => __( 'Revolut Pay Button Radius', 'revolut-gateway-for-woocommerce' ),
'label' => __( 'Button Radius', 'revolut-gateway-for-woocommerce' ),
'type' => 'select',
'description' => __( 'Select the button radius you would like to show.', 'revolut-gateway-for-woocommerce' ),
'default' => 'none',
'desc_tip' => true,
'options' => array(
'small' => __( 'Small', 'revolut-gateway-for-woocommerce' ),
'large' => __( 'Large', 'revolut-gateway-for-woocommerce' ),
'none' => __( 'None', 'revolut-gateway-for-woocommerce' ),
),
),
);
}
/**
* Display Revolut Pay icon
*/
public function get_icon() {
$icons_str = '';
$icons_str .= '<img class="revolut-card-gateway-icon-amex" src="' . WC_REVOLUT_PLUGIN_URL . '/assets/images/amex.svg" style="margin-left:2px" alt="Amex" />';
$icons_str .= '<img class="revolut-card-gateway-icon-visa" src="' . WC_REVOLUT_PLUGIN_URL . '/assets/images/visa.svg" style="margin-left:2px" alt="Visa" />';
$icons_str .= '<img class="revolut-card-gateway-icon-mastercard" src="' . WC_REVOLUT_PLUGIN_URL . '/assets/images/mastercard.svg" style="margin-left:2px" alt="MasterCard" />';
$icons_str .= '<img class="rev-pay-v2" src="' . WC_REVOLUT_PLUGIN_URL . '/assets/images/revolut.svg" alt="Revolut Pay" />';
return apply_filters( 'woocommerce_gateway_icon', $icons_str, $this->id );
}
/**
* Add public_id field and logo on card form
*
* @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 ) {
$total = WC()->cart->get_total( '' );
if ( $this->check_is_get_data_submitted( 'pay_for_order' ) && ! empty( $this->get_request_data( 'key' ) ) ) {
global $wp;
$order = wc_get_order( wc_clean( $wp->query_vars['order-pay'] ) );
$total = $order->get_total();
}
$currency = get_woocommerce_currency();
$total = $this->get_revolut_order_total( $total, $currency );
$mode = $this->api_settings->get_option( 'mode' );
$shipping_total = $this->get_cart_total_shipping();
$mobile_redirect_url = wc_get_checkout_url();
$available_card_brands = $this->get_available_card_brands( $this->get_revolut_public_id() );
$revolut_pay_v2_class_indicator = '';
if ( ! empty( $merchant_public_key ) ) {
$revolut_pay_v2_class_indicator = 'revolut-pay-v2';
}
return '<div id="woocommerce-revolut-pay-element" class="revolut-pay ' . $revolut_pay_v2_class_indicator . '" data-available-card-brands="' . $available_card_brands . '" data-redirect-url = "' . $mobile_redirect_url . '" data-mode="' . $mode . '" data-shipping-total="' . $shipping_total . '" data-currency="' . $currency . '" data-total="' . $total . '" data-textcolor="" data-locale="' . $this->get_lang_iso_code() . '" data-public-id="' . $public_id . '" data-merchant-public-key="' . $merchant_public_key . '"></div>
<input type="hidden" id="wc_' . $this->id . '_payment_nonce" name="wc_' . $this->id . '_payment_nonce" />';
}
}

View File

@@ -0,0 +1,634 @@
<?php
/**
* Revolut Payment Request
*
* Provides a gateway to accept payments through Apple and Google Pay.
*
* @package WooCommerce
* @category Payment Gateways
* @author Revolut
* @since 3.0
*/
if ( ! defined( 'ABSPATH' ) ) {
exit;
}
/**
* WC_Gateway_Revolut_Payment_Request class.
*/
class WC_Gateway_Revolut_Payment_Request extends WC_Payment_Gateway_Revolut {
const GATEWAY_ID = 'revolut_payment_request';
/**
* Constructor
*/
public function __construct() {
$this->id = self::GATEWAY_ID;
$this->method_title = __( 'Apple Pay / Google Pay', 'revolut-gateway-for-woocommerce' );
/* translators:%1s: %$2s: */
$this->method_description = sprintf( __( 'Accept Apple and Google payments easily and securely via %1$sRevolut%2$s.', 'revolut-gateway-for-woocommerce' ), '<a href="https://www.revolut.com/business/online-payments">', '</a>' );
$this->tab_title = __( 'Apple Pay / Google Pay', 'revolut-gateway-for-woocommerce' );
$this->title = __( 'Digital Wallet (ApplePay/GooglePay)', 'revolut-gateway-for-woocommerce' );
parent::__construct();
add_filter( 'wc_revolut_settings_nav_tabs', array( $this, 'admin_nav_tab' ), 2 );
add_action( 'wc_ajax_revolut_payment_request_add_to_cart', array( $this, 'revolut_payment_request_ajax_add_to_cart' ) );
add_action( 'wc_ajax_revolut_payment_request_get_shipping_options', array( $this, 'revolut_payment_request_ajax_get_shipping_options' ) );
add_action( 'wc_ajax_revolut_payment_request_update_shipping_method', array( $this, 'revolut_payment_request_ajax_update_shipping_method' ) );
add_action( 'wc_ajax_revolut_payment_request_update_payment_total', array( $this, 'revolut_payment_request_update_revolut_order_with_cart_total' ) );
add_action( 'wc_ajax_revolut_payment_request_create_order', array( $this, 'revolut_payment_request_ajax_create_order' ) );
add_action( 'wc_ajax_revolut_payment_request_get_payment_request_params', array( $this, 'revolut_payment_request_ajax_get_payment_request_params' ) );
if ( 'yes' !== $this->enabled || $this->api_settings->get_option( 'mode' ) === 'sandbox' ) {
return;
}
add_action( 'woocommerce_after_add_to_cart_quantity', array( $this, 'display_payment_request_button_html' ), 2 );
add_action( 'woocommerce_proceed_to_checkout', array( $this, 'display_payment_request_button_html' ), 2 );
add_action( 'wp_enqueue_scripts', array( $this, 'revolut_enqueue_payment_request_scripts' ) );
}
/**
* Get express checkout params
*/
public function revolut_payment_request_ajax_get_payment_request_params() {
check_ajax_referer( 'wc-revolut-get-payment-request-params', 'security' );
try {
wp_send_json(
array(
'success' => true,
'revolut_public_id' => $this->create_express_checkout_public_id(),
'checkout_nonce' => wp_create_nonce( 'woocommerce-process_checkout' ),
)
);
} catch ( Exception $e ) {
wp_send_json( array( 'success' => false ) );
$this->log_error( $e );
}
}
/**
* Add required scripts
*/
public function revolut_enqueue_payment_request_scripts() {
try {
wp_localize_script(
'revolut-woocommerce',
'revolut_payment_request_button_style',
array(
'payment_request_button_title' => $this->get_option( 'title' ),
'payment_request_button_type' => $this->get_option( 'payment_request_button_type' ),
'payment_request_button_theme' => $this->get_option( 'payment_request_button_theme' ),
'payment_request_button_radius' => $this->get_option( 'payment_request_button_radius' ),
'payment_request_button_size' => $this->get_option( 'payment_request_button_size' ),
)
);
if ( ! $this->page_supports_payment_request_button( $this->get_option( 'payment_request_button_locations' ) ) ) {
return false;
}
wp_register_script( 'revolut-core', $this->api_client->base_url . '/embed.js', false, WC_GATEWAY_REVOLUT_VERSION, true );
wp_register_script(
'revolut-woocommerce-payment-request',
plugins_url( 'assets/js/revolut-payment-request.js', WC_REVOLUT_MAIN_FILE ),
array(
'revolut-core',
'jquery',
),
WC_GATEWAY_REVOLUT_VERSION,
true
);
wp_localize_script(
'revolut-woocommerce-payment-request',
'wc_revolut_payment_request_params',
$this->get_wc_revolut_payment_request_params()
);
wp_enqueue_script( 'revolut-woocommerce-payment-request' );
} catch ( Exception $e ) {
$this->log_error( $e->getMessage() );
}
}
/**
* Check if the Revolut Pay Fast checkout payments active.
*/
public function is_revolut_pay_fast_checkout_active() {
$revolut_cc_gateway_options = get_option( 'woocommerce_revolut_pay_settings' );
return isset( $revolut_cc_gateway_options['revolut_pay_button_locations'] ) && $this->page_supports_payment_request_button( $revolut_cc_gateway_options['revolut_pay_button_locations'] ) && $this->is_shipping_required();
}
/**
* Update Revolut order with cart total amount
*
* @param string $revolut_public_id Revolut public id.
*
* @param bool $is_revolut_pay indicator.
*
* @throws Exception Exception.
*/
public function update_revolut_order_with_cart_total( $revolut_public_id, $is_revolut_pay = false ) {
$revolut_order_id = $this->get_revolut_order_by_public_id( $revolut_public_id );
$revolut_order = $this->api_client->get( "/orders/$revolut_order_id" );
$revolut_order_shipping_total = $this->get_revolut_order_total_shipping( $revolut_order );
$cart_subtotal = round( (float) ( WC()->cart->get_subtotal() + WC()->cart->get_subtotal_tax() + $revolut_order_shipping_total ), 2 );
$this->log_info(
array(
'is_revolut_pay' => $is_revolut_pay,
'cart_total_without_shipping' => $cart_subtotal,
'cart_total' => WC()->cart->get_total( '' ),
'wc_shipping_total' => WC()->cart->get_shipping_total(),
'revolut_shipping_total' => $revolut_order_shipping_total,
)
);
$descriptor = new WC_Revolut_Order_Descriptor( $is_revolut_pay ? $cart_subtotal : WC()->cart->get_total( '' ), get_woocommerce_currency(), null );
$public_id = $this->update_revolut_order( $descriptor, $revolut_public_id, true );
if ( $public_id !== $revolut_public_id ) {
throw new Exception( 'Can not update the Order' );
}
$revolut_order_id = $this->get_revolut_order_by_public_id( $public_id );
$revolut_order = $this->api_client->get( "/orders/$revolut_order_id" );
$this->log_info( 'revolut_order' );
$this->log_info( $revolut_order );
return $this->get_revolut_order_amount( $revolut_order );
}
/**
* Check is payment method available
*/
public function is_available() {
if ( ( 'yes' === $this->enabled && is_product() ) || ( $this->check_is_post_data_submitted( 'payment_method' ) && $this->get_post_request_data( 'payment_method' ) === $this->id ) ) {
return true;
}
$payment_request_button_locations = $this->get_option( 'payment_request_button_locations' );
if ( empty( $payment_request_button_locations ) ) {
$payment_request_button_locations = array();
}
if ( is_checkout() ) {
return 'yes' === $this->enabled && in_array( 'checkout', $payment_request_button_locations, true ) && ! $this->api_settings->is_sandbox();
}
return false;
}
/**
* Initialize Gateway Settings Form Fields
*/
public function init_form_fields() {
$this->form_fields = array(
'enabled' => array(
'title' => __( 'Enable/Disable', 'revolut-gateway-for-woocommerce' ),
'label' => sprintf(
/* translators:%1s: %$2s: %3$s: %4$s: */
__( 'Enable Payment Request Buttons. (Apple Pay/Google Pay) %1$sBy using Apple Pay, you agree with %2$sApple\'s%3$s terms of service. (Apple Pay domain verification is performed automatically in live mode.) %4$s', 'revolut-gateway-for-woocommerce' ),
'<br />',
'<a href="https://www.revolut.com/legal/payment-terms-applepay" target="_blank">',
'</a>',
$this->check_authentication_required() ? '<br /> <p style="color:red">' . __( 'Payment with Apple/Google Pay buttons wont be possible for guest users until Guest checkout is enabled', 'revolut-gateway-for-woocommerce' ) . '</p>' : ''
),
'type' => 'checkbox',
'description' => __( 'If enabled, users will be able to pay using Apple Pay (Safari & iOS), Google Pay (Chrome & Android) or native W3C Payment Requests if supported by the browser.', 'revolut-gateway-for-woocommerce' ),
'default' => 'yes',
'desc_tip' => true,
),
'title' => array(
'title' => __( 'Title', 'revolut-gateway-for-woocommerce' ),
'type' => 'text',
'description' => __( 'This controls the title that the user sees during checkout. Plugin will add the button\'s name (Apple Pay or Google Pay) before this title.', 'revolut-gateway-for-woocommerce' ),
'default' => '(via Revolut)',
'desc_tip' => true,
),
'payment_request_button_type' => array(
'title' => __( 'Payment Request Button Action', 'revolut-gateway-for-woocommerce' ),
'label' => __( 'Button Action', 'revolut-gateway-for-woocommerce' ),
'type' => 'select',
'description' => __( 'Select the button type you would like to show.', 'revolut-gateway-for-woocommerce' ),
'default' => 'buy',
'desc_tip' => true,
'options' => array(
'buy' => __( 'Buy', 'revolut-gateway-for-woocommerce' ),
'donate' => __( 'Donate', 'revolut-gateway-for-woocommerce' ),
'pay' => __( 'Pay', 'revolut-gateway-for-woocommerce' ),
),
),
'payment_request_button_theme' => array(
'title' => __( 'Payment Request Button Theme', 'revolut-gateway-for-woocommerce' ),
'label' => __( 'Button Theme', 'revolut-gateway-for-woocommerce' ),
'type' => 'select',
'description' => __( 'Select the button theme you would like to show.', 'revolut-gateway-for-woocommerce' ),
'default' => 'dark',
'desc_tip' => true,
'options' => array(
'dark' => __( 'Dark', 'revolut-gateway-for-woocommerce' ),
'light' => __( 'Light', 'revolut-gateway-for-woocommerce' ),
'light-outlined' => __( 'Light-Outline', 'revolut-gateway-for-woocommerce' ),
),
),
'payment_request_button_radius' => array(
'title' => __( 'Payment Request Button Radius', 'revolut-gateway-for-woocommerce' ),
'label' => __( 'Button Radius', 'revolut-gateway-for-woocommerce' ),
'type' => 'select',
'description' => __( 'Select the button radius you would like to show.', 'revolut-gateway-for-woocommerce' ),
'default' => 'none',
'desc_tip' => true,
'options' => array(
'none' => __( 'None', 'revolut-gateway-for-woocommerce' ),
'small' => __( 'Small', 'revolut-gateway-for-woocommerce' ),
'large' => __( 'Large', 'revolut-gateway-for-woocommerce' ),
),
),
'payment_request_button_size' => array(
'title' => __( 'Payment Request Button Size', 'revolut-gateway-for-woocommerce' ),
'label' => __( 'Button Size', 'revolut-gateway-for-woocommerce' ),
'type' => 'select',
'description' => __( 'Select the button size you would like to show.', 'revolut-gateway-for-woocommerce' ),
'default' => 'large',
'desc_tip' => true,
'options' => array(
'small' => __( 'Small', 'revolut-gateway-for-woocommerce' ),
'large' => __( 'Large', 'revolut-gateway-for-woocommerce' ),
),
),
'payment_request_button_locations' => array(
'title' => __( 'Payment Request Button Locations', 'revolut-gateway-for-woocommerce' ),
'type' => 'multiselect',
'description' => __( 'Select where you would like Payment Request Buttons to be displayed', 'revolut-gateway-for-woocommerce' ),
'desc_tip' => true,
'class' => 'wc-enhanced-select',
'options' => array(
'product' => __( 'Product', 'revolut-gateway-for-woocommerce' ),
'cart' => __( 'Cart', 'revolut-gateway-for-woocommerce' ),
'checkout' => __( 'Checkout', 'revolut-gateway-for-woocommerce' ),
),
'default' => array( 'product', 'cart' ),
'custom_attributes' => array(
'data-placeholder' => __( 'Select pages', 'revolut-gateway-for-woocommerce' ),
),
),
);
if ( $this->get_option( 'apple_pay_merchant_onboarded' ) === 'no' ) {
$this->form_fields['onboard_applepay'] = array(
'title' => __( 'Onboard shop domain for Apple Pay', 'revolut-gateway-for-woocommerce' ),
'type' => 'text',
'description' => '<button class="setup-applepay-domain" style="min-height: 30px;">Setup</button>
<p class="setup-applepay-domain-error" style="color:red;display: none"></p>
<p>Seems that there is a problem automatically onboarding your website for Apple Pay. You can also set this up manually by downloading this <a href="https://assets.revolut.com/api-docs/merchant-api/files/domain_validation_file_prod">file</a> and adding it to the root folder of your shop with the following uri <code>/.well-known/apple-developer-merchantid-domain-association</code>. To learn more about how to do this, visit our <a href="https://developer.revolut.com/docs/accept-payments/plugins/woocommerce/features#set-up-apple-pay-manually" target="_blank">documentation</a></p>',
);
}
}
/**
* Supported functionality
*/
public function init_supports() {
parent::init_supports();
$this->supports[] = 'refunds';
}
/**
* Display payment request button html
*/
public function display_payment_request_button_html() {
if ( ! $this->page_supports_payment_request_button( $this->get_option( 'payment_request_button_locations' ) ) ) {
return false;
}
if ( $this->is_revolut_pay_fast_checkout_active() ) {
?>
<div class="wc-revolut-payment-request-instance" id="wc-revolut-payment-request-container" style="clear:both;">
<div id="revolut-payment-request-button"></div>
<p id="wc-revolut-payment-request-button-separator" style="margin-top:1.5em;text-align:center;">&mdash;&nbsp;<?php echo esc_html( __( 'OR', 'revolut-gateway-for-woocommerce' ) ); ?>
&nbsp;&mdash;</p>
</div>
<?php
return;
}
?>
<div class="wc-revolut-payment-request-instance" id="wc-revolut-payment-request-container" style="clear:both;padding-top:1.5em;">
<div id="revolut-payment-request-button"></div>
<p id="wc-revolut-payment-request-button-separator" style="margin-top:1.5em;text-align:center;">&mdash;&nbsp;<?php echo esc_html( __( 'OR', 'revolut-gateway-for-woocommerce' ) ); ?>
&nbsp;&mdash;</p>
</div>
<?php
}
/**
* Ajax endpoint in order to create WooCommerce order
*/
public function revolut_payment_request_ajax_create_order() {
if ( WC()->cart->is_empty() ) {
wp_send_json_error( __( 'Empty cart', 'revolut-gateway-for-woocommerce' ) );
}
if ( ! defined( 'WOOCOMMERCE_CHECKOUT' ) ) {
define( 'WOOCOMMERCE_CHECKOUT', true );
}
$errors = new WP_Error();
try {
$wc_order_data = $this->get_wc_order_details();
} catch ( Exception $e ) {
$this->log_error( $e->getMessage() );
$errors->add( 'payment', __( 'Something went wrong', 'woocommerce' ) );
if ( ! empty( $this->get_post_request_data( 'revolut_payment_error' ) ) ) {
$errors->add( 'payment', $this->get_post_request_data( 'revolut_payment_error' ) );
$this->log_error( $this->get_post_request_data( 'revolut_payment_error' ) );
}
}
foreach ( $errors->errors as $code => $messages ) {
$data = $errors->get_error_data( $code );
foreach ( $messages as $message ) {
wc_add_notice( $message, 'error', $data );
}
}
if ( 0 === wc_notice_count( 'error' ) ) {
$_POST = array_merge( $_POST, $wc_order_data ); // phpcs:ignore
unset( $_POST['address_info'] ); // phpcs:ignore
$_POST['_wpnonce'] = wp_create_nonce( 'woocommerce-process_checkout' );
WC()->checkout()->process_checkout();
}
$messages = wc_print_notices( true );
wp_send_json(
array(
'result' => 'failure',
'messages' => $messages,
)
);
}
/**
* Get order details
*
* @throws Exception Exception.
*/
public function get_wc_order_details() {
$public_id = $this->get_post_request_data( 'revolut_public_id' );
if ( empty( $public_id ) ) {
throw new Exception( 'Public ID is missing for the session' );
}
$order_id = $this->get_revolut_order_by_public_id( $public_id );
if ( empty( $order_id ) ) {
throw new Exception( 'Can not find revolut order id' );
}
$address_info = $this->get_post_request_data( 'address_info' );
if ( empty( $address_info ) ) {
throw new Exception( 'Address information is missing' );
}
return $this->format_wc_order_details(
$this->get_post_request_data( 'address_info' ),
$this->get_posted_integer_data( 'shipping_required' ),
$this->get_post_request_data( 'revolut_gateway' )
);
}
/**
* Ajax endpoint for adding product to cart.
*
* @throws Exception Exception.
*/
public function revolut_payment_request_ajax_add_to_cart() {
try {
check_ajax_referer( 'wc-revolut-pr-add-to-cart', 'security' );
$revolut_public_id = $this->get_post_request_data( 'revolut_public_id' );
if ( empty( $revolut_public_id ) ) {
throw new Exception( 'Can not get required parameter' );
}
if ( ! defined( 'WOOCOMMERCE_CART' ) ) {
define( 'WOOCOMMERCE_CART', true );
}
WC()->shipping->reset_shipping();
$product_id = $this->get_posted_integer_data( 'product_id' );
$is_revolut_pay = $this->get_posted_integer_data( 'is_revolut_pay' );
$qty = ! $this->check_is_post_data_submitted( 'qty' ) ? 1 : $this->get_posted_integer_data( 'qty' );
$product = wc_get_product( $product_id );
$product_type = $product->get_type();
$global_cart = WC()->cart;
if ( ! $this->get_posted_integer_data( 'add_to_cart' ) ) {
WC()->cart = clone WC()->cart;
}
WC()->cart->empty_cart();
if ( 'simple' === $product_type || 'subscription' === $product_type ) {
WC()->cart->add_to_cart( $product->get_id(), $qty );
} elseif ( $this->check_is_post_data_submitted( 'attributes' ) && ( 'variable' === $product_type || 'variable-subscription' === $product_type ) ) {
$attributes = $this->get_post_request_data( 'attributes' );
$data_store = WC_Data_Store::load( 'product' );
$variation_id = $data_store->find_matching_product_variation( $product, $attributes );
WC()->cart->add_to_cart( $product->get_id(), $qty, $variation_id, $attributes );
}
WC()->shipping->reset_shipping();
WC()->cart->calculate_totals();
$total_amount = $this->update_revolut_order_with_cart_total( $revolut_public_id, $is_revolut_pay );
$is_cart_empty = ! WC()->cart->is_empty();
if ( ! $this->get_posted_integer_data( 'add_to_cart' ) ) {
WC()->cart = $global_cart;
}
$data['total']['amount'] = $total_amount;
$data['checkout_nonce'] = wp_create_nonce( 'woocommerce-process_checkout' );
$data['status'] = 'success';
$data['success'] = $is_cart_empty;
wp_send_json( $data );
} catch ( Exception $e ) {
$this->log_error( $e );
$data['status'] = 'fail';
$data['success'] = false;
wp_send_json( $data );
}
}
/**
* Ajax endpoint for listing shipping options
*
* @throws Exception Exception.
*/
public function revolut_payment_request_ajax_get_shipping_options() {
check_ajax_referer( 'wc-revolut-payment-request-shipping', 'security' );
try {
$revolut_public_id = $this->get_post_request_data( 'revolut_public_id' );
if ( empty( $revolut_public_id ) ) {
throw new Exception( 'Can not get required parameter' );
}
$shipping_address = filter_input_array(
INPUT_POST,
array(
'country' => FILTER_SANITIZE_STRING,
'state' => FILTER_SANITIZE_STRING,
'postcode' => FILTER_SANITIZE_STRING,
'city' => FILTER_SANITIZE_STRING,
'address' => FILTER_SANITIZE_STRING,
'address_2' => FILTER_SANITIZE_STRING,
)
);
$shipping_options = $this->get_shipping_options( $shipping_address );
if ( count( $shipping_options ) > 0 ) {
$this->update_shipping_method( $shipping_options[0] );
}
$total_amount = $this->update_revolut_order_with_cart_total( $revolut_public_id );
$data['success'] = true;
$data['status'] = 'success';
$data['total']['amount'] = $total_amount;
$data['shippingOptions'] = $shipping_options;
wp_send_json( $data );
} catch ( Exception $e ) {
$this->log_error( $e );
$data['status'] = 'fail';
$data['success'] = false;
$data['total']['amount'] = 0;
$data['shippingOptions'] = array();
wp_send_json( $data );
}
}
/**
* Ajax endpoint for updating shipping options
*
* @throws Exception Exception.
*/
public function revolut_payment_request_ajax_update_shipping_method() {
check_ajax_referer( 'wc-revolut-update-shipping-method', 'security' );
try {
if ( ! defined( 'WOOCOMMERCE_CART' ) ) {
define( 'WOOCOMMERCE_CART', true );
}
$revolut_public_id = $this->get_post_request_data( 'revolut_public_id' );
if ( empty( $revolut_public_id ) ) {
throw new Exception( 'Can not get required parameter' );
}
$shipping_method = filter_input( INPUT_POST, 'shipping_method', FILTER_DEFAULT, FILTER_REQUIRE_ARRAY );
$this->update_shipping_method( $shipping_method );
WC()->cart->calculate_totals();
$total_amount = $this->update_revolut_order_with_cart_total( $revolut_public_id );
$data['success'] = true;
$data['status'] = 'success';
$data['total']['amount'] = $total_amount;
wp_send_json( $data );
} catch ( Exception $e ) {
$this->log_error( $e );
$data['status'] = 'fail';
$data['success'] = false;
$data['total']['amount'] = 0;
wp_send_json( $data );
}
}
/**
* Ajax endpoint for updating shipping options
*
* @throws Exception Exception.
*/
public function revolut_payment_request_update_revolut_order_with_cart_total() {
check_ajax_referer( 'wc-revolut-update-order-total', 'security' );
try {
$revolut_public_id = $this->get_post_request_data( 'revolut_public_id' );
if ( empty( $revolut_public_id ) ) {
throw new Exception( 'Can not get required parameter' );
}
WC()->cart->calculate_totals();
$total_amount = $this->update_revolut_order_with_cart_total( $revolut_public_id, true );
$data['success'] = true;
$data['status'] = 'success';
$data['total']['amount'] = $total_amount;
wp_send_json( $data );
} catch ( Exception $e ) {
$this->log_error( $e );
$data['status'] = 'fail';
$data['success'] = false;
$data['total']['amount'] = 0;
wp_send_json( $data );
}
}
/**
* Display Revolut Pay icon
*/
public function get_icon() {
$icons_str = '';
$icons_str .= '<img src="' . WC_REVOLUT_PLUGIN_URL . '/assets/images/apple-pay-logo.svg" class="revolut-apple-pay-logo" style="max-width:50px;display:none" alt="Apple Pay" />';
$icons_str .= '<img src="' . WC_REVOLUT_PLUGIN_URL . '/assets/images/g-pay-logo.png" class="revolut-google-pay-logo" style="max-width:50px;display:none" alt="Google Pay" />';
return apply_filters( 'woocommerce_gateway_icon', $icons_str, $this->id );
}
/**
* Add public_id field and logo on card form
*
* @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 ) {
$total = WC()->cart->get_total( '' );
$currency = get_woocommerce_currency();
$total = $this->get_revolut_order_total( $total, $currency );
$mode = $this->api_settings->get_option( 'mode' );
$shipping_total = $this->get_cart_total_shipping();
return '<div id="woocommerce-revolut-payment-request-element" class="revolut-payment-request" data-mode="' . $mode . '" data-shipping-total="' . $shipping_total . '" data-currency="' . $currency . '" data-total="' . $total . '" data-textcolor="" data-locale="' . $this->get_lang_iso_code() . '" data-public-id="' . $public_id . '" data-merchant-public-key="' . $merchant_public_key . '"></div>
<input type="hidden" id="wc_' . $this->id . '_payment_nonce" name="wc_' . $this->id . '_payment_nonce" />';
}
}

View File

@@ -0,0 +1,77 @@
<?php
/**
* Revolut Api Settings
*
* Provides configuration for API settings
*
* @package WooCommerce
* @category Payment Gateways
* @author Revolut
* @since 2.0
*/
/**
* WC_Revolut_Settings_API class.
*/
class WC_Revolut_Advanced_Settings extends WC_Revolut_Settings_API {
/**
* Constructor
*/
public function __construct() {
$this->id = 'revolut_advanced_settings';
$this->tab_title = __( 'Advanced Settings', 'revolut-gateway-for-woocommerce' );
$this->init_form_fields();
$this->init_settings();
$this->hooks();
}
/**
* Add required filters
*/
public function hooks() {
add_action( 'woocommerce_settings_checkout', array( $this, 'admin_options' ) );
add_filter( 'wc_revolut_settings_nav_tabs', array( $this, 'admin_nav_tab' ), 10 );
add_action( 'woocommerce_update_options_checkout_' . $this->id, array( $this, 'process_admin_options' ) );
}
/**
* Displays configuration page with tabs
*/
public function admin_options() {
if ( $this->check_is_get_data_submitted( 'page' ) && $this->check_is_get_data_submitted( 'section' ) ) {
$is_revolut_api_section = 'wc-settings' === $this->get_request_data( 'page' ) && $this->id === $this->get_request_data( 'section' );
if ( $is_revolut_api_section ) {
echo wp_kses_post( '<table class="form-table">' );
$this->generate_settings_html( $this->get_form_fields(), true );
echo wp_kses_post( '</table>' );
}
}
}
/**
* Initialize Settings Form Fields
*/
public function init_form_fields() {
$this->form_fields = array(
'title' => array(
'type' => 'title',
'title' => __( 'Revolut Gateway - Advanced Settings', 'revolut-gateway-for-woocommerce' ),
),
'clear_unused_order_records' => array(
'title' => 'Clear unused orders now',
'type' => 'text',
'description' => '<button class="revolut_clear_unused_order_records" style="min-height: 30px;"><span id="span-for-active-button-sandbox">Clear</span></button><br><br><b>What is this?</b> The plugin creates a Revolut order every time a customer is attempting to pay. If you have fast checkout options active, this could mean that an order is created for every site visitor. If you have limited space on your database or you have a lot of site visitors, you might end up with a lot of unused orders. You can use this button to delete unused orders. WARNING: This could also delete orders that customers have not yet paid but have the intention to, so make sure that this is only used when there are no visitors on your website',
),
'consent_clear_unused_order_records' => array(
'title' => '',
'label' => __( 'By ticking this box I understand that unused order IDs stored in my websites database will be deleted. I understand as well that this is run at my own risk and could cause temporary issues with payments being failed.', 'revolut-gateway-for-woocommerce' ),
'type' => 'checkbox',
'default' => 'no',
'class' => 'info_clear_unused_order_records',
),
);
}
}

View File

@@ -0,0 +1,483 @@
<?php
/**
* Revolut Api Settings
*
* Provides configuration for API settings
*
* @package WooCommerce
* @category Payment Gateways
* @author Revolut
* @since 2.0
*/
/**
* WC_Revolut_Settings_API class.
*/
class WC_Revolut_Settings_API extends WC_Settings_API {
use WC_Revolut_Settings_Trait;
/**
* Constructor
*/
public function __construct() {
$this->id = 'revolut';
$this->tab_title = __( 'API Settings', 'revolut-gateway-for-woocommerce' );
$this->init_form_fields();
$this->init_settings();
$this->hooks();
}
/**
* Add required filters
*/
public function hooks() {
add_filter( 'wc_revolut_settings_nav_tabs', array( $this, 'admin_nav_tab' ), 1 );
add_action( 'woocommerce_settings_checkout', array( $this, 'output_settings_nav' ) );
add_action( 'woocommerce_settings_checkout', array( $this, 'admin_options' ) );
add_action( 'admin_notices', array( $this, 'add_revolut_description' ) );
add_action( 'admin_notices', array( $this, 'check_api_key' ) );
add_action( 'admin_notices', array( $this, 'maybe_register_webhook' ) );
add_action( 'admin_notices', array( $this, 'maybe_register_synchronous_webhooks' ) );
add_action( 'woocommerce_update_options_checkout_' . $this->id, array( $this, 'process_admin_options' ) );
}
/**
* Initialize Settings Form Fields
*/
public function init_form_fields() {
$mode = $this->get_option( 'mode' );
$mode = empty( $mode ) ? 'sandbox' : $mode;
$api_key_sandbox = $this->get_option( 'api_key_sandbox' );
$api_key_dev = $this->get_option( 'api_key_dev' );
$api_key_live = $this->get_option( 'api_key' );
$this->form_fields = array(
'title' => array(
'type' => 'title',
'title' => __( 'Revolut Gateway - API Settings', 'revolut-gateway-for-woocommerce' ),
),
'mode' => array(
'title' => __( 'Select Mode', 'revolut-gateway-for-woocommerce' ),
'description' => __( 'Select mode between live mode and sandbox.', 'revolut-gateway-for-woocommerce' ),
'desc_tip' => true,
'type' => 'select',
'default' => $mode,
'options' => array(
'sandbox' => __( 'Sandbox', 'revolut-gateway-for-woocommerce' ),
'live' => __( 'Live', 'revolut-gateway-for-woocommerce' ),
// phpcs:ignore
// 'dev' => __('Dev', 'revolut-gateway-for-woocommerce'),
),
),
'api_key_sandbox' => array(
'title' => __( 'Sandbox API secret key' ),
'description' => __( 'Sandbox API secret key from your Merchant settings on Revolut.', 'revolut-gateway-for-woocommerce' ),
'desc_tip' => true,
'default' => $api_key_sandbox,
'type' => 'password',
'class' => 'enabled-sandbox',
),
// phpcs:ignore
// 'api_key_dev' => array(
// 'title' => __( 'API Key Dev' ),
// 'description' => __( 'API Key from your Merchant settings on Revolut.', 'revolut-gateway-for-woocommerce' ),
// 'desc_tip' => true,
// 'default' => $api_key_dev,
// 'type' => 'password',
// 'class' => 'enabled-sandbox',
// ),
'api_key' => array(
'title' => __( 'Production API secret key', 'revolut-gateway-for-woocommerce' ),
'type' => 'password',
'description' => __( 'Production API secret key from your Merchant settings on Revolut.', 'revolut-gateway-for-woocommerce' ),
'desc_tip' => true,
'default' => $api_key_live,
'class' => 'enabled-live',
),
'payment_action' => array(
'title' => __( 'Payment Action', 'revolut-gateway-for-woocommerce' ),
'type' => 'select',
'default' => 'authorize_and_capture',
'options' => array(
'authorize' => __( 'Authorize Only', 'revolut-gateway-for-woocommerce' ),
'authorize_and_capture' => __( 'Authorize and Capture', 'revolut-gateway-for-woocommerce' ),
),
'description' => __(
'Select "Authorize Only" mode. This allows the payment to be captured up to 7 days after the user has placed the order (e.g. when the goods are shipped or received).
If not selected, Revolut will try to authorize and capture all payments.',
'revolut-gateway-for-woocommerce'
),
'desc_tip' => true,
),
'accept_capture' => array(
'title' => '',
'label' => __( 'Automatically capture order in Revolut', 'revolut-gateway-for-woocommerce' ),
'type' => 'checkbox',
'description' => __( 'Automatically try to capture orders when their status is changed.', 'revolut-gateway-for-woocommerce' ),
'default' => 'yes',
),
'customise_capture_status' => array(
'title' => '',
'label' => __( 'Customize status to trigger capture.', 'revolut-gateway-for-woocommerce' ),
'type' => 'checkbox',
'description' => __( 'Default when checkbox not selected: Processing, Completed', 'revolut-gateway-for-woocommerce' ),
'default' => 'yes',
),
'selected_capture_status_list' => array(
'title' => '',
'type' => 'multiselect',
'description' => __( 'Order Status for triggering the payment capture on Revolut. Default: processing, completed', 'revolut-gateway-for-woocommerce' ),
'desc_tip' => true,
'class' => 'wc-enhanced-select',
'options' => wc_get_order_statuses(),
'default' => array(
'wc-processing' => 'Processing',
'wc-completed' => 'Completed',
),
'custom_attributes' => array(
'data-placeholder' => __( 'Select status', 'revolut-gateway-for-woocommerce' ),
),
),
'disable_banner' => array(
'title' => 'Banner Visibility',
'label' => __( 'Customers can get instructions to signup to Revolut and get rewarded.', 'revolut-gateway-for-woocommerce' ),
'type' => 'checkbox',
'description' => 'This will allow them to pay via Revolut Pay the next time they visit your store and checkout faster.',
'default' => 'yes',
),
);
}
/**
* Displays configuration page with tabs
*/
public function admin_options() {
if ( $this->check_is_get_data_submitted( 'page' ) && $this->check_is_get_data_submitted( 'section' ) ) {
$is_revolut_api_section = 'wc-settings' === $this->get_request_data( 'page' ) && 'revolut' === $this->get_request_data( 'section' );
if ( $is_revolut_api_section ) {
echo wp_kses_post( '<table class="form-table">' );
$this->generate_settings_html( $this->get_form_fields(), true );
echo wp_kses_post( '</table>' );
}
}
}
/**
* Output Revolut description.
*
* @since 2.0.0
*/
public function add_revolut_description() {
if ( $this->check_is_get_data_submitted( 'page' ) && $this->check_is_get_data_submitted( 'section' ) ) {
$is_revolut_section = 'wc-settings' === $this->get_request_data( 'page' ) && in_array( $this->get_request_data( 'section' ), WC_REVOLUT_GATEWAYS, true );
if ( $is_revolut_section ) {
if ( isset( $this->settings['api_key'] ) && empty( $this->settings['api_key'] ) ) {
?>
<div class="notice notice-info sf-notice-nux is-dismissible" xmlns="" id="revolut_notice">
<div class="notice-content">
<p>
Welcome to the <b>Revolut Gateway for Woocommerce plugin!</b>
</p>
<p>
To start accepting payments from your customers at great rates, you'll need to follow
three
simple steps:
</p>
<ul style="list-style-type: disc; margin-left: 50px;">
<li>
<a href="https://business.revolut.com/signup">Sign up for Revolut Business</a> if
you
don't
have an account already.
</li><li>
Once your Revolut Business account has been approved, <a target="_blank" href="https://business.revolut.com/merchant">apply
for a Merchant
Account</a>
</li>
<li>
<a target="_blank" href="https://business.revolut.com/settings/merchant-api">Get
your Production API key</a>
and
paste it in the corresponding field below
</li>
</ul>
<p>
<a target="_blank" href="https://www.revolut.com/business/online-payments">Find out
more</a> about why
accepting
payments through Revolut is the right decision for your business.
</p>
<p>
If you'd like to know more about how to configure this plugin for your needs, <a
target="_blank"
href="https://developer.revolut.com/docs/accept-payments/plugins/woocommerce/configuration">check
out
our documentation.</a>
</p>
</div>
</div>
<?php
} else {
?>
<script>
jQuery(document).ready(function ($) {
$("#revolut_notice").hide();
});
</script>
<?php
}
}
}
}
/**
* Add admin notice when set up failed
*/
public function check_api_key() {
if ( $this->check_is_get_data_submitted( 'page' ) && $this->check_is_get_data_submitted( 'section' ) ) {
$is_revolut_section = 'wc-settings' === $this->get_request_data( 'page' ) && in_array( $this->get_request_data( 'section' ), WC_REVOLUT_GATEWAYS, true );
if ( $is_revolut_section ) {
$api_key_sandbox = $this->get_option( 'api_key_sandbox' );
$api_key_live = $this->get_option( 'api_key' );
if ( empty( $api_key_sandbox ) && empty( $api_key_live ) ) {
$this->add_error_message( __( 'Revolut requires an API Key to work.', 'revolut-gateway-for-woocommerce' ) );
}
}
}
}
/**
* Setup Revolut webhook if not configured
*/
public function maybe_register_webhook() {
$api_client = new WC_Revolut_API_Client( $this );
if ( empty( $api_client->api_key ) ) {
return false;
}
if ( ! $this->check_is_shop_needs_webhook_setup() ) {
return false;
}
if ( ! $this->setup_revolut_webhook() ) {
return false;
}
$this->add_success_message( __( 'Webhook url successfully configured', 'revolut-gateway-for-woocommerce' ) );
}
/**
* Setup Revolut synchronous webhooks if not configured
*/
public function maybe_register_synchronous_webhooks() {
$api_client = new WC_Revolut_API_Client( $this );
if ( empty( $api_client->api_key ) ) {
return false;
}
if ( ! $this->setup_revolut_synchronous_webhook() ) {
/* translators:%1s: %$2s: */
$this->add_error_message( sprintf( __( 'Synchronous Webhook setup unsuccessful. Please make sure you are using the correct %1$sAPI key%2$s. If the problem persists, please reach out to support via our in-app chat.', 'revolut-gateway-for-woocommerce' ), '<a href="https://developer.revolut.com/docs/accept-payments/get-started/generate-the-api-key" target="_blank">', '</a>' ) );
return false;
}
}
/**
* Revolut location setup
*
* @throws Exception Exception.
*/
public function setup_revolut_location() {
$domain = get_site_url();
$location_name = str_replace( array( 'https://', 'http://' ), '', $domain );
$api_client = new WC_Revolut_API_Client( $this, true );
$locations = $api_client->get( '/locations' );
if ( ! empty( $locations ) ) {
foreach ( $locations as $location ) {
if ( isset( $location['name'] ) && $location['name'] === $domain && ! empty( $location['id'] ) ) {
return $location['id'];
}
}
}
$body = array(
'name' => $location_name,
'type' => 'online',
'details' => array(
'domain' => $domain,
),
);
$location = $api_client->post( '/locations', $body );
if ( ! isset( $location['id'] ) || empty( $location['id'] ) ) {
throw new Exception( 'Can not create location object.' );
}
return $location['id'];
}
/**
* Check is shop needs webhook setup
*/
public function check_is_shop_needs_webhook_setup() {
try {
$web_hook_url = get_site_url( null, '/wp-json/wc/v3/revolut', 'https' );
if ( $this->get_option( 'revolut_webhook_domain' ) === $web_hook_url ) {
return false;
}
$api_client = new WC_Revolut_API_Client( $this );
$web_hook_url_list = $api_client->get( '/webhooks' );
if ( ! empty( $web_hook_url_list ) ) {
$web_hook_url_list = array_column( $web_hook_url_list, 'url' );
if ( in_array( $web_hook_url, $web_hook_url_list, true ) ) {
return false;
}
}
} catch ( Exception $e ) {
$this->add_error_message( $e->getMessage() );
}
return true;
}
/**
* Revolut webhook setup
*/
public function setup_revolut_webhook() {
try {
$web_hook_url = get_site_url( null, '/wp-json/wc/v3/revolut', 'https' );
$body = array(
'url' => $web_hook_url,
'events' => array(
'ORDER_COMPLETED',
'ORDER_AUTHORISED',
),
);
$api_client = new WC_Revolut_API_Client( $this );
$response = $api_client->post( '/webhooks', $body );
if ( isset( $response['id'] ) && ! empty( $response['id'] ) ) {
$this->update_option( 'revolut_webhook_domain', $web_hook_url );
return true;
}
} catch ( Exception $e ) { // phpcs:ignore
// Prevent double logs. Exception logged previously.
}
return false;
}
/**
* Revolut webhook setup
*/
public function setup_revolut_synchronous_webhook() {
try {
$web_hook_url = get_site_url( null, '/wp-json/wc/v3/revolut', 'https' );
$location_id = $this->setup_revolut_location();
$mode = $this->get_option( 'mode' );
$mode = empty( $mode ) ? 'sandbox' : $mode;
if ( $this->get_option( 'revolut_pay_synchronous_webhook_domain_' . $mode . '_' . $location_id ) === $web_hook_url ) {
return true;
}
$body = array(
'url' => $web_hook_url,
'event_type' => 'fast_checkout.validate_address',
'location_id' => $location_id,
);
$api_client = new WC_Revolut_API_Client( $this, true );
$response = $api_client->post( '/synchronous-webhooks', $body );
if ( isset( $response['signing_key'] ) && ! empty( $response['signing_key'] ) ) {
$this->update_option( 'revolut_' . $mode . '_location_id', $location_id );
$this->update_option( 'revolut_pay_synchronous_webhook_domain_' . $mode . '_' . $location_id, $web_hook_url );
$this->update_option( 'revolut_pay_synchronous_webhook_domain_' . $mode . '_signing_key', $response['signing_key'] );
$this->add_success_message( __( 'Synchronous Webhook url successfully configured', 'revolut-gateway-for-woocommerce' ) );
return true;
}
$this->add_error_message( wp_json_encode( $response ) );
} catch ( Exception $e ) {
$this->add_error_message( $e->getMessage() );
}
return false;
}
/**
* Get Revolut Location
*/
public function get_revolut_location() {
$mode = empty( $this->get_option( 'mode' ) ) ? 'sandbox' : $this->get_option( 'mode' );
return $this->get_option( 'revolut_' . $mode . '_location_id' );
}
/**
* Display error message
*
* @param string $message display message.
*/
public function add_error_message( $message ) {
echo wp_kses_post( '<div class="error revolut-passphrase-message"><p>' . $message . '</p></div>' );
}
/**
* Display success message
*
* @param string $message display message.
*/
public function add_success_message( $message ) {
echo wp_kses_post( '<div style="border-left-color: green" class="error revolut-passphrase-message"><p>' . $message . '</p></div>' );
}
/**
* Check is data submitted for GET request.
*
* @param string $submit request key.
*/
public function check_is_get_data_submitted( $submit ) {
return isset( $_GET[ $submit ] ); // phpcs:ignore
}
/**
* Safe get request data
*
* @param string $get_key request key.
*/
public function get_request_data( $get_key ) {
if ( ! isset( $_GET[ $get_key ] ) ) { // phpcs:ignore
return null;
}
return $this->recursive_sanitize_text_field( $_GET[ $get_key ] ); // phpcs:ignore
}
/**
* Clear data.
*
* @param mixed $var data for cleaning.
*/
public function recursive_sanitize_text_field( $var ) {
if ( is_array( $var ) ) {
return array_map( array( $this, 'recursive_sanitize_text_field' ), $var );
} else {
return sanitize_text_field( wp_unslash( $var ) );
}
}
}

View File

@@ -0,0 +1,538 @@
<?php
/**
* Revolut Helper
*
* Helper class for required tools.
*
* @package WooCommerce
* @category Payment Gateways
* @author Revolut
* @since 2.0
*/
if ( ! defined( 'ABSPATH' ) ) {
exit;
}
/**
* WC_Gateway_Revolut_Helper_Trait trait.
*/
trait WC_Gateway_Revolut_Express_Checkout_Helper_Trait {
/**
* Free shipping.
*
* @var array
*/
public static $free_shipping = array(
array(
'id' => 'free_shipping',
'amount' => '0',
'description' => '',
'label' => 'SHIPPING',
),
);
/**
* Calculate shipping
*
* @param array $address customer address info.
*/
public function calculate_shipping( $address = array() ) {
$country = $address['country'];
$state = $this->convert_state_name_to_id( $address['country'], $address['state'] );
$postcode = $address['postcode'];
$city = $address['city'];
$address_1 = $address['address'];
$address_2 = $address['address_2'];
WC()->shipping->reset_shipping();
if ( $postcode && WC_Validation::is_postcode( $postcode, $country ) ) {
$postcode = wc_format_postcode( $postcode, $country );
}
if ( $country ) {
WC()->customer->set_location( $country, $state, $postcode, $city );
WC()->customer->set_shipping_location( $country, $state, $postcode, $city );
} else {
WC()->customer->set_billing_address_to_base();
WC()->customer->set_shipping_address_to_base();
}
WC()->customer->set_calculated_shipping( true );
WC()->customer->save();
$packages = array();
$package = array();
$package['contents'] = WC()->cart->get_cart();
$package['contents_cost'] = 0;
$package['applied_coupons'] = WC()->cart->applied_coupons;
$package['user']['ID'] = get_current_user_id();
$package['destination']['country'] = $country;
$package['destination']['state'] = $state;
$package['destination']['postcode'] = $postcode;
$package['destination']['city'] = $city;
$package['destination']['address'] = $address_1;
$package['destination']['address_2'] = $address_2;
foreach ( WC()->cart->get_cart() as $item ) {
if ( $item['data']->needs_shipping() ) {
if ( isset( $item['line_total'] ) ) {
$package['contents_cost'] += $item['line_total'];
}
}
}
$packages[0] = $package;
$packages = apply_filters( 'woocommerce_cart_shipping_packages', $packages );
WC()->shipping->calculate_shipping( $packages );
}
/**
* Get shipping options
*
* @param array $shipping_address customer address info.
*/
public function get_shipping_options( $shipping_address ) {
$shipping_options = array();
$GLOBALS['wp']->query_vars['rest_route'] = 'wc/store/v3/cart';
$chosen_shipping_methods = WC()->session->get( 'chosen_shipping_methods' );
$this->calculate_shipping( $shipping_address );
WC()->cart->calculate_totals();
$packages = WC()->shipping->get_packages();
if ( empty( $packages ) && ! WC()->customer->has_calculated_shipping() ) {
return $shipping_options;
}
$package = $packages[0];
if ( empty( $package ) || empty( $package['rates'] ) ) {
return $shipping_options;
}
foreach ( $package['rates'] as $rate ) {
$shipping_cost = (float) $rate->get_cost() + (float) $rate->get_shipping_tax();
$shipping_cost = wc_format_decimal( $shipping_cost, wc_get_price_decimals() );
$shipping_options[] = array(
'id' => $rate->id,
'label' => $rate->label . ' ' . $shipping_cost . ' ' . get_woocommerce_currency(),
'description' => '',
'amount' => $shipping_cost * 100,
);
}
if ( isset( $shipping_options[0] ) ) {
if ( isset( $chosen_shipping_methods[0] ) ) {
$chosen_method_id = $chosen_shipping_methods[0];
$compare_shipping_options = function ( $a, $b ) use ( $chosen_method_id ) {
if ( $a['id'] === $chosen_method_id ) {
return -1;
}
if ( $b['id'] === $chosen_method_id ) {
return 1;
}
return 0;
};
usort( $shipping_options, $compare_shipping_options );
}
$first_shipping_method_id = $shipping_options[0]['id'];
$this->update_shipping_method( array( $first_shipping_method_id ) );
}
WC()->cart->calculate_totals();
return $shipping_options;
}
/**
* Update shipping method in WC cart.
*
* @param array $shipping_methods shipping method list.
*/
public function update_shipping_method( $shipping_methods ) {
$chosen_shipping_methods = WC()->session->get( 'chosen_shipping_methods' );
if ( is_array( $shipping_methods ) ) {
foreach ( $shipping_methods as $i => $value ) {
$chosen_shipping_methods[ $i ] = wc_clean( $value );
}
}
WC()->session->set( 'chosen_shipping_methods', $chosen_shipping_methods );
WC()->cart->calculate_totals();
}
/**
* Get Required parameters for Revolut order.
*/
public function get_revolut_order_descriptor() {
if ( $this->is_product() ) {
$product = $this->get_product_data();
return new WC_Revolut_Order_Descriptor( $product['productPrice'], get_woocommerce_currency(), null );
}
return new WC_Revolut_Order_Descriptor( WC()->cart->get_total( '' ), get_woocommerce_currency(), null );
}
/**
* Check is product page.
*/
public function is_product() {
if ( is_product() || wc_post_content_has_shortcode( 'product_page' ) ) {
$product = $this->get_product();
if ( 'subscription' !== $product->get_type() ) {
return true;
}
}
return false;
}
/**
* Get product data.
*/
public function get_product_data() {
if ( ! $this->is_product() ) {
return false;
}
$product = $this->get_product();
if ( 'variable' === $product->get_type() ) {
$variation_attributes = $product->get_variation_attributes();
$attributes = array();
foreach ( $variation_attributes as $attribute_name => $attribute_values ) {
$attribute_key = 'attribute_' . sanitize_title( $attribute_name );
if ( $this->check_is_get_data_submitted( $attribute_key ) ) {
$attributes[ $attribute_key ] = sanitize_text_field( wp_unslash( $_GET[ $attribute_key ] ) ); // phpcs:ignore
} else {
$attributes[ $attribute_key ] = $product->get_variation_default_attribute( $attribute_name );
}
}
$data_store = WC_Data_Store::load( 'product' );
$variation_id = $data_store->find_matching_product_variation( $product, $attributes );
if ( ! empty( $variation_id ) ) {
$product = wc_get_product( $variation_id );
}
}
$data = array();
$data['productPrice'] = $this->get_product_price( $product );
$data['shipping_required'] = ( wc_shipping_enabled() && $product->needs_shipping() && 0 !== wc_get_shipping_method_count( true ) );
return $data;
}
/**
* Get product price
*
* @param object $product WooCommerce product.
*/
public function get_product_price( $product ) {
$product_price = $product->get_price();
if ( 'subscription' === $product->get_type() && class_exists( 'WC_Subscriptions_Product' ) ) {
$product_price = $product->get_price() + WC_Subscriptions_Product::get_sign_up_fee( $product );
}
return $product_price;
}
/**
* Get product object.
*/
public function get_product() {
global $post;
if ( is_product() ) {
return wc_get_product( $post->ID );
} elseif ( wc_post_content_has_shortcode( 'product_page' ) ) {
// Get id from product_page shortcode.
preg_match( '/\[product_page id="(?<id>\d+)"\]/', $post->post_content, $shortcode_match );
if ( ! isset( $shortcode_match['id'] ) ) {
return false;
}
return wc_get_product( $shortcode_match['id'] );
}
return false;
}
/**
* Get redirect URL.
*/
public function get_redirect_url() {
global $post;
if ( is_product() ) {
return get_permalink( $post->ID );
} elseif ( wc_post_content_has_shortcode( 'product_page' ) ) {
// Get id from product_page shortcode.
preg_match( '/\[product_page id="(?<id>\d+)"\]/', $post->post_content, $shortcode_match );
if ( isset( $shortcode_match['id'] ) ) {
return get_permalink( $shortcode_match['id'] );
}
}
if ( is_cart() ) {
return wc_get_cart_url();
}
return wc_get_checkout_url();
}
/**
* Get parameters
*/
public function get_wc_revolut_payment_request_params() {
try {
$revolut_public_id = $this->create_express_checkout_public_id();
$total = WC()->cart->get_total( '' );
$currency = get_woocommerce_currency();
$total = $this->get_revolut_order_total( $total, $currency );
$revolut_payment_request_settings = get_option( 'woocommerce_revolut_payment_request_settings', array() );
$revolut_pay_settings = get_option( 'woocommerce_revolut_pay_settings', array() );
return array(
'total' => $total,
'currency' => $currency,
'locale' => $this->get_lang_iso_code(),
'publicToken' => $this->get_merchant_public_api_key(),
'ajax_url' => WC_AJAX::get_endpoint( '%%wc_revolut_gateway_ajax_endpoint%%' ),
'revolut_public_id' => $revolut_public_id,
'revolut_pay_origin_url' => str_replace( array( 'https://', 'http://' ), '', get_site_url() ),
'revolut_pay_button_theme' => ! empty( $revolut_pay_settings['revolut_pay_button_theme'] ) ? $revolut_pay_settings['revolut_pay_button_theme'] : '',
'revolut_pay_button_size' => ! empty( $revolut_pay_settings['revolut_pay_button_size'] ) ? $revolut_pay_settings['revolut_pay_button_size'] : '',
'revolut_pay_button_radius' => ! empty( $revolut_pay_settings['revolut_pay_button_radius'] ) ? $revolut_pay_settings['revolut_pay_button_radius'] : '',
'payment_request_button_type' => ! empty( $revolut_payment_request_settings['payment_request_button_type'] ) ? $revolut_payment_request_settings['payment_request_button_type'] : '',
'payment_request_button_theme' => ! empty( $revolut_payment_request_settings['payment_request_button_theme'] ) ? $revolut_payment_request_settings['payment_request_button_theme'] : '',
'payment_request_button_radius' => ! empty( $revolut_payment_request_settings['payment_request_button_radius'] ) ? $revolut_payment_request_settings['payment_request_button_radius'] : '',
'payment_request_button_size' => ! empty( $revolut_payment_request_settings['payment_request_button_size'] ) ? $revolut_payment_request_settings['payment_request_button_size'] : '',
'shipping_options' => array(),
'nonce' => array(
'payment' => wp_create_nonce( 'wc-revolut-payment-request' ),
'shipping' => wp_create_nonce( 'wc-revolut-payment-request-shipping' ),
'update_shipping' => wp_create_nonce( 'wc-revolut-update-shipping-method' ),
'update_order_total' => wp_create_nonce( 'wc-revolut-update-order-total' ),
'load_order_data' => wp_create_nonce( 'wc-revolut-load-order-data' ),
'cancel_order' => wp_create_nonce( 'wc-revolut-cancel-order' ),
'get_express_checkout_params' => wp_create_nonce( 'wc-revolut-get-express-checkout-params' ),
'get_payment_request_params' => wp_create_nonce( 'wc-revolut-get-payment-request-params' ),
'checkout' => wp_create_nonce( 'woocommerce-process_checkout' ),
'add_to_cart' => wp_create_nonce( 'wc-revolut-pr-add-to-cart' ),
'get_selected_product_data' => wp_create_nonce( 'wc-revolut-get-selected-product-data' ),
'log_errors' => wp_create_nonce( 'wc-revolut-log-errors' ),
'clear_cart' => wp_create_nonce( 'wc-revolut-clear-cart' ),
),
'is_product_page' => $this->is_product(),
'redirect_url' => $this->get_redirect_url(),
'is_cart_page' => is_cart(),
'product' => $this->get_product_data(),
'shipping_required' => $this->is_shipping_required(),
'free_shipping_option' => self::$free_shipping,
'error_messages' => array(
'checkout_general' => __( 'Something went wrong while processing the order. Please try again', 'revolut-gateway-for-woocommerce' ),
'cart_create_failed' => __( 'An error occurred while creating WooCommerce cart', 'revolut-gateway-for-woocommerce' ),
),
);
} catch ( Exception $e ) {
$this->log_error( $e->getMessage() );
}
}
/**
* Create Revolut order for express checkout.
*/
public function create_express_checkout_public_id() {
$revolut_public_id = $this->get_revolut_express_checkout_public_id();
$descriptor = $this->get_revolut_order_descriptor();
if ( null === $revolut_public_id ) {
$revolut_public_id = $this->create_revolut_order( $descriptor, true );
$this->set_revolut_express_checkout_public_id( $revolut_public_id );
} else {
$revolut_public_id = $this->update_revolut_order( $descriptor, $revolut_public_id, true );
$this->set_revolut_express_checkout_public_id( $revolut_public_id );
}
return $revolut_public_id;
}
/**
* Check if shipping required for the order.
*/
public function is_shipping_required() {
if ( $this->is_product() ) {
$product = $this->get_product_data();
return isset( $product['shipping_required'] ) ? $product['shipping_required'] : false;
}
if ( is_cart() ) {
return ! is_null( WC()->cart ) && WC()->cart->needs_shipping();
}
return false;
}
/**
* Check is page supports payment request button
*
* @param array $payment_request_button_locations configuration.
*/
public function page_supports_payment_request_button( $payment_request_button_locations ) {
if ( empty( $payment_request_button_locations ) ) {
$payment_request_button_locations = array();
}
if ( ! is_cart() && ! $this->is_product() ) {
return false;
}
if ( $this->is_product() && ! in_array( 'product', $payment_request_button_locations, true ) ) {
return false;
}
if ( is_cart() && ! in_array( 'cart', $payment_request_button_locations, true ) ) {
return false;
}
if ( $this->is_subscription_product() ) {
return false;
}
if ( ! $this->check_order_creation_possible() ) {
return false;
}
return true;
}
/**
* Check is subscription product.
*/
public function is_subscription_product() {
if ( ! class_exists( 'WC_Subscriptions_Product' ) ) {
return false;
}
if ( $this->is_product() ) {
$product = $this->get_product();
if ( WC_Subscriptions_Product::is_subscription( $product ) ) {
return true;
}
}
if ( is_cart() ) {
foreach ( WC()->cart->get_cart() as $cart_item_key => $cart_item ) {
$_product = apply_filters( 'woocommerce_cart_item_product', $cart_item['data'], $cart_item, $cart_item_key );
if ( WC_Subscriptions_Product::is_subscription( $_product ) ) {
return true;
}
}
}
return false;
}
/**
* Check is creating WooCommerce order possible.
*/
public function check_order_creation_possible() {
if ( is_user_logged_in() || ! $this->check_authentication_required() ) {
return true;
}
return false;
}
/**
* Covert Revolut address type into the required form of express checkout.
*
* @param array $address from api.
*/
public function convert_revolut_address_to_express_checkout_address( $address ) {
$address['country'] = $address['country_code'];
$address['addressLine'] = array( $address['street_line_1'], '' );
$address['address'] = $address['street_line_1'];
$address['address_2'] = '';
$address['postalCode'] = $address['postcode'];
$address['region'] = ! empty( $address['region'] ) ? $address['region'] : '';
$address['state'] = $address['region'];
return $address;
}
/**
* Check if authentication is required.
*/
public function check_authentication_required() {
if ( 'no' === get_option( 'woocommerce_enable_guest_checkout', 'yes' ) && ! $this->check_account_creation_possible() ) {
return true;
}
return false;
}
/**
* Check if account creation possible
*/
public function check_account_creation_possible() {
return (
'yes' === get_option( 'woocommerce_enable_signup_and_login_from_checkout', 'no' ) &&
'yes' === get_option( 'woocommerce_registration_generate_username', 'yes' ) &&
'yes' === get_option( 'woocommerce_registration_generate_password', 'yes' )
);
}
/**
* Load sate id by name if the api sends state name.
*
* @param string $country_id id country.
* @param string $state_name state name.
*/
public function convert_state_name_to_id( $country_id, $state_name ) {
$wc_states = WC()->countries->get_states( $country_id );
if ( empty( $wc_states ) || empty( $state_name ) ) {
return $state_name;
}
foreach ( $wc_states as $state_id => $wc_state_name ) {
if ( strtolower( $wc_state_name ) === strtolower( $state_name ) || strtolower( $state_id ) === strtolower( $state_name ) ) {
return $state_id;
}
}
// if the standard search fails search county by removing Co prefix for Irish states.
if ( 'IE' === $country_id ) {
$state_name = str_replace( 'Co. ', '', $state_name );
foreach ( $wc_states as $state_id => $wc_state_name ) {
if ( strtolower( $wc_state_name ) === strtolower( $state_name ) || strtolower( $state_id ) === strtolower( $state_name ) ) {
return $state_id;
}
}
}
return $state_name;
}
}

View File

@@ -0,0 +1,948 @@
<?php
/**
* Revolut Helper
*
* Helper class for required tools.
*
* @package WooCommerce
* @category Payment Gateways
* @author Revolut
* @since 2.0
*/
if ( ! defined( 'ABSPATH' ) ) {
exit;
}
/**
* WC_Gateway_Revolut_Helper_Trait trait.
*/
trait WC_Gateway_Revolut_Helper_Trait {
use WC_Revolut_Settings_Trait;
use WC_Revolut_Logger_Trait;
/**
* Create Revolut Order
*
* @param WC_Revolut_Order_Descriptor $order_descriptor Revolut Order Descriptor.
*
* @param bool $is_express_checkout indicator.
*
* @return mixed
* @throws Exception Exception.
*/
public function create_revolut_order( WC_Revolut_Order_Descriptor $order_descriptor, $is_express_checkout = false ) {
$capture = 'authorize' === $this->api_settings->get_option( 'payment_action' ) || $is_express_checkout ? 'manual' : 'automatic';
$body = array(
'amount' => $order_descriptor->amount,
'currency' => $order_descriptor->currency,
'capture_mode' => $capture,
);
if ( ! empty( $order_descriptor->revolut_customer_id ) ) {
$body['customer'] = array( 'id' => $order_descriptor->revolut_customer_id );
}
if ( $is_express_checkout ) {
$body['cancel_authorised_after'] = WC_REVOLUT_AUTO_CANCEL_TIMEOUT;
$location_id = $this->api_settings->get_revolut_location();
if ( $location_id ) {
$body['location_id'] = $location_id;
}
}
$json = $this->api_client->post( '/orders', $body, false, true );
if ( isset( $json['token'] ) ) {
$json['public_id'] = $json['token'];
}
if ( empty( $json['id'] ) || empty( $json['public_id'] ) ) {
throw new Exception( 'Something went wrong: ' . wp_json_encode( $json, JSON_PRETTY_PRINT ) );
}
global $wpdb;
$result = $wpdb->query(
$wpdb->prepare(
'INSERT INTO ' . $wpdb->prefix . "wc_revolut_orders (order_id, public_id)
VALUES (UNHEX(REPLACE(%s, '-', '')), UNHEX(REPLACE(%s, '-', '')))",
array(
$json['id'],
$json['public_id'],
)
)
); // db call ok; no-cache ok.
if ( 1 !== $result ) {
throw new Exception( 'Can not save Revolut order record on DB:' . $wpdb->last_error );
}
if ( $is_express_checkout ) {
$this->add_or_update_temp_session( $json['id'] );
}
return $json['public_id'];
}
/**
* Retrieve the revolut customer's id.
*
* @param string $billing_phone holds customer email address.
* @param string $billing_email holds customer billing phone.
* @throws Exception Exception.
*/
public function get_or_create_revolut_customer( $billing_phone = '', $billing_email = '' ) {
if ( empty( $billing_email ) || empty( $billing_phone ) ) {
$wc_customer = WC()->customer;
$billing_email = $wc_customer->get_billing_email();
$billing_phone = $wc_customer->get_billing_phone();
}
if ( empty( $billing_email ) || empty( $billing_phone ) ) {
return;
}
$revolut_customer_id = $this->get_revolut_customer_id();
if ( empty( $revolut_customer_id ) ) {
$revolut_customer_id = $this->create_revolut_customer( $billing_phone, $billing_email );
return $revolut_customer_id;
}
return $revolut_customer_id;
}
/**
* Update the revolut customer's phone.
*
* @param string $revolut_customer_id customer_id.
* @param string $billing_phone billing phone number.
* @throws Exception Exception.
* @return void|null
*/
public function update_revolut_customer( $revolut_customer_id, $billing_phone ) {
if ( empty( $revolut_customer_id ) || empty( $billing_phone ) ) {
return null;
}
$this->api_client->patch( "/customers/$revolut_customer_id", array( 'phone' => $billing_phone ) );
}
/**
* Create revolut customer.
*
* @return $revolut_customer_id revolut customer id.
* @param string $billing_phone holds customer billing phone.
* @param string $billing_email holds customer email address.
* @throws Exception Exception.
*/
public function create_revolut_customer( $billing_phone, $billing_email ) {
try {
if ( empty( $billing_phone ) || empty( $billing_email ) ) {
return;
}
$revolut_customer_id = null;
$body = array(
'phone' => $billing_phone,
'email' => $billing_email,
);
$revolut_customer = $this->api_client->get( '/customers?term=' . $billing_email );
$revolut_customer_id = ! empty( $revolut_customer[0]['id'] ) ? $revolut_customer[0]['id'] : '';
if ( ! $revolut_customer_id ) {
$revolut_customer = $this->api_client->post( '/customers', $body );
$revolut_customer_id = ! empty( $revolut_customer['id'] ) ? $revolut_customer['id'] : '';
}
if ( ! $revolut_customer_id ) {
return $revolut_customer_id;
}
$this->insert_revolut_customer_id( $revolut_customer_id );
$this->update_revolut_customer( $revolut_customer_id, $billing_phone );
return $revolut_customer_id;
} catch ( Exception $e ) {
$this->log_error( 'create_revolut_customer: ' . $e->getMessage() );
}
}
/**
* Save Revolut customer id.
*
* @param string $revolut_customer_id Revolut customer id.
*
* @throws Exception Exception.
*/
protected function insert_revolut_customer_id( $revolut_customer_id ) {
if ( empty( get_current_user_id() ) ) {
return;
}
global $wpdb;
$revolut_customer_id = "{$this->api_client->mode}_$revolut_customer_id";
$wpdb->query(
$wpdb->prepare(
"INSERT INTO {$wpdb->prefix}wc_revolut_customer (wc_customer_id, revolut_customer_id)
VALUES (%d, %s) ON DUPLICATE KEY UPDATE wc_customer_id = VALUES(wc_customer_id)",
array( get_current_user_id(), $revolut_customer_id )
)
); // db call ok; no-cache ok.
}
/**
* Update Revolut Order.
*
* @param WC_Revolut_Order_Descriptor $order_descriptor Revolut Order Descriptor.
* @param String $public_id Revolut public id.
* @param Bool $is_revpay_express_checkout is revpay express checkout.
*
* @return mixed
* @throws Exception Exception.
*/
public function update_revolut_order( WC_Revolut_Order_Descriptor $order_descriptor, $public_id, $is_revpay_express_checkout = false ) {
$order_id = $this->get_revolut_order_by_public_id( $public_id );
$body = array(
'amount' => $order_descriptor->amount,
'currency' => $order_descriptor->currency,
'customer_id' => $order_descriptor->revolut_customer_id,
);
if ( empty( $order_id ) ) {
return $this->create_revolut_order( $order_descriptor, $is_revpay_express_checkout );
}
$revolut_order = $this->api_client->get( "/orders/$order_id" );
if ( ! isset( $revolut_order['public_id'] ) || ! isset( $revolut_order['id'] ) || 'PENDING' !== $revolut_order['state'] ) {
return $this->create_revolut_order( $order_descriptor, $is_revpay_express_checkout );
}
$revolut_order = $this->api_client->patch( "/orders/$order_id", $body );
if ( ! isset( $revolut_order['public_id'] ) || ! isset( $revolut_order['id'] ) ) {
return $this->create_revolut_order( $order_descriptor, $is_revpay_express_checkout );
}
if ( $is_revpay_express_checkout ) {
$this->add_or_update_temp_session( $revolut_order['id'] );
}
return $revolut_order['public_id'];
}
/**
* Convert saved customer session into current session.
*
* @param string $id_revolut_order Revolut order id.
*
* @return void.
*/
public function convert_revolut_order_metadata_into_wc_session( $id_revolut_order ) {
WC()->initialize_session();
WC()->initialize_cart();
global $wpdb;
$temp_session = $wpdb->get_row( $wpdb->prepare( 'SELECT temp_session FROM ' . $wpdb->prefix . 'wc_revolut_temp_session WHERE order_id=%s', array( $id_revolut_order ) ), ARRAY_A ); // db call ok; no-cache ok.
$this->log_info( 'start convert_revolut_order_metadata_into_wc_session temp_session:' );
$this->log_info( $temp_session['temp_session'] );
$wc_order_metadata = json_decode( $temp_session['temp_session'], true );
$id_wc_customer = (int) $wc_order_metadata['id_customer'];
if ( $id_wc_customer ) {
wp_set_current_user( $id_wc_customer );
}
WC()->session->set( 'cart', $wc_order_metadata['cart'] );
WC()->session->set( 'cart_totals', $wc_order_metadata['cart_totals'] );
WC()->session->set( 'applied_coupons', $wc_order_metadata['applied_coupons'] );
WC()->session->set( 'coupon_discount_totals', $wc_order_metadata['coupon_discount_totals'] );
WC()->session->set( 'coupon_discount_tax_totals', $wc_order_metadata['coupon_discount_tax_totals'] );
WC()->session->set( 'get_removed_cart_contents', $wc_order_metadata['get_removed_cart_contents'] );
$session = new WC_Cart_Session( WC()->cart );
$session->get_cart_from_session();
}
/**
* Get order details
*
* @param array $address Customer address.
* @param bool $shipping_required is shipping option required for the current order.
* @param string $gateway selected payment gateway.
* @throws Exception Exception.
*/
public function format_wc_order_details( $address, $shipping_required, $gateway ) {
if ( empty( $address['billingAddress'] ) ) {
throw new Exception( 'Billing address is missing' );
}
if ( $shipping_required && empty( $address['shippingAddress'] ) ) {
throw new Exception( 'Shipping address is missing' );
}
if ( empty( $address['email'] ) ) {
throw new Exception( 'User Email information is missing' );
}
$revolut_billing_address = $address['billingAddress'];
$revolut_customer_email = $address['email'];
$revolut_customer_full_name = ! empty( $revolut_billing_address['recipient'] ) ? $revolut_billing_address['recipient'] : '';
$revolut_customer_billing_phone = ! empty( $revolut_billing_address['phone'] ) ? $revolut_billing_address['phone'] : '';
$revolut_customer_shipping_phone = '';
$wc_shipping_address = array();
list($billing_firstname, $billing_lastname) = $this->parse_customer_name( $revolut_customer_full_name );
if ( isset( $address['shippingAddress'] ) && ! empty( $address['shippingAddress'] ) ) {
$revolut_shipping_address = $address['shippingAddress'];
$revolut_customer_shipping_phone = ! empty( $revolut_shipping_address['phone'] ) ? $revolut_shipping_address['phone'] : '';
$revolut_customer_shipping_full_name = ! empty( $revolut_shipping_address['recipient'] ) ? $revolut_shipping_address['recipient'] : '';
$shipping_firstname = $billing_firstname;
$shipping_lastname = $billing_lastname;
if ( ! empty( $revolut_customer_shipping_full_name ) ) {
list($shipping_firstname, $shipping_lastname) = $this->parse_customer_name( $revolut_customer_shipping_full_name );
}
if ( empty( $revolut_customer_shipping_phone ) && ! empty( $revolut_customer_billing_phone ) ) {
$revolut_customer_shipping_phone = $revolut_customer_billing_phone;
}
$wc_shipping_address = $this->get_wc_shipping_address( $revolut_shipping_address, $revolut_customer_email, $revolut_customer_shipping_phone, $shipping_firstname, $shipping_lastname );
}
if ( empty( $revolut_customer_billing_phone ) && ! empty( $revolut_customer_shipping_phone ) ) {
$revolut_customer_billing_phone = $revolut_customer_shipping_phone;
}
$wc_billing_address = $this->get_wc_billing_address( $revolut_billing_address, $revolut_customer_email, $revolut_customer_billing_phone, $billing_firstname, $billing_lastname );
if ( $shipping_required ) {
$wc_order_data = array_merge( $wc_billing_address, $wc_shipping_address );
} else {
$wc_order_data = $wc_billing_address;
}
$wc_order_data['ship_to_different_address'] = $shipping_required;
$wc_order_data['revolut_pay_express_checkout'] = 'revolut_pay' === $gateway;
$wc_order_data['terms'] = 1;
$wc_order_data['order_comments'] = '';
return $wc_order_data;
}
/**
* Get first and lastname from customer full name string.
*
* @param string $full_name Customer full name.
*/
public function parse_customer_name( $full_name ) {
$full_name_list = explode( ' ', $full_name );
if ( count( $full_name_list ) > 1 ) {
$lastname = array_pop( $full_name_list );
$firstname = implode( ' ', $full_name_list );
return array( $firstname, $lastname );
}
$firstname = $full_name;
$lastname = 'undefined';
return array( $firstname, $lastname );
}
/**
* Create billing address for order.
*
* @param array $shipping_address Shipping address.
* @param string $revolut_customer_email Email.
* @param string $revolut_customer_phone Phone.
* @param string $firstname Firstname.
* @param string $lastname Lastname.
*/
public function get_wc_shipping_address( $shipping_address, $revolut_customer_email, $revolut_customer_phone, $firstname, $lastname ) {
if ( isset( $shipping_address['country'] ) ) {
$shipping_address['country'] = strtoupper( $shipping_address['country'] );
}
$address['shipping_first_name'] = $firstname;
$address['shipping_last_name'] = $lastname;
$address['shipping_email'] = $revolut_customer_email;
$address['shipping_phone'] = $revolut_customer_phone;
$address['shipping_country'] = ! empty( $shipping_address['country'] ) ? $shipping_address['country'] : '';
$address['shipping_address_1'] = ! empty( $shipping_address['addressLine'][0] ) ? $shipping_address['addressLine'][0] : '';
$address['shipping_address_2'] = ! empty( $shipping_address['addressLine'][1] ) ? $shipping_address['addressLine'][1] : '';
$address['shipping_city'] = ! empty( $shipping_address['city'] ) ? $shipping_address['city'] : '';
$address['shipping_state'] = ! empty( $shipping_address['region'] ) ? $this->convert_state_name_to_id( $shipping_address['country'], $shipping_address['region'] ) : '';
$address['shipping_postcode'] = ! empty( $shipping_address['postalCode'] ) ? $shipping_address['postalCode'] : '';
$address['shipping_company'] = '';
return $address;
}
/**
* Create billing address for order.
*
* @param array $billing_address Billing address.
* @param string $revolut_customer_email Email.
* @param string $revolut_customer_phone Phone.
* @param string $firstname Firstname.
* @param string $lastname Lastname.
*/
public function get_wc_billing_address( $billing_address, $revolut_customer_email, $revolut_customer_phone, $firstname, $lastname ) {
if ( isset( $billing_address['country'] ) ) {
$billing_address['country'] = strtoupper( $billing_address['country'] );
}
$address = array();
$address['billing_first_name'] = $firstname;
$address['billing_last_name'] = $lastname;
$address['billing_email'] = $revolut_customer_email;
$address['billing_phone'] = $revolut_customer_phone;
$address['billing_country'] = ! empty( $billing_address['country'] ) ? $billing_address['country'] : '';
$address['billing_address_1'] = ! empty( $billing_address['addressLine'][0] ) ? $billing_address['addressLine'][0] : '';
$address['billing_address_2'] = ! empty( $billing_address['addressLine'][1] ) ? $billing_address['addressLine'][1] : '';
$address['billing_city'] = ! empty( $billing_address['city'] ) ? $billing_address['city'] : '';
$address['billing_state'] = ! empty( $billing_address['region'] ) ? $this->convert_state_name_to_id( $billing_address['country'], $billing_address['region'] ) : '';
$address['billing_postcode'] = ! empty( $billing_address['postalCode'] ) ? $billing_address['postalCode'] : '';
$address['billing_company'] = '';
return $address;
}
/**
* Check if payment is pending.
*
* @param string $revolut_order_id Revolut order id.
*/
protected function is_pending_payment( $revolut_order_id ) {
$revolut_order = $this->api_client->get( '/orders/' . $revolut_order_id );
return ! isset( $revolut_order['state'] ) || ( isset( $revolut_order['state'] ) && 'PENDING' === $revolut_order['state'] );
}
/**
* Save or Update customer session temporarily.
*
* @param string $revolut_order_id Revolut order id.
*
* @throws Exception Exception.
*/
public function add_or_update_temp_session( $revolut_order_id ) {
$order_metadata['id_customer'] = get_current_user_id();
$order_metadata['cart'] = WC()->cart->get_cart_for_session();
$order_metadata['cart_totals'] = WC()->cart->get_totals();
$order_metadata['applied_coupons'] = WC()->cart->get_applied_coupons();
$order_metadata['coupon_discount_totals'] = WC()->cart->get_coupon_discount_totals();
$order_metadata['coupon_discount_tax_totals'] = WC()->cart->get_coupon_discount_tax_totals();
$order_metadata['get_removed_cart_contents'] = WC()->cart->get_removed_cart_contents();
$temp_session = wp_json_encode( $order_metadata );
global $wpdb;
$wpdb->query(
$wpdb->prepare(
'INSERT INTO ' . $wpdb->prefix . 'wc_revolut_temp_session (order_id, temp_session)
VALUES (%s, %s) ON DUPLICATE KEY UPDATE temp_session = VALUES(temp_session)',
array(
$revolut_order_id,
$temp_session,
)
)
); // db call ok; no-cache ok.
}
/**
* Get Revolut customer id.
*
* @param int $wc_customer_id WooCommerce customer id.
*/
public function get_revolut_customer_id( $wc_customer_id = false ) {
if ( ! $wc_customer_id ) {
$wc_customer_id = get_current_user_id();
}
if ( empty( $wc_customer_id ) ) {
return null;
}
global $wpdb;
$revolut_customer_id = $wpdb->get_col( $wpdb->prepare( 'SELECT revolut_customer_id FROM ' . $wpdb->prefix . 'wc_revolut_customer WHERE wc_customer_id=%s', array( $wc_customer_id ) ) ); // db call ok; no-cache ok.
$revolut_customer_id = reset( $revolut_customer_id );
if ( empty( $revolut_customer_id ) ) {
$revolut_customer_id = null;
}
$revolut_customer_id_with_mode = explode( '_', $revolut_customer_id );
if ( count( $revolut_customer_id_with_mode ) > 1 ) {
list( $api_mode, $revolut_customer_id ) = $revolut_customer_id_with_mode;
if ( $api_mode !== $this->api_client->mode ) {
$this->delete_customer_record( $wc_customer_id );
return null;
}
}
// verify customer id through api.
$revolut_customer = $this->api_client->get( '/customers/' . $revolut_customer_id );
if ( empty( $revolut_customer['id'] ) ) {
$this->delete_customer_record( $wc_customer_id );
return null;
}
return $revolut_customer_id;
}
/**
* Remove customer db record
*
* @param string $wc_customer_id customer id.
*/
public function delete_customer_record( $wc_customer_id ) {
global $wpdb;
$wpdb->delete( // phpcs:ignore
$wpdb->prefix . 'wc_revolut_customer',
array(
'wc_customer_id' => $wc_customer_id,
)
);
}
/**
* Update Revolut Order Total
*
* @param float $order_total Order total.
* @param string $currency Order currency.
* @param string $public_id Order public id.
*
* @return bool
* @throws Exception Exception.
*/
public function update_revolut_order_total( $order_total, $currency, $public_id ) {
$order_id = $this->get_revolut_order_by_public_id( $public_id );
$order_total = round( $order_total, 2 );
$revolut_order_total = $this->get_revolut_order_total( $order_total, $currency );
$body = array(
'amount' => $revolut_order_total,
'currency' => $currency,
);
if ( empty( $order_id ) ) {
return false;
}
$revolut_order = $this->api_client->get( "/orders/$order_id" );
if ( ! isset( $revolut_order['public_id'] ) || ! isset( $revolut_order['id'] ) || 'PENDING' !== $revolut_order['state'] ) {
return false;
}
$revolut_order = $this->api_client->patch( "/orders/$order_id", $body );
if ( ! isset( $revolut_order['public_id'] ) || ! isset( $revolut_order['id'] ) ) {
return false;
}
return true;
}
/**
* Fetch Revolut order by public id
*
* @param String $public_id Revolut public id.
*
* @return string|null
*/
public function get_revolut_order_by_public_id( $public_id ) {
global $wpdb;
// resolve into order_id.
return $this->uuid_dashes(
$wpdb->get_col( // phpcs:ignore
$wpdb->prepare(
'SELECT HEX(order_id) FROM ' . $wpdb->prefix . 'wc_revolut_orders
WHERE public_id=UNHEX(REPLACE(%s, "-", ""))',
array( $public_id )
)
)
);
}
/**
* Load Merchant Public Key from API.
*
* @return string
*/
public function get_merchant_public_api_key() {
try {
$merchant_public_key = $this->get_revolut_merchant_public_key();
if ( ! empty( $merchant_public_key ) ) {
return $merchant_public_key;
}
$merchant_public_key = $this->api_client->get( WC_GATEWAY_PUBLIC_KEY_ENDPOINT, true );
$merchant_public_key = isset( $merchant_public_key['public_key'] ) ? $merchant_public_key['public_key'] : '';
if ( empty( $merchant_public_key ) ) {
return '';
}
$this->set_revolut_merchant_public_key( $merchant_public_key );
return $merchant_public_key;
} catch ( Exception $e ) {
return '';
}
}
/**
* Check Merchant Account features.
*
* @return bool
*/
public function check_feature_support() {
try {
$this->api_client->set_public_key( $this->get_revolut_merchant_public_key() );
$merchant_features = $this->api_client->get( '/public/merchant', true );
return isset( $merchant_features['features'] ) && is_array( $merchant_features['features'] ) && in_array(
WC_GATEWAY_REVPAY_INDEX,
$merchant_features['features'],
true
);
} catch ( Exception $e ) {
return false;
}
}
/**
* Checks if page is pay for order and change subs payment page.
*
* @return bool
*/
public function is_subs_change_payment() {
return ( isset( $_GET['pay_for_order'] ) && isset( $_GET['change_payment_method'] ) ); // phpcs:ignore
}
/**
* Unset Revolut public_id
*/
protected function unset_revolut_public_id() {
WC()->session->__unset( "{$this->api_client->mode}_revolut_public_id" );
}
/**
* Unset Revolut public_id
*/
protected function unset_revolut_express_checkout_public_id() {
WC()->session->__unset( "{$this->api_client->mode}_revolut_express_checkout_public_id" );
}
/**
* Set Revolut public_id
*
* @param string $value Revolut public id.
*/
protected function set_revolut_public_id( $value ) {
WC()->session->set( "{$this->api_client->mode}_revolut_public_id", $value );
}
/**
* Set Revolut public_id
*
* @param string $value Revolut public id.
*/
public function set_revolut_express_checkout_public_id( $value ) {
WC()->session->set( "{$this->api_client->mode}_revolut_express_checkout_public_id", $value );
}
/**
* Get Revolut public_id
*
* @return array|string|null
*/
protected function get_revolut_public_id() {
$public_id = WC()->session->get( "{$this->api_client->mode}_revolut_public_id" );
if ( empty( $public_id ) ) {
return null;
}
$order_id = $this->get_revolut_order_by_public_id( $public_id );
if ( empty( $order_id ) ) {
return null;
}
return $public_id;
}
/**
* Get Revolut public_id
*
* @return array|string|null
*/
protected function get_revolut_express_checkout_public_id() {
return WC()->session->get( "{$this->api_client->mode}_revolut_express_checkout_public_id" );
}
/**
* Get Revolut Merchant Public Key
*
* @return array|string|null
*/
protected function get_revolut_merchant_public_key() {
return WC()->session->get( "{$this->api_client->mode}_revolut_merchant_public_key" );
}
/**
* Set Revolut Merchant Public Key
*
* @param string $value Revolut Merchant public Key.
*/
protected function set_revolut_merchant_public_key( $value ) {
WC()->session->set( "{$this->api_client->mode}_revolut_merchant_public_key", $value );
}
/**
* Replace dashes
*
* @param mixed $uuid uuid.
*
* @return string|string[]|null
*/
protected function uuid_dashes( $uuid ) {
if ( is_array( $uuid ) ) {
if ( isset( $uuid[0] ) ) {
$uuid = $uuid[0];
}
}
$result = preg_replace( '/(\w{8})(\w{4})(\w{4})(\w{4})(\w{12})/i', '$1-$2-$3-$4-$5', $uuid );
return $result;
}
/**
* Check if is not minor currency
*
* @param string $currency currency.
*
* @return bool
*/
public function is_zero_decimal( $currency ) {
return 'jpy' === strtolower( $currency );
}
/**
* Get order total for Api.
*
* @param float $order_total order total amount.
* @param string $currency currency.
*/
public function get_revolut_order_total( $order_total, $currency ) {
$order_total = round( (float) $order_total, 2 );
if ( ! $this->is_zero_decimal( $currency ) ) {
$order_total = round( $order_total * 100 );
}
return (int) $order_total;
}
/**
* Get order total for WC order.
*
* @param float $revolut_order_total order total amount.
* @param string $currency currency.
*/
public function get_wc_order_total( $revolut_order_total, $currency ) {
$order_total = $revolut_order_total;
if ( ! $this->is_zero_decimal( $currency ) ) {
$order_total = round( $order_total / 100, 2 );
}
return $order_total;
}
/**
* Get total amount value from Revolut order.
*
* @param array $revolut_order Revolut order.
*/
public function get_revolut_order_amount( $revolut_order ) {
return isset( $revolut_order['order_amount'] ) && isset( $revolut_order['order_amount']['value'] ) ? (int) $revolut_order['order_amount']['value'] : 0;
}
/**
* Get shipping amount value from Revolut order.
*
* @param array $revolut_order Revolut order.
*/
public function get_revolut_order_total_shipping( $revolut_order ) {
$shipping_total = isset( $revolut_order['delivery_method'] ) && isset( $revolut_order['delivery_method']['amount'] ) ? (int) $revolut_order['delivery_method']['amount'] : 0;
$currency = $this->get_revolut_order_currency( $revolut_order );
if ( $shipping_total ) {
return $this->get_wc_order_total( $shipping_total, $currency );
}
return 0;
}
/**
* Get currency from Revolut order.
*
* @param array $revolut_order Revolut order.
*/
public function get_revolut_order_currency( $revolut_order ) {
return isset( $revolut_order['order_amount'] ) && isset( $revolut_order['order_amount']['currency'] ) ? $revolut_order['order_amount']['currency'] : '';
}
/**
* Get total shipping price.
*/
public function get_cart_total_shipping() {
$cart_totals = WC()->session->get( 'cart_totals' );
$shipping_total = 0;
if ( ! empty( $cart_totals ) && is_array( $cart_totals ) && in_array( 'shipping_total', array_keys( $cart_totals ), true ) ) {
$shipping_total = $cart_totals['shipping_total'];
}
return $this->get_revolut_order_total( $shipping_total, get_woocommerce_currency() );
}
/**
* Check is data submitted for GET request.
*
* @param string $submit request key.
*/
public function check_is_get_data_submitted( $submit ) {
return isset( $_GET[ $submit ] ); // phpcs:ignore
}
/**
* Check is data submitted for POST request.
*
* @param string $submit request key.
*/
public function check_is_post_data_submitted( $submit ) {
return isset( $_POST[ $submit ] ); // phpcs:ignore
}
/**
* Safe get posted integer data
*
* @param string $post_key request key.
*/
public function get_posted_integer_data( $post_key ) {
if ( ! isset( $_POST[ $post_key ] ) ) { // phpcs:ignore
return 0;
}
return (int) $_POST[ $post_key ]; // phpcs:ignore
}
/**
* Safe get posted data
*
* @param string $post_key request key.
*/
public function get_post_request_data( $post_key ) {
if ( ! isset( $_POST[ $post_key ] ) ) { // phpcs:ignore
return null;
}
return $this->recursive_sanitize_text_field( $_POST[ $post_key ]); // phpcs:ignore
}
/**
* Safe get request data
*
* @param string $get_key request key.
*/
public function get_request_data( $get_key ) {
if ( ! isset( $_GET[ $get_key ] ) ) { // phpcs:ignore
return null;
}
return $this->recursive_sanitize_text_field( $_GET[ $get_key ] ); // phpcs:ignore
}
/**
* Clear data.
*
* @param mixed $var data for cleaning.
*/
public function recursive_sanitize_text_field( $var ) {
if ( is_array( $var ) ) {
return array_map( array( $this, 'recursive_sanitize_text_field' ), $var );
} else {
return sanitize_text_field( wp_unslash( $var ) );
}
}
/**
* Get two-digit language iso code.
*/
public function get_lang_iso_code() {
return substr( get_locale(), 0, 2 );
}
/**
* Check order status
*
* @param String $order_status data for checking.
*/
public function check_is_order_has_capture_status( $order_status ) {
if ( 'authorize' !== $this->api_settings->get_option( 'payment_action' ) ) {
return false;
}
if ( 'yes' !== $this->api_settings->get_option( 'accept_capture' ) ) {
return false;
}
$order_status = ( 0 !== strpos( $order_status, 'wc-' ) ) ? 'wc-' . $order_status : $order_status;
$selected_capture_status_list = $this->api_settings->get_option( 'selected_capture_status_list' );
$customize_capture_status = $this->api_settings->get_option( 'customise_capture_status' );
if ( empty( $selected_capture_status_list ) || 'no' === $customize_capture_status ) {
$selected_capture_status_list = array( 'wc-processing', 'wc-completed' );
}
return in_array( $order_status, $selected_capture_status_list, true );
}
/**
* Check order status
*
* @param String $public_id data.
*/
public function get_available_card_brands( $public_id ) {
try {
$order_details = $this->api_client->get( "/orders/token/{$public_id}", false, true );
if ( ! isset( $order_details['availableCardBrands'] ) || empty( $order_details['availableCardBrands'] ) ) {
return '';
}
return implode( ',', array_map( 'strtolower', $order_details['availableCardBrands'] ) );
} catch ( Exception $e ) {
$this->log_error( 'get_available_card_brands: ' . $e->getMessage() );
}
}
}

View File

@@ -0,0 +1,63 @@
<?php
/**
* Logger trait
*
* Provides shared logic for logging errors
*
* @package WooCommerce
* @category Payment Gateways
* @author Revolut
* @since 2.0
*/
defined( 'ABSPATH' ) || exit();
if ( ! class_exists( 'WC_Logger' ) ) {
return;
}
/**
* WC_Revolut_Logger_Trait trait.
*/
trait WC_Revolut_Logger_Trait {
/**
* Logger status
*
* @var boolean
*/
protected $enable_logging = true;
/**
* Return error message
*
* @param String $message Log message.
*/
public function log_error( $message ) {
$logger = wc_get_logger();
$context = array( 'source' => 'revolut-gateway-for-woocommerce' );
if ( is_array( $message ) ) {
$message = wp_json_encode( $message );
}
$logger->error( $message, $context );
}
/**
* Return error message
*
* @param String $message Log message.
*/
public function log_info( $message ) {
$logger = wc_get_logger();
$context = array( 'source' => 'revolut-gateway-for-woocommerce' );
if ( is_array( $message ) ) {
$message = wp_json_encode( $message );
}
$logger->info( $message, $context );
}
}

View File

@@ -0,0 +1,63 @@
<?php
/**
* Settings trait
*
* Provides shared logic for navigation tab settings
*
* @package WooCommerce
* @category Payment Gateways
* @author Revolut
* @since 2.0
*/
defined( 'ABSPATH' ) || exit();
/**
* WC_Revolut_Settings_Trait trait.
*/
trait WC_Revolut_Settings_Trait {
/**
* Tab title
*
* @var string
*/
protected $tab_title;
/**
* API settings
*
* @var WC_Revolut_Settings_API
*/
protected $api_settings;
/**
* 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;
}
/**
* Display navigation for settings page
*/
public function output_settings_nav() {
if ( $this->check_is_get_data_submitted( 'page' ) && $this->check_is_get_data_submitted( 'section' ) ) {
$is_revolut_section = 'wc-settings' === $this->get_request_data( 'page' ) && in_array( $this->get_request_data( 'section' ), WC_REVOLUT_GATEWAYS, true ) || $this->get_request_data( 'section' ) === 'revolut_advanced_settings';
if ( $is_revolut_section ) {
include REVOLUT_PATH . 'templates/html-settings-nav.php';
}
}
}
/**
* Check API mode
*/
public function is_sandbox() {
return 'sandbox' === $this->get_option( 'mode' );
}
}

View File

@@ -0,0 +1,531 @@
# Copyright (C) 2022 Revolut
# This file is distributed under the same license as the Revolut Gateway for WooCommerce plugin.
msgid ""
msgstr ""
"Project-Id-Version: Revolut Gateway for WooCommerce 3.4.0\n"
"Report-Msgid-Bugs-To: https://wordpress.org/support/plugin/revolut-gateway-for-woocommerce\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: LANGUAGE <LL@li.org>\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"POT-Creation-Date: 2022-09-05T15:10:53+00:00\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"X-Generator: WP-CLI 2.5.0\n"
"X-Domain: revolut-gateway-for-woocommerce\n"
#. Plugin Name of the plugin
msgid "Revolut Gateway for WooCommerce"
msgstr ""
#. Plugin URI of the plugin
msgid "https://wordpress.org/plugins/revolut-gateway-for-woocommerce/"
msgstr ""
#. Description of the plugin
msgid "Accept card payments easily and securely via Revolut."
msgstr ""
#. Author of the plugin
#: includes/class-wc-revolut-privacy.php:24
msgid "Revolut"
msgstr ""
#. Author URI of the plugin
msgid "https://www.revolut.com/business/online-payments"
msgstr ""
#. translators: %s: Revolut Order ID.
#: api/class-revolut-webhook-controller.php:103
msgid "Payment has been successfully captured (Order ID: %s)"
msgstr ""
#: gateway-revolut.php:90
msgid "Settings"
msgstr ""
#: gateway-revolut.php:91
msgid "Support"
msgstr ""
#: gateway-revolut.php:92
msgid "Docs"
msgstr ""
#: includes/abstract/class-wc-payment-gateway-revolut.php:126
#: includes/gateways/class-wc-gateway-revolut-payment-request.php:157
msgid "Something went wrong while checking out. Payment was not taken. Please try again"
msgstr ""
#. translators: %s: Order Action.
#: includes/abstract/class-wc-payment-gateway-revolut.php:306
msgid "Customer will not be able to get a %s using this card!"
msgstr ""
#. translators:%1s: Order Action. %$2s: Order Action.
#: includes/abstract/class-wc-payment-gateway-revolut.php:310
msgid "Cannot %1$s Order - Error Id: %2$s."
msgstr ""
#. translators: %s: Revolut order id.
#: includes/abstract/class-wc-payment-gateway-revolut.php:602
#: includes/abstract/class-wc-payment-gateway-revolut.php:642
msgid "Can't retrieve payment amount for this order. Please check your Revolut Business account (Order ID: %s)"
msgstr ""
#: includes/abstract/class-wc-payment-gateway-revolut.php:1090
#: includes/settings/class-wc-revolut-settings-api.php:219
msgid "Revolut requires an API Key to work."
msgstr ""
#: includes/abstract/class-wc-payment-gateway-revolut.php:1121
msgid "Order amount can't be partially captured. Please try again or capture this payment from your Revolut Business web portal."
msgstr ""
#: includes/abstract/class-wc-payment-gateway-revolut.php:1130
msgid "Payment amount has been captured successfully."
msgstr ""
#: includes/abstract/class-wc-payment-gateway-revolut.php:1133
msgid "Order capture wasn't successful. Please try again or check your Revolut Business web portal for more information"
msgstr ""
#: includes/abstract/class-wc-payment-gateway-revolut.php:1185
msgid "Can't retrieve order information right now. Please try again later or process the refund via your Revolut Business account."
msgstr ""
#: includes/abstract/class-wc-payment-gateway-revolut.php:1190
msgid "The amount remaining for this order is less than the amount being refunded. Please check your Revolut Business account."
msgstr ""
#: includes/abstract/class-wc-payment-gateway-revolut.php:1196
msgid "Revolut: Can't refund this amount for this order. Please check your Revolut Business account."
msgstr ""
#. translators: %s: Revolut refund id.
#: includes/abstract/class-wc-payment-gateway-revolut.php:1211
msgid "Order has been successfully refunded (Refund ID: %s)."
msgstr ""
#: includes/abstract/class-wc-payment-gateway-revolut.php:1216
msgid "Revolut: This amount can't be refunded for this order. Please check your Revolut Business account."
msgstr ""
#: includes/abstract/class-wc-payment-gateway-revolut.php:1219
msgid "Revolut: Incomplete order can't be refunded"
msgstr ""
#: includes/class-wc-revolut-apple-pay-onboarding.php:260
msgid "Can not on-boarding Apple Pay merchant"
msgstr ""
#: includes/class-wc-revolut-apple-pay-onboarding.php:284
msgid "Apple Pay merchant on-boarded successfully"
msgstr ""
#: includes/class-wc-revolut-apple-pay-onboarding.php:337
msgid "Can not on-boarding Apple Pay merchant: Can not locate on-boarding file"
msgstr ""
#: includes/class-wc-revolut-apple-pay-onboarding.php:360
msgid "Can not remove on-boarding file"
msgstr ""
#: includes/class-wc-revolut-privacy.php:28
msgid "WooCommerce Revolut Order Data"
msgstr ""
#: includes/class-wc-revolut-privacy.php:37
msgid "WooCommerce Revolut Data"
msgstr ""
#. translators:%1s: %$2s:
#: includes/class-wc-revolut-privacy.php:78
msgid "By using this extension, you may be storing personal data or sharing data with an external service. %1$sLearn more about how this works, including what you may want to include in your privacy policy.%2$s"
msgstr ""
#: includes/class-wc-revolut-privacy.php:101
msgid "Orders"
msgstr ""
#: includes/class-wc-revolut-privacy.php:105
msgid "Revolut token"
msgstr ""
#: includes/class-wc-revolut-privacy.php:173
msgid "Revolut Order Data Erased."
msgstr ""
#: includes/gateways/class-wc-gateway-revolut-cc.php:23
msgid "Revolut Gateway - Credit/Debit Cards"
msgstr ""
#: includes/gateways/class-wc-gateway-revolut-cc.php:24
msgid "Credit/Debit Cards"
msgstr ""
#: includes/gateways/class-wc-gateway-revolut-cc.php:26
msgid "Pay with card"
msgstr ""
#. translators:%1s: %$2s:
#: includes/gateways/class-wc-gateway-revolut-cc.php:28
msgid "Accept card payments easily and securely via %1$sRevolut%2$s."
msgstr ""
#: includes/gateways/class-wc-gateway-revolut-cc.php:94
#: includes/gateways/class-wc-gateway-revolut-pay.php:84
#: includes/gateways/class-wc-gateway-revolut-payment-request.php:215
msgid "Enable/Disable"
msgstr ""
#: includes/gateways/class-wc-gateway-revolut-cc.php:95
#: includes/gateways/class-wc-gateway-revolut-pay.php:85
msgid "Enable "
msgstr ""
#: includes/gateways/class-wc-gateway-revolut-cc.php:97
#: includes/gateways/class-wc-gateway-revolut-pay.php:87
msgid "This controls whether or not this gateway is enabled within WooCommerce."
msgstr ""
#: includes/gateways/class-wc-gateway-revolut-cc.php:102
msgid "Title"
msgstr ""
#: includes/gateways/class-wc-gateway-revolut-cc.php:104
msgid "This controls the title that the user sees during checkout."
msgstr ""
#: includes/gateways/class-wc-gateway-revolut-cc.php:109
msgid "Save Cards"
msgstr ""
#: includes/gateways/class-wc-gateway-revolut-cc.php:110
msgid "Enable Payment with Saved Cards"
msgstr ""
#: includes/gateways/class-wc-gateway-revolut-cc.php:112
msgid "If enabled, users will be able to save their cards and use them to checkout in subsequent purchases. Card details are stored securely on Revolut servers"
msgstr ""
#: includes/gateways/class-wc-gateway-revolut-cc.php:117
msgid "Card widget style"
msgstr ""
#: includes/gateways/class-wc-gateway-revolut-cc.php:121
msgid "Customize card widget style"
msgstr ""
#: includes/gateways/class-wc-gateway-revolut-cc.php:122
msgid "Enable"
msgstr ""
#: includes/gateways/class-wc-gateway-revolut-cc.php:124
msgid "By enabling this option you can customize the style of the Revolut card widget"
msgstr ""
#: includes/gateways/class-wc-gateway-revolut-cc.php:130
msgid "Card widget background color"
msgstr ""
#: includes/gateways/class-wc-gateway-revolut-cc.php:132
msgid "This controls the background color of the Revolut card widget"
msgstr ""
#: includes/gateways/class-wc-gateway-revolut-cc.php:138
msgid "Card widget font color"
msgstr ""
#: includes/gateways/class-wc-gateway-revolut-cc.php:140
msgid "This controls the text color of the Revolut Card widget"
msgstr ""
#: includes/gateways/class-wc-gateway-revolut-cc.php:146
msgid "Revolut logo theme"
msgstr ""
#: includes/gateways/class-wc-gateway-revolut-cc.php:151
#: includes/gateways/class-wc-gateway-revolut-pay.php:99
#: includes/gateways/class-wc-gateway-revolut-payment-request.php:250
msgid "Dark"
msgstr ""
#: includes/gateways/class-wc-gateway-revolut-cc.php:152
#: includes/gateways/class-wc-gateway-revolut-pay.php:100
#: includes/gateways/class-wc-gateway-revolut-payment-request.php:251
msgid "Light"
msgstr ""
#: includes/gateways/class-wc-gateway-revolut-cc.php:154
msgid "This controls the color of the Revolut"
msgstr ""
#: includes/gateways/class-wc-gateway-revolut-cc.php:414
msgid "N/A"
msgstr ""
#. translators:%1s: Card type %$2s: Card last four digits
#: includes/gateways/class-wc-gateway-revolut-cc.php:419
msgid "Via %1$s card ending in %2$s"
msgstr ""
#: includes/gateways/class-wc-gateway-revolut-cc.php:588
msgid "Save payment information to my account for future purchases."
msgstr ""
#: includes/gateways/class-wc-gateway-revolut-cc.php:607
msgid "Update the Payment Method used for all of my active subscriptions."
msgstr ""
#: includes/gateways/class-wc-gateway-revolut-pay.php:24
msgid "Revolut Gateway - Revolut Pay"
msgstr ""
#: includes/gateways/class-wc-gateway-revolut-pay.php:25
msgid "Revolut Pay"
msgstr ""
#: includes/gateways/class-wc-gateway-revolut-pay.php:27
#: includes/gateways/class-wc-gateway-revolut-pay.php:31
msgid "Get Cashback"
msgstr ""
#. translators:%1s: %$2s:
#: includes/gateways/class-wc-gateway-revolut-pay.php:29
msgid "Accept payments easily and securely via %1$sRevolut%2$s."
msgstr ""
#: includes/gateways/class-wc-gateway-revolut-pay.php:92
msgid "Revolut Pay Button Theme"
msgstr ""
#: includes/gateways/class-wc-gateway-revolut-pay.php:93
#: includes/gateways/class-wc-gateway-revolut-payment-request.php:244
msgid "Button Theme"
msgstr ""
#: includes/gateways/class-wc-gateway-revolut-pay.php:95
#: includes/gateways/class-wc-gateway-revolut-payment-request.php:246
msgid "Select the button theme you would like to show."
msgstr ""
#: includes/gateways/class-wc-gateway-revolut-pay.php:101
#: includes/gateways/class-wc-gateway-revolut-payment-request.php:252
msgid "Light-Outline"
msgstr ""
#: includes/gateways/class-wc-gateway-revolut-pay.php:105
msgid "Revolut Pay Button Size"
msgstr ""
#: includes/gateways/class-wc-gateway-revolut-pay.php:106
#: includes/gateways/class-wc-gateway-revolut-payment-request.php:270
msgid "Button Size"
msgstr ""
#: includes/gateways/class-wc-gateway-revolut-pay.php:108
#: includes/gateways/class-wc-gateway-revolut-payment-request.php:272
msgid "Select the button size you would like to show."
msgstr ""
#: includes/gateways/class-wc-gateway-revolut-pay.php:112
#: includes/gateways/class-wc-gateway-revolut-pay.php:125
#: includes/gateways/class-wc-gateway-revolut-payment-request.php:265
#: includes/gateways/class-wc-gateway-revolut-payment-request.php:277
msgid "Large"
msgstr ""
#: includes/gateways/class-wc-gateway-revolut-pay.php:113
#: includes/gateways/class-wc-gateway-revolut-pay.php:124
#: includes/gateways/class-wc-gateway-revolut-payment-request.php:264
#: includes/gateways/class-wc-gateway-revolut-payment-request.php:276
msgid "Small"
msgstr ""
#: includes/gateways/class-wc-gateway-revolut-pay.php:117
msgid "Revolut Pay Button Radius"
msgstr ""
#: includes/gateways/class-wc-gateway-revolut-pay.php:118
#: includes/gateways/class-wc-gateway-revolut-payment-request.php:257
msgid "Button Radius"
msgstr ""
#: includes/gateways/class-wc-gateway-revolut-pay.php:120
#: includes/gateways/class-wc-gateway-revolut-payment-request.php:259
msgid "Select the button radius you would like to show."
msgstr ""
#: includes/gateways/class-wc-gateway-revolut-pay.php:126
#: includes/gateways/class-wc-gateway-revolut-payment-request.php:263
msgid "None"
msgstr ""
#: includes/gateways/class-wc-gateway-revolut-payment-request.php:42
#: includes/gateways/class-wc-gateway-revolut-payment-request.php:45
msgid "Apple Pay / Google Pay"
msgstr ""
#. translators:%1s: %$2s:
#: includes/gateways/class-wc-gateway-revolut-payment-request.php:44
msgid "Accept Apple and Google payments easily and securely via %1$sRevolut%2$s."
msgstr ""
#: includes/gateways/class-wc-gateway-revolut-payment-request.php:47
msgid "Digital Wallet (ApplePay/GooglePay)"
msgstr ""
#: includes/gateways/class-wc-gateway-revolut-payment-request.php:72
msgid "Something went wrong"
msgstr ""
#: includes/gateways/class-wc-gateway-revolut-payment-request.php:158
msgid "An error occurred while creating WooCommerce cart"
msgstr ""
#. translators:%1s: %$2s: %3$s: %4$s:
#: includes/gateways/class-wc-gateway-revolut-payment-request.php:218
msgid "Enable Payment Request Buttons. (Apple Pay/Google Pay) %1$sBy using Apple Pay, you agree with %2$sApple's%3$s terms of service. (Apple Pay domain verification is performed automatically in live mode.) %4$s"
msgstr ""
#: includes/gateways/class-wc-gateway-revolut-payment-request.php:222
msgid "Payment with Apple/Google Pay buttons wont be possible for guest users until Guest checkout is enabled"
msgstr ""
#: includes/gateways/class-wc-gateway-revolut-payment-request.php:225
msgid "If enabled, users will be able to pay using Apple Pay (Safari & iOS), Google Pay (Chrome & Android) or native W3C Payment Requests if supported by the browser."
msgstr ""
#: includes/gateways/class-wc-gateway-revolut-payment-request.php:230
msgid "Payment Request Button Action"
msgstr ""
#: includes/gateways/class-wc-gateway-revolut-payment-request.php:231
msgid "Button Action"
msgstr ""
#: includes/gateways/class-wc-gateway-revolut-payment-request.php:233
msgid "Select the button type you would like to show."
msgstr ""
#: includes/gateways/class-wc-gateway-revolut-payment-request.php:237
msgid "Buy"
msgstr ""
#: includes/gateways/class-wc-gateway-revolut-payment-request.php:238
msgid "Donate"
msgstr ""
#: includes/gateways/class-wc-gateway-revolut-payment-request.php:239
msgid "Pay"
msgstr ""
#: includes/gateways/class-wc-gateway-revolut-payment-request.php:243
msgid "Payment Request Button Theme"
msgstr ""
#: includes/gateways/class-wc-gateway-revolut-payment-request.php:256
msgid "Payment Request Button Radius"
msgstr ""
#: includes/gateways/class-wc-gateway-revolut-payment-request.php:269
msgid "Payment Request Button Size"
msgstr ""
#: includes/gateways/class-wc-gateway-revolut-payment-request.php:281
msgid "Payment Request Button Locations"
msgstr ""
#: includes/gateways/class-wc-gateway-revolut-payment-request.php:283
msgid "Select where you would like Payment Request Buttons to be displayed"
msgstr ""
#: includes/gateways/class-wc-gateway-revolut-payment-request.php:287
msgid "Product"
msgstr ""
#: includes/gateways/class-wc-gateway-revolut-payment-request.php:288
msgid "Cart"
msgstr ""
#: includes/gateways/class-wc-gateway-revolut-payment-request.php:292
msgid "Select pages"
msgstr ""
#: includes/gateways/class-wc-gateway-revolut-payment-request.php:299
msgid "Onboard shop domain for Apple Pay"
msgstr ""
#: includes/gateways/class-wc-gateway-revolut-payment-request.php:360
msgid "OR"
msgstr ""
#: includes/gateways/class-wc-gateway-revolut-payment-request.php:372
msgid "Empty cart"
msgstr ""
#: includes/settings/class-wc-revolut-settings-api.php:26
msgid "API Settings"
msgstr ""
#: includes/settings/class-wc-revolut-settings-api.php:58
msgid "Revolut Gateway - API Settings"
msgstr ""
#: includes/settings/class-wc-revolut-settings-api.php:61
msgid "Select Mode"
msgstr ""
#: includes/settings/class-wc-revolut-settings-api.php:62
msgid "Select mode between live mode and sandbox."
msgstr ""
#: includes/settings/class-wc-revolut-settings-api.php:67
msgid "Sandbox"
msgstr ""
#: includes/settings/class-wc-revolut-settings-api.php:68
msgid "Live"
msgstr ""
#: includes/settings/class-wc-revolut-settings-api.php:75
msgid "Sandbox API secret key from your Merchant settings on Revolut."
msgstr ""
#: includes/settings/class-wc-revolut-settings-api.php:91
msgid "Production API secret key"
msgstr ""
#: includes/settings/class-wc-revolut-settings-api.php:93
msgid "Production API secret key from your Merchant settings on Revolut."
msgstr ""
#: includes/settings/class-wc-revolut-settings-api.php:99
msgid "Payment Action"
msgstr ""
#: includes/settings/class-wc-revolut-settings-api.php:103
msgid "Authorize Only"
msgstr ""
#: includes/settings/class-wc-revolut-settings-api.php:104
msgid "Authorize and Capture"
msgstr ""
#: includes/settings/class-wc-revolut-settings-api.php:115
msgid "Automatically capture order in Revolut"
msgstr ""
#: includes/settings/class-wc-revolut-settings-api.php:117
msgid "Automatically try to capture orders when their status is changed to Processing or Completed."
msgstr ""
#. translators:%1s: %$2s:
#: includes/settings/class-wc-revolut-settings-api.php:241
msgid "Webhook setup unsuccessful. Please make sure you are using the correct %1$sAPI key%2$s. If the problem persists, please reach out to support via our in-app chat."
msgstr ""
#: includes/settings/class-wc-revolut-settings-api.php:245
msgid "Webhook url successfully configured"
msgstr ""

View File

@@ -0,0 +1,363 @@
=== Revolut Gateway for WooCommerce ===
Contributors: revolutbusiness
Tags: revolut, revolut business, revolut pay, payments, gateway, payment gateway, credit card, card
Requires at least: 4.4
Tested up to: 6.3
Stable tag: 4.9.5
Requires PHP: 7.0
License: GPLv2 or later
License URI: http://www.apache.org/licenses/LICENSE-2.0
Save on accepting payments with the Revolut Gateway for WooCommerce plugin for your store. With Revolut, you can accept card payments in up to 22 currencies, access your funds quickly with next-day settlement, and manage your business's money all in one place.
== Description ==
## What does this plugin do for you
### Features:
- Accept debit and credit card payments [at great rates](https://www.revolut.com/business/business-account-plans)
- Accept payments via Revolut Pay
- Customize the style of the card field in the checkout
- Customize the payment actions (Authorize only or Authorize and capture)
- Refund and capture payments directly from your WooCommerce admin section
- Support for [WooCommerce subscriptions](https://woocommerce.com/products/woocommerce-subscriptions/)
- Support for manual order creation
- Support for payments with Apple Pay and Google Pay
### Revolut Pay:
- Offer your customers a 1-click, easy checkout experience with Revolut Pay and enjoy your higher acceptance rates on top of lower transaction fees
- Take advantage of cashback rewards up to £/€20 for non-Revolut customers who checkout with you using Revolut Pay
- Get your money within 24 hours for Revolut Pay transactions
### Express checkout options:
- Offer a seamless checkout experience with Revolut Pay - Express checkout: automatically collect customers' shipping and delivery details and speed up the checkout process
- Accept payments via Apple Pay and Google Pay using the Revolut Gateway, let your customers pay without a hassle using their mobile wallets
### Great pricing:
- Pocket more of what you earn with low, competitive pricing for businesses of all sizes
- Get started with processing rates of 1% + £/€0.20 for local, consumer cards, and 2.8% + £/€0.20 for all other cards
- Never pay extra for different currencies, next-day settlement, or fraud monitoring
### Improved checkout conversion:
- Complete sales more quickly and increase conversions by enabling hassle-free Revolut Pay, which lets customers check out in just one click
- Earn profit more efficiently by increasing your payment authorisation rates via Revolut Pay compared to card payments
### Power your international commerce:
- Accept payments in up to 22 currencies via card and 29 currencies via Revolut Pay using dedicated currency accounts
- Hold and exchange 30+ currencies with no hidden fees
- Manage FX market risk by getting a fixed FX rate for future exchanges
### Settlement and security:
- Get your earnings deposited directly to your Revolut Business account with next-day settlement
- Reduce your risk of fraud by relying on Revolut's array of fraud monitoring tools that can flag early signs
- Our payments product is both encrypted and PCI DSS certified
## What your customers will like
Keeping your customers happy is huge, and offering them the simplest and smoothest customer payment experience helps you do just that. With our payment gateway, customers can:
- Pay in the currency of their choice
- Access cashback rewards when they sign up for and check out with Revolut Pay
- Experience streamlined checkout
- Checkout faster with Revolut Pay using their Revolut account
- Enjoy peace of mind with our secure payment processing
== Installation ==
To use the plugin you need to have a [Revolut Business account](https://business.revolut.com/signup "Sign up for a Business account") and an active [Merchant Account](https://business.revolut.com/merchant/ "Apply for a merchant account").
If you don't have a Revolut Business account:
- Sign up for a Business account and when asked the reason for opening the account make sure to select "Receive payments from customers" as one of the reasons
- Provide a description for your business and indicate a category that most closely defines your activities
- Provide the domain of your WooCommerce website when asked about website of your business
If you already have a Revolut Business account but your Merchant Account is not active:
- Go to the Home section in the Revolut Business web portal and select the [**Merchant tab**](https://business.revolut.com/merchant/)
- Click **Get started** and follow the steps to fill in the information of your business
- When prompted, provide the domain of your WooCommerce website
That's it! As soon as you install the Revolut Gateway for WooCommerce plugin you will be ready to start accepting payments. If you want to know more about the advantages of accepting payments via Revolut, you can take a look in [our website](https://www.revolut.com/business/online-payments).
To start accepting payments from your customers at great rates, install the plugin by following [this tutorial](https://developer.revolut.com/docs/guides/accept-payments/plugins/woocommerce/installation). After successful installation, configure the plugin, following [this tutorial](https://developer.revolut.com/docs/guides/accept-payments/plugins/woocommerce/configuration).
== Screenshots ==
1. Searching for the Revolut Gateway for WooCommerce plugin
2. The Revolut Gateway plugin has been added to your Wordpress plugins
3. The general Revolut API settings page for the Revolut Gateway for WooCommerce plugin
4. The Credit card payment settings
5. The Revolut Pay Button settings
== Changelog ==
= 4.9.5 =
* Fixed creating customer objects
= 4.9.4 =
* Fixed file system compatibility issue
* Fixed Apple Pay country code issue
= 4.9.3 =
* Fixed location registration issue
= 4.9.2 =
* Updated payment gateway logos
* Fixed payment request button issue
* Fixed changing subscription payment method issue
= 4.9.1 =
* Fixed subscription renewal issue
* Improved registering address validation endpoint for Fast checkout
= 4.9.0 =
* Improved Revolut Pay mobile redirects
* Fixed saving customer ids
= 4.8.0 =
* Updated promotional banners
= 4.7.1 =
* Added Cardholder Name input for card gateway
= 4.7.0 =
* Updated plugin description
= 4.6.0 =
* Updated payment method logos
= 4.5.0 =
* Added auto cancel feature for express checkout orders
* Fixed widget initialization issue at payment method add page
* Fixed validation issue at order pay page
= 4.4.0 =
* Fixed tax issue for express checkout shipping methods
* Fixed checkout validation for payment request buttons
* Added clear button for clearing unused information
* Added title configuration for payment request buttons
= 4.3.0 =
* Enabled Apple Pay and Google Pay payment options in checkout page
* Fixed express checkout issue for mobile browsers
* Fixed subscriptions issue
= 4.2.0 =
* Added order state selection for manual capture payments
* Fixed registering webhooks
= 4.1.0 =
* Added Popup card widget
* Fixed product page issue
= 4.0.2 =
* Adjusted minimum PHP version requirement
= 4.0.1 =
* Fixed warnings from lower version of PHP
* Increased recommended version of PHP
= 4.0.0 =
* Fast checkout full launch
= 3.9.0 =
* Fixed express checkout caching
* Fixed admin notifications
= 3.8.0 =
* Added Revolut Pay Express checkout functionality
= 3.7.0 =
* Improved webhook processing
* Updated cashback currency
= 3.6.0 =
* Updated currency list
* Fixed order validation result parsing issue
= 3.5.0 =
* Improved order result processing
* Added compatibility with review plugin
= 3.4.0 =
* Fixed parse notice
= 3.3.0 =
* Fixed subscriptions issue
= 3.2.2 =
* Added payment logos for Revolut Pay method
= 3.2.1 =
* Fixed partial refund issue
* Fixed cart clearing issue
* Fixed order creation issue when card field is empty
= 3.2.0 =
* Added the new version of Revolut Pay widget
= 3.1.6 =
* Fixing compatibility issue with PHP versions
= 3.1.5 =
* Fix minor payment button reloading issue
= 3.1.4 =
* Fixing compatibility issue with the older PHP versions
= 3.1.3 =
* Refactor to adhere to WordPress conventions
* Security updates
= 3.1.2 =
* Fixing security and vulnerability issues
= 3.1.1 =
* Added compatibility for Germanized plugin
* Added size configuration options for Payment Buttons (ApplePay&GooglePay)
= 3.1.0 =
* Added feature to trigger Apple Pay setup manually
* Added feature to set Webhooks automatically
* Fixed duplicated OR labels for payment buttons
= 3.0.2 =
* Fix minor issue ajax endpoint url
= 3.0.1 =
* Fix Pay Button minor issue for out of stock products
= 3.0.0 =
* Payment Request Button (ApplePay&GooglePay) support added
= 2.5.2 =
* Fix minor issue for payment amount validation
= 2.5.1 =
* Fix saved payment methods issue after customer login
= 2.5.0 =
* Avoid duplicated payments when customer account settings is enabled
= 2.4.2 =
* Fix duplicated order status update
* Validate saved payment tokens through API
= 2.4.1 =
* Fix refund issue
* Fix webhook callback order not found issue
= 2.4.0 =
* Refresh checkout page without reloading
* Update payment amount after order creation
* Fix card widget reloading when save card checkbox is updating
* Add configuration in order enable/disable card save feature
= 2.3.3 =
* Fix order process error when create customer checkbox is enabled
* Fix setting webhook issue
= 2.3.2 =
* Minor issues refactored
* Missing dependency issue solved
= 2.3.1 =
* Fixed duplicated order issue
* Tested with the latest WordPress and WooCommerce versions
= 2.3.0 =
* Optimize checkout validation
= 2.2.9 =
* Fix manual order page stack in loading issue
* Fix API callback issue
* Localization files added
* Information about failed Payment attempts added into the order
= 2.2.8 =
* Update available Revolut order currency list
* Update documentation link
= 2.2.7 =
* Fix duplicated API order creation
= 2.2.6 =
* Fix missing parameter issue
= 2.2.5 =
* Improve Revolut Widget error reporting
= 2.2.4 =
* Fix payment process error when some checkout address fields are missing
= 2.2.3 =
* Fix checkout validation issue
= 2.2.2 =
* Minor bug fixes
= 2.2.1 =
* Hotfix for version 2.2.0 for sites that did not have the WooCommerce subscriptions plugin
= 2.2.0 =
* Support for [WooCommerce subscriptions](https://woocommerce.com/products/woocommerce-subscriptions/)
* Support saving card information
= 2.1.0 =
* Support Multisite Wordpress installations
* Support Card Widget styling
* Support manual payments
* Support for multilanguage sites. The text inside of the Card widget will now adapt to the language of the website.
= 2.0.0 =
* Added Revolut Pay
= 1.2.5 =
* Create Woocommerce Order even if transaction failed
* Adjust create order flow
* Allow customer to update payment information at checkout
* Create Woocommerce order before verifying Revolut payment
* Handle webhook responses for different Woo order statuses
* Handle webhook received after payment
= 1.2.4 =
* Compatible with Jupiter theme
= 1.2.3 =
* Added support for refunding orders from the WooCommerce Order view
* Added support to capture orders by changing the status of the order in the WooCommerce order view
* Added webhook support. You can now setup webhooks from the plugin settings. Orders captured in the Revolut Business web portal will change the status of the WooCommerce order
* Fixed bug for mySQL versions older than 5.6.5 where "Something went wrong" was displayed instead of the card field
* Fixed code that was causing PHP notices and warnings to appear in the logs
* Fixed wording of multiple messages to improve clarity
= 1.2.1 =
* Fixed bug that created failed orders even if payment had been captured
* Added instructions in the settings page to get started quickly and easily
= 1.2.0 =
* Added support for "Authorize Only" order types
* Added option to easily switch between "Sandbox" and "Live" environments by keeping the keys saved
* Improved the Checkout widget visually to be compatible with more themes
* Fixed bug that created uncaptured transactions if the checkout form was not properly filled out by the user
= 1.1.5 =
* Minor bug fixes
= 1.0.1 =
* Fixing some compatibility issues with certain WooCommerce themes
= 1.0 =
* First stable version of the Revolut Gateway for WooCommerce plugin
== Upgrade Notice ==
= 1.0 =
* First stable version of the Revolut Gateway for WooCommerce plugin

View File

@@ -0,0 +1,35 @@
<?php
/**
* Settings navigation template.
*
* @package WooCommerce
* @category Payment Gateways
* @author Revolut
* @since 1.0.0
*/
global $current_section;
$revolut_configuration_tabs = apply_filters( 'wc_revolut_settings_nav_tabs', array() );
$last = count( $revolut_configuration_tabs );
$idx = 0;
$tab_active = false;
?>
<div class="wc-revolut-settings-logo">
<img style="height:50px;margin-bottom: 15px;margin-left:15px" src="<?php echo esc_url( WC_REVOLUT_PLUGIN_URL . '/assets/images/revolut_business_logo.png' ); ?>"/>
</div>
<div class="revolut-settings-nav">
<?php
foreach ( $revolut_configuration_tabs as $tab_id => $rev_tab ) :
$idx ++;
?>
<a class="nav-tab
<?php
if ( $current_section === $tab_id || ( ! $tab_active && $last === $idx ) ) {
echo 'nav-tab-active';
$tab_active = true;
}
?>
" href="<?php echo esc_url( admin_url( 'admin.php?page=wc-settings&tab=checkout&section=' . $tab_id ) ); ?>"><?php echo esc_attr( $rev_tab ); ?></a>
<?php endforeach; ?>
</div>
<div class="clear"></div>