<?php
/*####################################################################
 # Copyright ©2020 UseePay Ltd. All Rights Reserved.                 #
 # This file may not be redistributed in whole or significant part.  #
 # This file is part of the UseePay package and should not be used   #
 # and distributed for any other purpose that is not approved by     #
 # UseePay Ltd.                                                      #
 # https://www.useepay.com                                           #
 ####################################################################*/

if (!defined('ABSPATH')) exit; // Exit if accessed directly
// ini_set('display_errors', 1);
// error_reporting(E_ALL & ~E_NOTICE);

/**
 * Class WC_Gateway_UseePay
 */
class WC_Gateway_UseePay extends WC_UseePay_Payment_Gateway
{
    private $return_url;
    private $payment_async_notify_url;
    private $refund_async_notify_url;

    private $query_order_status_url;

    public function __construct()
    {
        parent::__construct();

        // WooCommerce required settings
        $this->icon               = apply_filters('woocommerce_useepay_icon', plugins_url('../assets/images/op_cards.jpg', __FILE__));
        $this->has_fields         = true;
        $this->order_button_text  = __('Complete Order', 'useepay-for-woocommerce');
        $this->method_description = __('UseePay Standard redirects customers to UseePay to enter their payment information.', 'useepay-for-woocommerce');
        $this->supports           = array(
            'products',
            'refunds',
        );

        $this->return_url = WC()->api_request_url('WC_useepay_return');

        // async notify
        $this->payment_async_notify_url = WC()->api_request_url('WC_useepay_notify');
        $this->refund_async_notify_url  = WC()->api_request_url('WC_useepay_refund_notify');

        $this->query_order_status_url = WC()->api_request_url("WC_useepay_query_order_status");

        // Actions
        add_filter('http_request_version', array($this, 'use_http_1_1'));
        add_action('woocommerce_update_options_payment_gateways_' . $this->id, array($this, 'process_admin_options')); // WC >= 2.0

        add_action('woocommerce_api_wc_useepay_return', array($this, 'return_handle'));

        add_action('woocommerce_api_wc_useepay_notify', array($this, 'payment_async_notify_handle'));
        add_action('woocommerce_api_wc_useepay_refund_notify', array($this, 'refund_async_notify_handle'));

        add_action('woocommerce_api_wc_useepay_query_order_status', array($this, 'query_order_status'));

        add_action('woocommerce_admin_order_data_after_billing_address', array($this, 'wc_useepay_display_order_meta_for_admin'));
    }

    /**
     * Admin Panel Option
     * - Options for bits like 'title' and account etc.
     *
     * @access public
     * @return void
     */
    public function admin_options()
    {
        echo '<h1>' . _e('UseePay', 'useepay-for-woocommerce') . '</h1>';
        echo '<p>' . _e('UseePay is a simple, secure and fast online payment gateway, customer can pay via debit card or credit card.', 'useepay-for-woocommerce') . '</p>';
        echo '<table class="form-table">';
        echo $this->generate_settings_html();
        echo '</table>';
    }


    /**
     * Set the HTTP version for the remote posts
     * https://developer.wordpress.org/reference/hooks/http_request_version/
     */
    public function use_http_1_1($httpversion)
    {
        return '1.1';
    }


    /**
     * Process Payment.
     *
     * Process the payment. Override this in your gateway. When implemented, this should.
     * return the success and redirect in an array. e.g:
     *
     *        return array(
     *            'result'   => 'success',
     *            'redirect' => $this->get_return_url( $order )
     *        );
     *
     * @param int $order_id Order ID.
     * @return array
     */
    public function process_payment($order_id)
    {
        WC_UseePay_Logger::log('Process payment with order_id: ' . $order_id);
        $order = wc_get_order($order_id);
        WC_UseePay_Logger::log('Process payment with order_key: ' . $order->get_order_key());
        if (empty($order)) {
            wc_add_notice('Order not exist!', 'error');
            return array(
                'result'   => 'fail',
                'redirect' => '',
            );
        }
        $parameters = $this->build_payment_request_parameters($order);

        WC_UseePay_Logger::log('Process payment with request parameters: ' . var_export($parameters, true));

        try {
            $response       = WC_UseePay_API::request($parameters);
            $error_code     = $response['errorCode'];
            $error_msg      = $response['errorMsg'];
            if ($response['redirectUrl']) {
                return array(
                    'result' => 'success',
                    'redirect' => $response['redirectUrl']
                );
            } else {
                $transaction_error_message = $error_code . "," . $error_msg;
                $this->mark_as_failed_payment($order, $transaction_error_message);
                wc_add_notice(__('(Transaction Error) something is wrong.', 'useepay-for-woocommerce') . ' ' . $transaction_error_message, 'error');
                return array(
                    'result'   => 'fail',
                    'redirect' => '',
                );
            }
        } catch (WC_UseePay_Exception $e) {
            wc_add_notice($e->get_error_message(), 'error');
            return array(
                'result'   => 'fail',
                'redirect' => '',
            );
        }

    }

