第三方支付
前言
前一段时间,分享了如何使用wordpress快速搭建一个电商独立站。没有对接支付系统,其实像主流的如支付宝,或者微信有成熟的插件可用。但一些小的三方支付通道,只有接口文档。没有插件,那就只能自己折腾了。照的网上的资料和官方文档,依葫芦画瓢终于搞出来了,特此记录。参考:使用WooCommerce支付网关 API 创建自定义支付网关的方法
支付流程
支付流程主要模块
类的初始化什么的比较简单,按照官方文档很快就写好了,主要是请求上游接口,异步回调,同步回调逻辑。
请求上游接口
process_payment($order_id) -> receipt_page($order) -> generate_form($order)process_payment(), woocommerce发起支付动作函数functionprocess_payment($order_id){$order=newWC_Order($order_id);//$current_version = get_option( woocommerce_version, null );//error_log($current_version);returnarray(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(),订单支付前准被页面函数functionreceipt_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(),订单参数准备函数,请求上游接口,获取支付链接publicfunctiongenerate_form($order_id){global$woocommerce,$wpdb;$order=newWC_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){caseUSD:$currency_symbol=2;break;caseSGD:$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]);thrownewException("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{thrownewException("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
;}
异步回调接口
接收上游渠道的通知,更新订单状态。check_ipn_response()functioncheck_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=newWC_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");}}
同步接口处理逻辑
从上游渠道返回后,逻辑处理页面。比如支付成功,跳转到结果页。支付失败,跳转到支付重新发起页。check_superpay_return()functioncheck_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){caseC:$order=newWC_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]不同,加了一个判断解决。if(strpos($_SERVER[HTTP_REFERER],order-pay)===false){echo$this->generate_form($order);}
文章评论