thinkPHP+easyWeChat开发微信公众号支付,企业付款,红包

easywechat 配置

 public function __construct()
    {
        $configModel = new Setting();
        $this->orderModel = new Orders();
        $this->memberModel = new Members();
        $config = [
            // 必要配置
            'app_id' => $configModel->get('ADMIN_APP_ID')->conf_value,
            'secret' => $configModel->get('ADMIN_SECRET')->conf_value,
            'mch_id' => $configModel->get('ADMIN_MCH_ID')->conf_value,
            'key' => $configModel->get('ADMIN_KEY')->conf_value,   // API 密钥

            // 如需使用敏感接口(如退款、发送红包等)需要配置 API
            'cert_path' => $configModel->get('ADMIN_CERT_PATH')->conf_value, // XXX: 绝对路径!!!!
            'key_path' => $configModel->get('ADMIN_KEY_PATH')->conf_value,    // XXX: 绝对路径!!!!

            'notify_url' => '',     // 可以在下单时单独设置覆盖它
            'log' => [
                'level' => 'debug',
                'permission' => 0777,
                'file' => Env::get('root_path') . 'runtime/wechat/wxpay.log',
            ],
        ];
        $this->app = Factory::payment($config);
    }

下单

参数释义;

body 备注
out_trade_no 商户内部定单号,不能重复,生成示例见附一
total_fee  金额,
notify_url 回调通知地址,此处设置会覆盖掉配置里面的

 $param = array(
            'body' => '书币',
            'out_trade_no' => $order_info['orderno'],
            'total_fee' => $order_info['price'],
            'notify_url' => $_SERVER['HTTP_HOST'].$_SERVER['SCRIPT_NAME'].'/index/notify/notify',
            'openid' => $_W['user']['base_openid'],

        );
        $wxPay = new WXPay();
        $res = $wxPay->WeixinPrePay($param);
        return json(['data'=>$res,'error'=>0,'message'=>'']);

WXpay

namespace WXPay;

use app\common\model\Members;
use app\common\model\Orders;
use app\common\model\Settlements;
use think\Model;
use EasyWeChat\Payment\Application;
use EasyWeChat\Payment\Order;
use think\Config;
use EasyWeChat\Factory;
use think\facade\Log;
use app\common\model\Setting;
use think\facade\Env;


class WXPay
{
    private $orderModel;
    private $memberModel;

    public function __construct()
    {
        $configModel = new Setting();
        $this->orderModel = new Orders();
        $this->memberModel = new Members();
        $config = [
            // 必要配置
            'app_id' => $configModel->get('ADMIN_APP_ID')->conf_value,
            'secret' => $configModel->get('ADMIN_SECRET')->conf_value,
            'mch_id' => $configModel->get('ADMIN_MCH_ID')->conf_value,
            'key' => $configModel->get('ADMIN_KEY')->conf_value,   // API 密钥

            // 如需使用敏感接口(如退款、发送红包等)需要配置 API
            'cert_path' => $configModel->get('ADMIN_CERT_PATH')->conf_value, // XXX: 绝对路径!!!!
            'key_path' => $configModel->get('ADMIN_KEY_PATH')->conf_value,    // XXX: 绝对路径!!!!

            'notify_url' => '',     // 可以在下单时单独设置覆盖它
            'log' => [
                'level' => 'debug',
                'permission' => 0777,
                'file' => Env::get('root_path') . 'runtime/wechat/wxpay.log',
            ],
        ];
        $this->app = Factory::payment($config);
    }

