前言
前一段时间,分享了如何使用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商城第四方支付插件