1.安装必要的第三方包
$ composer require overtrue/wechat:~5.0 -vvv
- 在控制器中添加微信支付调用方法
public function payOrder(Request $request)
{
$memberId = $request->attributes->get('memberId');
$orderSn = $request->get('orderSn');
$order = Orders::where('order_sn', $orderSn)->where('status', 0)->get()->toArray();
if (empty($order)) {
return ['code' => 404, 'massage' => '找不到订单!'];
}
try {
$config = Pay::payByWeChat(reset($order)['id'], $memberId);
return ['code' => 200, 'data' => $config];
} catch (\Exception $e) {
return ['code' => 404, 'massage' => $e->getMessage()];
}
}
3.在模型中创建支付方法
public static function getConfig()
{
$config = Configs::first()->toArray();
return [
// 必要配置
'app_id' => $config['app_id'] ?? env('WECHAT_APP_ID'),
'mch_id' => $config['mch_id'] ?? env('WECHAT_MCH_ID'),
'key' => $config['key'] ?? env('WECHAT_KEY'), // API 密钥
// 如需使用敏感接口(如退款、发送红包等)需要配置 API 证书路径(登录商户平台下载 API 证书)
// 'cert_path' => 'path/to/your/cert.pem', // 绝对路径!!!!
// 'key_path' => 'path/to/your/key', // 绝对路径!!!!
'notify_url' => route('order.notify'), // 你也可以在下单时单独设置来想覆盖它
// 'sandbox' => true, // 设置为 false 或注释则关闭沙箱模式
];
}
public static function payByWeChat($orderId, $memberId)
{
$goodsIds = OrderItems::where('orders_id', 11)->select('goods_id')->get()->toArray();
$goodsIds = array_column($goodsIds, 'goods_id');
$lastOrder = Orders::join('orders_items', 'orders_items.orders_id', '=', 'orders.id')
->where('orders.member_id', $memberId)
->where('orders.type', 0)
->whereIn('orders_items.goods_id', $goodsIds)
->where('orders.pay_time', '>=', date('Y-m-d'))
->orderBy('orders.pay_time', 'desc')
->get()
->toArray();
if (!empty($lastOrder)) {
throw new \Exception('今日该商品已达到购买上限, 支付失败!');
}
$order = Orders::find($orderId)->toArray();
$member = Members::find($memberId)->toArray();
$payment = Factory::payment(self::getConfig());
$jssdk = $payment->jssdk;
$result = $payment->order->unify([
'body' => env('APP_NAME'), // 订单说明
'out_trade_no' => $order['order_sn'], // 平台内部订单号
'total_fee' => $order['price'] * 100, // 价格, 单位为分
// 'spbill_create_ip' => '123.12.12.123', // 可选,如不传该参数,SDK 将会自动获取相应 IP 地址
// 'notify_url' => 'https://pay.weixin.qq.com/wxpay/pay.action', // 支付结果通知网址,如果不设置则会使用配置里的默认地址
'trade_type' => 'JSAPI', // 请对应换成你的支付方式对应的值类型 小程序为JSAPI
'openid' => $member['openid'],
]);
if ($result['return_code'] == 'SUCCESS' && $result['result_code'] == 'SUCCESS') {
$prepayId = $result['prepay_id'];
$config = $jssdk->sdkConfig($prepayId);
// $config['orderSn'] = $order['order_sn'];
// $config['orderId'] = $order['id'];
return $config;
// return response($config);
}
if ($result['return_code'] == 'FAIL' && array_key_exists('return_msg', $result)) {
throw new \Exception($result['return_msg']);
}
throw new \Exception($result['err_code_des']);
}
- 在控制器中添加微信回调方法
public function notify(Request $request)
{
$fields = $request->query->all();
return Pay::notifyByWeChat($fields);
}
5.在模型中创建微信回调处理方法
public static function notifyByWeChat($fields, $notify)
{
$config = self::getConfig();
$payment = Factory::payment($config);
$response = $payment->handlePaidNotify(function ($message, $fail) use ($fields) {
// 根据返回的订单号查询订单数据
$order = Orders::where('order_sn', $message['out_trade_no'])->get()->toArray();
if (!$order) {
$fail('订单不存在!');
}
$order = reset($order);
if ($order['status'] == '1') {
return true;
}
// 支付成功后的业务逻辑
if ($message['result_code'] === 'SUCCESS') {
$order['order_sn'] = $message['out_trade_no']; // 回调订单号
$order['pay_order_sn'] = $message['transaction_id']; // 回调流水号
$order['verification_code'] = Pay::generateVerificationCode();
$order['pay_time'] = date('Y-m-d H:i:s');
$order['status'] = 1;
$order = Orders::timestamps($order);
Orders::where('order_sn', $order['order_sn'])->update($order);
if ($order['type']) {
$card = OrderItems::where('order_id', $order['id']);
$timeLimit = reset($card)['time_limit'];
$member = Members::find($order['member_id'])->toArray();
$expireTime = strtotime($member['expire_time']);
if (empty($member['expire_time']) || $expireTime < time()) {
$time = date('Y-m-d', time() + $timeLimit * 86400);
} else {
$time = date('Y-m-d', $expireTime + $timeLimit * 86400);
}
$data = ['expire_time' => $time];
$data['status'] = 1;
$data['updated_at'] = date('Y-m-d H:i:s');
Members::where('id', $order['member_id'])->update($data);
}
}
return true;
});
return $response;
}
6.设置路由
Route::group([
'middleware' => 'jwt.user',
'prefix' => 'orders',
], function (Router $router) {
// 订单支付
$router->post('pay', 'OrderController@payOrder');
// 微信支付回调
$router->any('notify', 'OrderController@notify')->name('order.notify');
});
7.小程序端测试代码
wxml文件
<!--index.wxml-->
<view class="container">
<view class="userinfo">
<button wx:if="{{!hasUserInfo && canIUse}}" open-type="getUserInfo" bindgetuserinfo="getUserInfo"> 获取头像昵称 </button>
<block wx:else>
<image bindtap="bindViewTap" class="userinfo-avatar" src="{{userInfo.avatarUrl}}" mode="cover"></image>
<text class="userinfo-nickname">{{userInfo.nickName}}</text>
</block>
</view>
<view class="usermotto">
<text class="user-motto">{{motto}}</text>
</view>
</view>
// index.js
// 获取应用实例
const app = getApp()
Page({
data: {
motto: 'Hello World',
userInfo: {},
hasUserInfo: false,
canIUse: wx.canIUse('button.open-type.getUserInfo')
},
// 事件处理函数
bindViewTap() {
wx.navigateTo({
url: '../logs/logs'
})
},
onLoad() {
console.log(app.globalData)
if (app.globalData.userInfo) {
this.setData({
userInfo: app.globalData.userInfo,
hasUserInfo: true
})
} else if (this.data.canIUse) {
// 由于 getUserInfo 是网络请求,可能会在 Page.onLoad 之后才返回
// 所以此处加入 callback 以防止这种情况
app.userInfoReadyCallback = res => {
this.setData({
userInfo: res.userInfo,
hasUserInfo: true
})
}
} else {
// 在没有 open-type=getUserInfo 版本的兼容处理
wx.getUserInfo({
success: res => {
app.globalData.userInfo = res.userInfo
this.setData({
userInfo: res.userInfo,
hasUserInfo: true
})
}
})
}
},
getUserInfo(e) {
console.log(e)
var rawData = e.detail.rawData
app.globalData.userInfo = e.detail.userInfo
this.setData({
userInfo: e.detail.userInfo,
hasUserInfo: true
})
console.log(rawData)
wx.login({
success:function (res){
var code = res.code;
var token = null;
wx.request({
url: 'http://fiveyears.cc/wechat/auth',
header: {
'content-type': 'application/json'
},
data: {
code: code,
rawData: rawData
},
success(res) {
console.log(res)
token = res.data.token
console.log(token)
wx.request({
url: 'http://fiveyears.cc/orders/pay',
header: {
'content-type': 'application/json'
},
data: {
token: token,
orderSn: 'VIP2021021908181676096'
},
method: 'post',
success(res) {
console.log(res)
console.log(res.data)
console.log(res.data.data.timestamp)
wx.requestPayment({
'timeStamp':res.data.data.timestamp,//
'nonceStr': res.data.data.nonceStr,
'package': res.data.data.package,
'signType': 'MD5',
'paySign': res.data.data.paySign,
'success':function(res){
console.log(res);
},
'fail':function(res){
console.log('fail:'+JSON.stringify(res));
}
})
}
})
}
})
}
})
}
})
网友评论