Micro-channel payment distinguish

First:  JSAPI pay      https://pay.weixin.qq.com/wiki/doc/api/jsapi.php?chapter=7_1

Usage scenarios: JSAPI merchant payment means through micro-channel interface call JSAPI payment provider, the payment scenario invoking micro-channel module to complete the payment collection

Example A: Example B next line: No public scene C: PC websites scene

           A:                              B:      C:                        

 

 

 

 JSAPI payment instructions  

<?php
namespace App\Http\Controllers\Api;

use App\Api\Helpers\MoveNumber;
use App\Http\Controllers\Controller;
use App\Http\Middleware\ApiLog;
use App\Models\MShopOrders;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Validator;
use EasyWeChat\Factory;

/**
 * Orders
 *
 */
class NotifyController extends Controller {
    MoveNumber use;
    /**
     * Callback pay
     *
     */
    public function notify_wx()
    {
        writeLogs ([], 'has entered into the micro channel callback', 'notify'); // write log records
        $notify_data = file_get_contents("php://input");
        $notify_data = $this->from_xml($notify_data);
        writeLogs ($ notify_data, 'call back return data', 'notify'); // write log records
        if (!$notify_data) {
            writeLogs ($ notify_data, 'message is not received', 'notify'); // write log records
            $notify_data = $GLOBALS['HTTP_RAW_POST_DATA'] ?: '';
        }
        // Check test
        $return_data = $this->query_weixin_sign($notify_data);
        if (!$return_data) {
            writeLogs ($ notify_data, 'check failed test', 'notify'); // write log records
            echo 'fail';
            the;
        }
        writeLogs ($ notify_data, '- stamped by', 'notify'); // write log records

        if ($notify_data['return_code'] == 'SUCCESS' && $notify_data['result_code'] == 'SUCCESS') {
            $order_id = $notify_data['out_trade_no'];
            $check_data = MShopOrders::where(['order_sn' => $order_id])->first();
            if ($check_data['status'] == 0) {
                // transaction open
                DB::beginTransaction();
                try {
                    // Change Order Status
                    $result = MShopOrders::where(['order_sn' => $order_id])->update(['status'=> 1]);
                    if ( !$result ) {
                        DB::rollBack();
                    }
                    // Create Order No. camped
                    $move_order_id = $this->make_phone_order($order_id);
                    if ( $move_order_id == -1 ) {
                        DB::rollBack();
                        throw new \ LogicException ( 'account numbers to create a pre-order failed', 201);
                    }
                    // camped No. successfully updated order data
                    $res = MShopOrders::where(['order_sn' => $order_id])->update(['order_operator'=> $move_order_id]);
                    if ( !$res ) {
                        DB::rollBack();
                        throw new \ LogicException ( 'camped update number order failed', 202);
                    }
                    DB::commit();
                    echo 'success';
                    the;
                } catch (\Exception $e) {
                    writeLogs ($ notify_data, "pay callback update fails, the failure code:" $ e-> getCode () ", failed msg:"... $ e-> getMessage (), 'notify'); // write log records
                    DB::rollBack();
                    echo 'fail';
                    the;
                }
            }
            echo "success";
            the;
        }
    }

    /**
     * Generate signature - override this method
     * @Param array $ data configuration object
     *
     * @return float
     */
    public function query_weixin_sign($data)
    {
        $wxconfig = config("wechat.payment.default");
        // Signature Step 1: Pressing lexicographical sort parameter
        ksort($data);
        $checkSign = $data['sign'];
        unset($data['sign']);
        $string = $this->to_url_params($data);
        // Signature Step two: Add after the string KEY
        $string = $string . "&key=".$wxconfig['key'];
        // Signature Step three: MD5 or HMAC-SHA256 encryption
        if(strlen($checkSign) <= 32){
            // If the signature is less than or equal to 32, is used to verify md5
            $string = md5($string);
        } else {
            // check with sha256
            $string = hash_hmac("sha256",$string ,$wxconfig['key']);
        }
        // Signature Step four: all characters to uppercase
        $result = strtoupper($string);
        writeLogs ([ 'sign' => $ result, 'checksign' => $ checkSign], 'callback data signature verification', 'notify'); // write log records
        if($result == $checkSign) {
            return true;
        } else {
            return false;
        }
    }

