当前位置:首页 > uni-app > 正文内容

uniapp开发微信小程序微信支付实战

陈杰4个月前 (12-31)uni-app644

前端框架:uniapp

后端框架:laravel

后端依赖:overtrue/wechat


照例我们还是安装一下easywechat依赖

composer require overtrue/wechat:~4.0 -vvv

配置一下我们的微信支付的sdk参数


//微信支付配置
$wechat_pay_config  = [
   // 必要配置
 'app_id'     => 'wx***********',
   'mch_id'     => '1589*********',
   'key'        => 'emiaodui*************',      // API 密钥

 // 如需使用敏感接口(如退款、发送红包等)需要配置 API 证书路径(登录商户平台下载 API 证书)
   'cert_path'  => "/www/wwwroot/maijuanba/wechat_key/apiclient_cert.pem",       // XXX: 绝对路径!!!!
 'key_path'   => "/www/wwwroot/maijuanba/wechat_key/apiclient_key.pem",        // XXX: 绝对路径!!!!
 'notify_url' => env('APP_URL') . "/api/order/notify",    // 支付回调通知路径 你也可以在下单时单独设置来想覆盖它
];
define('wechat_pay_config', $wechat_pay_config);

注意我们的cert证书需要绝对路径


-----------------------------------------

配置完成了再理一下我们的支付思路


>用户选中商品

>提交订单给后端

>后端创建订单(存储需要购买的商品,数量,总金额是多少)

>提交给微信支付创建一个支付订单

>返回数据给前端js

>前端js吊起微信支付

>微信通知后端支付结果

>前端跳转到支付结果处理界面


大概思路和步骤就是这样了,那么就着手开始搞吧一步一步来看代码实现


---------------------------------------------

前端选中商品,调用后端创建订单接口

			create_order() {
				this.request.post('/order/create_order', {
					id: this.goods.id,
					number: this.number
				}).then(res => {
					if (res.code == 20000) {
						//调起支付
						this.request.pay(res.data.pay, res.data.order)
					} else {
						uni.showToast({
							title: res.msg,
							icon: 'none'
						})
						return
					}
				})
			},

传递参数是商品的id和需要购买的数量,如果创建订单成功会吊起request.pay()方法,这个方法我们后面再看,先一步一步的来


----------------------------------------------

看看我们后端的create_order方法


public function create_order(Request $request)
{
   try {
       DB::beginTransaction();
       $id     = (int)$request->input('id');
       $number = (int)$request->input('number');
       if ($number < 1 || $number > 999)
           return self::errorMsg('购买数量范围1-999');

       $goods = GoodsModel::query()->where('id', $id)->first();
       if (!isset($goods) || $goods->status !== 0)
           return self::errorMsg('没有找到该商品');
       if ($number > $goods->limit) {
           return self::errorMsg('该商品单次最多购买' . $goods->limit . '件!');
       }
       $order = OrderModel::query()->where('goods_id', $id)
           ->where('uid', $request->get('uid'))
           ->where('status', 0)
           ->first();

       if (isset($order))
           return self::errorMsg('你已经创建了该商品的订单,请完成支付或取消支付后重新购买');

       $count = CardModel::query()->where('goods_id', $id)->where('pay', 0)->count(); //现有库存
       $lock  = OrderModel::query()->where('goods_id', $id)->where('status', 0)->sum('number'); //锁定库存

       if ($lock >= $count)
           return self::errorMsg('当前库存不够');

       $count = $count - $lock;
       if ($number > $count)
           return self::errorMsg("当前库存不够,最多购买 $count ");

       $order            = new OrderModel();
       $order->uid       = $request->get('uid');
       $order->goods_id  = $id;
       $order->number    = $number;
       $order->price     = $number * $goods->money;
       $order->money     = $goods->money;
       $order->old_money = $goods->old_money;
       $order->old_price = $number * $goods->old_money;
       $order->des_money = $order->old_price - $order->price;
       $order->order_id  = date('YmdHis', time()) . str_pad($request->get('uid'), 9, '0', STR_PAD_LEFT);;
       $order->create_time = time();
       if ($order->save()) {
           $data['order'] = $order;
           $data['pay']   = $this->pay_order($goods->name . "*" . $order->number, $order, $request);
           DB::commit();
           return self::returnMsg($data);
       } else {
           DB::rollBack();
           return self::errorMsg();
       }
   } catch (\Exception $exception) {
       DB::rollBack();
       return self::errorMsg($exception->getMessage());
   }
}