    /**
     * Process refund.
     *
     * If the gateway declares 'refunds' support, this will allow it to refund.
     * a passed in amount.
     *
     * @param int $order_id Order ID.
     * @param float $amount Refund amount.
     * @param string $reason Refund reason.
     * @return boolean True or false based on success, or a WP_Error object.
     */
    public function process_refund($order_id, $amount = null, $reason = '')
    {
        $order = wc_get_order($order_id);

        if (!$this->can_refund_order($order)) {
            wc_add_wp_error_notices(new WP_Error('error', __('Refund failed.', 'useepay-for-woocommerce')));
            return false;
        }

        $parameters = $this->build_refund_request_parameters($order, $amount, $reason);

        try {
            $response       = WC_UseePay_API::request($parameters, true);
            $result_code    = $response['resultCode'];
            $error_code     = $response['errorCode'];
            $error_msg      = $response['errorMsg'];
            $transaction_id = $response['reference'];
            if ($result_code == "pending" && $error_code == "0000") {
                /* translators: 1: Refund amount, 2: Refund ID */
                $order->add_order_note(sprintf('Credit card refund approved;Refund ID: %s', $transaction_id));
                return true;
            } else {
                wc_add_notice($result_code . "," . $error_msg, 'error');
                return false;
            }
        } catch (WC_UseePay_Exception $e) {
            WC_UseePay_Logger::log('Refund Failed: ' . $e->get_localization_message());
            wc_add_wp_error_notices(new  WP_Error('error', $e->get_localization_message()));
            return false;
        }


    }

    /**
     * Can the order be refunded via Useepay?
     *
     * @param WC_Order $order Order object.
     * @return bool
     */
    function can_refund_order($order)
    {
        $has_api_creds = $this->get_merchant_no() && $this->get_app_id() && $this->get_secret_key();

        return $order && $order->get_id() && $has_api_creds;
    }

