小程序开发 —— 微信支付

小程序很好入门,做一个完整的商城也很方便。

对于微信产品,用微信支付也是顺理成章的。

本文的后台用 Laravel 实现(easywechat)。

一、前期准备

1、小程序 appid;

2、微信商户号;

3、商户秘钥;

二、小程序部分

1、支付按钮绑定 pay 事件

<button bindtap="pay" data-o>付款</button>

2、编写 pay 方法

思路:调用后台接口返回一些数据,然后在小程序端调用 wx.requestPayment 返回支付结果是否成功。

  /**
   * 付款
   */
  pay: function (e) {

    wx.request({
      url: app.globalData.baseUrl + 'api/wechat/pay',
      method: 'POST',
      data: {
        openId: app.globalData.openid,
        orderId: e.currentTarget.dataset.oid,
        appId: app.globalData.appId
      },

      header: {
        'Content-Type': 'application/json'
      },
      
      success: function (res) {
        var data = res.data.data;

        wx.requestPayment({
          'timeStamp': data.timeStamp,
          'nonceStr': data.nonceStr,
          'package': data.package,
          'signType': data.signType,
          'paySign': data.paySign,
          'success': function (res) {
            wx.showToast({
              title: '支付成功',
              icon: 'success',
              duration: 2000
            });
          },
          'fail': function (res) {
            wx.showToast({
              title: '支付失败',
              icon: 'none',
              duration: 2000
            });
          }
        });
      }
    })
  },

三、后台部分

思路:安装 wechat 开发包,配置小程序及支付信息,调用方法生成支付订单,进行二次签名返回数据给小程序。

1、安装 wechat 开发包

composer require overtrue/wechat -vvv

php artisan vendor:publish --provider="Overtrue\LaravelWeChat\ServiceProvider"

2、配置基本信息

在第一步生成的 config/wechat.php 文件中,修改成自己的信息。

/*
 * 小程序配置
 */
'mini_program' => [
    'default' => [
        'app_id'  => env('WECHAT_MINI_PROGRAM_APPID', ''),
        'secret'  => env('WECHAT_MINI_PROGRAM_SECRET', ''),
        'token'   => env('WECHAT_MINI_PROGRAM_TOKEN', ''),
        'aes_key' => env('WECHAT_MINI_PROGRAM_AES_KEY', ''),
    ],
],

/*
 * 微信支付配置
 */
'payment' => [
    'default' => [
        'sandbox'            => env('WECHAT_PAYMENT_SANDBOX', false),
        'app_id'             => env('WECHAT_PAYMENT_APPID', ''),
        'mch_id'             => env('WECHAT_PAYMENT_MCH_ID', 'your-mch-id'),
        'key'                => env('WECHAT_PAYMENT_KEY', 'key-for-signature'),
        'cert_path'          => env('WECHAT_PAYMENT_CERT_PATH', 'path/to/cert/apiclient_cert.pem'),
        'key_path'           => env('WECHAT_PAYMENT_KEY_PATH', 'path/to/cert/apiclient_key.pem'),
        'notify_url'         => 'http://example.com/payments/wechat-notify', // Default payment result notification address
    ],
    // ...
],

3、支付功能

public function __construct(Request $request
                            , Order $order){

    $wechat = \EasyWeChat::miniProgram();
    $pay = \EasyWeChat::payment();

    $this->wechat = $wechat;
    $this->pay = $pay;
    $this->request = $request;
    $this->order = $order;
}

/**
 * 通过 js_code 获取 openid
 */
public function getOpenId(){
    $code = $this->request->js_code;
    $out = $this->wechat->auth->session($code);

    return $this->success($out);
}

/**
 * wechat pay
 */
public function pay(){
    $appid = $this->request->appId;
    $openid = $this->request->openId;
    $orderid = $this->request->orderId;
    $order = $this->order->findOrFail($orderid);

    if(! $order){
        return $this->failed('order is not exist!');
    }

    // generate order
    $out = $this->pay->order->unify([
        'body'          => 'order name',            // order name
        'out_trade_no'  => $order->order_num,       // order number
        'trade_type'    => 'JSAPI',                 // must 'JSAPI'
        'openid'        => $openid,                 // user openid
        'total_fee'     => $order->price,           // order total price
    ]);

    // second sign
    if($out['return_code'] == 'success'){
        $param = [
            'appId'     => $appid,
            'timeStamp' => time(),
            'nonceStr'  => $out['nonce_str'],
            'package'   => 'prepay_prepay_id'],
            'signType'  => 'MD5',
        ];

// 注意文件最上面添加 use function EasyWeChat\Kernel\Support\generate_sign; $params['paySign'] = generate_sign($params, config('wechat.payment.default.key')); return $this->success($param); }else{ return $this->failed('wechat pay failed!'); } }

4、支付结果通知

支付回调路径在上面配置文件中已经设置好了。

    /**
     * payment result notify
     */
    public function notify(){
        $res = $this->wechat->handlePaidNotify(function($message, $fail){
            // find order
            $order = $this->order->where('order_num', $message['out_trade_no'])->get();

            if(!$order || $order->status == 3){
                return true;
            }

            // payment finish
            if($message['return_code'] == 'SUCCESS'){

                // payment success
                if($message['result_code'] == 'SUCCESS'){
                    $order->status = 3;
                    $order->save();

                // payment fail
                }elseif($message['result_code'] == 'FAIL'){
                    return $fail('payment fail');
                }
            }else{
                return $fail('connect fail');
            }

            return true;
        });

        $res->send();
    }

四、调试

。。