精华内容
下载资源
问答
  • 当今互联网之战源头就是线上支付竞争,颇有得支付者得"天下"气势,那么支付背后实现原理之一——扫码枪支付今天小艾带你们一探究竟!!! 扫码支付大致流程是这样。收银系统扫商品码生成订单->等待...

    当今互联网之战的源头就是线上支付的竞争,颇有得支付者得"天下"的气势,那么支付背后的实现原理之一的——扫码枪支付今天小艾带你们一探究竟!!!

    扫码支付的大致流程是这样的。收银系统扫商品码生成订单->等待用户展示付款码->扫码枪扫描用户付款码->等待第三方支付(微信/支付宝)返回的扣款状态完成订单;本人从事多年php开发工作,下面给大家展示下工作中封装好的微信扫码支付的案例。直接上代码

    /**
         * Notes:门店扫码支付
         * User: 小艾
         * Time:下午 4:14
         * DATE:2020/12/9 0009
         */
    public function Scantopay(){
            $common = new Common();
            if (request()->isPost()){
                $authCode = input('authCode','');//用户付款码
                $payAmount = input('payAmount','');//订单支付金额
                $outTradeNo = input('outTradeNo','');//订单号$out_trade_no
                $payment_type = input('payment_type',1);//支付方式  1-微信  2-支付宝  3-现金支付
                $weixinpay = new Scantopay();
                if (!empty($authCode) && !empty($payAmount) && !empty($outTradeNo)){
                    if($payment_type == 1){//调取微信扫码支付
                        $data = $weixinpay->weixinpay($authCode,$payAmount,$outTradeNo);
                        if($data['return_code']=='SUCCESS'){
                          //订单支付成功扣除门店库存
                            $result = $common->returnway(2000,'支付成功!',$data);
                            return json_encode($result);
                        }else{
                            $result = $common->returnway(4001,'支付支付!',$data);
                            return json_encode($result);
    
                        }
                    }elseif ($payment_type == 2){//调取支付宝扫码支付
                    }
                }else{
                    $result = $common->returnway(4001,'请求参数不能为空!',[]);
                    return json_encode($result);
                }
            }else{
                $result = $common->returnway(4000,'请求方式有误!',[]);
                return json_encode($result);
            }
    
        }
    

    直接调取上述类方法即可;其他文件代码整合如下修改自己的支付配置即可 :

    <?php
    
    /**
     * 扫码支付
     * 提醒:提交支付请求后微信会同步返回支付结果(没有异步回调通知)。当返回结果为“系统错误”时,商户系统等待5秒后调用【查询订单API】,查询支付实际交易结果;当返回结果为“USERPAYING”时,商户系统可设置间隔时间(建议10秒)重新查询支付结果,直到支付成功或超时(建议30秒);
     */
    namespace app\api\controller;
    use think\Controller;
    use think\Db;
    use think\Input;
    use think\facade\Request;
    use app\api\controller\Common;
    header("Access-Control-Allow-Origin:*");
    class Scantopay extends Controller{
    
        /**
         * @param $authCode//用户付款码
         * @param $payAmount//付款金额,单位:元
         * @param $outTradeNo//你自己的商品订单号
         * @return array
         */
        public function weixinpay($authCode,$payAmount,$outTradeNo){
            header('Content-type:text/html; Charset=utf-8');
            $mchid = '';          //微信支付商户号 PartnerID 通过微信支付商户资料审核后邮件发送
            $appid = '';  //公众号APPID 通过微信支付商户资料审核后邮件发送
            $apiKey = '';   //https://pay.weixin.qq.com 帐户设置-安全设置-API安全-API密钥-设置API密钥
            $orderName = '微信支付';    //订单标题
            $wxPay = new WxpayService($mchid,$appid,$apiKey);
    
            $wxPay->setTotalFee($payAmount);
            $wxPay->setOutTradeNo($outTradeNo);
            $wxPay->setOrderName($orderName);
            $wxPay->setAuthCode($authCode);
            $arr = $wxPay->createJsBizPackage();
            return $arr;
        }
    }
    
    
    class WxpayService
    {
        protected $mchid;
        protected $appid;
        protected $apiKey;
        protected $totalFee;
        protected $outTradeNo;
        protected $orderName;
        protected $authCode;
    
        public function __construct($mchid = '', $appid = '', $key = '')
        {
            $this->mchid = $mchid;
            $this->appid = $appid;
            $this->apiKey = $key;
        }
    
        public function setTotalFee($totalFee)
        {
            $this->totalFee = $totalFee;
        }
    
        public function setOutTradeNo($outTradeNo)
        {
            $this->outTradeNo = $outTradeNo;
        }
    
        public function setOrderName($orderName)
        {
            $this->orderName = $orderName;
        }
    
        public function setAuthCode($authCode)
        {
            $this->authCode = $authCode;
        }
    
        /**
         * 发起订单
         * @return array
         */
        public function createJsBizPackage()
        {
            $config = array(
                'mch_id' => $this->mchid,
                'appid' => $this->appid,
                'key' => $this->apiKey,
                'total_fee' => $this->totalFee,
                'out_trade_no' => $this->outTradeNo,
                'order_name' => $this->orderName,
                'auth_code' => $this->authCode,
            );
            //$orderName = iconv('GBK','UTF-8',$orderName);
            $unified = array(
                'appid' => $config['appid'],
                'attach' => 'pay',             //商家数据包,原样返回,如果填写中文,请注意转换为utf-8
                'body' => $config['order_name'],
                'mch_id' => $config['mch_id'],
                'nonce_str' => self::createNonceStr(),
                'out_trade_no' => $config['out_trade_no'],
                'spbill_create_ip' => '127.0.0.1',
                'total_fee' => intval($config['total_fee'] * 100),       //单位 转为分
                'auth_code' => $config['auth_code'],     //收款码,
                'device_info' => 'dedemao001',        //终端设备号(商户自定义,如门店编号)
    //            'limit_pay'=>'no_credit'            //指定支付方式  no_credit--指定不能使用信用卡支付
            );
            $unified['sign'] = self::getSign($unified, $config['key']);
            $responseXml = self::curlPost('https://api.mch.weixin.qq.com/pay/micropay', self::arrayToXml($unified));
            $unifiedOrder = simplexml_load_string($responseXml, 'SimpleXMLElement', LIBXML_NOCDATA);
            if ($unifiedOrder === false) {
                die('parse xml error');
            }
            if ($unifiedOrder->return_code != 'SUCCESS') {
                die('支付失败:错误码:' . $unifiedOrder->err_code . '。错误码说明:https://pay.weixin.qq.com/wiki/doc/api/micropay.php?chapter=9_10&index=1#7');
            }
            if ($unifiedOrder->result_code != 'SUCCESS') {
                die('支付失败:错误码:' . $unifiedOrder->err_code . '。错误码说明:https://pay.weixin.qq.com/wiki/doc/api/micropay.php?chapter=9_10&index=1#7');
            }
            return (array)$unifiedOrder;
        }
    
        public function notify()
        {
            $config = array(
                'mch_id' => $this->mchid,
                'appid' => $this->appid,
                'key' => $this->apiKey,
            );
            $postStr = $GLOBALS["HTTP_RAW_POST_DATA"];
            $postObj = simplexml_load_string($postStr, 'SimpleXMLElement', LIBXML_NOCDATA);
            if ($postObj === false) {
                die('parse xml error');
            }
            if ($postObj->return_code != 'SUCCESS') {
                die($postObj->return_msg);
            }
            if ($postObj->result_code != 'SUCCESS') {
                die($postObj->err_code);
            }
            $arr = (array)$postObj;
            unset($arr['sign']);
            if (self::getSign($arr, $config['key']) == $postObj->sign) {
                echo '<xml><return_code><![CDATA[SUCCESS]]></return_code><return_msg><![CDATA[OK]]></return_msg></xml>';
                return $postObj;
            }
        }
    
        /**
         * curl get
         *
         * @param string $url
         * @param array $options
         * @return mixed
         */
        public static function curlGet($url = '', $options = array())
        {
            $ch = curl_init($url);
            curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
            curl_setopt($ch, CURLOPT_TIMEOUT, 30);
            if (!empty($options)) {
                curl_setopt_array($ch, $options);
            }
            //https请求 不验证证书和host
            curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
            curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false);
            $data = curl_exec($ch);
            curl_close($ch);
            return $data;
        }
    
        public static function curlPost($url = '', $postData = '', $options = array())
        {
            if (is_array($postData)) {
                $postData = http_build_query($postData);
            }
            $ch = curl_init();
            curl_setopt($ch, CURLOPT_URL, $url);
            curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
            curl_setopt($ch, CURLOPT_POST, 1);
            curl_setopt($ch, CURLOPT_POSTFIELDS, $postData);
            curl_setopt($ch, CURLOPT_TIMEOUT, 30); //设置cURL允许执行的最长秒数
            if (!empty($options)) {
                curl_setopt_array($ch, $options);
            }
            //https请求 不验证证书和host
            curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
            curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false);
            $data = curl_exec($ch);
            curl_close($ch);
            return $data;
        }
    
        public static function createNonceStr($length = 16)
        {
            $chars = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789';
            $str = '';
            for ($i = 0; $i < $length; $i++) {
                $str .= substr($chars, mt_rand(0, strlen($chars) - 1), 1);
            }
            return $str;
        }
    
        public static function arrayToXml($arr)
        {
            $xml = "<xml>";
            foreach ($arr as $key => $val) {
                if (is_numeric($val)) {
                    $xml .= "<" . $key . ">" . $val . "</" . $key . ">";
                } else
                    $xml .= "<" . $key . "><![CDATA[" . $val . "]]></" . $key . ">";
            }
            $xml .= "</xml>";
            return $xml;
        }
    
        /**
         * 获取签名
         */
        public static function getSign($params, $key)
        {
            ksort($params, SORT_STRING);
            $unSignParaString = self::formatQueryParaMap($params, false);
            $signStr = strtoupper(md5($unSignParaString . "&key=" . $key));
            return $signStr;
        }
    
        protected static function formatQueryParaMap($paraMap, $urlEncode = false)
        {
            $buff = "";
            ksort($paraMap);
            foreach ($paraMap as $k => $v) {
                if (null != $v && "null" != $v) {
                    if ($urlEncode) {
                        $v = urlencode($v);
                    }
                    $buff .= $k . "=" . $v . "&";
                }
            }
            $reqPar = '';
            if (strlen($buff) > 0) {
                $reqPar = substr($buff, 0, strlen($buff) - 1);
            }
            return $reqPar;
        }
    }
    
    
    

    下篇文章写支付宝的扫码枪实例!欢迎━(`∀´)ノ亻!探讨

    展开全文
  • 解决扫码枪中文输入法冲突问题

    千次阅读 2020-07-29 16:13:43
    首先先了解扫码枪的原理,每次扫码枪扫描相当于执行了 》》扫码的数字+ enter事件 由于搜狗输入法在键入英文时点击enter等于回显,故在输入框里面监听不到enter事件,而且还会出现一些其他的文字 解决方案:type=...

    解决扫码枪输入input时受中文输入法的影响,监听不到回车事件和在中文输入法时扫码错误的情况

    首先先了解扫码枪的原理,每次扫码枪扫描相当于执行了 》》扫码的数字+ enter事件
    由于搜狗输入法在键入英文时点击enter等于回显,故在输入框里面监听不到enter事件,而且还会出现一些其他的文字
    解决方案:type=“password” 是不能输入中文的,故可以使用密码框实现扫码枪中文输入法的问题

    <!DOCTYPE html>
    <html lang="zh_CN">
    <meta charset="utf-8">
    <head>
        <meta content="text/html; charset=UTF-8" http-equiv="Content-Type">
        <title>lalalala</title>
    </head>
    <style>
        #show:after{
            content: "";
            display: inline-block;
            height: 18px;
            position: relative;
            border-right: solid 1px #666;
            top: 4px;
            left: 0px;
            opacity: 0;
        }
        .pad-input:focus + #show:after{
            animation: mymove 1.2s infinite;
        }
    
        @keyframes mymove
        {
            0%   {opacity: 0;}
            25%  {opacity: 0;}
            75%  {opacity: 1;}
            100% {opacity: 0;}
        }
    </style>
    <body>
    <div style="position: relative;width: 200px;">
        <input type="password" autocomplete="off" class="pad-input" style="height: 30px;width: 100%;">
        <div id="show" style="position: absolute;left: 2px;top:50%;transform: translate(0,-50%);border: none;height: 28px;pointer-events: none;background: #fff;width: 98%;" disabled>
            <span></span>
        </div>
    </div>
    <script>
        var obj = {};
        Object.defineProperty(obj, 'txt', {
            get: function () {
                return obj;
            },
            set: function (newValue) {
                document.getElementById('show').getElementsByTagName('span')[0].innerHTML  = newValue;
            }
        });
        document.getElementsByClassName("pad-input")[0].addEventListener('keyup', function (e) {
            obj.txt = e.target.value;
        });
    </script>
    </body>
    

    效果展示
    在这里插入图片描述
    添加了模拟的光标效果,实现扫码枪在搜狗输入法中文时,监听不到回车事件和在中文输入法时扫码错误的情况

    js拓展
    1.js事件
    例如最基本的,onbluer 获得焦点,onchenge 修改文本,onclick 鼠标点击事等等。
    这类代码写到标签中,

    ,这里注意的是函数名的双引号。

    2.dom的window操作
    window.open(url,name,spers,replace);注意此处的四个人属性值都加双引号用逗号隔开。
    url:打开的链接的地址。
    name:打开方式有四种,默认为_blank 打开新窗口
    _parent 打开到付及框架
    _sele 代替自身的页面
    _top 直接打开到顶级父级页面
    spers:多用于调整高度

     以下的window操作写法可以将window换成对应的对象名:
    window.close(); 关闭窗口
    window.moveto(x,y); 调整打开窗口的位置
    window.resize(x,y); 高宽    单位是像素
    

    3.延迟与间隔
    间隔 setInterval(“函数名”,间隔时间) 函数名需要添加双引号!! 时间是毫秒!
    setInterval() 方法会不停地调用函数,直到 clearInterval() 被调用或窗口被关闭。由

    setInterval() 返回的 ID 值可用作 clearInterval() 方法的参数。
    clearInterval(间隔的变量名);
    

    间隔多用于没有用户操作的情况下

    延迟
    setTimeout("函数名",间隔时间)  双引号注意!!
     方法用于在指定的毫秒数后调用函数或计算表达式。 
    

    4.操作html
    查找元素:
    根据id获取元素
    document.getElementById(“id”);
    根据class获取元素
    document.getElementsByClassName(“class”);
    根据标签名获取元素
    document.getElementsByTagName(“div”);
    根据name获取元素
    document.getElementsByName(“name”);
    注意添加引号!!

    5.改变html内容
    对象名.innerHTML;用于添加文本或者代码
    添加文本 .innertext;

    6.操作属性 此处注意添加双引号!!
    1.设置一个属性,添加或更改
    获取的对象.setAttribute(“属性名”,“属性值”)
    2.获取属性的值
    获取的对象.getAttribute(“属性名”);
    3.移除一个属性
    获取的对象.removeAttribute(“属性名”);
    7.操作样式
    1.操作样式
    获取的 对象.style.样式="" ; 样式中间的横杠去掉 且需要大写 例如
    backgroundColor

    2.获取样式
    Var a = 获取的对象.style.样式

    8.操作表单元素
    对象名.value;

    展开全文
  • 前几天弄完微信的条形支付,很多条友私信说想知道支付宝的原理,那么今天小艾带着一上午搞定的成果出现啦废话不多说直接上效果!!! 商家通过扫描线下买家支付宝钱包中的条码、二维码等方式完成支付(本文讲讲...

    前几天弄完微信的条形码支付,很多条友私信说想知道支付宝的原理,那么今天小艾带着一上午搞定的成果出现啦废话不多说直接上效果!!!

    1. 商家通过扫描线下买家支付宝钱包中的条码、二维码等方式完成支付(本文讲讲这个);

    2. 线下买家通过使用支付宝钱包扫一扫,扫描商家的二维码等方式完成支付。

    开发之前需要申请的开发参数详见支付宝开发平台进行申请

    开发步骤:

    步骤一、 下载官方demo 地址:https://opendocs.alipay.com/open/54/104506;放置项目框架(tp5)的vendor文件中
    在这里插入图片描述
    步骤二、配置自己开发申请的必要参数:

    <?php
    
    /**
     * 扫码支付
     * 提醒:提交支付请求后微信会同步返回支付结果(没有异步回调通知)。当返回结果为“系统错误”时,商户系统等待5秒后调用【查询订单API】,查询支付实际交易结果;当返回结果为“USERPAYING”时,商户系统可设置间隔时间(建议10秒)重新查询支付结果,直到支付成功或超时(建议30秒);
     */
    namespace app\api\controller;
    use think\Controller;
    use think\Db;
    use think\Input;
    use think\facade\Request;
    use app\api\controller\Common;
    
    header("Access-Control-Allow-Origin:*");
    header("Content-type: text/html; charset=utf-8");
    require_once $_SERVER['DOCUMENT_ROOT'].'/vendor/Alipaydangmianfu_demo/f2fpay/model/builder/AlipayTradePayContentBuilder.php';
    require_once $_SERVER['DOCUMENT_ROOT'].'/vendor/Alipaydangmianfu_demo/f2fpay/service/AlipayTradeService.php';
    /**
     * 支付宝当面付
     * @package app\api\controller
     */
    class Alipay{
        /**
         * Notes:
         * User: 小艾
         * Time:下午 1:51
         *$authCode   用户支付码
         *$totalAmount 支付金额
         *$outTradeNo 订单号
         * DATE:2020/12/10 0010
         */
        public function alipay($authCode,$totalAmount,$outTradeNo){
            $common = new Common();
            $config = array (
                //签名方式
                'sign_type' => "RSA2",
                //支付宝公钥    
                'alipay_public_key'=>'',
                //商户私钥
                'merchant_private_key' => "",
    
                //编码格式
                'charset' => "UTF-8",
    
                //支付宝网关
                'gatewayUrl' => "https://openapi.alipay.com/gateway.do",
    
                //应用ID
                'app_id' => "2016111102724113",
    
                //异步通知地址,只有扫码支付预下单可用
                'notify_url' => "",
    
                //最大查询重试次数
                'MaxQueryRetry' => "10",
    
                //查询间隔
                'QueryDuration' => "3"
            );
            // (必填) 商户网站订单系统中唯一订单号,64个字符以内,只能包含字母、数字、下划线,
            // 需保证商户系统端不能重复,建议通过数据库sequence生成,
    //        $outTradeNo = "Dsx" . date('Ymdhis') . mt_rand(100, 1000);
            $subject = "第三巷条形码支付";
    //        $totalAmount = $_POST['payAmount'];    // (必填) 订单总金额,单位为元,不能超过1亿元
    
            // (必填) 付款条码,用户支付宝钱包手机app点击“付款”产生的付款条码
    //        $authCode = $_POST['auth_code']; //28开头18位数字
    
    
    
            // 支付超时,线下扫码交易定义为5分钟
            $timeExpress = "5m";
            // 创建请求builder,设置请求参数
            $barPayRequestBuilder = new \AlipayTradePayContentBuilder();
    
    
            $barPayRequestBuilder->setOutTradeNo($outTradeNo);
            $barPayRequestBuilder->setTotalAmount($totalAmount);
            $barPayRequestBuilder->setAuthCode($authCode);
            $barPayRequestBuilder->setTimeExpress($timeExpress);
            $barPayRequestBuilder->setSubject($subject);
            // 调用barPay方法获取当面付应答
            $barPay = new \AlipayTradeService($config);
            $barPayResult = $barPay->barPay($barPayRequestBuilder);
            switch ($barPayResult->getTradeStatus()) {
                case "SUCCESS":
    //                echo "支付宝支付成功:" . "<br>--------------------------<br>";
                    $data = $barPayResult->getResponse();
                    $result = $common->returnway(2000,"支付宝支付成功!",$data);
                    return json_encode($result);
                    break;
                case "FAILED":
    //                echo "支付宝支付失败!!!" . "<br>--------------------------<br>";
                    if (!empty($barPayResult->getResponse())) {
                        $data = $barPayResult->getResponse();
                        $result = $common->returnway(2002,"支付宝支付失败!",$data);
                        return json_encode($result);
                    }
                    break;
                case "UNKNOWN":
    //                echo "系统异常,订单状态未知!!!" . "<br>--------------------------<br>";
                    if (!empty($barPayResult->getResponse())) {
                        $result = $common->returnway(4000,"系统异常,订单状态未知!",$barPayResult->getResponse());
                        return json_encode($result);
                    }
                    break;
                default:
                    echo "不支持的交易状态,交易返回异常!!!";
                    break;
            }
            return;
        }
    
    }
    
    

    步骤三、接收前端参数 调取下列方法即可

    /**
         * Notes:门店扫码支付
         * User: 小艾
         * Time:下午 4:14
         * DATE:2020/12/9 0009
         */
        public function Scantopay(){
            header("Access-Control-Allow-Origin:*");
            $common = new Common();
            if (request()->isPost()){
                $authCode = input('authCode','');//用户付款码
                $payAmount = input('payAmount','');//订单支付金额
                $outTradeNo = input('outTradeNo','');//订单号$out_trade_no
                $payment_type = input('payment_type',1);//支付方式  1-微信  2-支付宝  3-现金支付
    
                if (!empty($authCode) && !empty($payAmount) && !empty($outTradeNo)){
                    if($payment_type == 1){//调取微信扫码支付
                        $weixinpay = new Scantopay();
                        $data = $weixinpay->weixinpay($authCode,$payAmount,$outTradeNo);
                        if($data['return_code']=='SUCCESS'){//订单支付成功扣除门店库存
                            $result = $common->returnway(2000,'支付成功!',$data);
                            return json_encode($result);
                        }else{
                            $result = $common->returnway(4001,'支付支付!',$data);
                            return json_encode($result);
    
                        }
                    }elseif ($payment_type == 2){//调取支付宝扫码支付
                        $alipay = new Alipay();
                        $data = $alipay->alipay($authCode,$payAmount,$outTradeNo);
                        print_r($data);die;
    //                    if($data['return_code']=='SUCCESS'){
    //                        $result = $common->returnway(2000,'支付成功!',$data);
    //                        return json_encode($result);
    //                    }
                    }
                }else{
                    $result = $common->returnway(4001,'请求参数不能为空!',[]);
                    return json_encode($result);
                }
            }else{
                $result = $common->returnway(4000,'请求方式有误!',[]);
                return json_encode($result);
            }
    
        }
    

    和微信的原理效果一样,所以我封装到一起了,阅读到这里的好友们有没有get到程序的乐趣?

    如果你有更好的封装效果欢迎留言!!! 注:做支付、办理个人POS(利率低至0.38,银联代理不跳码)扫码备注来意加好友!!!
    在这里插入图片描述

    展开全文
  • ps:付款支付别称有很多,如微信支付端支付产品为付款支付(之前文档叫做刷卡支付),而支付宝端产品为当面付-条支付,而有些文档会成为二维码被支付。 下文统一使用微信定义方式,统称为付款支付。 ...

    前言

    最近由于业务需求,需要开发付款码功能,该接口底层将会聚合市面上主流钱包 APP 的付款码功能,如微信支付,支付宝支付。

    ps:付款码支付别称有很多,如微信支付端支付产品为付款码支付(之前的文档叫做刷卡支付),而支付宝端产品为当面付-条支付,而有些文档会成为二维码被扫支付

    下文统一使用微信的定义方式,统称为付款码支付。

    可能有些同学对于付款码支付这个听起来很陌生,其实这个功能我们可能每天都在被使用。

    像我们在便利店买个早饭,最后结账时,使用支付宝/微信支付付款。收银员会让我们展示支付宝/微信付款码,然后使用扫码枪获取此码,最后上送给微信/支付宝服务端完成一次扣款。

    以支付宝为例,具体用户端支付流程如下:

     

     

     

    付款码支付后台调用流程如下:

     

     

     

    付款码支付详细版流程

    微信/支付宝付款码支付调用流程大同小异,官网写的都比较清楚,这里直接用支付宝的官网的流程。

     

     

     

    从上面的流程可以看到,付款码支付可以说是一个同步的接口,即接口同步返回扣款结果,无需通过另外异步通知获取结果。

    不过这里我们需要注意,由于涉及安全风控等问题,付款码支付过程用户端可能需要输入密码确认支付,此时付款码接口将会返回等待用户支付。

    接入时务必这正确判断返回信息,若返回以下结果,代表此时用户正在输入密码。

    • 微信支付: err_code=USERPAYING 或 err_code=SYSTEMERROR
    • 支付宝: code=10003 或 code=20000

    微信付款码支付在以下情况需要输入密码二次确认。

     

     

     

    支付宝官方文档暂未找到相关规则,经过测试当支付金额大于 2000 ,需要输入密码。如果有熟悉其他验密规则的同学,可以在评论区留言一下。

    另外一点需要注意的是,微信/支付宝其他支付接口,支付成功之后,微信/支付宝服务端将会发送消息通知支付结果。但是付款码不一样,该接口是不会有消息通知。

    所以如果付款码支付若返回等待用户输入密码,商家后台服务必须定时调用调用微信支付/支付宝查询接口,获取支付结果。

     

     

     

    撤销支付

    如果在一段时间内比如 30s,轮询查询支付结果返回都是等待用户支付,或者支付交易过程返回失败或支付系统超时,这两种情况官方文档都是建议立刻调用撤销接口撤销交易。

    如果此订单用户支付失败,撤销接口将会订单关闭;如果用户支付成功,撤销接口将会订单资金退还给用户。

    也就是说撤销支付接口功能上等同于关闭订单加上退款。虽然撤销也具有退款功能,但是两者存在比较大的区别:

    支付类型限制

    微信/支付宝撤销支付仅能撤销付款码支付类型的订单,而退款可以支持多种支付类型的订单。

    退款金额

    撤销接口只能是全额退款,而退款接口支持传入金额,可以全额退款,也可以部分退款。

    时间限制

    撤销接口时间限制比较短,比如微信支付撤销支持 7 天内的订单,而支付宝撤销接口仅支持当天的订单。

    但是退款接口可以支持较长时间订单退款,比如微信支付退款支持一年内的订单,而支付宝仅支持 3 个月内订单。

    基于以上区别,其他正常支付的单如需实现相同功能请调用退款接口,官方文档建议仅在异常的情况下才建议调用撤销支付接口。

    另外再说一点,有些地方这个功能接口称为冲正接口,如下面工商二维码支付。

     

    实际上提供的功能与微信/支付宝撤销类似,这里需要各家支付公司提供文档具体研究。

    撤销支付相关问题

    由于撤销支付,可能导致退款,也可能关闭订单,接入之前一直有些问题弄不清楚,在官方文档处也没有查询到任何资料,没办法只好实测验证相关问题。

    由于规定,支付机构不能直连微信/支付宝,所以以下测试基于银联微信/支付宝通道。

    银联提供的接口与直连微信/支付宝存在些许差别,但是主要功能一样。

    重复撤销

    通过实测,微信/支付宝撤销接口幂等实现,重复撤销返回结果一致。

    不过需要注意需要正确判断撤销的返回结果。

    比如微信撤销接口成功判断还需要结合 recall 字段,支付宝也有类似字段。

     

     

     

    订单状态

    微信/支付宝订单状态处理不太一致,微信订单状态比较复杂:

     

    也就是说,付款码订单一旦被撤销成功,再次查询订单,状态将会返回为已撤销(REVOKED)

    另外微信对于付款码支付订单有限制,是无法调用关闭订单接口关闭订单,所以在付款码的场景中,是不存在订单状态为 CLOSED—已关闭

    接下来说下支付宝的状态,支付宝文档没要给出类似的订单状态机,我根据官方一些文档,以及一些测试结果总结出下方订单状态图。

     

     

     

    所以支付宝的付款码订单一旦撤销成功,再次查询原单状态将会返回 TRADE_CLOSED

    对账文件数据

    当天产生交易之后,次日我们需要拉取微信/支付宝对账文件,逐一核对数据,防止少账,多账问题。

    对账设计流程可以参考之前写过的文章:

    聊聊对账系统的设计方案

    微信/支付宝对账文件只会记录交易成功的订单,所以未支付的订单被撤销是不会出现在对账文件中。但是如果支付成功了,然后又被撤销成功,将会在对账文件中产生两笔记录,一笔正交易,一笔反向退款记录。

    正交易与普通的退款的记录都比较好识别,一般可以使用我们上送给微信支付宝订单号。但是撤销导致退款记录,我们无法仅用一个单号识别,我们需要结合另外的字段区分判断。

    微信对账文件撤销产生那笔退款,交易状态为 REVOKED,所以我们可以采用商户订单号加交易状态识别出一条记录是否为撤销产生退款记录。

     

     

     

    上面银联订单号可以当做是微信支付宝内部产生订单号

    支付宝对账文件比较麻烦,撤销产生的退款记录不能跟微信根据交易状态区分。从对账文件上看支付宝撤销产生退款与普通退款接口产生退款记录是一样的。

     

     

    仔细研究对账文件可以发现一些区别,撤销导致退款记录退款批次与正交易支付宝内部订单号是一致的。而正常退款记录,退款批次号是由商户自己上送的。所以我们可以以此筛选出撤销产生的退款记录。

    撤销失败

    极端情况下,有可能产生多次撤销都失败的奇葩情况,那怎么办?

    这种情况下就不用往系统自动处理方向考虑了,通过线下人工介入处理吧,毕竟这种概率太低了。引用知乎**@天顺**的文章中一句话:

    很多时候人工保障比你动脑筋想异常中的异常如何系统自动处理来得反而高效和低成本

    这句话大家仔细品,越品越有道理!

    最后说一句(求点赞、转发+关注)

    付款码支付接入其实比较简单,主要难点在于撤销接口引入之后对于现有的系统的改造,比如撤销成功的订单之后,是直接修改原单的成功状态到撤销状态,还是说再创建一条撤销记录?还有对账系统核对时,对端记录可能比本端多,如何核对?这些问题大家在接入之后一定结合现有系统好好思考一下。

    最后,文章难免存在一些疏漏,大家如果发现,可以在评论区留言指出,谢谢支持。

    如果你也在从事支付,或者正在对接支付,欢迎加我微信,一起讨论问题,一起成长~


    作者:楼下小黑哥
    链接:https://juejin.im/post/5e97c109e51d4546cc26ca21

    展开全文
  • 扫码枪获取数据处理

    2020-12-04 11:07:01
    扫码枪的工作原理和键盘输入事件一样: 方法一、在created钩子函数里面监听键盘输入的事件获取扫码枪输入的值: var b = ""; var _this = this; document.onkeydown = function() { if (event.keyCode != 13) ...
  • 写在前面话 项目需求,使用扫码枪扫描二维码,并把内容写入单片机内。一开始要求是把固件和生产信息同时写入 ...之前项目买 USB 扫码枪原理是模拟键盘输出,不是工业串口输出。为了省下100多块钱,我决定
  • C# 通过钩子原理实现对USB扫码枪驱动,亲测有效,这个是我已经运用到项目开发软件中一个子功能,拿出来和大家分享下!
  • js获取USB扫码枪数据

    万次阅读 热门讨论 2018-08-22 15:46:58
    扫码枪扫描到条形码每一位会触发一次onkeydown事件 比如扫描条码位‘1234567890’条形码,会连续执行10次onkeydown事件 条码扫描到最后一位,会直接触发Enter 代码 需要引入jQuery,我这里用是...
  • 扫码支付原理

    千次阅读 2019-10-27 22:20:47
    一、主动扫码 1、网页上购物后扫码支付 二维码对应URL中有商家信息及订单信息,扫码后通过我们支付宝或微信把钱转给商家账户...1、别人用手机扫我们自己收钱码或扫码枪扫我们自己收钱码 二维码上是我们账...
  • 原理就是监听键盘输入,比如扫一个为697059613012669条形码,用扫码枪扫一下会在光标位置依次输出: 6 9 7 0 5 9 6 1 3 0 2 6 但这不是完整,所以需要写一个函数scanEvent来整理收集到每个编号。 let code...
  • 软件介绍: Honey Well扫描枪在WINDOWS 32 X...安装并连接设备后,能够通过串口方式访问USB接口Honey Well扫码枪,通过虚拟串口读取数据并上位到软件中。内含条码基本知识.ppt课件,对读懂扫码原理非常有用。
  • c# 全局钩子实现扫码枪获取信息。 原文:c# 全局钩子实现扫码枪获取信息。1.扫描枪获取数据原理基本相当于键盘数据,获取扫描枪扫描出来数据,一般分为两种实现方式。  a)文本框输入获取焦点,...
  • 在react中如何实现扫码枪输入

    千次阅读 2018-07-03 14:03:07
    原理就是监听键盘输入,比如扫一个为697059613012669条形码,用扫码枪扫一下会在光标位置依次输出: 6 9 7 0 5 9 6 1 3 0 2 6 但这不是完整,所以需要写一个函数scanEvent来整理收集到每个编号。 let ...
  • 条码扫描器是针对条形译码一种专业条码设备。它有很多种叫法,如条码扫描、扫描、条码阅读器、条码读取器、条码扫描仪。接下来描述中我们会在几种名称之间进行任意切换,其实概念是一样。条码扫描器一般...
  • 51单片机 使用条码扫描条码后 条码内容显示在数码管上 使用protues仿真做成 压缩包含有protues程序和keil程序 我只做了数字显示 字母和符号可以自己添加 主要是理解原理
  • 条码扫描器是针对条形译码一种专业条码设备。它有很多种叫法,如条码扫描、扫描、条码阅读器、条码读取器、条码扫描仪。接下来描述中我们会在几种名称之间进行任意切换,其实概念是一样。 条码扫描器...
  • 原理扫码枪和键盘输入是一个效果,支持一次扫码输入13个字符,jsonkeydown事件监听,键盘输入事件,获取商品条形码号ajax弹窗打开对应商品明细页面,光标默认停到快递号文本框,再次扫码快递单号。完成录入。 ...
  • 通过修改前段代码实现,基本就是利用password框不能输入中文的原理。亲测有效,直接上代码: <html><head> <meta content="text/html; charset=UTF-8" http-equiv="Content-Type"> <title>...
  • 通过本课程学习,了解扫描设备工作原理,以及如何识别整件条形和单件条形商品。适用人群电脑爱好者、所有职场人士,IT软件开发人员课程简介现在是信息化时代,也是扫描时代,作为软件开发IT人士,在开发软件...
  • 现在是信息化时代,也是扫描时代,作为软件开发IT人士,在开发软件... 本课程章节计划表: 第一章 扫描枪扫码识别解析概述 第二章 扫描工作原理 第三章 扫描条形码如何识别单件条码和整件条码 第四章 注意事项、总结
  • Android 扫码枪 读取(外接键盘读取)1、概述android 设备外接一个 标准扫码枪,要把扫码枪扫到内容取出来。...扫码枪和外接键盘原理是一样,类比,也特意拿了个外接键盘一起调研了。2、扫码枪-输入设备项...

空空如也

空空如也

1 2
收藏数 36
精华内容 14
关键字:

扫码枪的原理