    public function from_xml($xml)
    {
        if (!$xml) {
            echo "xml data exception!";
        }
        // will be converted to XML xml array prohibit references to external entities
        libxml_disable_entity_loader(true);
        $data = json_decode(json_encode(simplexml_load_string($xml, 'SimpleXMLElement', LIBXML_NOCDATA)), true);
        return $data;
    }

    /**
     * Url parameter formatted into formatting parameters
     * @Param array $ datas parameters
     *
     * @return string
     */
    private function to_url_params($datas)
    {
        $buff = "";
        foreach ($datas as $k => $v) {
            if ($k != "sign" && $v != "" && !is_array($v)) {
                $buff .= $k . "=" . $v . "&";
            }
        }
        $buff = trim($buff, "&");
        return $buff;
    }
}

  

First, the use of scenarios and descriptions

     Usage scenarios: merchant has H5 mall site, the user via a message or two-dimensional code scanning when you open the page in the micro letter, you can call micro-channel flow to complete a single purchase payment under.

 Description: a graphic user opens the message or scanning two-dimensional code, the payment open pages in the micro channel built-in browser.

     JSAPI 2. By using the micro-business web front end provided by letter, call micro-channel payment module. In this way, the need for purchase orders for the purchase process in the business page.

Second, prepare for work

No public needs to pay in advance in micro-channel public platform service configuration, including setting up payment authorization directory , testing paid directories and white list , set the JS port security domain and set the authorization callback page domain .

1. Before the public micro-channel payment, we need to apply for a public number, and feature requests micro-channel pay.

 

2. The payment authorization directory:

Location: micro-channel pay -> Development Configuration -> number of public pay

1) All numbers using public payment initiate a payment request link address, have to be paid under the authority of the directory;

2) the official payment authorization set up to three directory, set up to test an authorized directory, and the domain name must be filed by ICP; == "Up to now (2017.11.15) the payment authorization directory settings have been moved to

Merchant platform -> Products -> Development configuration (? Portal: https: //pay.weixin.qq.com/wiki/doc/api/jsapi.php chapter = 7_3), and can set up to five simultaneously table of Contents

Directory Example:

      ||||||||     If no authorization directory or not, when the phone calls micro-channel jsapi error :  

 

 

3) header to include http or https, and must be refined to a secondary or tertiary directory, "/" slash the left end.

Business page address in initiating the payment must be under the authority of the directory, otherwise it will prompt "the current page URL is not registered" when calling the single interface.

 

 

Here again long-winded to add two points:

1) without the use of the framework, such as the official sdk download, into the root directory on the demo, demo / example / jaspi.php, authorize catalog refer to http: // www ××× .com / demo. / example /

2) the case of using the framework, such ThinkPHP, named Test item, directory structure, test / Application / Home / controller / WxpayController.class.php, authorized directory may refer to http: // www ××× .com /. index.php / Home / Wxpay /

 

3. JS interface security domain:

Location: micro-channel pay -> Public No. Settings -> Feature Settings -> JS interface security domain

Description: After setting JS port security domain, the public can call the numbers developer of JS WeChat open interfaces in this domain.

Precautions:

1) domain can fill three, or more than one requirement is a domain name (for example: qq.com, or www.qq.com), need to use letters, numbers, and "-" combination, do not support IP address and port number;

2) Fill in the domain name must be verified by ICP record;

3) modify and save up to three times within a calendar month.

 

4. Authorizes callback page :( domain name must be used to pay jsapi)

Location: micro-channel pay -> Interface Permissions -> Web users authorized to obtain basic information

用户在网页授权页同意授权给公众号后,微信会将授权数据传给一个回调页面,回调页面需在此域名下,以确保安全可靠。

注意事项:

1) 回调页面域名需使用字母、数字及“-”的组合,不支持IP地址及端口号。填写的域名需与实际回调URL中的域名相同;

2) 填写的域名须通过ICP备案的验证。

获取用户授权时redirect_uri对应的URL必须在此域名下,否则回调的地址会无法打开。

 

 

 

三、开发步骤

说明:整个微信公众号支付的流程如下:

【1】用户点击公众号内微信商城打开H5的支付页面

【2】H5页面通过JS调用微信支付接口

【3】微信服务器通过判断输入的JSON数据,返回给客户端相应的成功或失败信息