    /**
     * Build parameters for payment
     *
     * @param $order
     * @return array
     */
    function build_payment_request_parameters($order)
    {
        $currency    = $order->get_currency();    //	交易币种
        $amount      = Wc_UseePay_Util::convert_woo_price_to_useepay_price($currency, $order->get_total(), 2);
        $notifyUrl   = $this->payment_async_notify_url; //	商户通知地址
        $redirectUrl = $this->return_url; //	商户通知地址

        $goods_name_desc = $this->get_goods_name_desc($order);
        $goodsInfo       = [];
        foreach ($order->get_items() as $lineitem) {
            $_product         = $order->get_product_from_item($lineitem);
            $temp             = [];
            $temp['name']     = strval($lineitem->get_name());
            $temp['sku']      = empty(strval($_product->get_data()['sku'])) ? 'sku' : strval($_product->get_data()['sku']);
            if (!empty($_product->get_data()['sale_price'])) {
                $temp['price']    = strval(Wc_UseePay_Util::convert_woo_price_to_useepay_price($currency, $_product->get_data()['sale_price']));
            }
            $temp['quantity'] = strval($lineitem->get_data()['quantity']);
            $goodsInfo[]      = $temp;
        }
        $billingStreet  = $this->clean($order->get_billing_address_1());
        $billingHouseNo = $this->clean($order->get_billing_address_2());
        $billingCity    = $order->get_billing_city(); //	账单城市
        $billingState   = $order->get_billing_state(); //	账单州省
        if ($billingState == null || strlen(trim($billingState)) <= 0) {
            $billingState = $billingCity;
        }

        $shippingStreet  = $this->clean($order->get_shipping_address_1());
        $shippingHouseNo = $this->clean($order->get_shipping_address_2());
        $shippingCity    = $order->get_shipping_city(); //	收货人城市
        $shippingState   = $order->get_shipping_state(); //	收货人州省
        if ($shippingState == null || strlen(trim($shippingState)) <= 0) {
            $shippingState = $billingState;
        }

        $shippingStreet = empty($shippingStreet) ? $billingStreet : $shippingStreet;
        $shippingCity   = empty($shippingCity) ? $billingCity : $shippingCity;
        $shippingState  = empty($shippingState) ? $billingState : $shippingState;
        $orderInfo      = [
            "subject"         => empty(trim($goods_name_desc["product_names"])) ? "Goods Name" : trim($goods_name_desc["product_names"]) ,
            "goodsInfo"       => $goodsInfo,
            "shippingAddress" => [
                "email"      => trim($order->get_billing_email()),
                "phoneNo"    => trim($order->get_billing_phone()),
                "firstName"  => empty(trim($order->get_shipping_first_name())) ? trim($order->get_billing_first_name()) : trim($order->get_shipping_first_name()),
                "lastName"   => empty(trim($order->get_shipping_last_name())) ? trim($order->get_billing_last_name()) : trim($order->get_shipping_last_name()),
                "street"     => trim($shippingStreet),
                "postalCode" => empty(trim($order->get_shipping_postcode())) ? trim($order->get_billing_postcode()) : trim($order->get_shipping_postcode()),
                "city"       => trim($shippingCity),
                "state"      => trim($shippingState),
                "country"    => empty(trim($order->get_shipping_country())) ? trim($order->get_billing_country()) : trim($order->get_shipping_country()),
                "houseNo"    => $shippingHouseNo,
            ]
        ];

        $userInfo = [
            'userId'     => trim($order->user_id), // 用户在商户系统的id
            'ip'         => trim($order->get_customer_ip_address()),  // 用户下单IP
            'email'      => trim($order->get_billing_email()),     // 用户email
            'phoneNo'    => trim($order->get_billing_phone()), // 用户phone
            'createTime' => '', // 用户的注册时间
        ];

        $payerInfo   = [
            'paymentMethod'       => 'credit_card',
            'authorizationMethod' => 'cvv',
            'billingDescriptor'   => '',
            'billingAddress'      => [
                'houseNo'    => $billingHouseNo,
                'email'      => trim($order->get_billing_email()),
                'phoneNo'    => trim($order->get_billing_phone()),
                'firstName'  => trim($order->get_billing_first_name()),
                'lastName'   => trim($order->get_billing_last_name()),
                'street'     => trim($billingStreet), // 账单街道
                'postalCode' => trim($order->get_billing_postcode()), // 账单邮政编码
                'city'       => trim($billingCity),   // 账单城市
                'state'      => trim($billingState),  // 账单省份
                'country'    => trim($order->get_billing_country()) // 账单国家英文二字码
            ]
        ];

        $fingerPrintId = $_COOKIE["CO_XD_FP_ID"];
        $deviceInfo    = [
            'fingerPrintId' => trim($fingerPrintId), // 设备指纹
        ];

        $terminalType = $this->getTerminalType();

        $billCountryCode = trim($order->get_billing_country()) ; 	//需转换 账单国家代码

        $transaction_id = $order->get_transaction_id();
        if (!$transaction_id) {
            $transaction_id = $this->get_useepay_order_transaction_id($order);
            $this->update_transaction_id($transaction_id, $order);
        }

        //组装参数
        return array(
            'transactionType'           => 'pay',
            'version'                   => '1.0',
            'signType'                  => 'MD5',
            'merchantNo'                => $this->get_merchant_no(),
            'transactionId'             => $transaction_id,
            'transactionExpirationTime' => '2880',
            'appId'                     => $this->get_app_id(),
            'amount'                    => $amount,
            'currency'                  => $currency,
            'notifyUrl'                 => $notifyUrl,
            'redirectUrl'               => $redirectUrl,
            'autoRedirect'               => 'false',
            'returnUrl'                 => wc_get_checkout_url(),
            'echoParam'                 => $order->get_id(),
            'reserved'                  => '{"pluginName":"woocommerce-cashier","pluginVersion":"1.0.18","origVersion":"2.0"}',
            'terminalType'              => $terminalType,
            'language'                  => 'en',
            'country'                   => $billCountryCode,

            'orderInfo'  => json_encode($orderInfo),
            'userInfo'   => json_encode($userInfo),
            'payerInfo'  => json_encode($payerInfo),
            'deviceInfo' => json_encode($deviceInfo),
        );
    }