    /**
     * 预支付
     * @param $data
     * @param $openid
     * @return array
     */
    public function WeixinPrePay($data)
    {
        $attributes = [
            'body' => $data['body'],
            'out_trade_no' => $data['out_trade_no'],
            'total_fee' => $data['total_fee'] * 100,
            'notify_url' => $data['notify_url'], // 回调地址
            'trade_type' => 'JSAPI',
            'openid' => $data['openid'],
        ];

        $result = $this->app->order->unify($attributes);
        if ($result['return_code'] == 'SUCCESS' && $result['result_code'] == 'SUCCESS') {
            $prepayId = $result['prepay_id'];
            $jssdk = $this->app->jssdk;
            $config = $jssdk->sdkConfig($prepayId);   //JSSDK 支付参数
            $buildConfig = $jssdk->buildConfig(array('chooseWXPay'));  //jssdk 支付配置
            $json = $jssdk->bridgeConfig($prepayId);  //WeixinJSBridge 支付配置
            return ['status' => 200, 'msg' => '', 'config' => $config, 'buildConfig' => $buildConfig, 'WeixinJSBridge' => $json];
        } else {
            return ['status' => 400, 'msg' => '调起支付失败,请稍后尝试'];
        }
    }
$config  jssdk支付参数  
$jssdk->bridgeConfig($prepayId);   WeixinJSBridge 支付配置
$buildConfig   jdsdk配置

html页面发起支付

微信文档:https://pay.weixin.qq.com/wiki/doc/api/jsapi.php?chapter=7_3

https://mp.weixin.qq.com/wiki?t=resource/res_main&id=mp1421141115

ps:不能拉起支付窗口时请检查当前域名是否在微信商户里js授权列表

1.jssdk 方式

需要先配置  wx.config 

<script src="//res.wx.qq.com/open/js/jweixin-1.2.0.js" type="text/javascript" charset="utf-8"></script>
<script src="//code.jquery.com/jquery-3.1.1.min.js"></script>
<script type="text/javascript" charset="utf-8">
    wx.config({$buildConfig|raw});
</script>
<body class="bg-secondary">

			<button class="btn btn-default1 h50 fs18 mt20  layout1 confirm" id="ok">jssdk确认支付</button>
			<button class="btn btn-default1 h50 fs18 mt20  layout1 confirm" id="ok2">JSBridge确认支付</button>
			

		
	</body>
	<script>

		
		//方式一
        function onBridgeReady(){
            WeixinJSBridge.invoke(
                'getBrandWCPayRequest', {$WeixinJSBridge|raw},
                function(res){
                    if(res.err_msg == "get_brand_wcpay_request:ok" ) {
                        alert("支付成功");
                        //window.location.href="__URL__/user_pay_success&order_id=1";
                    }else{
                        alert(res.errMsg);
                        alert("交易失败,请重试");
                        //window.location.href="__URL__/index?v="+Math.random();
                    }
                }
            );
        }
		$(function(){

		    
		    // 方式二
			$("#ok").click(function(){

                wx.chooseWXPay({
                    timestamp: '{$config['timestamp']}',
                    nonceStr: '{$config['nonceStr']}',
                    package: '{$config['package']}',
                    signType: '{$config['signType']}',
                    paySign: '{$config['paySign']}', // 支付签名
	                success: function (res) {
	                    if(res.errMsg == "chooseWXPay:ok" ) {
	                        alert('支付成功。');
	                       //window.location.href="__URL__/user_pay_success&order_id=";
	                    }else{
	                        alert(res.errMsg);
	                        alert("支付失败,请返回重试。");
	                        //window.location.href="__URL__/index?v="+Math.random();
	                    }

	                },
	                cancel:function(res){

	                }
	            });

			})



            $("#ok2").click(function(){

                onBridgeReady();

            })
		})

