WooCommerce对接第三方支付插件开发

2023-11-17 14:05:00 浏览数 (3)

前言

前一段时间,分享了如何使用wordpress快速搭建一个电商独立站。没有对接支付系统,其实像主流的如支付宝,或者微信有成熟的插件可用。但一些小的三方支付通道,只有接口文档。没有插件,那就只能自己折腾了。照的网上的资料和官方文档,依葫芦画瓢终于搞出来了,特此记录。

参考:使用WooCommerce支付网关 API 创建自定义支付网关的方法

支付流程

主要模块

请求上游接口

process_payment($order_id) -> receipt_page($order) -> generate_form($order)

process_payment(), woocommerce发起支付动作函数

代码语言:javascript复制
      function process_payment($order_id)
                {
                        $order = new WC_Order($order_id);
                        //$current_version = get_option( 'woocommerce_version', null );
                        //error_log($current_version);

                        return array
                        (
                            'result' => 'success',
                            'redirect'  => esc_url_raw(add_query_arg('order-pay', $order->get_id(), add_query_arg('key', $order->get_order_key(), wc_get_page_permalink( 'checkout' ))))
                        );
                }

receipt_page(),订单支付前准被页面函数

代码语言:javascript复制
        function receipt_page($order)
                {
                        echo ''.__('Thank you for your order, please click the button below to pay.', 'superxpay-for-woocommerce').'';
                        //error_log($_SERVER['HTTP_REFERER']);

                        //解决函数被调用2次的问题
                        if ( strpos($_SERVER['HTTP_REFERER'], 'order-pay') === false ) {
                                echo $this->generate_form($order);
                        }
                }

generate_form(),订单参数准备函数,请求上游接口,获取支付链接