    /**
     * Get terminal type
     * @return string
     */
    public function getTerminalType()
    {
        $terminalType = 'WEB';
        $useragent = $_SERVER['HTTP_USER_AGENT'];
        if (preg_match('/(android|bb\d+|meego).+mobile|avantgo|bada\/|blackberry|blazer|compal|elaine|fennec|hiptop|iemobile|ip(hone|od)|iris|kindle|lge |maemo|midp|mmp|netfront|opera m(ob|in)i|palm( os)?|phone|p(ixi|re)\/|plucker|pocket|psp|series(4|6)0|symbian|treo|up\.(browser|link)|vodafone|wap|windows (ce|phone)|xda|xiino/i', $useragent) || preg_match('/1207|6310|6590|3gso|4thp|50[1-6]i|770s|802s|a wa|abac|ac(er|oo|s\-)|ai(ko|rn)|al(av|ca|co)|amoi|an(ex|ny|yw)|aptu|ar(ch|go)|as(te|us)|attw|au(di|\-m|r |s )|avan|be(ck|ll|nq)|bi(lb|rd)|bl(ac|az)|br(e|v)w|bumb|bw\-(n|u)|c55\/|capi|ccwa|cdm\-|cell|chtm|cldc|cmd\-|co(mp|nd)|craw|da(it|ll|ng)|dbte|dc\-s|devi|dica|dmob|do(c|p)o|ds(12|\-d)|el(49|ai)|em(l2|ul)|er(ic|k0)|esl8|ez([4-7]0|os|wa|ze)|fetc|fly(\-|_)|g1 u|g560|gene|gf\-5|g\-mo|go(\.w|od)|gr(ad|un)|haie|hcit|hd\-(m|p|t)|hei\-|hi(pt|ta)|hp( i|ip)|hs\-c|ht(c(\-| |_|a|g|p|s|t)|tp)|hu(aw|tc)|i\-(20|go|ma)|i230|iac( |\-|\/)|ibro|idea|ig01|ikom|im1k|inno|ipaq|iris|ja(t|v)a|jbro|jemu|jigs|kddi|keji|kgt( |\/)|klon|kpt |kwc\-|kyo(c|k)|le(no|xi)|lg( g|\/(k|l|u)|50|54|\-[a-w])|libw|lynx|m1\-w|m3ga|m50\/|ma(te|ui|xo)|mc(01|21|ca)|m\-cr|me(rc|ri)|mi(o8|oa|ts)|mmef|mo(01|02|bi|de|do|t(\-| |o|v)|zz)|mt(50|p1|v )|mwbp|mywa|n10[0-2]|n20[2-3]|n30(0|2)|n50(0|2|5)|n7(0(0|1)|10)|ne((c|m)\-|on|tf|wf|wg|wt)|nok(6|i)|nzph|o2im|op(ti|wv)|oran|owg1|p800|pan(a|d|t)|pdxg|pg(13|\-([1-8]|c))|phil|pire|pl(ay|uc)|pn\-2|po(ck|rt|se)|prox|psio|pt\-g|qa\-a|qc(07|12|21|32|60|\-[2-7]|i\-)|qtek|r380|r600|raks|rim9|ro(ve|zo)|s55\/|sa(ge|ma|mm|ms|ny|va)|sc(01|h\-|oo|p\-)|sdk\/|se(c(\-|0|1)|47|mc|nd|ri)|sgh\-|shar|sie(\-|m)|sk\-0|sl(45|id)|sm(al|ar|b3|it|t5)|so(ft|ny)|sp(01|h\-|v\-|v )|sy(01|mb)|t2(18|50)|t6(00|10|18)|ta(gt|lk)|tcl\-|tdg\-|tel(i|m)|tim\-|t\-mo|to(pl|sh)|ts(70|m\-|m3|m5)|tx\-9|up(\.b|g1|si)|utst|v400|v750|veri|vi(rg|te)|vk(40|5[0-3]|\-v)|vm40|voda|vulc|vx(52|53|60|61|70|80|81|83|85|98)|w3c(\-| )|webc|whit|wi(g |nc|nw)|wmlb|wonu|x700|yas\-|your|zeto|zte\-/i', substr($useragent, 0, 4))) {
            $terminalType = 'H5';
        }
        return $terminalType;
    }

