Plugin Directory

Changeset 2884147


Ignore:
Timestamp:
03/21/2023 09:56:35 AM (3 years ago)
Author:
best2pay
Message:

v2.0 added reverse, complete

Location:
best2pay-payment-method-visamastercard
Files:
2 edited

Legend:

Unmodified
Added
Removed
  • best2pay-payment-method-visamastercard/best2pay-payment_method.php

    r2841630 r2884147  
    11<?php
    2 /* 
    3     This program is free software; you can redistribute it and/or modify
    4     it under the terms of the GNU General Public License, version 2, as
    5     published by the Free Software Foundation.
    6 
    7     This program is distributed in the hope that it will be useful,
    8     but WITHOUT ANY WARRANTY; without even the implied warranty of
    9     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    10     GNU General Public License for more details.
    11 
    12     You should have received a copy of the GNU General Public License
    13     along with this program; if not, write to the Free Software
    14     Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
     2declare(strict_types=1);
     3
     4
     5/*
     6        This program is free software; you can redistribute it and/or modify
     7        it under the terms of the GNU General Public License, version 2, as
     8        published by the Free Software Foundation.
     9
     10        This program is distributed in the hope that it will be useful,
     11        but WITHOUT ANY WARRANTY; without even the implied warranty of
     12        MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
     13        GNU General Public License for more details.
     14
     15        You should have received a copy of the GNU General Public License
     16        along with this program; if not, write to the Free Software
     17        Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
    1518*/
    1619/**
     
    2831 */
    2932
     33
    3034defined('ABSPATH') or die("No script kiddies please!");
    3135
    3236if (false) {
    33     __('Best2Pay payment method (Visa/MasterCard)');
    34     __('Receive payments via Visa/Mastercard easily with Best2Pay bank cards processing');
     37    __('Best2Pay payment method (Visa/MasterCard)');
     38    __('Receive payments via Visa/Mastercard easily with Best2Pay bank cards processing');
    3539}
    3640
     
    3943function init_woocommerce_best2pay()
    4044{
    41     if (!class_exists('WC_Payment_Gateway')) {
    42         return;
    43     }
    44 
    45     load_plugin_textdomain('best2pay-payment_method', false, dirname(plugin_basename(__FILE__)) . '/languages');
    46 
    47     class woocommerce_best2pay extends WC_Payment_Gateway
    48     {
    49 
    50         public function __construct()
    51         {
    52             $this->id = 'best2pay';
    53             $this->method_title = __('Best2Pay', 'best2pay-payment_method');
    54             $this->title = __('Оплата банковской картой', 'best2pay-payment_method');
    55             $this->description = __("через платежную систему <a href=\"http://www.best2pay.net\" target=\"_blank\">Best2Pay</a>", 'best2pay-payment_method');
    56             $this->icon = plugins_url('best2pay.png', __FILE__);
    57             $this->has_fields = true;
    58             $this->notify_url = add_query_arg('wc-api', 'best2pay_notify', home_url('/'));
    59             $this->callback_url = add_query_arg('wc-api', 'best2pay', home_url('/'));
    60 
    61             $this->init_form_fields();
    62             $this->init_settings();
    63 
    64             // variables
    65             $this->sector = $this->settings['sector'];
    66             $this->password = $this->settings['password'];
    67             $this->testmode = $this->settings['testmode'];
    68             $this->twostepsmode = $this->settings['twostepsmode'];
    69             // $this->halvaparts = $this->settings['halvaparts'];
    70             $this->mode = $this->settings['mode'];
    71             switch ($this->mode) {
    72                 case 1:
    73                     $this->title = 'Оплатить заказ Частями';
    74                     $this->icon = plugins_url('halva.svg', __FILE__);
    75                     $this->description = '<iframe style="width:100%;height:180px;border:none;" src="'.plugins_url('halva_widget.php', __FILE__).'?amount='.print_r(WC()->cart->cart_contents_total, true).'"></iframe>';
    76                     break;
    77                 case 2:
    78                     $this->title = 'Оплатить по QR';
    79                     $this->icon = null;
    80                     break;
    81             }
    82             // actions
    83             add_action('init', array($this, 'successful_request'));
    84             add_action('woocommerce_api_best2pay', array($this, 'callback_from_gateway'));
    85             add_action('woocommerce_api_best2pay_notify', array($this, 'notify_from_gateway'));
    86             add_action('woocommerce_update_options_payment_gateways_' . $this->id, array($this, 'process_admin_options'));
    87         }
    88 
    89         /**
    90          * Admin Panel Options
    91          **/
    92         public function admin_options()
    93         {
    94             ?>
    95             <h3><?php _e('Best2Pay', 'best2pay-payment_method'); ?></h3>
    96             <p><?php _e("Payments with bank cards via the <a href=\"http://www.best2pay.net\" target=\"_blank\">Best2Pay</a> payment system.", 'best2pay-payment_method'); ?></p>
    97             <table class="form-table">
    98                 <?php
    99                 // Generate the HTML For the settings form.
    100                 $this->generate_settings_html();
    101                 ?>
    102             </table><!--/.form-table-->
    103             <?php
    104         }
    105 
    106         /**
    107          * Initialise Gateway Settings Form Fields
    108          */
    109         public function init_form_fields()
    110         {
    111 
    112             //  array to generate admin form
    113             $this->form_fields = array(
    114                 'enabled' => array(
    115                     'title' => __('Enable/Disable', 'best2pay-payment_method'),
    116                     'type' => 'checkbox',
    117                     'label' => __('Enable Best2Pay checkout method', 'best2pay-payment_method'),
    118                     'default' => 'yes'
    119                 ),
    120 
    121                 'sector' => array(
    122                     'title' => __('Sector ID', 'best2pay-payment_method'),
    123                     'type' => 'text',
    124                     'description' => __('Your shop identifier at Best2Pay', 'best2pay-payment_method'),
    125                     'default' => 'test'
    126                 ),
    127 
    128                 'password' => array(
    129                     'title' => __('Password', 'best2pay-payment_method'),
    130                     'type' => 'text',
    131                     'description' => __('Password to use for digital signature', 'best2pay-payment_method'),
    132                     'default' => 'test'
    133                 ),
    134 
    135                 'testmode' => array(
    136                     'title' => __('Test Mode', 'best2pay-payment_method'),
    137                     'type' => 'select',
    138                     'options' => array(
    139                         '1' => __('Test mode - real payments will not be processed', 'best2pay-payment_method'),
    140                         '0' => __('Production mode - payments will be processed', 'best2pay-payment_method')
    141                     ),
    142                     'description' => __('Select test or live mode', 'best2pay-payment_method')
    143                 ),
    144                 /*'mode' => array(
    145                     'title' => __('Payment mode', 'best2pay-payment_method'),
    146                     'type' => 'select',
    147                     'options' => array(
    148                         '0' => __('Standard acquiring', 'best2pay-payment_method'),
    149                         '1' => __('Just installment', 'best2pay-payment_method'),
    150                         '2' => __('Just purchase by QR', 'best2pay-payment_method')
    151                     ),
    152                     'description' => __('Select payment mode', 'best2pay-payment_method'),
    153                 ),*/
    154                 'mode' => array(
    155                     'title' => __('Режим оплаты', 'best2pay-payment_method'),
    156                     'type' => 'select',
    157                     'options' => array(
    158                         '0' => __('Стандартный эквайринг', 'best2pay-payment_method'),
    159                         '1' => __('Только Халва.Частями', 'best2pay-payment_method'),
    160                         '2' => __('Только СБП', 'best2pay-payment_method')
    161                     ),
    162                     'description' => __('Выберите режим оплаты', 'best2pay-payment_method'),
    163                 ),
    164                 'twostepsmode' => array(
    165                     'title' => __('2 steps payment mode', 'best2pay-payment_method'),
    166                     'type' => 'select',
    167                     'options' => array(
    168                         '1' => __('On', 'best2pay-payment_method'),
    169                         '0' => __('Off', 'best2pay-payment_method')
    170                     ),
    171                     'description' => __('Turn on 2 steps mode', 'best2pay-payment_method')
    172                 ),
    173                 /*'deferred' => array(
    174                     'title' => __('Deferred payment', 'best2pay-payment_method'),
    175                     'type' => 'select',
    176                     'options' => array(
    177                         '1' => __('On', 'best2pay-payment_method'),
    178                         '0' => __('Off', 'best2pay-payment_method')
    179                     ),
    180                     'description' => __('Making of an email message with a link to payment (payment is not carried out)', 'best2pay-payment_method')
    181                 )*/
    182             );
    183 
    184         }
    185 
    186         /**
    187          * Register order @ Best2Pay and redirect user to payment form
    188          **/
    189         public function process_payment($order_id)
    190         {
    191             $order = new WC_Order($order_id);
    192             switch ($order->get_currency()) {
    193                 case 'EUR':
    194                     $currency = '978';
    195                     break;
    196                 case 'USD':
    197                     $currency = '840';
    198                     break;
    199                 default:
    200                     $currency = '643';
    201                     break;
    202             }
    203 
    204             $best2pay_url = "https://test.best2pay.net";
    205             if ($this->testmode == "0")
    206                 $best2pay_url = "https://pay.best2pay.net";
    207 
    208             switch (intval($this->mode)) {
    209                 case 1:
    210                     $best2pay_operation = 'custom/svkb/PurchaseWithInstallment';
    211                     break;
    212                 case 2:
    213                     $best2pay_operation = 'PurchaseSBP';
    214                     break;
    215                 default:
    216                     $best2pay_operation = "Purchase";
    217                     if ($this->twostepsmode == "1")
    218                         $best2pay_operation = "Authorize";
    219             }
    220 
    221             $signature = base64_encode(md5($this->sector . intval($order->get_total() * 100) . $currency . $this->password));
    222 
    223             $wc_order = wc_get_order($order_id);
    224             $items = $wc_order->get_items();
    225             $fiscalPositions = '';
    226             $fiscalAmount = 0;
    227 
    228             foreach ($items as $item_id => $item) {
    229                 $item_data = $item->get_data();
    230                 $fiscalPositions .= $item_data['quantity'] . ';';
    231                 $elementPrice = $item->get_product()->get_price() * 100;
    232                 $fiscalPositions .= $elementPrice . ';';
    233                 $fiscalPositions .= ($item_data['total_tax']) ?: 6 . ';';   // tax
    234                 $fiscalPositions .= str_ireplace([';', '|'], '', $item_data['name']) . '|';
    235 
    236                 $fiscalAmount += $item_data['quantity'] * $elementPrice;
    237             }
    238             if ($wc_order->get_shipping_total()) {
    239                 $fiscalPositions .= '1;' . $wc_order->get_shipping_total() * 100 . ';6;Доставка|';
    240                 $fiscalAmount += $wc_order->get_shipping_total() * 100;
    241             }
    242             $fiscalDiff = abs($fiscalAmount - intval($order->get_total() * 100));
    243             if ($fiscalDiff) {
    244                 $fiscalPositions .= '1;' . $fiscalDiff . ';6;Скидка;14|';
    245             }
    246             $fiscalPositions = substr($fiscalPositions, 0, -1);
    247 
    248             $args = array(
    249                 'body' => array(
    250                     'sector' => $this->sector,
    251                     'reference' => $order->get_id(),
    252                     'amount' => intval($order->get_total() * 100),
    253                     'fiscal_positions' => $fiscalPositions,
    254                     'description' => sprintf(__('Order #%s', 'best2pay-payment_method'), ltrim($order->get_order_number(), '#')),
    255                     'email' => $order->get_billing_email(),
    256                     // 'notify_customer' => ($this->deferred) ? 1 : 0,
    257                     'currency' => $currency,
    258                     'mode' => 1,
    259                     'url' => $this->callback_url,
    260                     'signature' => $signature
    261                 )
    262             );
    263 
    264             $remote_post = wp_remote_post($best2pay_url . '/webapi/Register', $args);
    265             $remote_post = (isset($remote_post['body'])) ? $remote_post['body'] : $remote_post;
    266             $b2p_order_id = ($remote_post) ? $remote_post : null;
    267 
    268             if (intval($b2p_order_id) == 0) {
    269                 $request_body = $args['body'];
    270                 $request_body['email'] = ($request_body['email']) ? 'isset' : 'isnotset';
    271                 $request_body['signature'] = ($request_body['signature']) ? 'isset' : 'isnotset';
    272                 $this->logIt('Не удалось зарегистрировать заказ', array('b2p_order_id' => $b2p_order_id, 'request_body' => $request_body));
    273                 return false;
    274             }
    275 
    276             $signature = base64_encode(md5($this->sector . $b2p_order_id . $this->password));
    277 
    278             $order->update_status('on-hold');
    279 
    280             /*if ($this->deferred) {
    281                 wp_redirect($this->get_return_url($wc_order));
    282                 exit();
    283             }*/
    284 
    285             return array(
    286                 'result' => 'success',
    287                 'redirect' => "{$best2pay_url}/webapi/{$best2pay_operation}?sector={$this->sector}&id={$b2p_order_id}&signature={$signature}"
    288             );
    289         }
    290 
    291         /**
    292          * Callback from payment gateway was received
    293          **/
    294         public function callback_from_gateway()
    295         {
    296             // check payment status
    297             $b2p_order_id = intval($_REQUEST["id"]);
    298             if (!$b2p_order_id)
    299                 return false;
    300 
    301             $b2p_operation_id = intval($_REQUEST["operation"]);
    302             if (!$b2p_operation_id) {
    303                 $order_id = intval($_REQUEST["reference"]);
    304                 $order = wc_get_order($order_id);
    305                 if ($order)
    306                     $order->cancel_order(__("The order wasn't paid.", 'best2pay-payment_method'));
    307 
    308                 wc_add_notice(__("The order wasn't paid.", 'best2pay-payment_method'), 'error');
    309                 $get_checkout_url = apply_filters('woocommerce_get_checkout_url', WC()->cart->get_checkout_url());
    310                 wp_redirect($get_checkout_url);
    311                 exit();
    312             }
    313 
    314             // check payment operation state
    315             $signature = base64_encode(md5($this->sector . $b2p_order_id . $b2p_operation_id . $this->password));
    316 
    317             $best2pay_url = "https://test.best2pay.net";
    318             if ($this->testmode == "0")
    319                 $best2pay_url = "https://pay.best2pay.net";
    320 
    321             $context = stream_context_create(array(
    322                 'http' => array(
    323                     'header' => "Content-type: application/x-www-form-urlencoded\r\n",
    324                     'method' => 'POST',
    325                     'content' => http_build_query(array(
    326                         'sector' => $this->sector,
    327                         'id' => $b2p_order_id,
    328                         'operation' => $b2p_operation_id,
    329                         'signature' => $signature
    330                     )),
    331                 )
    332             ));
    333 
    334             $repeat = 3;
    335 
    336             while ($repeat) {
    337 
    338                 $repeat--;
    339 
    340                 // pause because of possible background processing in the Best2Pay
    341                 sleep(2);
    342                 $args = array(
    343                     'body' => array(
    344                         'sector' => $this->sector,
    345                         'id' => $b2p_order_id,
    346                         'operation' => $b2p_operation_id,
    347                         'signature' => $signature
    348                     )
    349                 );
    350                 $xml = wp_remote_post($best2pay_url . '/webapi/Operation', $args)['body'];
    351 
    352                 if (!$xml)
    353                     break;
    354                 $xml = simplexml_load_string($xml);
    355                 if (!$xml)
    356                     break;
    357                 $response = json_decode(json_encode($xml));
    358                 if (!$response)
    359                     break;
    360                 if (!$this->orderAsPayed($response))
    361                     continue;
    362 
    363                 wp_redirect($this->get_return_url(wc_get_order($response->reference)));
    364                 exit();
    365 
    366             }
    367 
    368             $order_id = intval($response->reference);
    369             $order = wc_get_order($order_id);
    370             if ($order)
    371                 $order->cancel_order(__("The order wasn't paid [1]: " . $response->message . '.', 'best2pay-payment_method'));
    372 
    373             wc_add_notice(__("The order wasn't paid [1]: ", 'best2pay-payment_method') . $response->message . '.', 'error');
    374             $get_checkout_url = apply_filters('woocommerce_get_checkout_url', WC()->cart->get_checkout_url());
    375             wp_redirect($get_checkout_url);
    376             exit();
    377 
    378         }
    379 
    380         /**
    381          * Payment notify from gateway was received
    382          **/
    383         public function notify_from_gateway()
    384         {
    385             global $wp_filesystem;
    386             if (empty($wp_filesystem)) {
    387                 require_once(ABSPATH . '/wp-admin/includes/file.php');
    388                 WP_Filesystem();
    389             }
    390 
    391             // $xml = file_get_contents("php://input");
    392             $xml = $wp_filesystem->get_contents('php://input');
    393             if (!$xml)
    394                 return false;
    395             $xml = simplexml_load_string($xml);
    396             if (!$xml)
    397                 return false;
    398             $response = json_decode(json_encode($xml));
    399             if (!$response)
    400                 return false;
    401 
    402             if (!$this->orderAsPayed($response)) {
    403                 $order_id = intval($response->reference);
    404                 $order = wc_get_order($order_id);
    405                 if ($order)
    406                     $order->cancel_order(__("The order wasn't paid [2]: ", 'best2pay-payment_method') . $response->message . '.');
    407                 exit();
    408             }
    409 
    410             die("ok");
    411 
    412         }
    413 
    414         private function orderAsPayed($response)
    415         {
    416             // looking for an order
    417             $order_id = intval($response->reference);
    418             if ($order_id == 0)
    419                 return false;
    420 
    421             $order = wc_get_order($order_id);
    422             if (!$order)
    423                 return false;
    424 
    425             // check payment state
    426             if (($response->type != 'PURCHASE_BY_QR' && $response->type != 'PURCHASE' && $response->type != 'EPAYMENT' && $response->type != 'AUTHORIZE') || $response->state != 'APPROVED')
    427                 return false;
    428 
    429             if ($order->get_date_paid())
    430                 exit();
    431 
    432             // check server signature
    433             $tmp_response = json_decode(json_encode($response), true);
    434             unset($tmp_response["signature"]);
    435             unset($tmp_response["ofd_state"]);
    436             unset($tmp_response["protocol_message"]);
    437 
    438             $signature = base64_encode(md5(implode('', $tmp_response) . $this->password));
    439 
    440             if ($signature !== $response->signature) {
    441                 $order->update_status('fail', $response->message);
    442                 return false;
    443             }
    444 
    445             $order->add_order_note(__('Payment completed.', 'best2pay-payment_method'));
    446             $order->payment_complete();
    447 
    448             // echo '<pre>' . print_r($tmp_response, true) . '<br>' . $signature . '<br>' . print_r($response, true); die();
    449 
    450             /*
    451              * сохраним в мета заказа выбранный на момент оплаты режим (1 или 2 стадии)
    452              */
    453             $b2p_mode = ($this->settings['twostepsmode']) ? 2 : 1;
    454             update_post_meta($order_id, 'b2p_payment_mode', $b2p_mode);
    455 
    456             return true;
    457 
    458         }
    459 
    460 
    461         /**
    462          * @param string $message
    463          * @param array $details
    464          */
    465         public function logIt(string $message, array $details = [])
    466         {
    467             $log = fopen($this->getLogFileName(), 'a+') or die("logging trouble");
    468             $date = date("d.m.y H:i:s");
    469             $msg = $date . "\t" . $message;
    470             if ($details) {
    471                 $msg .= "\n" . print_r($details, true);
    472             }
    473             $msg .= "\n\n\n";
    474             fprintf($log, chr(0xEF) . chr(0xBB) . chr(0xBF));
    475             fwrite($log, $msg);
    476             fclose($log);
    477         }
    478 
    479         public function getLogFileName()
    480         {
    481             $signature = base64_encode($this->sector . $this->password . $_SERVER['HTTP_HOST']);
    482             $signature = str_ireplace('=', '', $signature);
    483             return 'b2p_log_' . $signature . '.txt';
    484         }
    485 
    486 
    487     } // class
    488 
    489     function add_best2pay_gateway($methods)
    490     {
    491         $methods[] = 'woocommerce_best2pay';
    492         return $methods;
    493     }
    494 
    495     add_filter('woocommerce_payment_gateways', 'add_best2pay_gateway');
     45    if (!class_exists('WC_Payment_Gateway')) {
     46        return;
     47    }
     48   
     49    load_plugin_textdomain('best2pay-payment_method', false, dirname(plugin_basename(__FILE__)) . '/languages');
     50   
     51    class woocommerce_best2pay extends WC_Payment_Gateway
     52    {
     53        protected array $pay_states = ['PURCHASE', 'PURCHASE_BY_QR', 'AUTHORIZE', 'COMPLETE'];
     54        protected array $cancel_types = ['REVERSE'];
     55        public function __construct()
     56        {
     57            $this->id = 'best2pay';
     58            $this->method_title = __('Best2Pay', 'best2pay-payment_method');
     59            $this->title = __('Оплата банковской картой', 'best2pay-payment_method');
     60            $this->description = __("через платежную систему <a href=\"http://www.best2pay.net\" target=\"_blank\">Best2Pay</a>", 'best2pay-payment_method');
     61            $this->icon = plugins_url('best2pay.png', __FILE__);
     62            $this->has_fields = true;
     63            $this->notify_url = add_query_arg('wc-api', 'best2pay_notify', home_url('/'));
     64            $this->callback_url = add_query_arg('wc-api', 'best2pay', home_url('/'));
     65           
     66            $this->supports = array('refunds', 'products');
     67           
     68            $this->init_form_fields();
     69            $this->init_settings();
     70           
     71            // variables
     72            $this->sector = $this->settings['sector'];
     73            $this->password = $this->settings['password'];
     74            $this->testmode = $this->settings['testmode'];
     75            $this->twostepsmode = $this->settings['twostepsmode'];
     76           
     77            //statuses
     78            $this->status_completed = $this->settings['custom_successfully_paid'];
     79            $this->status_registered = $this->settings['custom_registered'];
     80            $this->status_authorized = $this->settings['custom_authorized'];
     81            $this->status_cancelled = $this->settings['custom_cancelled'];
     82           
     83            $this->mode = $this->settings['mode'];
     84            switch ($this->mode) {
     85                case 1:
     86                    $this->title = 'Оплатить заказ Частями';
     87                    $this->icon = plugins_url('halva.svg', __FILE__);
     88                    $this->description = '<iframe style="width:100%;height:180px;border:none;" src="'.plugins_url('halva_widget.php', __FILE__).'?amount='.print_r(WC()->cart->cart_contents_total, true).'"></iframe>';
     89                    break;
     90                case 2:
     91                    $this->title = 'Оплатить по QR';
     92                    $this->icon = null;
     93                    break;
     94            }
     95            // actions
     96            add_action('init', array($this, 'successful_request'));
     97            add_action('woocommerce_api_best2pay', array($this, 'callback_from_gateway'));
     98            add_action('woocommerce_api_best2pay_notify', array($this, 'notify_from_gateway'));
     99            add_action('woocommerce_api_best2pay_complete', array($this, 'best2pay_make_complete'));
     100            add_action('woocommerce_update_options_payment_gateways_' . $this->id, array($this, 'process_admin_options'));
     101            add_action('woocommerce_order_item_add_action_buttons', array($this, 'wc_order_item_add_complete_button'), 10, 1);
     102        }
     103       
     104        function wc_order_item_add_complete_button($order)
     105        {
     106            $label = esc_html__('Complete', 'woocommerce');
     107            $slug = 'custom';
     108            $custom_status = $this->status_authorized;
     109            $nonce_complete = wp_create_nonce('best2pay_complete' . $order->get_id());
     110            if($order->get_payment_method() == 'best2pay'){
     111                if('wc-' . $order->get_status() == $custom_status){
     112                    ?>
     113                    <script src="<?php echo plugins_url('js/scripts.js', plugin_basename(__FILE__)); ?>"></script>
     114                    <input type="hidden" id="nonce_best2pay_complete" value="<?php echo $nonce_complete; ?>">
     115                    <button type="button" id="button_best2pay_complete"
     116                            class="button <?php echo $slug; ?>-items"><?php echo $label; ?></button>
     117                    <?php
     118                }
     119            }
     120        }
     121       
     122        public function best2pay_make_complete()
     123        {
     124            $nonce_complete = $_REQUEST['best2pay_nonce_value'];
     125            $order_id = $_REQUEST['order_id'];
     126            if(wp_verify_nonce($nonce_complete, 'best2pay_complete' . $order_id)){
     127                $order = wc_get_order($order_id);
     128                $b2p_order_id = get_post_meta($order_id, 'best2pay_order_id', true);
     129                $currency = $this->convert_currency();
     130                $best2pay_url = $this->best2pay_get_url();
     131                $b2p_payment_method = substr(get_post_meta($order_id, 'best2pay_payment_method', true), 0, 6);
     132                $best2pay_operation = ($b2p_payment_method == 'custom') ? 'custom/svkb/Complete' : 'Complete';
     133                $signature = $this->make_signature([$this->sector, $b2p_order_id, intval($order->get_total() * 100), $currency]);
     134               
     135                $args = array(
     136                    'body' => array(
     137                        'sector' => $this->sector,
     138                        'id' => $b2p_order_id,
     139                        'amount' => intval($order->get_total() * 100),
     140                        'currency' => $currency,
     141                        'signature' => $signature
     142                    )
     143                );
     144                $remote_url = $best2pay_url . '/webapi/' . $best2pay_operation;
     145                $remote_post = wp_remote_post($remote_url, $args);
     146                $current_status = json_decode(json_encode(simplexml_load_string($remote_post['body'])), true)["order_state"];
     147               
     148                $remote_post = json_encode(simplexml_load_string($remote_post['body']));
     149               
     150                if($current_status == "COMPLETED"){
     151                    $order->update_status(strtolower($current_status));
     152                }
     153                update_post_meta($order_id, 'best2pay_payment_method', strtolower($current_status));
     154               
     155                echo $remote_post;
     156            }
     157            exit();
     158        }
     159       
     160        /**
     161         * Set custom status
     162         */
     163        public function order_status_filter($order_statuses, $status_name, $custom_status_name)
     164        {
     165            foreach($order_statuses as $key => $status) {
     166                if($status_name === $key){
     167                    $order_statuses[$status_name] = _x($custom_status_name, 'Order status', 'woocommerce');
     168                }
     169            }
     170            return $order_statuses;
     171        }
     172       
     173        /**
     174         * Admin Panel Options
     175         **/
     176        public function admin_options()
     177        {
     178            ?>
     179            <h3><?php _e('Best2Pay', 'best2pay-payment_method'); ?></h3>
     180            <p><?php _e("Payments with bank cards via the <a href=\"http://www.best2pay.net\" target=\"_blank\">Best2Pay</a> payment system.", 'best2pay-payment_method'); ?></p>
     181            <table class="form-table">
     182                <?php
     183                // Generate the HTML For the settings form.
     184                $this->generate_settings_html();
     185                ?>
     186            </table><!--/.form-table-->
     187            <?php
     188        }
     189       
     190        /**
     191         * Initialise Gateway Settings Form Fields
     192         */
     193        public function init_form_fields()
     194        {
     195            $wc_statuses = wc_get_order_statuses();
     196            //  array to generate admin form
     197            $this->form_fields = array(
     198                'enabled' => array(
     199                    'title' => __('Enable/Disable', 'best2pay-payment_method'),
     200                    'type' => 'checkbox',
     201                    'label' => __('Enable Best2Pay checkout method', 'best2pay-payment_method'),
     202                    'default' => 'yes'
     203                ),
     204               
     205                'sector' => array(
     206                    'title' => __('Sector ID', 'best2pay-payment_method'),
     207                    'type' => 'text',
     208                    'description' => __('Your shop identifier at Best2Pay', 'best2pay-payment_method'),
     209                    'default' => 'test'
     210                ),
     211               
     212                'password' => array(
     213                    'title' => __('Password', 'best2pay-payment_method'),
     214                    'type' => 'text',
     215                    'description' => __('Password to use for digital signature', 'best2pay-payment_method'),
     216                    'default' => 'test'
     217                ),
     218               
     219                'testmode' => array(
     220                    'title' => __('Test Mode', 'best2pay-payment_method'),
     221                    'type' => 'select',
     222                    'options' => array(
     223                        '1' => __('Test mode - real payments will not be processed', 'best2pay-payment_method'),
     224                        '0' => __('Production mode - payments will be processed', 'best2pay-payment_method')
     225                    ),
     226                    'description' => __('Select test or live mode', 'best2pay-payment_method')
     227                ),
     228                /*'mode' => array(
     229                        'title' => __('Payment mode', 'best2pay-payment_method'),
     230                        'type' => 'select',
     231                        'options' => array(
     232                                '0' => __('Standard acquiring', 'best2pay-payment_method'),
     233                                '1' => __('Just installment', 'best2pay-payment_method'),
     234                                '2' => __('Just purchase by QR', 'best2pay-payment_method')
     235                        ),
     236                        'description' => __('Select payment mode', 'best2pay-payment_method'),
     237                ),*/
     238                'mode' => array(
     239                    'title' => __('Режим оплаты', 'best2pay-payment_method'),
     240                    'type' => 'select',
     241                    'options' => array(
     242                        '0' => __('Стандартный эквайринг', 'best2pay-payment_method'),
     243                        '1' => __('Только Халва.Частями', 'best2pay-payment_method'),
     244                        '2' => __('Только СБП', 'best2pay-payment_method')
     245                    ),
     246                    'description' => __('Выберите режим оплаты', 'best2pay-payment_method'),
     247                ),
     248                'twostepsmode' => array(
     249                    'title' => __('2 steps payment mode', 'best2pay-payment_method'),
     250                    'type' => 'select',
     251                    'options' => array(
     252                        '1' => __('On', 'best2pay-payment_method'),
     253                        '0' => __('Off', 'best2pay-payment_method')
     254                    ),
     255                    'description' => __('Turn on 2 steps mode', 'best2pay-payment_method')
     256                ),
     257                /*'deferred' => array(
     258                        'title' => __('Deferred payment', 'best2pay-payment_method'),
     259                        'type' => 'select',
     260                        'options' => array(
     261                                '1' => __('On', 'best2pay-payment_method'),
     262                                '0' => __('Off', 'best2pay-payment_method')
     263                        ),
     264                        'description' => __('Making of an email message with a link to payment (payment is not carried out)', 'best2pay-payment_method')
     265                )*/
     266                //statuses
     267                'custom_registered' => array(
     268                    'title' => __('Order registered', 'best2pay-payment_method'),
     269                    'type' => 'select',
     270                    'options' => $wc_statuses,
     271                ),
     272                'custom_authorized' => array(
     273                    'title' => __('Order authorized', 'best2pay-payment_method'),
     274                    'type' => 'select',
     275                    'options' => $wc_statuses,
     276                ),
     277                'custom_successfully_paid' => array(
     278                    'title' => __('Order successfully paid', 'best2pay-payment_method'),
     279                    'type' => 'select',
     280                    'options' => $wc_statuses,
     281                ),
     282                'custom_cancelled' => array(
     283                    'title' => __('Order cancelled', 'best2pay-payment_method'),
     284                    'type' => 'select',
     285                    'options' => $wc_statuses,
     286                )
     287            );
     288           
     289        }
     290       
     291        public function convert_currency(): string
     292        {
     293            $currency = get_woocommerce_currency();
     294            switch($currency) {
     295                case 'EUR':
     296                    $currency = '978';
     297                    break;
     298                case 'USD':
     299                    $currency = '840';
     300                    break;
     301                default:
     302                    $currency = '643';
     303                    break;
     304            }
     305            return $currency;
     306        }
     307       
     308        /**
     309         * Register order @ Best2Pay and redirect user to payment form
     310         **/
     311        public function process_payment($order_id)
     312        {
     313            $order = new WC_Order($order_id);
     314            $currency = $this->convert_currency();
     315           
     316            $best2pay_url = $this->best2pay_get_url();
     317           
     318            switch (intval($this->mode)) {
     319                case 1:
     320                    $best2pay_operation = $this->twostepsmode ? 'custom/svkb/AuthorizeWithInstallment' : 'custom/svkb/PurchaseWithInstallment';
     321                    break;
     322                case 2:
     323                    $best2pay_operation = 'PurchaseSBP';
     324                    break;
     325                default:
     326                    $best2pay_operation = "Purchase";
     327                    if ($this->twostepsmode == "1")
     328                        $best2pay_operation = "Authorize";
     329            }
     330           
     331            $signature = base64_encode(md5($this->sector . intval($order->get_total() * 100) . $currency . $this->password));
     332           
     333            $wc_order = wc_get_order($order_id);
     334            $items = $wc_order->get_items();
     335            $fiscalPositions = '';
     336            $fiscalAmount = 0;
     337           
     338            foreach ($items as $item_id => $item) {
     339                $item_data = $item->get_data();
     340                $fiscalPositions .= $item_data['quantity'] . ';';
     341                $elementPrice = $item->get_product()->get_price() * 100;
     342                $fiscalPositions .= $elementPrice . ';';
     343                $fiscalPositions .= ($item_data['total_tax']) ?: 6 . ';';   // tax
     344                $fiscalPositions .= str_ireplace([';', '|'], '', $item_data['name']) . '|';
     345               
     346                $fiscalAmount += $item_data['quantity'] * $elementPrice;
     347            }
     348            if ($wc_order->get_shipping_total()) {
     349                $fiscalPositions .= '1;' . $wc_order->get_shipping_total() * 100 . ';6;Доставка|';
     350                $fiscalAmount += $wc_order->get_shipping_total() * 100;
     351            }
     352            $fiscalDiff = abs($fiscalAmount - intval($order->get_total() * 100));
     353            if ($fiscalDiff) {
     354                $fiscalPositions .= '1;' . $fiscalDiff . ';6;Скидка;14|';
     355            }
     356            $fiscalPositions = substr($fiscalPositions, 0, -1);
     357           
     358            $args = array(
     359                'body' => array(
     360                    'sector' => $this->sector,
     361                    'reference' => $order->get_id(),
     362                    'amount' => intval($order->get_total() * 100),
     363                    'fiscal_positions' => $fiscalPositions,
     364                    'description' => sprintf(__('Order #%s', 'best2pay-payment_method'), ltrim($order->get_order_number(), '#')),
     365                    'email' => $order->get_billing_email(),
     366                    // 'notify_customer' => ($this->deferred) ? 1 : 0,
     367                    'currency' => $currency,
     368                    'mode' => 1,
     369                    'url' => $this->callback_url,
     370                    'signature' => $signature
     371                )
     372            );
     373           
     374            $remote_post = wp_remote_post($best2pay_url . '/webapi/Register', $args);
     375            $remote_post = (isset($remote_post['body'])) ? $remote_post['body'] : $remote_post;
     376            $b2p_order_id = ($remote_post) ? $remote_post : null;
     377           
     378            if (intval($b2p_order_id) == 0) {
     379                $request_body = $args['body'];
     380                $request_body['email'] = ($request_body['email']) ? 'isset' : 'isnotset';
     381                $request_body['signature'] = ($request_body['signature']) ? 'isset' : 'isnotset';
     382                $this->logIt('Не удалось зарегистрировать заказ', array('b2p_order_id' => $b2p_order_id, 'request_body' => $request_body));
     383                return false;
     384            }
     385           
     386            update_post_meta($order->get_id(), "best2pay_order_id", $b2p_order_id);
     387            update_post_meta($order->get_id(), "best2pay_payment_method", $best2pay_operation);
     388           
     389            $signature = base64_encode(md5($this->sector . $b2p_order_id . $this->password));
     390           
     391            /*if ($this->deferred) {
     392                    wp_redirect($this->get_return_url($wc_order));
     393                    exit();
     394            }*/
     395           
     396            return array(
     397                'result' => 'success',
     398                'redirect' => "{$best2pay_url}/webapi/{$best2pay_operation}?sector={$this->sector}&id={$b2p_order_id}&signature={$signature}"
     399            );
     400        }
     401       
     402        public function process_refund($order_id, $amount = null, $reason = '', $from_callback = false): bool
     403        {
     404            if(!$from_callback){
     405                $best2pay_url = $this->best2pay_get_url();
     406                $order = wc_get_order($order_id);
     407                $best2pay_order_id = get_post_meta($order_id, 'best2pay_order_id', true);
     408                $halva = 'custom/svkb/';
     409                $best2pay_payment_method = get_post_meta($order_id, 'best2pay_payment_method', true);
     410                $halva = (strpos($best2pay_payment_method, 'Installment')) ? $halva : '';
     411                $amount = intval($amount * 100) ?: intval($order->get_total() * 100);
     412                $sector = $this->sector;
     413                $currency = $this->convert_currency();
     414                $signature = $this->make_signature([$sector, $best2pay_order_id, $amount, $currency]);
     415               
     416                $args = array(
     417                    'body' => array(
     418                        'sector' => $sector,
     419                        'id' => $best2pay_order_id,
     420                        'signature' => $signature,
     421                        'amount' => $amount,
     422                        'currency' => $currency
     423                    )
     424                );
     425                $xml = wp_remote_post($best2pay_url . '/webapi/' . $halva . 'Reverse', $args);
     426                $response = $this->parse_xml($xml['body']);
     427                if (isset($response->order_state)){
     428                    if(in_array($response->type, $this->cancel_types)){
     429                        return true;
     430                    }
     431                } else {
     432                    $this->logIt('best2pay: ', array($response));
     433                    return false;
     434                }
     435            }
     436            return !($this->orderWasRefund($response));
     437        }
     438       
     439        private function best2pay_get_url(): string
     440        {
     441            $best2pay_url = "https://test.best2pay.net";
     442            //          $best2pay_url = "https://dev2.best2pay.net";
     443            if($this->testmode == "0"){
     444                $best2pay_url = "https://pay.best2pay.net";
     445            }
     446            return $best2pay_url;
     447        }
     448       
     449        private function make_signature(array $parameters)
     450        {
     451            return base64_encode(md5(implode('', $parameters) . $this->password));
     452        }
     453       
     454        public function parse_xml(string $xml)
     455        {
     456            $xml = simplexml_load_string($xml);
     457            if(!$xml){
     458                return false;
     459            }
     460            return json_decode(json_encode($xml));
     461        }
     462       
     463        /**
     464         * Callback from payment gateway was received
     465         **/
     466        public function callback_from_gateway()
     467        {
     468            // check payment status
     469            $b2p_order_id = intval($_REQUEST["id"]);
     470            if (!$b2p_order_id)
     471                return false;
     472           
     473            $b2p_operation_id = intval($_REQUEST["operation"]);
     474            if (!$b2p_operation_id) {
     475                $order_id = intval($_REQUEST["reference"]);
     476                $order = wc_get_order($order_id);
     477                if ($order)
     478                    $order->cancel_order(__("The order wasn't paid.", 'best2pay-payment_method'));
     479               
     480                wc_add_notice(__("The order wasn't paid.", 'best2pay-payment_method'), 'error');
     481                $get_checkout_url = apply_filters('woocommerce_get_checkout_url', WC()->cart->get_checkout_url());
     482                wp_redirect($get_checkout_url);
     483                exit();
     484            }
     485           
     486            // check payment operation state
     487            $signature = base64_encode(md5($this->sector . $b2p_order_id . $b2p_operation_id . $this->password));
     488           
     489            $best2pay_url = $this->best2pay_get_url();
     490           
     491            $context = stream_context_create(array(
     492                'http' => array(
     493                    'header' => "Content-type: application/x-www-form-urlencoded\r\n",
     494                    'method' => 'POST',
     495                    'content' => http_build_query(array(
     496                        'sector' => $this->sector,
     497                        'id' => $b2p_order_id,
     498                        'operation' => $b2p_operation_id,
     499                        'signature' => $signature
     500                    )),
     501                )
     502            ));
     503           
     504            $repeat = 3;
     505           
     506            while ($repeat) {
     507               
     508                $repeat--;
     509               
     510                // pause because of possible background processing in the Best2Pay
     511                sleep(2);
     512                $args = array(
     513                    'body' => array(
     514                        'sector' => $this->sector,
     515                        'id' => $b2p_order_id,
     516                        'operation' => $b2p_operation_id,
     517                        'signature' => $signature
     518                    )
     519                );
     520                $xml = wp_remote_post($best2pay_url . '/webapi/Operation', $args)['body'];
     521               
     522                $response = $this->parse_xml($xml);
     523                if($this->orderWasRefund($response)){
     524                    return $from_callback = true;
     525                }
     526               
     527                if (!$this->orderAsPayed($response))
     528                    continue;
     529               
     530                wp_redirect($this->get_return_url(wc_get_order($response->reference)));
     531                exit();
     532            }
     533           
     534            $order_id = intval($response->reference);
     535            $order = wc_get_order($order_id);
     536            if ($order)
     537                $order->cancel_order(__("The order wasn't paid [1]: " . $response->message . '.', 'best2pay-payment_method'));
     538           
     539            wc_add_notice(__("The order wasn't paid [1]: ", 'best2pay-payment_method') . $response->message . '.', 'error');
     540            $get_checkout_url = apply_filters('woocommerce_get_checkout_url', WC()->cart->get_checkout_url());
     541            wp_redirect($get_checkout_url);
     542            exit();
     543        }
     544       
     545        /**
     546         * Payment notify from gateway was received
     547         **/
     548        public function notify_from_gateway()
     549        {
     550            global $wp_filesystem;
     551            if (empty($wp_filesystem)) {
     552                require_once(ABSPATH . '/wp-admin/includes/file.php');
     553                WP_Filesystem();
     554            }
     555            $xml = $wp_filesystem->get_contents('php://input');
     556            $response = $this->parse_xml($xml);
     557           
     558            $order_id = intval($response->reference);
     559            $order = wc_get_order($order_id);
     560            if($this->orderWasRefund($response)){
     561                $amount_from_response = $response->amount;
     562                $this->process_refund($order_id,$amount_from_response);
     563            }
     564            $response_order_state = 'status_' . strtolower($response->order_state);
     565            $order->update_status(str_replace('wc-', '', $this->$response_order_state));
     566            die("ok");
     567        }
     568       
     569        private function orderWasRefund($response)
     570        {
     571            $order = $this->best2pay_find_order($response);
     572            if(in_array($response->type, $this->cancel_types) && ($response->state == 'APPROVED')){
     573                $order->add_order_note(__('Refund completed.', 'best2pay-payment_method'));
     574                $order->cancel_order((__("The order was refund.", 'best2pay-payment_method')));
     575                return true;
     576            }
     577            return false;
     578        }
     579       
     580        private function best2pay_find_order($response)
     581        {
     582            if(intval($response->reference) == 0){
     583                return false;
     584            }
     585            $order_id = $response->reference;
     586           
     587            $order = wc_get_order($order_id);
     588            if(!$order){
     589                return false;
     590            }
     591            return $order;
     592        }
     593       
     594        private function orderAsPayed($response)
     595        {
     596            $order = $this->best2pay_find_order($response);
     597            $tmp_response = json_decode(json_encode($response), true);
     598            unset($tmp_response["signature"]);
     599            unset($tmp_response["ofd_state"]);
     600            unset($tmp_response["protocol_message"]);
     601           
     602            $signature = $this->make_signature($tmp_response);
     603            if ($signature !== $response->signature) return false;
     604           
     605            $response_order_state = 'status_' . strtolower($tmp_response['order_state']);
     606            $order->update_status(str_replace('wc-', '', $this->$response_order_state));
     607            return true;
     608           
     609            /*
     610             * сохраним в мета заказа выбранный на момент оплаты режим (1 или 2 стадии)
     611             */
     612            $b2p_mode = ($this->settings['twostepsmode']) ? 2 : 1;
     613            update_post_meta($order_id, 'b2p_payment_mode', $b2p_mode);
     614           
     615            return true;
     616        }
     617       
     618       
     619        /**
     620         * @param string $message
     621         * @param array $details
     622         */
     623        public function logIt(string $message, array $details = [])
     624        {
     625            $log = fopen(ABSPATH . $this->getLogFileName(), 'a+') or die("logging trouble");
     626            $date = date("d.m.y H:i:s");
     627            $msg = $date . "\t" . $message;
     628            if ($details) {
     629                $msg .= "\n" . print_r($details, true);
     630            }
     631            $msg .= "\n\n\n";
     632            fprintf($log, chr(0xEF) . chr(0xBB) . chr(0xBF));
     633            fwrite($log, $msg);
     634            fclose($log);
     635        }
     636       
     637        public function getLogFileName()
     638        {
     639            $signature = base64_encode($this->sector . $this->password . $_SERVER['HTTP_HOST']);
     640            $signature = str_ireplace('=', '', $signature);
     641            return 'b2p_log_' . $signature . '.txt';
     642        }
     643       
     644       
     645    } // class
     646   
     647    function add_best2pay_gateway($methods)
     648    {
     649        $methods[] = 'woocommerce_best2pay';
     650        return $methods;
     651    }
     652   
     653    add_filter('woocommerce_payment_gateways', 'add_best2pay_gateway');
    496654}
  • best2pay-payment-method-visamastercard/readme.txt

    r2884140 r2884147  
    55Requires at least: 4.7
    66Requires PHP: 7.4
    7 Stable tag: 1.2.7
     7Stable tag: 2.0
    88License: GPLv3
    99License URI: https://www.gnu.org/licenses/gpl-3.0.html
Note: See TracChangeset for help on using the changeset viewer.