	</script>
</html>

2.WeixinJSBridge方式

function onBridgeReady(){
		   WeixinJSBridge.invoke(
		       'getBrandWCPayRequest', {$rspArray['payinfo']},
		       function(res){     
		           if(res.err_msg == "get_brand_wcpay_request:ok" ) {
		           	// alert("支付成功");
		           	window.location.href="__URL__/user_pay_success&order_id={$order['id']}";
		           }else{
		           	alert("交易失败,请重试");
		           	window.location.href="__URL__/index?v="+Math.random();
		           }
		       }
		   ); 
		}


//官方示例
function onBridgeReady(){
   WeixinJSBridge.invoke(
      'getBrandWCPayRequest', {
         "appId":"wx2421b1c4370ec43b",     //公众号名称,由商户传入     
         "timeStamp":"1395712654",         //时间戳,自1970年以来的秒数     
         "nonceStr":"e61463f8efa94090b1f366cccfbbb444", //随机串     
         "package":"prepay_id=u802345jgfjsdfgsdg888",     
         "signType":"MD5",         //微信签名方式:     
         "paySign":"70EA570631E4BB79628FBCA90534C63FF7FADD89" //微信签名 
      },
      function(res){
      if(res.err_msg == "get_brand_wcpay_request:ok" ){
      // 使用以上方式判断前端返回,微信团队郑重提示:
            //res.err_msg将在用户支付成功后返回ok,但并不保证它绝对可靠。
      } 
   }); 
}
if (typeof WeixinJSBridge == "undefined"){
   if( document.addEventListener ){
       document.addEventListener('WeixinJSBridgeReady', onBridgeReady, false);
   }else if (document.attachEvent){
       document.attachEvent('WeixinJSBridgeReady', onBridgeReady); 
       document.attachEvent('onWeixinJSBridgeReady', onBridgeReady);
   }
}else{
   onBridgeReady();
}

支付成功回调

此处根据订单号识别订单类型,然后执行各自逻辑,当没有回复微信时,微信会多次发通知,所以在此处要判断是否处理过,避免重复购买

$order = $this->getInfoByOrderNo($message['out_trade_no']);
if (!$order || $order['status'] == 1) { // 如果订单不存在 或者 订单已经支付过了
    return true;
}
 /**
     * Notes:支付回调,根据订单号前两位判断交易类型,然后交给相应Model处理
     * @author:xxf
     * Date: 2018/5/8
     * Time: 14:46
     * @param $type 支付类型
     * @throws \EasyWeChat\Kernel\Exceptions\Exception
     */
    public function notify()
    {
        $response = $this->app->handlePaidNotify(
            function ($message, $fail) {
                Log::info('微信支付回调:' . json_encode($message));

                if ($message['return_code'] === 'SUCCESS') { // return_code 表示通信状态,不代表支付状态
                    // 用户是否支付成功
                    if ($message['result_code'] === 'SUCCESS') {
                        $type = substr($message['out_trade_no'], 0, 2); //订单号前两位判断支付场景,CX促销活动,CZ普通充值
                        switch ($type) {
                            case 'CZ';
                                $this->orderModel->payRechargeNotify($message);
                                break;
                            case 'CX';
                                $this->orderModel->payActivityNotify($message);
                                break;
                            default:
                                return $fail('单号异常,请稍后再通知我');
                                break;
                        }

                        // 用户支付失败
                    } elseif ($message['result_code'] === 'FAIL') {
                        //db('user_orders')->where('id',$message['out_trade_no'])->update('status',7);
                    }
                } else {
                    return $fail('通信失败,请稍后再通知我');
                }
                return true; // 返回处理完成
            });
        $response->send();
    }

到此 支付完成

企业付款

企业付款,退款,发送红包等接口必须配合证书路径

public function payToBalance($data)
    {
        $data = array(
            'partner_trade_no' => $data['partner_trade_no'], // 商户订单号
            'openid' => $data['openid'],
            'check_name' => 'FORCE_CHECK', // NO_CHECK:不校验真实姓名, FORCE_CHECK:强校验真实姓名
            're_user_name' => $data['realname'],
            'amount' => $data['amount'] * 100, // 付款金额,单位为分
            'desc' => $data['desc'], // 付款操作说明信息。必填

        );
        $result = $this->app->transfer->toBalance($data);
        Log::info('付款到余额:' . json_encode($result));
        return $result;
    }

付款到 红包,银行卡相关接口

WXpay.php

<?php

namespace app\wechatPay;

use think\Model;
use EasyWeChat\Payment\Application;
use EasyWeChat\Payment\Order;
use think\Config;
use EasyWeChat\Factory;
use think\Log;


class Wxpay
{

    public function __construct()
    {

        $config = [
            // 必要配置
            'app_id' => 'wxc0330dcea20',
            'secret' => 'c96af09b',
            'mch_id' => '14963',
            'key' => '7c44f0413daljoeihoandjnaahdhawee',   // API 密钥

            // 如需使用敏感接口(如退款、发送红包等)需要配置 API
            'cert_path' => ROOT_PATH . 'public/wechat/apiclient_cert.pem', // XXX: 绝对路径!!!!
            'key_path' => ROOT_PATH . 'public/wechat/apiclient_key.pem',    // XXX: 绝对路径!!!!

            'notify_url' => '/user/index/notify',     // 可以在下单时单独设置覆盖它
            'log' => [
                'level' => 'debug',
                'permission' => 0777,
                'file' => ROOT_PATH . 'runtime/wechat/wxpay.log',
            ],
        ];
        $this->app = Factory::payment($config); 
    }