    /**
     * Build parameters for refund
     *
     * @param $order
     * @param null $amount
     * @param string $reason
     * @return array
     */
    function build_refund_request_parameters($order, $amount = null, $reason = '')
    {
        $uniqId        = md5(uniqid(microtime(true), true));
        $transactionId = time() . substr($uniqId, 0, 6);

        $currency = $order->get_currency();    //	交易币种
        $amount   = Wc_UseePay_Util::convert_woo_price_to_useepay_price($currency, $amount, 2);
        //组装参数
        $parameters = array(
            'transactionType'       => 'refund',
            'version'               => '1.0',
            'signType'              => 'MD5',
            'merchantNo'            => self::get_merchant_no(),
            'transactionId'         => $transactionId,
            'originalTransactionId' => $order->get_transaction_id(),
            'amount'                => $amount,
            'notifyUrl'             => $this->refund_async_notify_url,
            'echoParam'             => $order->get_id(),
            'reserved'              => '{"pluginName":"woocommerce","pluginVersion":"1.0.16","origVersion":"2.0"}',
        );

        WC_UseePay_Logger::log("useepay request:" . var_export($parameters, true));
        return $parameters;
    }

    protected function mark_as_failed_payment($order, $message)
    {
        $order->add_order_note(sprintf("Credit card payment failed with message: '%s'", $message));
    }

    protected function do_order_complete_tasks($order, $transaction_id)
    {
        // 在修改订单状态之前再次查询订单状态，防止重复扣库存
        $order = wc_get_order($order->get_id());

        if ($order->get_status() == 'processing' || $order->get_status() == 'completed') {
            WC_UseePay_Logger::log($_POST['transactionId'] . ', ' . $transaction_id . 'order is ' . $order->get_status() . ' ignore update order status');
            return;
        }

        global $woocommerce;
        if ($order->get_status() == 'completed')
            return;

        if ($order->get_status() == 'pending') {
            $order->add_order_note(
                sprintf("Credit card payment completed with transaction id of '%s'", $transaction_id)
            );
        }
        WC_UseePay_Logger::log($_POST['transactionId'] . ', ' . $transaction_id . ' modify order complete');
        $order->payment_complete();
        $woocommerce->cart->empty_cart();

        unset(WC()->session->get_session_data()['order_awaiting_payment']);
    }


    protected function do_order_on_hold_tasks($order, $transaction_id)
    {
        global $woocommerce;
        if ($order->get_status() == 'completed')
            return;

         if ($order->get_status() == 'pending') {
             $order->add_order_note(
                sprintf("Credit card authorize with transaction id of '%s'", $transaction_id)
            );
        }

        $order->update_status('on-hold', __('Awaiting capture'));

        $woocommerce->cart->empty_cart();
        unset(WC()->session->get_session_data()['order_awaiting_payment']);
    }