前面有一大堆的的业务逻辑,什么库存啊,限量购买啊,存在相同的订单啊,前面都通过了才可以调用我们的pay_order()方法并存储我们的订单信息入数据库,进入重头戏

            $data['order'] = $order;
           $data['pay']   = $this->pay_order($goods->name . "*" . $order->number, $order, $request); //我们要发起支付了

----------------------------------------------


看看pay_order方法

    public function pay_order($sub, $order, $request)
   {

       $app   = Factory::payment(wechat_pay_config);
       $jssdk = $app->jssdk;

       $res = $app->order->unify([
           'body'         => $sub,
           'out_trade_no' => $order->order_id,
           'total_fee'    => $order->price * 100,
      'trade_type'   => 'JSAPI', // 请对应换成你的支付方式对应的值类型
      'openid'       => $request->get('member')['openid']
       ]);

       if (!isset($res) || $res['result_code'] !== "SUCCESS")
           throw new \Exception($res['err_code_des']);

       $js        = $jssdk->bridgeConfig($res['prepay_id'], false);
       $res['js'] = $js;
       return $res;
   }


Factory类位置

use EasyWeChat\Factory;

需要注意的的是,微信的金额单位为角,我们的单位为元,有小数点用decimal类型存储,所以需要*100


这一步就是通知微信支付服务器,我们需要创建一个支付订单,让微信服务器创建一个并告诉我们调用的令牌,我们拿到令牌后再返回给我们的前端

-------------------------------------------------


现在一切顺利,我们的用户购买的商品库存够,也没发生什么其他意外,已经可以开始支付了,那么就回到我们第一步的提到的request.pay方法

	pay(data, order) {
		console.log(data);
		uni.requestPayment({
			provider: 'wxpay',
			appId: data.js.appId,
			timeStamp: data.js.timeStamp,
			nonceStr: data.js.nonceStr,
			package: data.js.package,
			signType: 'MD5',
			paySign: data.js.paySign,
			success: function(res) {
				uni.showToast({
					title: '支付成功',
					icon: "success"
				})
				setTimeout(() => {
					uni.navigateTo({
						url: "/pages/tabbar/card/pay?id=" + order.id
					})
				}, 2000)
				console.log('success:' + JSON.stringify(res));
			},
			fail: function(err) {
				console.log('fail:' + JSON.stringify(err));
			}
		});
	},


uniapp为我们提供了

uni.requestPayment()

我们在后端拿到的

this.request.pay(res.data.pay, res.data.order)

数据传递给该方法,后端返回给了我们令牌,正确传参就可以了,这样就发起支付了

注意success回调指的不是支付成功,而是正确吊起微信支付,就触发success,所以是否支付成功我们还是要跳转到支付结果页面去。

那么到底有没有支付成功呢?微信服务器会直接告诉我们的后端


--------------------------------------


看看我们后端的微信回调方法


    public function notify(Request $request)
   {
       $app      = Factory::payment(wechat_pay_config);
       $response = $app->handlePaidNotify(function ($message, $fail) {
       // 你的逻辑

           DB::beginTransaction();
           try {
               $order = OrderModel::with(['goods'])->where('order_id', $message['out_trade_no'])->first();
               if (!isset($order)) {
                   $fail('订单不存在');
                   return false;
               }

               if ($order->status == 1)
                   return true; //订单已支付

        if ($order->status == 0) {
                   //订单未支付 写确认逻辑
          $order->status        = 1;
                   $order->pay_time      = time();
                   $order->sdk_order_id  = $message['transaction_id'];
                   $order->goods->number += $order->number;
                   $card                 = CardModel::query()->where('goods_id', $order->goods_id)
                       ->where('pay', 0)
                       ->orderByDesc('prior')
                       ->orderBy('id')
                       ->limit($order->number)
                       ->get();

                   foreach ($card as $k => $v) {
                       $v->pay      = 2;
                       $v->pay_time = $order->pay_time;
                       $v->order_id = $order->id;
                       $v->uid      = $order->uid;
                       $v->money    = $order->money;
                       $v->save();
                   }

                   $order->save();
                   $order->goods->save();

                   $member            = MembersModel::query()->where('id', $order->uid)->first();
                   $member->money     += $order->price;
                   $member->old_money += $order->old_price;
                   $member->save();

                   DB::commit();
                   return true;
               }

               $fail('啥子错误!');
               return false;
           } catch (\Exception $exception) {
               $fail($exception->getMessage());
           }
       });
       return $response;
   }