    /**
     * 预支付
     * @param $data
     * @param $openid
     * @return array
     */
    public function WeixinPrePay($data, $openid)
    {
        Log::init([
            'type' => 'File',
            'path' => APP_PATH . 'logs/'
        ]);

        $attributes = [
            'body' => $data['body'],
            'out_trade_no' => $data['out_trade_no'],
            'total_fee' => $data['total_fee'] * 100,
            'notify_url' => $data['notify_url'], // 回调地址
            'trade_type' => 'JSAPI',
            'openid' => $openid,
        ];

        $result = $this->app->order->unify($attributes);
        Log::info('微信支付参数:' . json_encode($attributes));
        Log::info('支付结果:' . json_encode($result));
        if ($result['return_code'] == 'SUCCESS' && $result['result_code'] == 'SUCCESS') {
            $prepayId = $result['prepay_id'];
            $jssdk = $this->app->jssdk;
            $config = $jssdk->sdkConfig($prepayId);   //JSSDK 支付参数
            $buildConfig = $this->app->jssdk->buildConfig(array('chooseWXPay'));  //jssdk 支付配置
            $json = $jssdk->bridgeConfig($prepayId);  //WeixinJSBridge 支付配置
            return ['status' => 200, 'msg' => '', 'data' => $config, 'buildConfig' => $buildConfig, 'WeixinJSBridge' => $json];
        } else {
            return ['status' => 400, 'msg' => '调起支付失败,请稍后尝试'];
        }
    }

    public function buildConfig()
    {


        $buildConfig = $this->app->jssdk->buildConfig(array('chooseWXPay'));  //jssdk 配置

        return $buildConfig;

    }


    /**
     * 提现到余额
     * Notes:
     * @author:xxf
     * Date: 2018/5/8
     * Time: 14:11
     * @param $data
     * @return array|\EasyWeChat\Kernel\Support\Collection|object|\Psr\Http\Message\ResponseInterface|string
     * @throws \EasyWeChat\Kernel\Exceptions\InvalidConfigException
     */
    public function payToBalance($data)
    {
        $data = array(
            'partner_trade_no' => $data['partner_trade_no'], // 商户订单号
            'openid' => $data['openid'],
            'check_name' => 'FORCE_CHECK', // NO_CHECK:不校验真实姓名, FORCE_CHECK:强校验真实姓名
            're_user_name' => $data['realname'],
            'amount' => $data['amount'] * 100, // 付款金额,单位为分
            'desc' => $data['desc'], // 付款操作说明信息。必填

        );
        $result = $this->app->transfer->toBalance($data);
        Log::info('付款到余额:' . json_encode($result));
        return $result;
    }


    /**
     * 查询付款到零钱的订单
     * @param $partnerTradeNo
     * @author xingxiong.fei@163.com
     * @throws \EasyWeChat\Kernel\Exceptions\InvalidConfigException
     */
    public function getToBalanceOrder($partnerTradeNo)
    {

        $result = $this->app->transfer->queryBalanceOrder($partnerTradeNo);

        return $result;
    }


    /**
     * 付款到银行卡
     * @author xingxiong.fei@163.com
     * @throws \EasyWeChat\Kernel\Exceptions\InvalidConfigException
     * @throws \EasyWeChat\Kernel\Exceptions\RuntimeException
     */
    public function payToBankCard()
    {
        $result = $this->app->transfer->toBankCard([
            'partner_trade_no' => '1229222022',
            'enc_bank_no' => '6214830901234564', // 银行卡号
            'enc_true_name' => 'cc',   // 银行卡对应的用户真实姓名
            'bank_code' => '1001', // 银行编号
            'amount' => 100,  // 单位:分
            'desc' => '测试',
        ]);

        return $result;
    }

    /**
     * 付款到银行查询
     * @param $partnerTradeNo
     * @author xingxiong.fei@163.com
     * @return array|\EasyWeChat\Kernel\Support\Collection|object|\Psr\Http\Message\ResponseInterface|string
     * @throws \EasyWeChat\Kernel\Exceptions\InvalidConfigException
     */
    public function getToBankCardOrder($partnerTradeNo)
    {

        return $this->app->transfer->queryBankCardOrder($partnerTradeNo);
    }

    /**
     * Notes:发送红包
     * Date: 2019/6/26
     * Time: 11:03
     * @return mixed
     */
    public function redPacket()
    {
        $redpackData = [
            'mch_billno'   => 'xy123456',
            'send_name'    => '测试红包',
            're_openid'    => 'oxTWIuGaIt6gTKsQRLau2M0yL16E',
            'total_num'    => 1,  //固定为1,可不传
            'total_amount' => 100,  //单位为分,不小于100
            'wishing'      => '祝福语',
            'client_ip'    => '192.168.0.1',  //可不传,不传则由 SDK 取当前客户端 IP
            'act_name'     => '测试活动',
            'remark'       => '测试备注',
            // ...
        ];

        $result = $this->app->redpack->sendNormal($redpackData);

        return $result;
    }