    function return_handle()
    {
        global $woocommerce;
        if (!empty($_GET) && !empty($_GET['resp'])) {
            $_POST = json_decode(stripslashes(urldecode($_GET['resp'])), true);
        } else if (!empty($_GET) && !empty($_GET['resultCode'])) {
            $_POST = stripslashes_deep($_GET);
            unset($_POST['wc-api']);
            foreach ($_POST as $key => $value) {
                $_POST[$key] = urldecode($value);
            }
        } else {
            $_POST = stripslashes_deep($_POST);
        }
        $order_id = $_POST['echoParam']; //	系统订单号
        $order    = wc_get_order($order_id);

        WC_UseePay_Logger::log($order_id . ' return response : ' . var_export($_POST, true));
        if (!Wc_UseePay_Util::verify_signature($_POST, $this->get_secret_key())) {
            WC_UseePay_Logger::log($_POST['reference'] . '	verifyByArray in return failed!');
            return;
        }

        //处理返回结果
        $result_code    = $_POST['resultCode'];
        $error_code     = $_POST['errorCode'];
        $errorMsg       = $_POST['errorMsg'];
        $transaction_id = $_POST['echoParam'];
        if ($result_code == "succeed") {
            // payment successfully
            $woocommerce->cart->empty_cart();
            WC_UseePay_Logger::log($_POST['transactionId'] . ', ' . $transaction_id . ' received in return.');
            $this->do_order_complete_tasks($order, $transaction_id);
            $appendHtml = "window.parent.location.href='" . $this->get_return_url($order) . "';";
        } else if ('failed' == $result_code || 'closed' == $result_code || 'cancelled' == $result_code) {
            WC_UseePay_Logger::log($_POST['transactionId'] . ', ' . $transaction_id . ' received in return.');
            $order->update_status("failed");
            $appendHtml = "window.parent.location.href='" . $this->get_return_url($order) . "';";
        } else if ('pending' == $result_code) {
            echo '<link rel="stylesheet" type="text/css" href="' . plugins_url('../assets/css/useepay-styles.css', __FILE__) . '">';
            echo '<script type="text/javascript" src="' . plugins_url("../assets/js/jquery-1.9.1.min.js", __FILE__)  . '"></script>';
            echo '<script type="text/javascript" src="' .  plugins_url('../assets/js/useepay-1.0.1.js', __FILE__). '"></script>';
            $loading_img      = plugins_url("../assets/images/loading.gif", __FILE__)  ;
            $loading_text     = __('Processing...', 'useepay-for-woocommerce');
            $review_order_url = $this->get_return_url($order);
            $poll_url         = add_query_arg('order_id', $order_id, $this->query_order_status_url);
            $order_status     = $order->get_status();
            WC_UseePay_Logger::log('return_handle: order status: ' . $order_status);
            echo "
                <script type='text/javascript'>
                    $(function() {
                        window.UseePay.showPageLoading('$loading_img', '$loading_text');
                        window.UseePay.pollOrderStatusAndRedirect('$poll_url', '$review_order_url', '$order_status');
                    });
                </script>
                ";
            exit;
        } else {
            if (!empty($_POST['redirectUrl'])) {
                $woocommerce->cart->empty_cart();
                unset(WC()->session->get_session_data()['order_awaiting_payment']);
            }
            if ('pending' == $result_code) {
                $order->update_status("AUTHENTICATION REQUIRED");
            }
            $appendHtml = "window.parent.location.href='" . $this->get_return_url($order) . "';";
        }
        $html = "<div></div><script type='text/javascript'>if (window.parent.document.getElementById(\"isGather\")) { window.parent.postMessage(" . json_encode($_POST) . ", location.protocol + \"//\" + location.host);} else {$appendHtml}</script>";
        echo $html;
        exit;
    }

    /**
     * UseePay async notify handle for payment
     */
    function payment_async_notify_handle()
    {   
        $_POST   = stripslashes_deep($_POST);
        $orderId = $_POST['echoParam'];
        $order   = wc_get_order($orderId);
        WC_UseePay_Logger::log($orderId . ' notify response : ' . var_export($_POST, true));
        if (!Wc_UseePay_Util::verify_signature($_POST, $this->get_secret_key())) {
            WC_UseePay_Logger::log($_POST['reference'] . '	verify signature in notice failed!');
            return;
        }

        //处理返回结果
        $resultCode = $_POST['resultCode'];
        $errorMsg   = $_POST['errorMsg'];
        $reference  = $_POST['reference'];

        if ('succeed' != $resultCode && 'failed' != $resultCode && 'closed' != $resultCode && 'cancelled' != $resultCode && 'pending_review' != $resultCode) {
            WC_UseePay_Logger::log($_POST['transactionId'] . ', ' . $orderId . ' 支付订单非终态，忽略该异步通知');
            exit();
        }

        /**
         * 订单处于completed /processing 则不修改订单状态
         * Order status. Options: pending, processing, on-hold, completed, cancelled, refunded, failed and trash. Default is pending.
         */
        if ('pending' !== $order->status && 'on-hold' !== $order->status){
            return;
        }

        WC_UseePay_Logger::log($_POST['transactionId'] . ', ' . $orderId . ' received in notice.');
        if ($resultCode == "succeed") { // 支付成功
            $this->do_order_complete_tasks($order, $reference);
            echo 'OK';
        } else if ('failed' == $resultCode || 'closed' == $resultCode || 'cancelled' == $resultCode) {
            global $woocommerce;
            $order->update_status("failed");
            $woocommerce->cart->empty_cart();

            unset(WC()->session->get_session_data()['order_awaiting_payment']);
            echo 'OK';
        } else if ("pending_review" == $resultCode) {
           WC_UseePay_Logger::log($_POST['transactionId'] . ', ' . $orderId . ' pending_review');
           $this->do_order_on_hold_tasks($order, $orderId);
           echo 'ok';
        }
    }

