銀聯(lián)支付

銀聯(lián)支付

商戶入駐

1. 填寫商戶基礎(chǔ)信息

2. 提交信息后,跳轉(zhuǎn)銀聯(lián)簽約頁面完成簽約

3. 簽約完成后,如果是對公賬戶,需要等待銀聯(lián)打款(交易附言可能會有交易碼),在完成對公賬戶打款驗證

4. 等待銀聯(lián)審核完成,下發(fā)商戶號

支付

主從商戶模式

  • 支付寶

    • APP支付

      • 通過APP支付接口下單,成功后得到支付要素(js串),通過在APP內(nèi)集成銀聯(lián)提供的SDK,吊起APP支付

        • 支付成功后回調(diào)下單時上送的回調(diào)地址,進(jìn)行對應(yīng)回調(diào)處理
    • 生活窗支付

      • 下單后,得到支付要素,通過支付要素、單號,在瀏覽器中跳轉(zhuǎn)到自己的收銀頁面,調(diào)起支付寶收銀臺

        <html>
        <head>
            <meta http-equiv="Content-Type" content="text/html; charset=GBK">
            <title>跳轉(zhuǎn)支付中...</title>
            <meta name="viewport" content="width=device-width, initial-scale=1, user-scalable=0">
            <script src="<?php echo env('WEB_SERVER');?>/web/js/jquery.min.js" type="text/javascript"></script>
            <script>
                var tradeNo = <?php echo json_encode($tradeNo);?>;
                var return_url = '<?php echo $return_url;?>';
                // 調(diào)試時可以通過在頁面定義一個元素,打印信息,使用alert方法不夠優(yōu)雅
                function log(obj) {
                    $("#result").append(obj).append(" ").append("<br />");
                }
        
                $(document).ready(function(){
                    // 頁面載入完成后即喚起收銀臺
                    // 此處${tradeNO}為模板語言語法,實際調(diào)用樣例類似為tradePpay("2016072621001004200000000752")
                    tradePay(tradeNo);
        
                    // 點擊payButton按鈕后喚起收銀臺
                    $("#payButton").click(function() {
                        tradePay(tradeNo);
                    });
        
                    // 通過jsapi關(guān)閉當(dāng)前窗口,僅供參考,更多jsapi請訪問
                    // /aod/54/104510
                    $("#closeButton").click(function() {
                        AlipayJSBridge.call('closeWebview');
                    });
                });
        
                // 由于js的載入是異步的,所以可以通過該方法,當(dāng)AlipayJSBridgeReady事件發(fā)生后,再執(zhí)行callback方法
                function ready(callback) {
                    if (window.AlipayJSBridge) {
                        callback && callback();
                    } else {
                        document.addEventListener('AlipayJSBridgeReady', callback, false);
                    }
                }
        
                function tradePay(tradeNO) {
                    ready(function(){
                        // 通過傳入交易號喚起快捷調(diào)用方式(注意tradeNO大小寫嚴(yán)格)
                        AlipayJSBridge.call("tradePay", {
                            tradeNO: tradeNO
                        }, function (data) {
                            if ("9000" == data.resultCode) {
                                log("支付成功");
                                window.location.href=return_url;
                            }
                        });
                    });
                }
            </script>
        </head>
        <body>
            <p id="result">result: </p>
        </body>
        </html>
        
        • 支付成功后回調(diào)下單時上送的回調(diào)地址,進(jìn)行對應(yīng)回調(diào)處理
    • H5支付

      • 下單后,得到一個url,在瀏覽器中跳轉(zhuǎn)后,會調(diào)起手機支付寶APP

        • 支付成功后回調(diào)下單時上送的回調(diào)地址,進(jìn)行對應(yīng)回調(diào)處理
  • 微信

    • APP支付

      • 通過APP支付接口下單,成功后得到支付要素(js串),通過在APP內(nèi)集成銀聯(lián)提供的SDK,吊起APP支付

        • 支付成功后回調(diào)下單時上送的回調(diào)地址,進(jìn)行對應(yīng)回調(diào)處理
    • 公眾號支付

      • 下單后,得到支付要素,通過支付要素、單號,在微信客戶端內(nèi)跳轉(zhuǎn)到自己的收銀頁面,調(diào)起微信收銀臺
        <html>
        <head>
            <meta http-equiv="Content-Type" content="text/html; charset=GBK">
            <title>跳轉(zhuǎn)支付中...</title>
            <meta name="viewport" content="width=device-width, initial-scale=1, user-scalable=0">
            <script src="<?php echo env('WEB_SERVER');?>/web/js/jquery.min.js" type="text/javascript"></script>
            <script>
                var json = <?php echo json_encode($data);?>;
                var return_url = '<?php echo $return_url;?>';
                $(function(){
                    onBridgeReady(json);
                });
        
                function onBridgeReady(content){
                    WeixinJSBridge.invoke(
                        'getBrandWCPayRequest', content,
                        function(res){
                            if(res.err_msg == "get_brand_wcpay_request:ok" )
                            {
                                window.location.href=return_url;
                            }     // 使用以上方式判斷前端返回,微信團(tuán)隊鄭重提示:res.err_msg將在用戶支付成功后返回    ok,但并不保證它絕對可靠。
                        }
                    );
                }
                if (typeof WeixinJSBridge == "undefined"){
                    if( document.addEventListener ){
                        document.addEventListener('WeixinJSBridgeReady', function(){
                            onBridgeReady(json)
                        }, false);
                    }else if (document.attachEvent){
                        document.attachEvent('WeixinJSBridgeReady',  function(){
                            onBridgeReady(json)
                        });
                        document.attachEvent('onWeixinJSBridgeReady',  function(){
                            onBridgeReady(json)
                        });
                    }
                }else{
                    onBridgeReady(json);
                }
            </script>
        </head>
        <body>
        </body>
        </html>
        ```
      
          - 支付成功后回調(diào)下單時上送的回調(diào)地址,進(jìn)行對應(yīng)回調(diào)處理
      
      
    • 小程序支付

  • 銀聯(lián)

    • B掃C支付(條碼支付)
    • C掃B支付(主動掃碼支付)

獨立商戶模式

  • 支付寶

    • APP支付
    • 生活窗支付
    • H5支付
  • 微信

    • APP支付
    • 公眾號支付
    • 小程序支付
  • 銀聯(lián)

    • B掃C支付(條碼支付)
    • C掃B支付(主動掃碼支付)

結(jié)算

自動清分

  • 在商戶進(jìn)件時,設(shè)置好清分比例,每筆訂單支付成功后,銀聯(lián)按設(shè)置比例自動清分

指令清分

  • 每日通過上送清分指令文件到銀聯(lián)SFTP服務(wù)器,告訴銀聯(lián)每筆訂單如何進(jìn)行分賬

對賬

每天14點以后,銀聯(lián)將前一日的訂單對賬文件推送至服務(wù)器,用戶通過SFTP方式,到銀聯(lián)服務(wù)器下載每日的對賬文件

部分代碼

<?php
/**
 * Created by PhpStorm.
 * User: isesame
 * Date: 2019/11/05
 * Time: 19:08
 * 銀聯(lián)支付服務(wù)
 */

namespace App\Http\Services\PayClass;

use App\Http\Services\BaseService;
use App\Http\Services\Params\ChinaUMSPay\Exceptions\CurlException;
use App\Http\Services\Params\Params;


class ChinaUMSPayService extends BaseService
{

  public $notifyUrl; //支付回調(diào)地址

  public function __construct()
  {
    $this->notifyUrl = env('WEB_SERVER').'/chinaums/pay/getNotify';
  }

  public function getAuthorization($content)
  {
    $arr['appId'] = config('chinaumspay.AppId');
    $arr['timestamp'] = date('YmdHis');//yyyyMMddHHmmss
    $arr['nonce'] = md5(uniqid(microtime(true),true));
    $arr['content'] = json_encode($content);
    $strA=bin2hex(hash('sha256', $arr['content'], true));
    $appKey = config('chinaumspay.AppKey');

    $signature = base64_encode(hash_hmac('sha256',$arr['appId'].$arr['timestamp'].$arr['nonce'].$strA, $appKey, true));
    $Authorization="OPEN-BODY-SIG AppId=\"".$arr['appId']."\", Timestamp=\"".$arr['timestamp']."\", Nonce=\"".$arr['nonce']."\", Signature=\"".$signature."\"";
    return $Authorization;
  }

  public function getH5Authorization($content)
  {
    $arr['appId'] = config('chinaumspay.AppId');
    $arr['authorization'] = 'OPEN-FORM-PARAM';
    $arr['timestamp'] = date('YmdHis');//yyyyMMddHHmmss
    $arr['nonce'] = md5(uniqid(microtime(true),true));
    $arr['content'] = json_encode($content);
    $strA=bin2hex(hash('sha256', $arr['content'], true));
    $appKey = config('chinaumspay.AppKey');

    $signature = base64_encode(hash_hmac('sha256',$arr['appId'].$arr['timestamp'].$arr['nonce'].$strA, $appKey, true));
    $arr['signature'] = $signature;
    return $arr;
  }

  /**
   * @param Params $params
   * @return mixed
   * @throws \Exception
   */
  public function ChinaUMSRequest(Params $params)
  {
    $param = array_filter($params->toArray(), function ($item) {
      return $item !== "" && !is_null($item);
    }); //object to array

    $request_url = array_pull($param,'request_url');
    $Authorization = $this->getAuthorization($param);
    $header[]='AUTHORIZATION:'.$Authorization;


    app('myLog')->lumenLog('銀聯(lián)轉(zhuǎn)發(fā)接口請求參數(shù),trade:' . json_encode($param), 'chinaums_trade');

    // 請求銀聯(lián)
    try {
      $result = $this->postUmsCurl($request_url, $param, $header);
    } catch (\Exception $e) {
      throw new \Exception('請求轉(zhuǎn)發(fā)銀聯(lián)接口失敗請稍后重試!', 602);
    }

    app('myLog')->lumenLog('銀聯(lián)接口請求成功,return:' . json_encode($result), 'chinaums_trade_success');
    return json_decode(json_encode($result),true);
  }

  /**
   * @param Params $params
   * @return mixed
   * @throws \Exception
   */
  public function ChinaUMSH5Request(Params $params)
  {
    $param = array_filter($params->toArray(), function ($item) {
      return $item !== "" && !is_null($item);
    }); //object to array

    $request_url = array_pull($param,'request_url');

    app('myLog')->lumenLog('銀聯(lián)轉(zhuǎn)發(fā)接口請求參數(shù),trade:' . json_encode($param), 'chinaums_trade');
    $param = $this->getH5Authorization($param);
    $request_url = $request_url .'?'. http_build_query($param);

    return $request_url;
  }

  /**
   * 請求商戶接口
   * @param Params $params
   * @return mixed
   * @throws \Exception
   */
  public function ChinaUMSBusinessRequest(Params $params)
  {
    if (env('APP_ENV') == 'dev') {
      $key = 'udik876ehjde32dU61edsxsf';
      $business_accesser_id = '100004';
    } else {
      $key = config('chinaumspay.business_key');
      $business_accesser_id = config('chinaumspay.business_accesser_id');
    }
    $param = array_filter($params->toArray(), function ($item) {
      return $item !== "" && !is_null($item);
    }); //object to array

    $request_url = array_pull($param,'request_url');

    $json_str = json_encode($param);
    $sign_data = hash('sha256', $json_str);
    $json_data = self::encrypt($json_str, $key);
    $arr = [
      'json_data' => $json_data,
      'sign_data' => $sign_data,
      'accesser_id' => $business_accesser_id
    ];

    app('myLog')->lumenLog('銀聯(lián)轉(zhuǎn)發(fā)接口請求參數(shù),trade:' . json_encode($param), 'chinaums_trade');

    try {
      $result = postCurl($request_url, $arr);
    } catch (\Exception $e) {
      throw new \Exception('請求轉(zhuǎn)發(fā)銀聯(lián)接口失敗請稍后重試!', 602);
    }

    app('myLog')->lumenLog('銀聯(lián)接口請求成功,return:' . json_encode($result), 'chinaums_trade_success');
    return json_decode($result,true);
  }

  /**
   * 請求UMS
   * @param $url
   * @param array $body
   * @param array $header
   * @param string $method
   * @return bool|mixed
   * @throws CurlException
   */
  public function postUmsCurl($url, $body = array(), $header = array(), $method = 'POST')
  {
    $curl = curl_init(); //初始化
    $body = json_encode($body);
    curl_setopt($curl, CURLOPT_URL,$url); //設(shè)置url
    array_push($header, 'Accept:application/json');
    array_push($header, 'Content-Type:application/json;charset=utf-8');
    array_push($header, 'Content-Length:'.strlen($body));
    curl_setopt($curl, CURLOPT_HTTPHEADER,$header);
    curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, 0); // 對認(rèn)證證書來源的檢查
    curl_setopt($curl, CURLOPT_SSL_VERIFYHOST, 0); // 從證書中檢查SSL加密算法是否存在 設(shè)為0表示不檢查證書 設(shè)為1表示檢查證書中是否有CN(common name)字段 設(shè)為2表示在1的基礎(chǔ)上校驗當(dāng)前的域名是否與CN匹配
//    curl_setopt($curl, CURLOPT_USERAGENT, $_SERVER['HTTP_USER_AGENT']); // 模擬用戶使用的瀏覽器
    curl_setopt($curl, CURLOPT_FOLLOWLOCATION, 1); // 使用自動跳轉(zhuǎn)
    curl_setopt($curl, CURLOPT_AUTOREFERER, 1); // 自動設(shè)置Referer
    curl_setopt($curl, CURLOPT_POST, 1); // 發(fā)送一個常規(guī)的Post請求
    curl_setopt($curl, CURLOPT_POSTFIELDS,$body);
    curl_setopt($curl, CURLOPT_TIMEOUT, 30); // 設(shè)置超時限制防止死循環(huán)
    curl_setopt($curl, CURLOPT_HEADER, 0); // 顯示返回的Header區(qū)域內(nèi)容
    curl_setopt($curl, CURLOPT_RETURNTRANSFER, 1); // 獲取的信息以文件流的形式返回
    $return = curl_exec($curl);
    $err = curl_error($curl);
    $errno = curl_errno($curl);
    curl_close($curl);

    if ($errno) {
      app('log')->error(sprintf(
        'postUmsCurl %s %s error: %s[%s] body: %s%s',
        strtoupper($method),
        $url,
        $err,
        $errno,
        json_encode(
          $body,
          JSON_UNESCAPED_SLASHES
          | JSON_UNESCAPED_UNICODE
          | JSON_PRETTY_PRINT
          | JSON_FORCE_OBJECT
        ),
        PHP_EOL
      ));
      return false;
    } else {
      app('log')->error(sprintf(
        'postUmsCurl %s %s body: %s%s response: %s%s',
        strtoupper($method),
        $url,
        json_encode(
          $body,
          JSON_UNESCAPED_SLASHES
          | JSON_UNESCAPED_UNICODE
          | JSON_PRETTY_PRINT
          | JSON_FORCE_OBJECT
        ),
        PHP_EOL,
        $return,
        PHP_EOL
      ));
    }

    if($return === false){
      throw new CurlException('ChinaUms請求失敗', 501);
    }
    $return=json_decode($return,true);
    return $return;
  }

  // 加密算法
  public static function encrypt($str, $key)
  {
    $desJsonStr = self::pkcs5Pad($str, 8);
    if (strlen($desJsonStr) % 8) {
      $desJsonStr = str_pad($desJsonStr, strlen($desJsonStr) + 8 - strlen($desJsonStr) % 8, "\0");
    }
    $method = 'DES-EDE3';
    return bin2hex(openssl_encrypt($desJsonStr, $method, $key, OPENSSL_RAW_DATA | OPENSSL_NO_PADDING));
  }

  public static function pkcs5Pad($text, $byteLen)
  {
    $pad = $byteLen - (strlen($text) % $byteLen);
    return $text . str_repeat(chr($pad), $pad);
  }

}

1、getAuthorization為除H5支付外的支付簽名方法

2、getH5Authorization為H5支付簽名算法

3、ChinaUMSRequest為支付請求方法

4、ChinaUMSH5Request為H5支付請求方法

5、ChinaUMSBusinessRequest為銀聯(lián)商戶入駐請求方法

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

友情鏈接更多精彩內(nèi)容