    /**
     * Notes:支付回调
     * @author:xxf
     * Date: 2018/5/8
     * Time: 14:46
     * @param $type 支付类型
     * @throws \EasyWeChat\Kernel\Exceptions\Exception
     */
    public function notify()
    {
        Log::init([
            'type' => 'File',
            'path' => APP_PATH . 'logs/'
        ]);


        $response = $this->app->handlePaidNotify(
            function ($message, $fail) {

                Log::info('微信支付回调:' . json_encode($message));
                $type = substr($message['out_trade_no'], 0, 2); //订单号前两位判断何种支付,CC乘车 BX保险 YH购买优惠券 BZ 保证金
                 //每日收入
                $date = date("Y-m-d", time());
                $temp = db('profit_day')->where('day', $date)->find();
                if (!$temp)
                {
                    $data['day'] = $date;
                    db('profit_day')->insert($data);
                }
                /*if ($type == 'CC'){
                    $order = db('user_orders')->where('order_number',$message['out_trade_no'])->find();
                }
                $order = db('user_orders')->where('order_number',$message['out_trade_no'])->find();
                if (!$order || $order['status']==7) { // 如果订单不存在 或者 订单已经支付过了
                    return true;
                }*/
                if ($message['return_code'] === 'SUCCESS') { // return_code 表示通信状态,不代表支付状态
                    // 用户是否支付成功
                    if ($message['result_code'] === 'SUCCESS') {
                        switch ($type) {
                            case 'CC';
                                $order = db('user_orders')->where('order_number', $message['out_trade_no'])->find();
                                if (!$order || $order['orderStatus'] == 6) { // 如果订单不存在 或者 订单已经支付过了
                                    return true;
                                }
                                db('user_orders')->where('order_number', $message['out_trade_no'])->update(['orderStatus' => 6]);
                                db('profit_day')->where('day', $date)->setInc('pay_profit', $message['total_fee']/100);
                                break;
                            case 'YH';
                                $order = db('coupon_user')->where('order_number', $message['out_trade_no'])->find();
                                if (!$order || $order['status'] == 1) {
                                    return true;
                                }
                                db('coupon_user')->where('order_number', $message['out_trade_no'])->update(['status' => 1]);
                                db('profit_day')->where('day', $date)->setInc('coupon_profit', $message['total_fee']/100);
                                break;
                            case 'BZ';
                                $order = db('bail')->where('order_number', $message['out_trade_no'])->find();
                                if (!$order || $order['status'] == 1) {
                                    return true;
                                }
                                db('bail')->where('order_number', $message['out_trade_no'])->update(['pay_status' => 1]);
                                db('user')->where('uid', $order['uid'])->setInc('cancel_times');
                                break;
                            case 'BX';
                                $order = db('insurance_user')->where('order_number', $message['out_trade_no'])->find();
                                if (!$order || $order['status'] == 1) {
                                    return true;
                                }
                                db('insurance_user')->where('order_number', $message['out_trade_no'])->update(['status' => 1]);
                                db('profit_day')->where('day', $date)->setInc('insurance_profit', $message['total_fee']/100);
                                break;

                        }
                        /*
                        db('user_orders')->where('order_number',$message['out_trade_no'])->update(['status' => 7]);*/


                        // 用户支付失败
                    } elseif ($message['result_code'] === 'FAIL') {
                        //db('user_orders')->where('id',$message['out_trade_no'])->update('status',7);
                    }
                } else {
                    return $fail('通信失败,请稍后再通知我');
                }
                return true; // 返回处理完成
            });
        $response->send();
    }

}

附一  生成订单号

/**
 * 生成订单号
 * Time: 11:15
 * @param $type 订单类型
 * @return string
 */
function makeOrdersn($type='')
{
    @date_default_timezone_set("PRC");
    //订单号码主体(YYYYMMDDHHIISSNNNNNNNN)
    $order_id_main = $type.date('YmdHis') . rand(10000000,99999999);
    $order_id_len = strlen($order_id_main);
    $order_id_sum = 0;
    for($i=0; $i<$order_id_len; $i++){
        $order_id_sum += (int)(substr($order_id_main,$i,1));
    }
    //唯一订单号码(YYYYMMDDHHIISSNNNNNNNNCC)
    $order_id = $order_id_main . str_pad((100 - $order_id_sum % 100) % 100,2,'0',STR_PAD_LEFT);
    return $order_id;
}

评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

flysnownet

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值