    /**
     * Handle UseePay async notify for refund
     *
     * @access public
     * @return void
     */
    function refund_async_notify_handle()
    {
        $_POST                 = stripslashes_deep($_POST);
        $originalTransactionId = $_POST['originalTransactionId']; // 原交易订单号
        $order                 = wc_get_order($originalTransactionId);

        WC_UseePay_Logger::log($_POST['transactionId'] . ' refund notify response : ' . var_export($_POST, true));
        if (!Wc_UseePay_Util::verify_signature($_POST, $this->get_secret_key())) {
            WC_UseePay_Logger::log($_POST['reference'] . '	verify signature in refund notice failed!');
            return;
        }

        //处理返回结果
        $resultCode = $_POST['resultCode'];
        $errorCode  = $_POST['errorCode'];
        $errorMsg   = $_POST['errorMsg'];

        if ($resultCode == "succeed" && $errorCode == "0000") {
            $refund_amount = Wc_UseePay_Util::convert_useepay_price_to_woo_price($order->get_currency(), $_POST['amount'], 2);
            $order->add_order_note(
                sprintf('Credit card refund succeed;Refund ID: %s ; Refund Amount: %s', $_POST['reference'], $refund_amount)
            );
        } else {
            $errorMessage = $errorCode . "," . $errorMsg;
            $order->add_order_note(
                sprintf('Credit card refund failed;Refund ID: %s;errorMessage: %s', $_POST['reference'], $errorMessage)
            );
        }
    }

    function get_goods_name_desc($order)
    {

        // ini_set('display_errors', 1);
        // error_reporting(E_ALL & ~E_NOTICE);
        $result = array(
            "product_names"        => "",
            "product_descriptions" => ""
        );

        if (sizeof($order->get_items()) > 0) {
            foreach ($order->get_items() as $item) {
                if ($item['product_id'] > 0) {
                    if ($result["product_names"] != "") $result["product_names"] .= "|";
                    if ($result["product_descriptions"] != "") $result["product_descriptions"] .= "|";
                    $_product                       = $order->get_product_from_item($item);
                    $result["product_names"]        .= $_product->get_data()["name"];
                    $result["product_descriptions"] .= $_product->get_data()["description"];

                }
            }
        }
        //截断
        if (strlen($result["product_names"]) > 200) $result["product_names"] = mb_strcut($result["product_names"], 0, 256);
        if (strlen($result["product_descriptions"]) > 2000) $result["product_descriptions"] = mb_strcut($result["product_descriptions"], 0, 2000);

        //  var_dump($result);
        return $result;
    }

    function clean($str = '')
    {
        $clean = str_replace(array('%'), '', $str);
        $clean = sanitize_text_field($clean);
        $clean = html_entity_decode($clean, ENT_NOQUOTES);
        return $clean;
    }


    function wc_useepay_display_order_meta_for_admin($order)
    {
        $trade_no = get_post_meta($order->get_id(), 'UseePay Trade No.', true);
        if (!empty($trade_no)) {
            echo '<p><strong>' . __('UseePay Trade No.:', 'useepay') . '</strong><br />' . $trade_no . '</p>';
        }
    }

    function query_order_status()
    {
        WC_UseePay_Logger::log('Start to query order status with query parameters: ' . var_export($_GET, true));
        $order_id = $_GET['order_id'];
        $order    = wc_get_order($order_id);
        if ($order === false) {
            WC_UseePay_Logger::log('Query order status finished, ' . $order_id . ' not exist');
            exit(-1);
        } else {
            WC_UseePay_Logger::log('Query order status finished: ' . $order->get_status());
            exit($order->get_status());
        }
    }

    /**
	 * Sets transaction ID to the WC order.
	 *
	 * @param string               $transaction_id The transaction ID to set.
	 * @param WC_Order             $wc_order The order to set transaction ID to.
	 *
	 * @return bool
	 */
	protected function update_transaction_id(string $transaction_id, WC_Order $wc_order): bool {
		try {
			$wc_order->set_transaction_id( $transaction_id );
			$wc_order->save();

			$wc_order->add_order_note(
				sprintf(
					/* translators: %s is the Useepay transaction ID */
					__( 'Useepay transaction ID: %s', 'woocommerce-useepay-payments' ),
					$transaction_id
				)
			);

			return true;
		} catch ( Exception $exception ) {
			WC_UseePay_Logger::log('Failed to set transaction ID '.$transaction_id . $exception->getMessage());
			return false;
		}
	}

    protected function get_useepay_order_transaction_id( WC_Order $order ): ?string {
		return  substr($order->get_order_number() . '.' . md5(uniqid(microtime(true), true)), 0, 16);
	}
}

?>