前面两行主要就是鉴定微信支付传递给我们的数据是否合法,easychat已经为我们做了这些鉴定了,所以直接写我们的逻辑就行了。


如果订单不存在,或者订单已经支付成功了,那么我们就不应该继续给用户增加金额了对吧,只有正确的支付才能让我们的订单完成,然后把商品给用户。


当订单完成了,我们前端的支付结果页面就可以通过order订单的id去查数据库该订单是否支付成功了。



------------------------------------------


还有一个地方,订单创建成功了,微信也吊起支付了,但是发现钱包里面钱不够该怎么办(我当然不可能帮用户把微信钱包充满!!!!)


但是等一会用户的老公给她转了200块钱还是想购买我们的商品,当然要有一个继续支付的按钮让用户继续完成刚刚创建的订单。


前端代码,继续支付按钮的逻辑

			continue_order(id) {
				this.request.post('/order/continue_order', {
					id: id,
				}).then(res => {
					if (res.code == 20000) {
						//吊起支付
						this.request.pay(res.data.pay, res.data.order)
					} else {
						uni.showToast({
							title: res.msg,
							icon: 'none'
						})
						return
					}
				})
			},


后端代码,继续支付的令牌获取

public function continue_order(Request $request)
{
   try {
       $id    = (int)$request->input('id');
       $order = OrderModel::with(['goods:id,name'])->where('id', $id)->first();
       if (!isset($order) || $order->uid !== $request->get('uid'))
           return self::errorMsg('没有找到此订单');

       if ($order->status !== 0)
           return self::errorMsg('该订单已支付或者已过期');

       if ($order->status == 0 and $order->create_time + 300 < time())
           return self::errorMsg('该订单已过期');

       $data['order'] = $order;
       $data['pay']   = $this->pay_order($order->goods->name . "*" . $order->number, $order, $request);
       return self::returnMsg($data);
   } catch (\Exception $exception) {
       return self::errorMsg($exception->getMessage());
   }
}


这样一顿操作后,用户就可以继续支付我们刚刚的订单了


------------------------------------------------


还有我们的order表的数据结构

# Host: blog.95shouyou.com  (Version: 5.7.32-log)
# Date: 2020-12-31 14:47:53
# Generator: MySQL-Front 5.3  (Build 4.234)

/*!40101 SET NAMES utf8 */;

#
# Structure for table "order"
#

CREATE TABLE `order` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `uid` int(11) NOT NULL DEFAULT '0' COMMENT '用户id',
  `goods_id` int(11) NOT NULL DEFAULT '0' COMMENT '商品id',
  `number` int(11) NOT NULL DEFAULT '0' COMMENT '购买数量',
  `price` decimal(10,2) NOT NULL DEFAULT '0.00' COMMENT '购买总价',
  `money` decimal(10,2) NOT NULL DEFAULT '0.00' COMMENT '购买单价',
  `create_time` int(11) NOT NULL DEFAULT '0' COMMENT '创建日期',
  `status` tinyint(3) NOT NULL DEFAULT '0' COMMENT '0:未支付 1:支付 2:过期',
  `pay_time` int(11) NOT NULL DEFAULT '0' COMMENT '支付日期',
  `order_id` varchar(255) NOT NULL DEFAULT '0' COMMENT '自有订单id',
  `sdk_order_id` varchar(255) DEFAULT NULL COMMENT '第三方订单id',
  `old_money` decimal(10,2) NOT NULL DEFAULT '0.00' COMMENT '优惠前单价',
  `old_price` decimal(10,2) NOT NULL DEFAULT '0.00' COMMENT '优惠前总价',
  `des_money` decimal(10,2) NOT NULL DEFAULT '0.00' COMMENT '为用户节省的钱',
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;


扫描二维码至手机访问

扫描二维码推送至手机访问。

版权声明:本文由何烦过虎溪发布,如需转载请注明出处。

转载请注明出处:http://95shouyou.com/?id=29

分享给朋友:
返回列表

没有更早的文章了...

没有最新的文章了...

发表评论

访客

看不清,换一张

◎欢迎参与讨论,请在这里发表您的看法、交流您的观点。