代码语言:javascript复制
    public function generate_form($order_id)
        {
            global $woocommerce, $wpdb;
                    $order = new WC_Order( $order_id );

            $curl_api   = "https://payment.superxpay.com/api/pay/SuperXPay";

            $mref = "REF".substr(md5(uniqid(rand(), true)), 0, 9);

            $current_version = get_option( 'woocommerce_version', null );

                    define( 'WOOCOMMERCE_CHECKOUT', true );
                    WC()->cart->calculate_totals();
                    $amountcents = round($order->get_total() * 100);
                    $charge = number_format($order->get_total(), '2', '.', '');

                    if($amountcents==0){
                        $order_id = wc_get_order_id_by_order_key($_GET['key']);
                        $order    = wc_get_order( $order_id );
                        $amountcents = round($order->get_total() * 100);
                        $charge = number_format($order->get_total(), '2', '.', '');
                    }

            $MerchantNo  =  $this->superxpay_merchantno;
                    $private_key =   html_entity_decode($this->superxpay_merchantkey);
            $ChannelType  =  $this->superxpay_channeltype;
            $PayWay  =  $this->superxpay_payway;

                    $customer_mail = $order->get_billing_email();

            $currency_symbol ='';
                    $currency_code = get_woocommerce_currency();
                    switch ($currency_code) {
                        case 'USD':
                            $currency_symbol = 2;
                            break;
                        case 'SGD':
                            $currency_symbol = 9;
                            break;
                        default:
                            $currency_symbol = 2;
                    }

            //基本url
                        $base_url = esc_url( home_url( '/' ));

            //同步回调url
            $return_url = WC()->api_request_url( 'wc_superxpay_return' ) ;
            $check = strpos($return_url, '?');
            if ( $check !== false) {
                $return_url = $return_url . "&mref=" . $mref;
            } else {
                $return_url = $return_url . "?mref=" . $mref;
            }

            //构造提交参数
                        $Body = array(
                            "MerchantNo"         => $MerchantNo,
                            "OutTradeNo"         => $mref,
                            "ChannelType"        => $ChannelType,
                            "CurrencyType"       => $currency_symbol,
                            "Amount"             => $amountcents,      // 分
                            "Body"               => $customer_mail,
                            "NotifyUrl"          => WC()->api_request_url( 'wc_superxpay_notify' ),   //异步,注意去掉  woocommerce_api_
                            "ReturnUrl"          => $return_url,   //同步回调地址
                            "Attach"             => "",
                            "Remark"             => "",
                            "TransData"          => "{ "PayWay": "" . $PayWay . ""}",
                        );

                        $checksum = md5($Body['Amount'] . '&' . $Body['Body'] . '&' . $Body['ChannelType'] . '&' . $Body['CurrencyType'] . '&' . $Body['MerchantNo'] . '&' . $Body['NotifyUrl'] . '&' . $Body['OutTradeNo'] . '&' . $Body['TransData'] . '&' . $private_key);

                        $Body["Sign"] = $checksum;

            //打印参数
            error_log(__METHOD__ . PHP_EOL .print_r($Body, true));

            //构建提交变量
            $args = array(
                                'timeout'     => 45,
                                'redirection' => 5,
                                'httpversion' => '1.0',
                                'blocking'    => true,
                                'body'        => $Body,
                        );

            //php打印调用堆栈
            /*
            $tracelog = '';
            $array =debug_backtrace();
            unset($array[0]);
               foreach($array as $row)
                {
                       $tracelog .= $row['file'].':'.$row['line'].'行,调用方:'.$row['function']."n";
                }
            error_log($tracelog);
            */

            $postRequest = wp_remote_post($curl_api, $args);

            if ($postRequest['response']['code'] === 200) {
                        $result = json_decode($postRequest['body'], true, 512, JSON_BIGINT_AS_STRING);
                    } else {
                        error_log(__METHOD__ . PHP_EOL . 'Code:' . $postRequest['response']['code'] . PHP_EOL. ' Error:' . $postRequest['response']['message']);

                        throw new Exception("Unable to reach Viva Payments (" . $postRequest['response']['message'] . ")");
                    }

            error_log(__METHOD__ . PHP_EOL .print_r($result, true));

                    if ($result['Code'] === 1000) {
                            $OrderNo = $result['Data']['OrderNo'];
                   $PayUrl = $result['Data']['ResultCode'];
                    } else {
                            throw new Exception("Unable to create order code (" . $result['Msg'] . ")");
                    }

                    $query = "insert into {$wpdb->prefix}superxpay_data (ref, ordercode, email, orderid, total_cost, currency, order_state, timestamp) values ('".$mref."', '".$OrderNo."','". $customer_mail ."','". $order_id . "',$amountcents,'978','I', now())";
                    $wpdb->query($query);

                return
                        ''."n".
                        ''.__('Pay Now', 'superxpay-for-woocommerce').''."n".
                ''.__('Cancel', 'superxpay-for-woocommerce').''."n".
                        '';
        }

异步回调接口

接收上游渠道的通知,更新订单状态。

代码语言:javascript复制
    function check_ipn_response()
        {
            global $woocommerce, $wpdb;

            if (($_SERVER['REQUEST_METHOD'] === 'POST') && preg_match("/wc_superxpay_notify/i", $_SERVER['REQUEST_URI'])) {
                $response = file_get_contents("php://input");
                error_log(__METHOD__ . PHP_EOL .print_r($response, true));

                if ( $response ) {
                    $res_data = json_decode($response, true, 512, JSON_BIGINT_AS_STRING);
                    $private_key =   html_entity_decode($this->superxpay_merchantkey);
                    $statustr = $this->superxpay_processing;

                                $checksum = md5($res_data['OrderNo'] . '&' . $res_data['MerchantNo'] . '&' . $res_data['Amount'] . '&' . $res_data['OutTradeNo'] . '&' . $res_data['Status'] . '&' . $private_key);

                    //error_log($checksum);
                    //error_log($res_data['Sign']);

                    if ($checksum == $res_data['Sign']) {
                        $tm_ref = $res_data['OutTradeNo'];
                        $check_query = $wpdb->get_results("SELECT orderid,order_state FROM {$wpdb->prefix}superxpay_data WHERE ref = '".addslashes($tm_ref)."'", ARRAY_A);
                                       $check_query_count = count($check_query);

                        //error_log("SELECT orderid,order_state FROM {$wpdb->prefix}superxpay_data WHERE ref = '".addslashes($tm_ref)."'");
                        //error_log($check_query_count);
                        if( $check_query_count >= 1 ) {
                            if($check_query[0]['order_state'] == 'I' && $res_data['Status'] == '1') {
                                $query = "update {$wpdb->prefix}superxpay_data set order_state='C' where ref='".addslashes($tm_ref)."'";
                                                $wpdb->query($query);

                                $inv_id = $check_query[0]['orderid'];
                                                $order = new WC_Order($inv_id);
                                $order->update_status($statustr, __('Order has been paid by ID: ' . $res_data['OrderNo'], 'superxpay-for-woocommerce'));
                                wc_reduce_stock_levels( $order->get_id() );
                                add_post_meta( $inv_id, '_paid_date', current_time('mysql'), true );
                                update_post_meta( $inv_id, '_transaction_id', wc_clean($tm_ref) );

                                $order->payment_complete(wc_clean($tm_ref));
                                                $woocommerce->cart->empty_cart();
                            }
                        }

                    }
                }
                //接口返回
                exit("SUCCESS");
            }

        }

