• braintree api调用记录


    国外的支付集成接入。

    只使用基础的卡支付,跟PayPal支付。

    braintree 有沙盒环境可以申请测试,有php sdk包直接下载调用,非常简单。

    1,声明配置信息

    private $_debug         = false;
    
        private $_pay_method    = 'braintree';
        private $_config        = null;
        private $_gateway       = null;
        private $_merchantAccountId     = [ 'usd' => 'xxxUSD' ]; //货币对应的merchantAccountId,建议自定义该值,
        private $_customerPre   = ''; //用户名前缀,用户生成顾客id,
        private $_customerId    = null;
        public  $_err           = '';
      
      
    public function __construct() { if( $this->_debug ) { $this->_config['environment'] = 'sandbox'; $this->_config['merchantId'] = '6xqytmznhcczwwph'; $this->_config['publicKey'] = 'ks2j7rg234tq7fm7'; $this->_config['privateKey'] = '13012ef64ae8b95443f08226ac25c890'; $this->_merchantAccountId['usd'] = ''; //测试使用默认,也可以自定义, $this->_customerPre = 'test1'; }else { $this->_config['environment'] = 'production'; $this->_config['merchantId'] = ''; $this->_config['publicKey'] = ''; $this->_config['privateKey'] = ''; $this->_customerPre = 'Pro'; }
       //实例化gate类,为基础类 import(
    "Pay.braintree_macaroon_app.lib.Braintree", VENDOR_PATH, '.php' ); $this->_gateway = new Braintree_Gateway( [ 'merchantId' => $this->_config['merchantId'], 'publicKey' => $this->_config['publicKey'], 'privateKey' => $this->_config['privateKey'], 'environment' => $this->_config['environment'], 'timeout' => 2, ] ); }

    2,生成并获取顾客id,顾客id可以保留顾客的支付方式,方便其下次直接已购买,而不用重复输入卡或者paypal信息

    /**
        create table uro_braintree_uid(
        id int unsigned not null auto_increment,
        uid int unsigned not null default 0 comment '本站id',
        bid varchar(256) not null default '' comment 'braintree customerid',
        primary key (`id`),
        unique key (`uid`)
        ) engine innodb charset utf8 comment 'braintree 用户对应关系表,creditcard,paypal等信息以后可加字段';
         * 获取、创建braintree 用户,
         * author liuxiaodong
         * date 2018/7/31 15:38
         * @param $uid
         * @return string
         */
        private function getCreateCustom( $uid )
        {
            $model      = M('braintreeUid');
            $bid        = $model->where( ['uid' => $uid] )->getField( 'bid' );
            if( $bid )
                return $bid;
    
            try{
                $res        = $this->_gateway->customer()->create( [
                    'id'    => $this->_customerPre . $uid
                ] );
                if( $res->success ) {
                    $bid    = $res->customer->id;
                    if( !$model->add( ['uid' => $uid, 'bid' => $bid] ) )
                        $this->_warnNotice( 'send -- into db error', '数据入库失败,入库数据为 = '.  json_encode( ['uid' => $uid, 'bid' => $bid] ) . ',err =' . $model->getLastSql() .'|'. $model->getDbError() );
                }else
                    $this->_warnNotice( 'send -- res error', '请求braintree服务器,生成用户信息失败 = ' . json_encode( $res ) );
    
                return $bid;
            }catch ( Exception $e ) {
                $this->_warnNotice( 'send -- createCustom', '请求braintree服务器,抛出异常' . json_encode( $e ) );
                return '';
            }
        }

    3,获取客户端token,同时可以追加自己的信息,比如这边追加返回了订单的信息,让客户端回传,

    /**
         * 初始化订单信息,返回 clientoken,orderinfo 信息
         * author liuxiaodong
         * date 2018/7/27 17:56
         * @param array $params
         * @return array
         */
        public function send( $order )
        {
            $this->_customerId  = $this->getCreateCustom( $order['braintree']['uid'] );
    
            $this->_warnNotice( 'send -- getClientToken', 'get request', 'debug' );
    
            $res            = ['clientoken' => '', 'transaction' => []];
            try{
                $res['clientoken']      = $this->_gateway->clientToken()->generate( [
                    'customerId'        => $this->_customerId
                ] );
            }catch ( Exception $e ) {
                $this->_warnNotice( 'send -- getClientToken', '错误信息:格式化exception ==' . json_encode( $e ) . ' , errmsg = ' . $e->getMessage()  );
                return [];
            }
    
            $res['transaction']     = $this->_encrypt( $order['braintree'] ); 
            $this->_warnNotice( 'send -- getClientToken', 'send request' . json_encode( $res ), 'debug' );
    
            return $res;
        }

    4,支付, 是客户端请求后,请求braintree直接获取支付结果,做逻辑操作。

    //此接口做支付
        public function notify( $params )
        {
            $this->_warnNotice( 'notify', '参数' . json_encode( $params ), 'debug' );
    
            if( empty( $params['nonce'] )
                || empty( $params['transaction'] )
            ) {
                $this->_warnNotice( 'notify', '请求参数异常 无nonce、transaction, 参数为 == ' . json_encode( $params ) );
                $this->_err         = 'invalid params';
                return false;
            }
    
            $transaction        = $this->_decrypt( $params['transaction'] );
            if( empty( $transaction ) || !is_array( $transaction ) ) {
                $this->_warnNotice( 'notify', '参数异常, 无transaction == ' . json_encode( $params ) );
                $this->_err         = 'invalid params';
                return false;
            }
    
            //读取订单信息
            $model          = D('Common/OrderRetail');
            $order          = $model->find( $transaction['oid'] );
            if( !$order ) {
                $this->_err         = 'invalid order info';
                $this->_warnNotice( 'notify', '读取订单信息异常 == ' . json_encode( $transaction ) . ' from ' . $params['client'] . ' order == ' . json_encode( $order ) . ' sql ==' . $model->getLastSql() );
                return false;
            }
    
            if( $order['amount'] != $transaction['amount'] ) {
                $this->_err         = 'check amount error';
                $this->_warnNotice( 'notify', '核对订单金额失败 == ' . json_encode( $transaction ) . ' from ' . $params['client'] . ' order amount = ' .$order['amount'] );
                return false;
            }
    
            $amount     = $transaction['amount'];
            if( $this->_debug )
                $amount = 0.01; //debug下请保证前端使用的金额也是0.01 
    
            //商品信息
            foreach ( $transaction['goods'] as $v ) {
                $lineItems[] = [
                    'description'   => $transaction['oid'], // Maximum 127 characters
                    'kind'          => 'debit',
                    'name'          => mb_substr( $v['product_info']['name'], 0, 30, 'utf8' ) . '...',
                    'productCode'   => $v['product_id'], //gid
                    'quantity'      => $v['num'],
                    'totalAmount'   => $v['product_info']['price'] * $v['product_info']['num'],
                    'unitAmount'    => $v['product_info']['price'],
                    'url'           => ''
                ];
            }
    
            $this->_customerId      = $this->getCreateCustom( $transaction['uid'] );
            $trans      = [
                'amount'                => $amount, //总金额
                'merchantAccountId'     => $this->_merchantAccountId['usd'], //merchantAccountId
                'paymentMethodNonce'    => $params['nonce'],
                'lineItems'             => $lineItems,
                'orderId'               => $transaction['oid'], //自定义的值
                'customerId'            => $this->_customerId,
                'options'               => [
                    'submitForSettlement'     => true, //申请结算,
                ]
            ];
            $this->_warnNotice( 'notify', 'sale 发送请求' . json_encode( $trans ) . 'from ' . $params['client'], 'debug' );
            $res        = $this->_gateway->transaction()->sale( $trans );
            $this->_warnNotice( 'notify', 'sale 结果' . json_encode( $res->success ) . 'from ' . $params['client'], 'debug' );
    
            if( $res->success ) {
                $trance         = $res->transaction;
               
                
           //个人逻辑
    return true; }else { $this->_err = $res->message . '('.$res->transaction->processorResponseCode.')'; $this->_warnNotice( 'notify', '请求 sale 发送交易抛出异常, 简讯 '.$this->_err.' 详情 == ' . json_encode( $res ), 'error' ); return false; } }

    5, 其他附加方法,报警;加解密

    /**
         * 获取客户端token
         * author liuxiaodong
         * date 2018/7/26 15:57
         * @return array
         */
        public function getClientToken()
        {
            try{
                $token      = $this->_gateway->clientToken()->generate();
                return [true, $token];
            }catch ( Exception $e ) {
                $this->_warnNotice( 'getClientToken', '获取clienttoken 失败。。'  . json_encode( $e ), 'error' );
                return [false, $e->getMessage()];
            }
        }
    
        private function _warnNotice( $action, $msg, $level = 'error' )
        {
            if( $level == 'debug' && !$this->_debug )
                return;
    
            $msg        .= PHP_EOL;
            Log::write( $action . ' -- ' . $msg, $level, '', C('LOG_PATH') . 'braintreeErr/' . date( 'Y-m-d' ) . '.log'  );
    
            if( !$this->_debug ) {
                $email      = new AliyunEail();
                $email->sendEmail( 'email...', 'braintree pay error',  date( 'Y-m-d H:i:s' ) . '<br />' . $msg );
            }
        }
    
        /**
         * Encrypts the input text using the cipher key
         *
         * @param $input
         * @return string
         */
        private function _encrypt( Array $input)
        {
            $input      = json_encode( $input );
            // Create a random IV. Not using mcrypt to generate one, as to not have a dependency on it.
            $iv = substr(uniqid("", true), 0, self::IV_SIZE);
            // Encrypt the data
            $encrypted = openssl_encrypt($input, "AES-256-CBC", 'key', 0, $iv);
            // Encode the data with IV as prefix
            return base64_encode($iv . $encrypted);
        }
    
        /**
         * Decrypts the input text from the cipher key
         *
         * @param $input
         * @return string
         */
        private function _decrypt($input)
        {
            // Decode the IV + data
            $input  = base64_decode($input);
            // Remove the IV
            $iv = substr($input, 0, self::IV_SIZE);
            // Return Decrypted Data
            $output     =  openssl_decrypt(substr($input, self::IV_SIZE), "AES-256-CBC", 'key', 0, $iv);
            return json_decode( $output, true );
        }
    
        public function getError()
        {
            $msg    = 'err: ';
            $msg    .= $this->_err ? $this->_err : 'server fail';
            return $msg;
        }

      

    截图:

    报警: (该错误是前段生成的金额跟后端的不一致导致,多是debug的时候)

  • 相关阅读:
    关于生成二维码的相关参考资料
    C#生成二维码的方法
    .NET 二维码生成(ThoughtWorks.QRCode)
    微信扫描二维码登录网站技术原理
    C# ArrayList的用法
    C#多线程编程
    c#使用多线程的几种方式示例详解
    解决Winform应用程序中窗体背景闪烁的问题
    C# 线程调用主线程中的控件
    30、网络编程
  • 原文地址:https://www.cnblogs.com/lxdd/p/9429990.html
Copyright © 2020-2023  润新知