官方demo结构如下:

 

1.JSAPI支付——H5网页端调起支付接口 

1)用户同意授权,获取code

请求链接:https://open.weixin.qq.com/connect/oauth2/authorize?appid=APPID&redirect_uri=REDIRECT_URI&response_type=code&scope=SCOPE&state=STATE#we-chat_redirect

 

 

2)如果有code,直接就通过code能获取用户openid

如果没有code,通过createOauthUrlForCode方法,传入必要参数,获取code

3)如果用户同意授权,页面将跳转至 redirect_uri/?code=CODE&state=STATE。

若用户禁止授权,则重定向后不会带上code参数,仅会带上state参数

redirect_uri?state=STATE

4)code说明以及scope的两种方式说明

【1】code作为换取access_token的票据,每次用户授权带上的code将不一样,code只能使用一次,5分钟未被使用自动过期。

这里获取到code 和 state(订单号) 后, 对订单进行验证,用户余额也进行验证,如果条件都满足则才能进行下面的流程。

【2】scope的两种方式说明:

微信提供了两种授权方式:snsapi_base和snsapi_userinfo。

snsapi_base:不弹出授权页面,直接跳转,只能获取用户openid;

snsapi_userinfo:弹出授权页面,可通过openid拿到昵称、性别、所在地。并且,即使在未关注的情况下,只要用户授权,也能获取其信息。

想要获取code,需要构造如下地址:

2. 通过code换取网页授权access_token (这里也获取到了openid)

1)请求链接:https://api.weixin.qq.com/sns/oauth2/access_token

?appid=APPID&secret=SECRET&code=CODE&grant_type=authorization_code

 

 

2)获取openid:openid是微信支付jsapi支付接口必须的参数

【1】如果网页授权的作用域为snsapi_base(静默授权),则本步骤中获取到网页授权access_token的同时,也获取到了openid,snsapi_base式的网页授权流程即到此为止。

【2】如果网页授权作用域为snsapi_userinfo,则此时开发者可以通过access_token和openid拉取用户信息了。

 

 

3)getOpenid方法中调用createOauthUrlForOpenid方法获取openid

3. 调用统一支付接口获取预付款id (这里有个小技巧:你如果直接把表单提交到这里,那就傻逼了。 你的服务器会和微信服务器交互2次,等拿到openid,你提交的数据早就被刷掉了,你可以把它放在session或者缓存里面,然后重定向到下面这个页面,等拿到openid后再从session里面拿数据。

官方文档说明:https://pay.weixin.qq.com/wiki/doc/api/jsapi.php?chapter=9_1

1) 设置必传参数,按照签名参数产生签名, 此时参与签名字段有 : appid, mch_id , nonce_str, openid, body , out_trade_no, total_fee, notify_url , trade_type

2) 将必传参数转成xml,createXml方法。

3) 使用xml,请求统一支付接口 https://api.mch.weixin.qq.com/pay/unifiedorder

4) 得到xml格式的返回值结果

5) 将结果转成数组,获取预支付id

4. 使用jsapi调起支付

1. 通过getParameters方法设置必传参数,接口输入数据为json

2. 根据官方demo中jsapi.php 调起支付,得到支付结果

 

注:使用以上方式判断前端返回,res.err_msg 将在用户支付成功后返回 ok,但不保证它绝对可靠。

 

四、可能遇到的问题

1. 返回参数是xml,而不是直接输出success ,这个与微信app支付有区别。

2. 参与签名字段要保证一致,保证前后签名一样。

3. 由于存在重新发送后台通知的情况,因此同样的通知可能会多次发送给商户系统。商户系统必须能够正确处理重复的通知。比如在支付成功后写入了支付日志,那么第二次回调前前判断是否已经有了支付日志,如果有,直接退出不作处理就好了。

4 . 当用户有余额,先用余额支付,剩下的才是微信 , 支付成功时,回调扣去余额

5. 如果同一笔订单号修改多次价格进行支付,第二次支付时,会出现生成预支付订单失败,主要原因是同一笔订单支付时,支付金额不能一样,或者给到第三方的订单号不一样,所以解决方法就是订单号+标志位(比如Z或A)+ 时间戳生成给到的第三方的支付号即可。

Guess you like

Origin www.cnblogs.com/liyanxi/p/12059125.html