同步接口处理逻辑

从上游渠道返回后,逻辑处理页面。比如支付成功,跳转到结果页。支付失败,跳转到支付重新发起页。

代码语言:javascript复制
    function check_superpay_return()
        {
            global $woocommerce, $wpdb;
            //error_log($_SERVER['REQUEST_URI']);
            if (($_SERVER['REQUEST_METHOD'] === 'GET') && preg_match("/wc_superxpay_return/i", $_SERVER['REQUEST_URI'])) {
                error_log(__METHOD__ . PHP_EOL .print_r($_GET, true));
                $tm_ref = $_GET['mref'];
                error_log($tm_ref);
                $check_query = $wpdb->get_results("SELECT orderid,order_state FROM {$wpdb->prefix}superxpay_data WHERE ref = '".addslashes($tm_ref)."'", ARRAY_A);
                $check_query_count = count($check_query);
                if($check_query_count >= 1){
                    $inv_id = $check_query[0]['orderid'];
                    $inv_state = $check_query[0]['order_state'];
                    switch ( $inv_state ) {
                        case 'C':
                            $order = new WC_Order($inv_id);
                             wp_redirect(esc_url_raw(add_query_arg('key', $order->get_order_key(), add_query_arg('order-received', $inv_id, $this->get_return_url($order)))));
                        break;
                        default:
                        wp_redirect( wc_get_cart_url() );
                    }
                    exit;
                }
            }
            wp_redirect(home_url());
        }

FAQ

请求上游接口,函数被调用2次的问题

找了很多的问题,也没找到办法解决。最后发现两次的$_SERVER['HTTP_REFERER']不同,加了一个判断解决。

代码语言:javascript复制
if ( strpos($_SERVER['HTTP_REFERER'], 'order-pay') === false ) {
    echo $this->generate_form($order);
}

checkout页面自动跳转

代码语言:javascript复制
 wc_enqueue_js('
                setInterval(function(){
                            $.blockUI({
                            message: "' . esc_js(__('Thank you for your order. We are now redirecting you to superxpay to make payment.', 'superxpay-for-woocommerce')) . '",
                            baseZ: 99999,
                            overlayCSS:
                            {
                            background: "#fff",
                            opacity: 0.6
                            },
                            css: {
                            padding:        "20px",
                            zindex:         "9999999",
                            textAlign:      "center",
                            color:          "#555",
                            border:         "3px solid #aaa",
                            backgroundColor:"#fff",
                            cursor:         "wait",
                            lineHeight:     "24px",
                            }
                            });
                    var start = new Date().getTime();
                    while (new Date().getTime() < start   1000);
                    document.getElementById("submit_superxpay_payment_button").click();
                },1000);
            ');

完整项目代码

wordpress商城第四方支付插件

0 人点赞