精华内容
下载资源
问答
  • 之前一篇文章介绍python3封装成类调用微信JSAPI下单、支付、生成付款码,本文介绍python实现微信分账功能。 微信支付里面分账接口调用时需要证书,本文介绍python使用证书。 1 JSAPI文档地址 JSAPI文档,普通商户...

    之前一篇文章介绍python3封装成类调用微信JSAPI下单、支付、生成付款码,本文介绍python实现微信分账功能。
    微信支付里面分账接口调用时需要证书,本文介绍python使用证书。

    1 JSAPI文档地址

    JSAPI文档,普通商户微信分账是通过https请求实现的。

    2 代码实现

    封装一个类WxPay,实现微信分账,有如下接口:

    • 普通商户添加分账接收方
    • 普通商户删除分账接收方
    • 普通商户单次分账请求
    • 普通商户查询分账请求
    • 普通商户完结分账

    2.1 类主体框架

    import logging
    import requests
    import time
    import json
    import hmac
    import hashlib
    
    headers = {
        'Accept': 'application/json, text/javascript, */*; q=0.01',
        'Accept-Encoding': 'gzip, deflate, br',
        'Accept-Language': 'zh-CN,zh;q=0.9,en;q=0.8',
        'Cache-Control': 'no-cache',
        'Connection': 'keep-alive',
        'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8',
        'Pragma': 'no-cache',
        'User-Agent': 'self-defind-user-agent',
        'Cookie': 'name=self-define-cookies-in header',
        'X-Requested-With': 'XMLHttpRequest'
    }
    
    def get_md5(data, salt=True):
        if salt:
            return hashlib.md5('get{0}{1}md5'.format(data, time.time()).encode(encoding='UTF-8')).hexdigest()
        else:
            return hashlib.md5(data.encode(encoding='UTF-8')).hexdigest()
    
    class WxPay:
        __key = 'xxxxxxxx'  # 商户API密钥,自己的商户密钥
        __appid = 'xxxxxxxxx'  # 小程序ID(是),自己的小程序ID
        __mch_id = 'xxxxxx'  # 商户号,自己的商户号
        __device_info = ''  # 设备号(否),这里用门店号做参数
        __nonce_str = ''  # 随机字符串(是)
        __sign = ''  # 签名(是)
        __body = ''  # 商品描述(是)
        __out_trade_no = ''  # 商户订单号(是),传入系统商品订单
        __total_fee = ''  # 标价金额(是),订单总金额,单位为分
        __spbill_create_ip = ''  # 终端IP(是)
        __notify_url = 'https://www.xxxxxx.com/'  # 通知地址(是),填项自己的url地址
        __trade_type = 'JSAPI'  # 交易类型(是),小程序支付
        __cert_name = 'xxxx.p12' # 证书名称
        __cert_pwd = 'xxxxx'  # 同__mch_id
    

    2.2 生成随机字符串函数

    在类里面定义随机字符串生成函数,代码如下:

    	@staticmethod
        def get_nonce_str():
            return get_md5(WxPay.__appid)
    

    2.3 生成MD5签名函数

    在类里面定义签名字符串生成函数,代码如下:

    	@staticmethod
        def get_sign_str(sign_dict: dict):
            data = ''
            sort_keys = sorted(sign_dict)  # 从小到大排序
            for i, key in enumerate(sort_keys):
                data += '{0}={1}&'.format(key, sign_dict.get(key, ''))
            data += 'key={0}'.format(WxPay.__key)
            print(data)
    
            return get_md5(data, False).upper()
    

    注意:签名里面的key一定要先按升序排序,再组合生成MD5

    2.4 生成HMAC-SHA256签名函数

    	@staticmethod
        def create_hmac_sha256_signature(key: str, message: str):
            byte_key = key.encode('utf-8')
            message = message.encode('utf-8')
            return hmac.new(byte_key, message, hashlib.sha256).hexdigest().upper()
    
        @staticmethod
        def get_sign_strc_hmac_sha256(sign_dict: dict):
            data = ''
            sort_keys = sorted(sign_dict)  # 从小到大排序
            for i, key in enumerate(sort_keys):
                data += '{0}={1}&'.format(key, sign_dict.get(key, ''))
            data += 'key={0}'.format(WxPay.__key)
            print(data)
    
            return WxPay.create_hmac_sha256_signature(WxPay.__key, data)
    

    2.5 数据转换函数

    	@staticmethod
        def get_xml_str(sign_dict: dict):
            xml_data = '<xml>'
            for k, v in sign_dict.items():
                xml_data += '<{0}>{1}</{0}>'.format(k, v)
            xml_data += '</xml>'
            # print(xml_data)
    
            return xml_data
    
    	@staticmethod
    	def xml_to_dict(xml_data: str):
    	    dict_data = {}
    	    result = xml_data.split('\n')
    	    for res in result:
    	        if 'total_fee' in res:
    	            dict_data['total_fee'] = res.split('<total_fee>')[-1].split('<')[0]
    	            continue
    	
    	        tmp1 = res.split('><![CDATA[')
    	        if len(tmp1) == 2:
    	            tmp2, tmp3 = tmp1[0].split('<'), tmp1[1].split(']')
    	            dict_data[tmp2[-1]] = tmp3[0] if tmp3 else ''
    	
    	    return dict_data
    

    2.6 创建带证书接口请求函数

    1. 先安装requests_pkcs12,用于发送带证书接口请求
    2. 微信申请证书,参照微信证书申请文档
    3. 代码如下:
    	@staticmethod
        def send_post_cert(url, jsonData):
            try:
                from requests_pkcs12 import post
                # 注意:用res.content,不用res.text,否则会有中文乱码
                res = post(url=url, data=jsonData.encode('utf-8'), headers=headers,
                           pkcs12_filename=WxPay.__cert_name, pkcs12_password=WxPay.__cert_pwd)
                print(res.content.decode("utf-8"))
                return res.content.decode("utf-8")
            except Exception as e:
                logging.error('[send_get]Failed to json.load, {0}'.format(e))
                return ''
    

    说明:

    • pkcs12_filename:对应的是证书名称
    • pkcs12_password:对应证书密码,密码是商户号
    • 证书格式:.p12格式证书

    2.7 普通商户添加分账接收方

    	@staticmethod
        def profit_add_receiver(type: str, account: str, relation_type: str):  # 普通商户添加分账接收方
            # https://pay.weixin.qq.com/wiki/doc/api/allocation.php?chapter=27_1&index=1
            nonce_str = WxPay.get_nonce_str()
            argc_dict = {'appid': WxPay.__appid, 'mch_id': WxPay.__mch_id,
                         'receiver': json.dumps({'account': account, 'relation_type': relation_type, 'type': type},
                                                separators=(',', ':'), ensure_ascii=False),
                         'nonce_str': nonce_str, 'sign_type': 'HMAC-SHA256'}
            sign_str = WxPay.get_sign_strc_hmac_sha256(argc_dict)
            argc_dict['sign'] = sign_str
    
            url = 'https://api.mch.weixin.qq.com/pay/profitsharingaddreceiver'
            data = WxPay.get_xml_str(argc_dict)
    
            return WxPay.send_post(url, data)
    

    2.8 普通商户删除分账接收方

    	@staticmethod
        def profit_del_receiver(type: str, account: str):  # 普通商户删除分账接收方
            # https://pay.weixin.qq.com/wiki/doc/api/allocation.php?chapter=27_1&index=1
            nonce_str = WxPay.get_nonce_str()
            argc_dict = {'appid': WxPay.__appid, 'mch_id': WxPay.__mch_id,
                         'receiver': json.dumps({'account': account, 'type': type},
                                                separators=(',', ':'), ensure_ascii=False),
                         'nonce_str': nonce_str, 'sign_type': 'HMAC-SHA256'}
            sign_str = WxPay.get_sign_strc_hmac_sha256(argc_dict)
            argc_dict['sign'] = sign_str
    
            url = 'https://api.mch.weixin.qq.com/pay/profitsharingremovereceiver'
            data = WxPay.get_xml_str(argc_dict)
    
            return WxPay.send_post(url, data)
    

    2.9 普通商户单次分账请求

    	@staticmethod
        def create_profit_sharing(transaction_id: str, out_order_no: str, type: str, account: str, amount: int,
                                  description: str):  # 普通商户单次分账请求
            # https://pay.weixin.qq.com/wiki/doc/api/allocation.php?chapter=27_1&index=1
            nonce_str = WxPay.get_nonce_str()
            argc_dict = {'appid': WxPay.__appid, 'mch_id': WxPay.__mch_id, 'transaction_id': transaction_id,
                         'out_order_no': out_order_no,
                         'receivers': json.dumps({'account': account, 'amount': amount, 'description': description,
                                                  'type': type}, separators=(',', ':'), ensure_ascii=False),
                         'nonce_str': nonce_str, 'sign_type': 'HMAC-SHA256'}
            sign_str = WxPay.get_sign_strc_hmac_sha256(argc_dict)
            argc_dict['sign'] = sign_str
    
            url = 'https://api.mch.weixin.qq.com/secapi/pay/profitsharing'
            data = WxPay.get_xml_str(argc_dict)
    
            return WxPay.send_post_cert(url, data)
    

    2.10 普通商户查询分账请求

    	@staticmethod
        def get_profit_sharing(transaction_id: str, out_order_no: str):  # 普通商户查询分账请求
            # https://pay.weixin.qq.com/wiki/doc/api/allocation.php?chapter=27_1&index=1
            nonce_str = WxPay.get_nonce_str()
            argc_dict = {'mch_id': WxPay.__mch_id, 'transaction_id': transaction_id,
                         'out_order_no': out_order_no, 'nonce_str': nonce_str, 'sign_type': 'HMAC-SHA256'}
            sign_str = WxPay.get_sign_strc_hmac_sha256(argc_dict)
            argc_dict['sign'] = sign_str
    
            url = 'https://api.mch.weixin.qq.com/pay/profitsharingquery'
            data = WxPay.get_xml_str(argc_dict)
    
            return WxPay.send_post(url, data)
    

    2.11 普通商户完结分账

    	@staticmethod
        def finish_profit_sharing(transaction_id: str, out_order_no: str, description: str):  # 普通商户完结分账
            # https://pay.weixin.qq.com/wiki/doc/api/allocation.php?chapter=27_1&index=1
            nonce_str = WxPay.get_nonce_str()
            argc_dict = {'appid': WxPay.__appid, 'mch_id': WxPay.__mch_id, 'transaction_id': transaction_id,
                         'out_order_no': out_order_no, 'description': description,
                         'nonce_str': nonce_str, 'sign_type': 'HMAC-SHA256'}
            sign_str = WxPay.get_sign_strc_hmac_sha256(argc_dict)
            argc_dict['sign'] = sign_str
    
            url = 'https://api.mch.weixin.qq.com/secapi/pay/profitsharingfinish'
            data = WxPay.get_xml_str(argc_dict)
    
            return WxPay.send_post_cert(url, data)
    

    3 完整代码

    完整代码和接口调用例子

    展开全文
  • 主要给大家介绍了关于C#实现微信分账功能的完整步骤,文中通过示例代码介绍的非常详细,对大家学习或者使用C#具有一定的参考学习价值,需要的朋友们下面来一起学习学习吧
  • 微信分账相关资料

    千次阅读 2021-04-22 17:08:01
    接口文档 ... 微信小程序后端java服务商分账实现 ... JAVA微信分账 http://www.cxyzjd.com/searchArticle?qc=java%E5%BE%AE%E4%BF%A1%E5%88%86%E8%B4%A6&..
    展开全文
  • 一、什么是微信分账 微信分账即微信推出的交易资金再分配产品,收款后按照平台的业务规则,无需中转直接进行资金分配;主要用于服务商帮助特约商户完成订单收单后的资金分配。 微信分账的推出主要有三个方面的原因...

    一、什么是微信分账

    微信分账即微信推出的交易资金再分配产品,收款后按照平台的业务规则,无需中转直接进行资金分配;主要用于服务商帮助特约商户完成订单收单后的资金分配。

    微信分账的推出主要有三个方面的原因:

    市场方面:

    在现有环境下,电商平台或者多级分销、加盟代理模式,订单参与方较多,需要用户统一付款后由平台方统一收款,再根据订单参与方统一分账。

    政策方面:

    市场需求与政策规范有所冲突,监管机构加大了对大商户+二清模式的打击力度。

    微信支付方面:

    在上述两个情况下,微信支付将自身的清结算能力赋能给平台商户。

    前提概念:

    • 分账方:即分账发起方,是商品或服务的提供方,这里指特约商户。
    • 分账接收方:接收分账资金的商户或个人,如:特约商户上游的供应方、合作的商户、商户的员工、商户的用户等。

    步骤:

    分账方通过微信收款的订单,由微信扣除手续费后,冻结在分账方的账户(分账方不可见)。

    分账方根据具体的业务情况和场景,通过微信分账接口,将订单的信息上传微信(分账接收方、分账金额等)。

    微信将相应资金,分配到各接收方账户中(微信商户账户或微信零钱)。

    资金流向说明:

    假设用户支付 1000 元:

    微信扣除 6 元手续费;

    微信将 994 元冻结至特约商户账户中(此时金额不可见);

    商户上传分账信息,为两个分账商户分别分账 50 元与 40 元;

    微信分别为两个分账接受方分账 50 元与 40 元;

    微信将剩余的 904 元结算至特约商户的账户中。

    微信分账的优点:

    • 合规:在微信体系内,由微信负责将交易资金分别结算给收款方,平台避免了违规的风险;
    • 合理纳税:各收款方根据真实收入合理纳税;
    • 开通周期短:与微信企业付款不同的是,企业无需三个月的等待期,可以通过微信服务商(例如 Ping++)开通,快速上线。

    二、微信分账适用场景

    酒店预订:

    用户缴纳订房费用后,资金可先冻结在酒店的商户号中,待用户确认到店消费后,服务商可根据情况,将资金分账给 OTA 平台、服务商或房东。

    订餐外卖:

    用户在订餐平台的某个餐饮商户下单完成支付后,用户支付的订餐资金先冻结在该餐饮商户的商户号中;待用户确认收货后,服务商掉按指令分账的接口,将订餐资金进行分配,例如分账给外卖员、订餐平台抽佣,剩余资金解冻给餐饮商户。

    停车场:

    用户在停车场缴纳停车费用后,资金先冻结在停车场的商户号中,服务商根据与停车证之间的协议,将停车费分配给其他微信支付商户,例如智能停车系统服务商。


    三、微信分账的特点

    分账接收方:支持 4 种方式创建接收方。

    • 公司:微信商户号(不限定是同义个服务商下的特约商户)
    • 个人:微信号、分账方公众号 OpenID、服务商公众号 OpenID

    支付方式:

    • 仅限于标记了的订单参与分账
    • 支持微信所有支付方式

    分账方式:

    • 基于订单进行分账
    • 先冻结、再分账
    • 最长冻结期限为 30 
    • 单笔订单分账方最多支持 50 
    • 可分账金额为扣除手续费后的金额
    • 为了保证特约商户的资金安全,特约商户可以设定允许服务商分配资金的最大比例

    报表:

    按照分账方、分账接收方可提供独立报表

    • 支付报表:

           分账方作为特约商户,按照支付、退款交易提供支付报表;

           信息:订单号、支付金额、手续费、付款用户、购买商品等。

    • 分账报表:

           分账方、分账接收方,按照每笔支付订单的分账金额,提供分账报表;

           信息:支付订单号、分账方、分账接收方、分账金额、分账时间等。 

    微信分账与微信企业付款的区别:


    四、微信分账如何开通

    • 通过有微信分账权限的支付服务商开通微信分账功能,目前 Ping++ 已对接微信分账接口。

     

    本文由 PingPlusPlus支付学院(IDpingxxpi)出品,未经允许,禁止转载。

     

     

    展开全文
  • ci微信支付,微信分账

    2020-01-15 09:27:31
    配置文件application\config\... <?...defined('BASEPATH') OR exit('No direct script access allowed'); /** * 微信分账支付配置 */ $config['wxpay_profitsharing'] = [ 'mch_id'=>'商户号', 'appid'=&...

    配置文件application\config\config.php

    <?php
    defined('BASEPATH') OR exit('No direct script access allowed');
    /**
    * 微信分账支付配置
    */
    $config['wxpay_profitsharing'] = [
        'mch_id'=>'商户号', 
        'appid'=>'商户APPID',
        'AppSecret'=> '密钥',
        'key'=>'key',
        'sandbox'=> false,  //沙盒环境
        'notify_url'=> '回调跳地址',
        "usecert" => [
            "cert"  => "apiclient_cert.pem",
            "key"   => "apiclient_key.pem"
        ]
    ];

    模型application\models\Wxpay_model.php

    <?php
    defined('BASEPATH') OR exit('No direct script access allowed');
    class Wxpay_model extends CI_Model
    {
        public $unifiedorderUrl;
        public $profitsharingaddreceiverUrl;
        public $profitsharingremovereceiverUrl;
        public $profitsharingUrl;
        public $conf;
        public function __construct()
        {
            parent::__construct();
            //自动判断是否用沙盒环境
            $this->conf = $this->config->item('wxpay_profitsharing');
            if($this->conf['sandbox'] == true){
                $baseUrl = "https://api.mch.weixin.qq.com/sandboxnew/pay/";
            }else{
                $baseUrl = "https://api.mch.weixin.qq.com/pay/";
            }
            $this->unifiedorderUrl = $baseUrl."unifiedorder"; //统一下单
            $this->profitsharingaddreceiverUrl = $baseUrl."profitsharingaddreceiver"; //添加分账接收方
            $this->profitsharingremovereceiverUrl = $baseUrl."profitsharingremovereceiver"; //添加分账接收方
            $this->profitsharingUrl = "https://api.mch.weixin.qq.com/secapi/pay/profitsharing"; //请求单次分账
        }
        /**
         * 创建支付
         * @param $param
         * @return false|string
         */
        public function createPay($param){
            $param['appid'] = $this->conf['appid'];
            $param['mch_id'] = $this->conf['mch_id'];
            $param['nonce_str'] = $this->noncestr();
            $param['spbill_create_ip'] = $this->input->ip_address();
            $param['notify_url'] = $this->conf['notify_url'];
            $param['trade_type'] = 'JSAPI';
            $param['sign'] = $this->sign($param, $this->getSignKey());//签名;
            $postXml = $this->arrayToXml($param); //转换成xml
            $resp = $this->httpRequest($this->unifiedorderUrl, $postXml);
            $xml = simplexml_load_string($resp);
            if((string)$xml->return_code != "SUCCESS" || (string)$xml->result_code != "SUCCESS"){
                log_message('error',$xml);
                return json_encode(['code'=>-1,'msg'=>(string)$xml->return_msg], JSON_UNESCAPED_UNICODE|JSON_UNESCAPED_SLASHES);
            }
            $payParam = array(
                'appId'         => $param['appid'],
                'package'       => "prepay_id=".(string)$xml->prepay_id,
                'nonceStr'      => $param['nonce_str'],
                'timeStamp'     => time(),
                'signType'      => 'MD5',
            );
            $signNew = $this->sign($payParam, $this->getSignKey());//生产js用的签名;
            $payParam['paySign'] = $signNew;
            return json_encode(['code'=>0,'msg'=>'ok','data'=>$payParam],JSON_UNESCAPED_UNICODE|JSON_UNESCAPED_SLASHES);
        }
        /**
         * 获取openid和其他参数
         * @param $arr  url参数
         * @return array|void
         */
        public function getOpenidAndState($arr){
            $appid = $this->conf['appid'];
            $secret = $this->conf['AppSecret'];
            $code = $this->input->get('code');
            $state2 = urldecode($this->input->get('state'));
            if(empty($code) && empty($state2)){ //没获取到code
                $redirectUri = urlencode("回调地址");
                $state1 = urlencode(json_encode($arr));
                $url = "https://open.weixin.qq.com/connect/oauth2/authorize?appid={$appid}&redirect_uri={$redirectUri}&response_type=code&scope=snsapi_base&state={$state1}#wechat_redirect";
                header("Location: {$url}");
                return;
            }else{ //已经获取code
                $accessToken = redis()->get('h5_access_token');
                redis()->close();
                if(empty($accessToken)) {
                    $url = "https://api.weixin.qq.com/sns/oauth2/access_token?appid={$appid}&secret={$secret}&code={$code}&grant_type=authorization_code";
                    $resJson = $this->httpGet($url);
                    $resArr = json_decode($resJson,true);
                    $refresh_token = $resArr['refresh_token'];
                    redis()->set('h5_access_token', $resJson, 7199);
                    redis()->close();
                }else{
                    $accessTokenArr =  json_decode($accessToken,true);
                    $refresh_token = $accessTokenArr['refresh_token'];
                }
                $url2 = "https://api.weixin.qq.com/sns/oauth2/refresh_token?appid={$appid}&grant_type=refresh_token&refresh_token=$refresh_token";
                $res2 = $this->httpGet($url2);
                $openid = json_decode($res2,true)['openid'];
                return ['openid'=>$openid, 'state'=>json_decode($state2,true)];
            }
        }
        /**
         * 获取验签秘钥
         * @return bool|string
         */
        public function getSignKey(){
            if($this->conf['sandbox'] == true){ //沙盒环境
                $arr = [
                    'mch_id'=>$this->conf['mch_id'],
                    'nonce_str'=>$this->noncestr()
                ];
                $sign = $this->sign($arr, $this->conf['key']);
                $postXml = "<xml>
                   <mch_id>{$arr['mch_id']}</mch_id>
                   <nonce_str>{$arr['nonce_str']}</nonce_str>
                   <sign>{$sign}</sign>
                </xml>";
                $resp = $this->httpRequest("https://api.mch.weixin.qq.com/sandboxnew/pay/getsignkey", $postXml);
                $xml = simplexml_load_string($resp);
                if((string)$xml->return_code=="SUCCESS"){
                    return (string)$xml->sandbox_signkey;
                }else{
                    return $resp;
                }
            }else{ //生产环境
                return $this->config->item('wxpay_profitsharing')['key'];
            }
        }
        /**
         * 添加分账接收方
         * @param $param
         * @return false|string
         */
        public function addreceiver($param){
            $param['appid'] = $this->conf['appid'];
            $param['mch_id'] = $this->conf['mch_id'];
            $param['nonce_str'] = $this->noncestr();
            $param['sign_type'] = 'HMAC-SHA256';
            $param['sign'] = $this->signSHA256($param, $this->getSignKey());//签名
            $postXml = $this->arrayToXml($param); //转换成xml
            $resp = $this->httpRequest($this->profitsharingaddreceiverUrl, $postXml);
            $xml = simplexml_load_string($resp);
            if((string)$xml->return_code != "SUCCESS" || (string)$xml->result_code != "SUCCESS"){
                log_message('error',$xml);
                return json_encode(['code'=>-1,'msg'=>(string)$xml->err_code_des], JSON_UNESCAPED_UNICODE|JSON_UNESCAPED_SLASHES);
            }
            $receiver = json_decode($param['receiver'], true);
            return json_encode(['code'=>0,'msg'=>'ok', 'data'=>$receiver],JSON_UNESCAPED_UNICODE|JSON_UNESCAPED_SLASHES);
        }
        /**
         * 申请单次分账
         * @param $param
         * @return false|string
         */
        public function applyProfitshare($param){
            $param['appid'] = $this->conf['appid'];
            $param['mch_id'] = $this->conf['mch_id'];
            $param['nonce_str'] = $this->noncestr();
            $param['sign_type'] = 'HMAC-SHA256';
            $param['sign'] = $this->signSHA256($param, $this->getSignKey());//签名
            $postXml = $this->arrayToXml($param); //转换成xml
            $resp = $this->httpRequest($this->profitsharingUrl, $postXml, true);
            $xml = simplexml_load_string($resp);
            if((string)$xml->return_code != "SUCCESS" || (string)$xml->result_code != "SUCCESS"){
                log_message('error',$xml);
                return json_encode(['code'=>-1,'msg'=>(string)$xml->err_code_des], JSON_UNESCAPED_UNICODE|JSON_UNESCAPED_SLASHES);
            }
            $receivers = json_decode($param['receivers'], true);
            return json_encode(['code'=>0,'msg'=>'ok', 'data'=>$receivers],JSON_UNESCAPED_UNICODE|JSON_UNESCAPED_SLASHES);
        }
        /**
         * 随机32位字符串
         * @return string
         */
        public function noncestr(){
            $result = '';
            $str = 'QWERTYUIOPASDFGHJKLZXVBNMqwertyuioplkjhgfdsamnbvcxz';
            for ($i=0;$i<32;$i++){
                $result .= $str[rand(0,48)];
            }
            return $result;
        }
        /**
         * MD5签名方式 $arr要先排好顺序  https://pay.weixin.qq.com/wiki/doc/api/jsapi_sl.php?chapter=4_3
         * 但是凡是调用接口的签名, 在StringA按ASCII码拼接完请求参数之后,都需要在结尾加上key值
         * @param $arr
         * @param $key  签名key
         * @return string
         */
        public function sign($arr, $key=null){
            $stringSign = '';
            ksort($arr);
            foreach ($arr as $k=>$v){
                $stringSign .= $k.'='.$v.'&';
            }
            $stringSign = trim($stringSign,"&");
            if($key){
                $stringSign .= "&key=".$key;
            }
            return strtoupper(md5($stringSign));
        }
        /**
         * HMAC-SHA256签名方式 $arr要先排好顺序  https://pay.weixin.qq.com/wiki/doc/api/jsapi_sl.php?chapter=4_3
         * @param $arr
         * @param null $key
         * @return string
         */
        public function signSHA256($arr, $key=null){
            $stringSign = '';
            ksort($arr);
            foreach ($arr as $k=>$v){
                $stringSign .= $k.'='.$v.'&';
            }
            $stringSign = trim($stringSign,"&");
            if($key){
                $stringSign .= "&key=".$key;
            }
            return  strtoupper(hash_hmac('sha256', $stringSign, $key));
        }
        /**
         * curl post请求
         * @param $url
         * @param array $data
         * @param array $headers
         * @param bool $useCert
         * @return bool|string
         */
        public function httpRequest($url,$data = null,$useCert=false,$headers=array())
        {
            $curl = curl_init();
            if( count($headers) >= 1 ){
                curl_setopt($curl, CURLOPT_HTTPHEADER, $headers);
            }
            curl_setopt($curl, CURLOPT_URL, $url);
            if($useCert == true){
                //使用证书:cert 与 key 分别属于两个.pem文件
                curl_setopt($curl,CURLOPT_SSLCERTTYPE,'PEM');
                curl_setopt($curl,CURLOPT_SSLCERT, $this->conf['usecert']['cert']);
                curl_setopt($curl,CURLOPT_SSLKEYTYPE,'PEM');
                curl_setopt($curl,CURLOPT_SSLKEY, $this->conf['usecert']['key']);
            }
            curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, FALSE);
            curl_setopt($curl, CURLOPT_SSL_VERIFYHOST, FALSE);
            if (!empty($data)){
                curl_setopt($curl, CURLOPT_POST, 1);
                curl_setopt($curl, CURLOPT_POSTFIELDS, $data);
            }
            curl_setopt($curl, CURLOPT_RETURNTRANSFER, 1);
            $output = curl_exec($curl);
            curl_close($curl);
            return $output;
        }
        /**
         * curl get请求
         * @param $url
         * @return bool|string
         */
        public function httpGet($url){
            $ch = curl_init();
            curl_setopt($ch, CURLOPT_URL,$url);
            curl_setopt($ch, CURLOPT_RETURNTRANSFER,1);
            curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
            curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false);
            $result = curl_exec($ch);
            curl_close ($ch);
            return $result;
        }
        /**
         * 将xml转为array
         * param string $xml
         */
        public function xmlToArray($xml)
        {
            if(!$xml){
                log_message('error',"支付xml数据异常!");
            }
            //将XML转为array
            //禁止引用外部xml实体
            libxml_disable_entity_loader(true);
            $values = json_decode(json_encode(simplexml_load_string($xml, 'SimpleXMLElement', LIBXML_NOCDATA)), true);
            return $values;
        }
        /**
         * 数组转换xml
         * param array $arr
         */
        public function arrayToXml($arr){
            if(!is_array($arr) || count($arr) <= 0){
                log_message('error',"数组数据异常!");
            }
            $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;
        }
    }

    控制器application\controllers\Pay.php

    <?php
    defined('BASEPATH') OR exit('No direct script access allowed');
    header("Access-Control-Allow-Credentials","true");
    header("Access-Control-Allow-Origin: * ");
    class Test extends CI_Controller
    {
        public function __construct()
        {
            parent::__construct();
            $this->load->model('Wxpay_model');
        }
        //html显示页
        public function merchantWxpay(){
            //获取参数
            $merchantId = $this->input->get('mid');
            $param = [ 'mid'=>$merchantId ];
            //获取用户openid
            $resArr  = $this->Wxpay_model->getOpenidAndState($param);
            $item = [
                'title'=>'店铺名',
                'desc'=>'店铺描述',
                'openid'=>$resArr['openid'],
                'mid'=>$resArr['state']['mid'] //商户id
            ];
            $this->load->view("wxpay", $item);
        }
        //发起输入密码请求
        public function merchantReceipt(){
            $openid = $this->input->post('openid');
            $mid = $this->input->post('mid');
            $money = $this->input->post('money');
            /**
             * todo   下单前动作
             */
            $param['openid'] = $openid;
            $param['out_trade_no'] = orderSn($mid); //生产订单号
            $param['sub_mch_id'] = '商户号';  //特约商户列表里的商户号
            $param['total_fee'] = $money * 100;
            $param['body'] = 'JSAPI_Test';
            $param['profit_sharing'] = "Y"; //开启分账
            $res = $this->Wxpay_model->createPay($param);
            echo $res;
        }
        //回调地址
        public function notifyProfitsharing(){
            $xml = file_get_contents('php://input');
            log_message('error',$xml);
            $param = $this->Wxpay_model->xmlToArray($xml);
            $sign = $param['sign'];
            unset($param['sign']);
            $signSelf = $this->Wxpay_model->sign($param, $this->Wxpay_model->getSignKey());//生签名
            //校验签名
            if($sign == $signSelf){
                if($param['return_code'] == 'SUCCESS' && $param['result_code'] == 'SUCCESS'){
                    $out_trade_no = $param['out_trade_no'];
                    $transaction_id = $param['transaction_id']; //微信返回
                    /**
                     * todo   处理回调动作
                     */
                    //https://pay.weixin.qq.com/wiki/doc/api/H5.php?chapter=9_7&index=7
                    echo "<xml><return_code><![CDATA[SUCCESS]]></return_code><return_msg><![CDATA[{$param['OK']}]]></return_msg></xml>";
                }else{
                    logMessage($param);
                    echo "<xml><return_code><![CDATA[FAIL]]></return_code><return_msg><![CDATA[{$param['err_code_des']}]]></return_msg></xml>";
                }
            }else{
                log_message('error','校验签名失败: '.$sign .'=='. $signSelf);
                echo "<xml><return_code><![CDATA[FAIL]]></return_code><return_msg><![CDATA[校验签名失败]]></return_msg></xml>";
            }
        }
        //添加分账接收方
        public function merchantAddreceiver(){
            /**
             * todo   添加前的处理
             */
            $item = [
                'type'=>'MERCHANT_ID',
                'account'=>'商户号',
                'name'=>'商户全称',
                'relation_type'=>'SERVICE_PROVIDER'
            ];
            $receiverJson = json_encode($item,JSON_UNESCAPED_UNICODE|JSON_UNESCAPED_SLASHES);
            $param['receiver'] = $receiverJson;
            $param['sub_mch_id'] = '1567643641';
            $res = $this->Wxpay_model->addreceiver($param);
            var_dump($res);
        }
        //申请分账
        public function applyProfitsharing(){
            //服务商最多可控制的分账资金是(订单金额-手续费)*该比例。如需修改,请联系特约商户。 (0.6%)
            $items = [
                [
                    'type'=>'MERCHANT_ID',
                    'account'=>'商户号',
                    'amount'=>0.03 * 100,
                    'description'=>'分账描述'
                ],
                [
                    'type'=>'PERSONAL_WECHATID',
                    'account'=>'个人微信号',
                    'amount'=>0.01 * 100,
                    'description'=>'分账描述'
                ],
            ];
            $receiverJson = json_encode($items,JSON_UNESCAPED_UNICODE|JSON_UNESCAPED_SLASHES);
            $param['receivers'] = $receiverJson;
            $param['sub_mch_id'] = '1567643641';
            $param['transaction_id'] = '4200000449201912198210883714';
            $param['out_order_no'] = 'ljsy2019121917080610000000148681';
            $res = $this->Wxpay_model->applyProfitshare($param);
            var_dump($res);
        }
    }

    站帮html页面application\views\wxpay.php

    <!DOCTYPE html>
    <html lang="zh-cn">
    <head>
        <meta charset="UTF-8">
        <meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
        <meta name="viewport" content="width=device-width, initial-scale=1,maximum-scale=1, user-scalable=no">
        <title>向商家付款</title>
        <link rel="stylesheet" href="https://cdn.staticfile.org/twitter-bootstrap/3.3.7/css/bootstrap.min.css" rel="stylesheet">
        <link rel="stylesheet" href="__ROOT__/statics/bbshop/news/css/basic.css">
        <link rel="stylesheet" href="__ROOT__/statics/bbshop/news/js/font-awesome/css/font-awesome.min.css">
        <style>
            .a{height:65px;line-height:65px;text-align:center;border:1px solid #ccc;background-color:white}
            .up{border-top:none}
            .left{border-left:none}
            .b{height:195px;padding:65px 0;background-color:deepskyblue}
            .b a{height:195px;display:block;font-size:20px;color:white}
            .b a:hover{text-decoration:none}
            .container-fluid{overflow:hidden;position:fixed;bottom:0;height:260px;color:#666;width:100%;font-size:30px;background-color:#ffffff}
            .form-group{margin:15px auto;width:90%}
            .form-group span{padding:5px 10px 0 0;float:right;font-size:15px;color:#999}
            .form-group .input-group input{height:60px;text-align:right;color:#333333;font-size:38px}
            .footer{overflow:hidden;position:fixed;bottom:280px;margin:0 auto;text-align:center;width:100%;color:#999;font-size:14px}
            .pay_logo{margin:0 auto;width:260px;height:100px}
            .pay_logo img{float:left;width:80px;height:80px}
            .pay_logo h1{font-size:26px;font-weight:normal;padding:15px 0 0 95px}
            .pay_logo p{padding:0 0 0 115px}
            .header{margin:15px auto;width:100%}
            body{background-color:#FFFFFF}
            .imgs{z-index:999;position:relative;top:-52px}
            *{-webkit-touch-callout:none;-webkit-user-select:none;-khtml-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none}
        </style>
    </head>
    <script>
        $(document).ready(function(){
            $("#input-money").focus(function(){
                document.activeElement.blur();
            });
        });
    </script>
    <body>
    <div class="header">
        <div class="pay_logo">
            <img src="__ROOT__/statics/bbshop/images/seller_logo.png" alt="">
            <h1><?php echo $title;?></h1>
            <!--<p>评分:4.9分</p>-->
        </div>
    </div>
    <form class="form-horizontal" action="" method="post" enctype="multipart/form-data" name="pay">
        <div class="form-group">
            <div class="input-group">
                <div class="input-group-addon" style="font-size: 30px;">¥</div>
                <input type="tel" name="money" value="1.01" id="input-money"  class="form-control" />
                <input type="hidden" name="mid" id="mid" value="<?php echo $mid;?>" />
                <input type="hidden" name="openid" id="openid" value="<?php echo $openid;?>" />
            </div>
            <span class="imgs"><img src="__ROOT__/statics/bbshop/images/cursor.gif" alt=""></span>
            <span><?php echo $desc;?></span>
        </div>
    </form>
    <!--<div class="footer">由 XXX 提供技术支持</div>-->
    <div class="container-fluid">
        <div class="row">
            <div class="col-xs-3 a" ontouchend="pay_money(this,1)">1</div>
            <div class="col-xs-3 a left" ontouchend="pay_money(this,1)">2</div>
            <div class="col-xs-3 a left" ontouchend="pay_money(this,1)">3</div>
            <div class="col-xs-3 a left" ontouchend="pay_money(this,3)"><i class="fa fa-remove"></i></div>
        </div>
        <div class="row">
            <div class="col-xs-9">
                <div class="row">
                    <div class="col-xs-4 a up" ontouchend="pay_money(this,1)">4</div>
                    <div class="col-xs-4 a up left" ontouchend="pay_money(this,1)">5</div>
                    <div class="col-xs-4 a up left" ontouchend="pay_money(this,1)">6</div>
                </div>
                <div class="row">
                    <div class="col-xs-4 a up" ontouchend="pay_money(this,1)">7</div>
                    <div class="col-xs-4 a up left" ontouchend="pay_money(this,1)">8</div>
                    <div class="col-xs-4 a up left" ontouchend="pay_money(this,1)">9</div>
                </div>
                <div class="row">
                    <div class="col-xs-8 a up" ontouchend="pay_money(this,1)">0</div>
                    <div class="col-xs-4 a up left" ontouchend="pay_money(this,1)">.</div>
                </div>
            </div>
            <div class="col-xs-3 b left" align="center">
                <a href="###" class="text" id="pay">确定
    支付</a>
            </div>
        </div>
    </div>
    <script src="https://cdn.staticfile.org/jquery/2.1.1/jquery.min.js"></script>
    <script src="https://cdn.staticfile.org/twitter-bootstrap/3.3.7/js/bootstrap.min.js"></script>
    <script>
        var fm = document.pay;
        function pay_money(obj,tip){
            if(tip==1){
                var con=document.getElementById('input-money').value;
                var num = con + obj.innerHTML;
                if(num == '.'){
                    num = '0.';
                }
                if(num>0){
                    $(".b").css('background','deepskyblue');
                }
                if(num>=1){
                    num = num.replace(/\b(0+)/gi,"");
                }            
                if(num<=99999.99 && num.toString().length<=8){
                    if(num.indexOf(".")>0){
                        num = num.replace(/\b(0+)/gi,"0");
                        if(num.toString().split(".")[1].length<=2){
                            document.getElementById('input-money').value = num;
                        }
                    }else {
                        document.getElementById('input-money').value = num;
                    }
                }
            }else if(tip==2){
                document.getElementById('input-money').value="";
            }else if(tip==3){
                var con = document.getElementById('input-money').value;
                var num = con.slice(0,-1);
                if(num < 0.01){
                    $(".b").css('background','lightblue');
                }
                document.getElementById('input-money').value = num;
            }
        }
        $('#pay').on('click',function () {
            var money = fm.money.value;
            var openid = fm.openid.value;
            var mid = fm.mid.value;
            $.post("https://xxxx/pay/merchantreceipt",
                {'mid':mid,'openid':openid,'money':money},
                function(resdata){
                    //console.log("resdata",resdata);
                    var payInfo = JSON.parse(resdata);
                    if(payInfo.code==0){
                        //https://pay.weixin.qq.com/wiki/doc/api/jsapi.php?chapter=7_7
                        WeixinJSBridge.invoke(
                            'getBrandWCPayRequest',{
                                "appId" : payInfo.data.appId, //公众号名称,由商户传入
                                "timeStamp": payInfo.data.timeStamp, //戳,自1970 年以来的秒数
                                "nonceStr" : payInfo.data.nonceStr, //随机串
                                "package" : payInfo.data.package,
                                "signType" : payInfo.data.signType, //微信签名方式:
                                "paySign" : payInfo.data.paySign  //微信签名,
                            },function(res){
                                //https://mp.weixin.qq.com/s/JEQnD_NmqNvYnCi5hCKW9g
                                if(res.err_msg == "get_brand_wcpay_request:ok" ) {
                                    console.log("充值成功!");
                                }
                            }
                        );
                    }
                }
            );
        });
    </script>
    </body>
    </html>

     

    展开全文
  • PAYJS开通微信分账功能以来,有很多同学咨询相关情况。很多同学关心有没有什么办法,可以让自己的商户号快速开通企业付款功能。这里就介绍下微信分账的具体相关内容,可以完美解决问题。 一、什么是微信分账微信...
  • PAYJS开通微信分账功能以来,有很多同学咨询相关情况。很多同学关心有没有什么办法,可以让自己的商户号快速开通企业付款功能。这里就介绍下微信分账的具体相关内容,可以完美解决问题。 一、什么是微信分账? ...
  • 微信分账说明

    千次阅读 2020-03-19 11:51:11
    分账,开通后产品设置,设置分账比例 2.添加分账接收方 添加分账接收方,也可以通过接口管理。交易中心->管理分账接收方。分账发起方选择本商户。点击添加分账接收方 3.根据开发文档分账 注意开发文档分普通...
  • 今天用java 调用 微信分账api 由于上传的数据是xml 格式, 用post请求发送 。在网上找的现成函数,微信服务器老是返回签名错误,但是我用postman 发送返回的数据没有问题,于是经过自己探索,写了个测试可用的post ...
  • 微信分账总结 1、关于微信的费率计算 金额单位首先转换为分(如果小于1元不收手续费)。 产生的手续费 = 实际支付金额 * 费率(整数位四舍五入) 例如:支付1元,费率为千分之6,则产生的手续费为 100 * 0.006 ...
  • Java微信分账怎么写

    2021-01-06 17:24:27
    刚做完微信支付到平台 然后从平台分账到商家 跪求帮助
  • C#微信分账功能

    2020-12-27 21:56:00
    分账比例:目前只有”低比例分账“vb.net教程小于等于30%分账分账金额需要减去(千6)手续费. 每一张订单只能分发,当前订单总额的百分之30可以分账; 比如:一张订单支付金额100元,这张订单只能分发29.82元。 ...
  • 先把分账金额返还给商户可以使用金额,微信再将剩余金额解冻到可使用金额,最后一起退款 3,如果订单已分账已结算–>先把分账金额返还给商户,再退款 4,如果多笔订单一起下单已分账未结算–>将分账金额返还到可用...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 4,423
精华内容 1,769
关键字:

微信分账