I have been doing business related to WeChat some time ago. Although it is not a new technology, I have never had the opportunity to come into contact with it before. Then I stepped on some pitfalls and took the time to organize and record it.
There are 7 types of WeChat payment, including: payment code payment, JSAPI payment, Native payment, APP payment, H5 payment, mini program payment, and face payment.
WeChat JSAPI payment is used in this business: the user enters the merchant’s H5 page by scanning the QR code on WeChat, following the official account, etc., and calls JSSDK within WeChat to complete the payment.

Documentation: https://pay.weixin.qq.com/wiki/doc/api/index.html

SDK: [https://pay.weixin.qq.com/wiki/doc/api/micropay.php?chapter=11_1

](https://pay.weixin.qq.com/wiki/doc/api/micropay.php?chapter=11_1) JSAPI payment needs to be opened in the browser in WeChat to activate WeChat payment. The effect is as follows Attached interface code A template engine is used in the code html:


{$competition\['username'\]}
Note: 1 diamond = 1 yuan, 1 diamond = {$activity\['offset'\]} ticket

JavaScript:

// vote var offset = {$activity[‘offset’]}; $(’#tips’).html(‘Giving {$prices[0]} diamonds to {$competition[‘code’]} number=’+({$prices[0]}*offset)+‘ticket’); $(’#vote’).click(function(){ $.post(’/index/index/detailed.html?cid={$cid}&aid={$aid}’,{ formhash:’{FORMHASH}’, submit:‘1’, type:1, openid:’{$_G[‘member’][‘openid’]}’ },function(res){ alert(res.msg); if (res.code == 0) { $(’.box-1 span’).text(res.data.all); $(’.box-2 span’).text(res.data.rank); $(’.box-3 span’).text(res.data.up + ’ticket’); } }); }) /* jQuery object level plug-in extension */ $.fn.extend({ /* Radio button */ hlRadio: function () { var radioEl=$(this); radioEl.click(function () { var price = 0; price = $(‘input:radio:checked’).val(); $(’#price’).val(’’); $(’#tips’).html(‘Giving ‘+price+’ diamond=’+(price*offset)+‘ticket’ to {$competition[‘code’]} number); radioEl.siblings(“div”).removeClass(“active”); $(this).siblings(“div”).addClass(“active”); }); }, }); $(“input[name=‘price’]”).hlRadio(); $(’#price’).bind(‘input propertychange’, function(){ var price = 0; price = $(’#price’).val(); $(’#tips’).html(‘Giving ‘+price+’ diamond=’+(price*offset)+‘ticket’ to {$competition[‘code’]} number); })

CSS part

.ul_box { margin:0 auto; padding:0; list-style:none; width: 344px; } .ul_box>li { padding:10px 10px 0 10px; overflow:hidden; border-bottom:#e5e5e5 solid 1px; } .ul_box>li:last-child { border-bottom:none; } .ul_box>li>div { float:left; } .ul_box>li>div:nth-child(1) { width:100px; } .ul_box>li>div:nth-child(2) { width:480px; overflow:hidden; } .label_box>label { display:block; float:left; margin:0 10px 10px 0; position:relative; overflow:hidden; } .label_box>label>input { position:absolute; top:0; left:-20px; } .label_box>label>div { width:100px; text-align:center; border:#dddddd solid 1px; height:40px; line-height:40px; color:#666666; user-select:none; overflow:hidden; position:relative; height: 75px; } .label_box>label>div.active{ border:#d51917 solid 1px; background-color: #fff9f8; color:#d51917; } .label_box>label>div.active:after { content:’’; display:block; width:20px; height:20px; background-color:#d51917; transform:skewY(-45deg); position:absolute; bottom:-10px; right:0; z-index:1; } .label_box>label>div.active:before { content:’’; display:block; width:3px; height:8px; border-right:#ffffff solid 2px; border-bottom:#ffffff solid 2px; transform:rotate(35deg); position:absolute; bottom:2px; right:4px; z-index:2; } .input{ height: 75px!important; border: 1px solid #DDD!important; position: initial!important; width: 100px!important; text-align: center!important; padding: 5px!important; font-size: 19px!important; } .am-modal-bd{ border-bottom: none; margin-top: 20px; } .am-modal-bd img{ width: 50px; border-radius: 50px; } .am-icon-diamond{ font-size: 20px; display: block; text-align: center; margin-bottom: -7px; }

Invoke WeChat payment, the js code here only takes effect in the WeChat mobile browser

//Call WeChat JS api payment function jsApiCall(appId,timeStamp,nonceStr,package,signType,paySign) { WeixinJSBridge.invoke( ‘getBrandWCPayRequest’,{ “appId”:appId, //official account name, passed in by the merchant “timeStamp”:timeStamp, //Timestamp, number of seconds since 1970 “nonceStr”:nonceStr, //random string “package”:package, “signType”:signType, //WeChat signature method: “paySign”:paySign //WeChat signature }, function(res){ if(res.err_msg == “get_brand_wcpay_request:ok” ){ WeixinJSBridge.log(res.err_msg); alert(‘voting successful’); // window.history.go(-1); var url = ‘/index/index/detailed.html?cid={$cid}&aid={$aid}’; window.location.href=url; // location.reload(); return false; } alert(‘voting failed’); } ); } // pay function callpay() { var price = ‘’; if ($(’#price’).val()) { price = $(’#price’).val(); }else if($(‘input:radio:checked’).val()){ price = $(‘input:radio:checked’).val(); }else{ alert(‘Please enter the purchase quantity’); } if (Number(price) <= 0) { alert(‘Please enter a positive number greater than 0’); $(’#price’).val(’’); return false } $.post(’/index/index/weixin.html?cid={$cid}&aid={$aid}’,{ formhash:’{FORMHASH}’, submit:‘1’, type:1, pay:1, price: price, openid:’{$_G[‘member’][‘openid’]}’ },function(res){ if (res.code ==0) { jsApiCall( res.data.appId, res.data.timeStamp, res.data.nonceStr, res.data.package, res.data.signType, res.data.paySign, ); }else{ alert(res.msg); } }); // if (typeof WeixinJSBridge == “undefined”){ // if(document.addEventListener){ // document.addEventListener(‘WeixinJSBridgeReady’, jsApiCall, false); // }else if (document.attachEvent){ // document.attachEvent(‘WeixinJSBridgeReady’, jsApiCall); // document.attachEvent(‘onWeixinJSBridgeReady’, jsApiCall); // } // }else{ // } }

The interface is based on Meizi UI, the effect is as shown below PHP backend, create local order

//①. Get user openid $tools = new JsApiPay(); $openid = $tools->Getopenid(); //If it already exists, you can assign it directly //②, Unified order placement $input = new WxPayUnifiedOrder(); $input->SetBody(“Buy Diamond Ticket”); $input->SetAttach(json_encode([ //Additional parameters ‘order’ => $order_id, ‘cid’ => $cid, ‘uid’ => $_G[‘uid’], ‘aid’ => $aid, ‘md5’ => $md5 ])); $input->SetOut_trade_no(WxPayConfig::MCHID.date(“YmdHis”)); $input->SetTotal_fee($price); //Price, unit cent, “Yuan Remember*100” $input->SetTime_start(date(“YmdHis”)); $input->SetTime_expire(date(“YmdHis”, time() + 600)); $input->SetGoods_tag(“test”); $input->SetNotify_url(WX_NOTIFY_URL); $input->SetTrade_type(“JSAPI”); $input->Setopenid($openid); $order = WxPayApi::unifiedOrder($input); $jsApiParameters = $tools->GetJsApiParameters($order); //Save local order DB::insert(‘vote_order’, [ ‘order’ => $order_id, ’time’ => time(), ‘price’ => intval($_GET[‘price’]), ‘uid’ => $_G[‘uid’], ‘openid’ => $openid, ‘ip’ => $ip ]); Json([‘code’ => 0, ‘msg’ => ‘Success’,‘data’ => json_decode($jsApiParameters,true)]); //Get the shared delivery address js function parameters // $editAddress = $tools->GetEditAddressParameters(); //debug($jsApiParameters); //③. To handle matters after success in supporting successful callback notification, see notify.php /** * Notice: * 1. When your callback address is inaccessible, the callback notification will fail. You can confirm whether the payment is successful by querying the order. * 2. The user openid needs to be filled in when making jsapi payment. There is a process for obtaining the openid in WxPay.JsApiPay.php (for documents, please refer to the “Webpage Authorization Interface” of the WeChat public platform. * Refer to http://mp.weixin.qq.com/wiki/17/c0f37d5704f0b64713d5d2c37b468d75.html) */

SetReturn\_code("FAIL"); $this->SetReturn\_msg($msg); $this->ReplyNotify(false); return; } else { //This branch successfully calls back to the NotifyCallBack method, and the process is completed after the processing is completed. $attach = json\_decode($msg\['attach'\], true); // file\_put\_contents('aaaa.txt',print\_r($attach,true)); $cid = $attach\['cid'\]; $aid = $attach\['aid'\]; $uid = $attach\['uid'\]; $order = $attach\['order'\]; $md5 = $attach\['md5'\]; $vote\_order = DB::fetch\_first("SELECT \* FROM " . DB::table('vote\_order') . " WHERE \`order\`='{$order}' and status = 0"); if (!$vote\_order) { $this->SetReturn\_code("SUCCESS"); $this->SetReturn\_msg("OK"); } $sign\_md5 = md5($vote\_order\['openid'\] . $vote\_order\['order'\] . $vote\_order\['uid'\] ); if ($sign\_md5 == $md5) { //All activity information $activity = DB::fetch\_first("SELECT \* FROM " . DB::table('vote\_activity') . " WHERE aid={$aid} "); $ip = $vote\_order\['ip'\]; $jewel\_vote = $vote\_order\['price'\] \* $activity\['offset'\]; // vote DB::query("UPDATE \`pre\_vote\_competition\` SET \`jewel\`=jewel+{$vote\_order\['price'\]},jewel\_vote=jewel\_vote+{$jewel\_vote} WHERE (\`cid\`='{$cid}')"); //Add voting record DB::insert('vote\_record',\[ 'time' => TIMESTAMP, 'openid' => $vote\_order\['openid'\], 'type' => 1, 'aid' => $aid, 'cid' => $cid, 'ip' => $ip, 'price' => $vote\_order\['price'\], 'jewel\_vote' => $jewel\_vote, 'uid' => $uid, 'order' => $vote\_order\['order'\] \]); //Update order status DB::query("UPDATE \`pre\_vote\_order\` SET \`status\` = 1 WHERE \`order\`={$order}"); //Update total activity revenue DB::query("UPDATE \`pre\_vote\_activity\` SET \`profit\`=profit+{$vote\_order\['price'\]} WHERE \`aid\`={$aid}"); } $this->SetReturn\_code("SUCCESS"); $this->SetReturn\_msg("OK"); } $this->ReplyNotify($needSign); } /\*\* \* \* Callback method entry, subclasses can override this method \* Notice: \* 1. The WeChat callback timeout is 2s. It is recommended that users use asynchronous processing and reply to the WeChat server immediately after successful confirmation. \* 2. When the WeChat server fails to call or receives a non-confirmation packet, it will initiate a retry. Make sure that your callback can be re-entered. \* @param array $data Parameters interpreted by the callback \* @param string $msg If the callback processing fails, the error message can be output to this method \* @return true callback is completed and does not require continued callback; false callback processing is not completed and requires continued callback \*/ public function NotifyProcess($data, &$msg) { //TODO user base needs to rewrite this method in the future. It will return true when successful and false when failed. return true; } /\*\* \* \* notify callback method. Parameters that need to be assigned and output need to be assigned in this method and cannot be overridden. \* @param array $data \* @return true callback is completed and does not require continued callback; false callback processing is not completed and requires continued callback \*/ final public function NotifyCallBack($data) { $msg = "OK"; $result = $this->NotifyProcess($data, $msg); if ($result == true) { $this->SetReturn\_code("SUCCESS"); $this->SetReturn\_msg("OK"); } else { $this->SetReturn\_code("FAIL"); $this->SetReturn\_msg($msg); } return $result; } /\*\* \* \* Reply notification \* @param bool $needSign whether signature output is required \*/ final private function ReplyNotify($needSign = true) { //If signature is required if ($needSign == true && $this->GetReturn\_code($return\_code) == "SUCCESS") { $this->SetSign(); } WxpayApi::replyNotify($this->ToXml()); } } Callback class call Handle(false); Note: WeChat Pay needs to configure a WeChat Payment authorization directory in the background, and the APPID and other parameters can be obtained in the WeChat Payment background. WeChat public account information configuration APPID: APPID bound to payment (must be configured, can be viewed in the account opening email) MCHID: Merchant ID (must be configured, can be viewed in the account opening email) KEY: Merchant payment key, refer to account opening email settings (must be configured, log in to the merchant platform to set it yourself) Set address: https://pay.weixin.qq.com/index.php/account/api\_cert APPSECRET: public account secert (only required for JSAPI payment, log in to the public platform and enter the developer center to set), Obtain address: https://mp.weixin.qq.com/advanced/advanced?action=dev&t=advanced/dev&token=2005451881&lang=zh\_CN ![](https://image.baidu.com/search/down?url=https://tva1.sinaimg.cn//large/0072Vf1pgy1g1l464jxqtj30qm0isgn0.jpg)