laravel 支付 微信 支付宝 yansongda插件 流程使用详解
使用yansongda 开发的 ali wechat pay
composer require yansongda/laravel-pay
routes\web.php 涉及的路由
Route::group(['prefix'=>'order'],function(){ Route::any('create', 'OrderController@create')->name("create_order"); Route::any('submit_order', 'OrderController@submit_order')->name("submit_order"); Route::any('list', 'OrderController@list_order')->name("list_order"); Route::any('contract', 'OrderController@contract')->name("order_contract"); Route::any('confirm_order_payment', 'OrderController@confirm_order_payment')->name("confirm_order_payment"); Route::any('wechat_scan', 'OrderController@wechat_scan')->name("wechat_scan"); Route::any('find_order', 'OrderController@find_order')->name("find_order"); Route::any('payment', 'OrderController@payment')->name("payment"); Route::any('export', 'OrderController@export')->name("export"); }); //回调不能有权限控制 Route::any('wechat_notify', 'Home\Member\OrderController@wechat_notify')->name("wechat_notify"); Route::any('ali_notify', 'Home\Member\OrderController@ali_notify')->name("ali_notify"); Route::any('ali_return', 'Home\Member\OrderController@ali_return')->name("ali_return");
Middleware\VerifyCsrfToken.php 注意点支付回调,需要屏蔽csrf
<?php namespace App\Http\Middleware; use Illuminate\Foundation\Http\Middleware\VerifyCsrfToken as Middleware; class VerifyCsrfToken extends Middleware { /** * Indicates whether the XSRF-TOKEN cookie should be set on the response. * * @var bool */ protected $addHttpCookie = true; /** * The URIs that should be excluded from CSRF verification. * * @var array */ protected $except = [ 'wechat_notify', 'ali_notify', 'wechat', 'wechat/*', 'payments/*' ]; }
Member\OrderController.php alipay wechat return 和notify 回调处理逻辑
/** * @param Request $request * @return mixed * @throws \Yansongda\Pay\Exceptions\InvalidSignException */ public function ali_return(Request $request){ Log::info('ali_return', ['start']); $alipay = Pay::alipay($this->ali_config); try{ $data = $alipay->verify(); // 是的,验签就这么简单! Log::info('Alipay return', $data->all()); $out_trade_no = $data->out_trade_no; $order_id = Common::getOrderIdFromOutTradeNo($out_trade_no); Order::where('id','=',$order_id)->update(['is_pay'=>1,'status' => 2,'pay_method'=>'支付宝','trade_no'=>$data->trade_no]); //更新销售合同支付状态 SaleOrder::where('order_id','=',$order_id)->update(['is_pay'=>1,'price_pay'=>DB::raw('price')]); return redirect(route("list_order")); }catch (Exception $e){ Log::info('data', ['e'=>$e]); } } /** * 阿里支付通知 * @param Request $request * @return \Symfony\Component\HttpFoundation\Response * @throws \Yansongda\Pay\Exceptions\InvalidSignException */ public function ali_notify(Request $request){ $alipay = Pay::alipay($this->ali_config); try{ $data = $alipay->verify(); // 是的,验签就这么简单! Log::info('Alipay notify', $data->all()); if ($data->trade_status == 'TRADE_SUCCESS') { $out_trade_no = $data->out_trade_no; $order_id = Common::getOrderIdFromOutTradeNo($out_trade_no); Order::where('id','=',$order_id)->update(['is_pay'=>1,'status' => 2,'pay_method'=>'支付宝','trade_no'=>$data->trade_no]); //第一次回调 客户已付金额相增 if(!Common::getSalePay($out_trade_no)) Order::where('id','=',$order_id)->increment('user_price_pay', $data->total_amount); //更新销售合同支付状态 SaleOrder::where('order_id','=',$order_id)->update(['is_pay'=>1,'price_pay'=>DB::raw('price')]); //新增支付记录 $trade = array( 'pay_method'=>'支付宝', 'order_id'=>$order_id, 'out_trade_no'=>$out_trade_no, 'trade_no'=>$data->trade_no, 'trade_price'=>$data->total_amount, 'trade_status'=>$data->trade_status, 'trade_time'=>$data->gmt_payment, 'notify_data'=>$data, ); Common::createSalePay($trade); Log::info('Alipay notify result_code', ['pay success']); }else{ Log::info('Alipay notify',['pay error']); } }catch (Exception $e){ Log::info('data', ['e'=>$e]); } return $alipay->success(); } public function wechat_scan(Request $request){ $user_id = isset(auth('member')->user()->id) ?auth('member')->user()->id : 0; $order_id = $request->get('order_id'); $order = Order::find($order_id); if(!$order){ return Redirect::to('list_order')->with('message', '没有订单,支付错误'); } if($order->user_id !=$user_id){ return Redirect::to('list_order')->with('message', '你没有权限,支付错误'); } return view('new_home.member.order.wechat_scan', compact('order')); } //微信支付回调 public function wechat_notify(Request $request) { Log::info('Wechat notify', ['start']); $pay = Pay::wechat($this->wechat_config); try { // 验签! $data = $pay->verify(); Log::info('Wechat notify verify', ['data'=>$data->all()]); if(isset($data->result_code) && $data->result_code=='SUCCESS'){ Log::info('Wechat notify verify result_code', ['pay success']); $this->updateOrder($data); return $pay->success(); }else{ Log::info('Wechat notify',['pay error']); } } catch (Exception $e) { return $e->getMessage(); } } //更新订单状态 protected function updateOrder($data){ Log::info("wechat notify data",['data'=>$data]); $out_trade_no = $data->out_trade_no; $order_id = Common::getOrderIdFromOutTradeNo($out_trade_no); $trade_no = $data->trade_no??$data->transaction_id; $trade_price = ($data->total_fee /100); Order::where('id','=',$order_id)->update(['is_pay'=>1,'status' => 2,'trade_no'=>$trade_no,'pay_method'=>'微信']); //第一次回调 客户已付金额相增 if(!Common::getSalePay($out_trade_no)) Order::where('id','=',$order_id)->increment('user_price_pay', $trade_price); //更新销售合同支付状态 SaleOrder::where('order_id','=',$order_id)->update(['is_pay'=>1,'price_pay'=>DB::raw('price')]); //新增支付记录 //微信金额是以分为单位 $trade = array( 'pay_method'=>'微信', 'order_id'=>$order_id, 'out_trade_no'=>$out_trade_no, 'trade_no'=>$trade_no, 'trade_price'=>$trade_price, 'trade_status'=>$data->result_code, 'trade_time'=>date('Y-m-d H:i:s', strtotime($data->time_end)), 'notify_data'=>json_encode($data->all()), ); Common::createSalePay($trade); return 1; } public function find_order(Request $request){ $out_trade_no = $request->get('id'); $order_id = Common::getOrderIdFromOutTradeNo($out_trade_no); $order = [ 'out_trade_no' => $out_trade_no, ]; //判断是否已经获取回调 if(Order::where(['id'=>$order_id, 'is_pay'=>1])->first()){ Log::info("wechat has huidiao", ['has']); return 1; } $result = Pay::wechat($this->wechat_config)->find($order); Log::info("wechat findOrder", ['data'=>$result]); if($result['trade_state']=='SUCCESS'){ $this->updateOrder($result); }else{ return 2; } }
Member\payment.blade.php 订单支付页面
@extends('new_home.member.base') @section('content') <ul id="myTab" class="nav nav-tabs"> <li class="active"><a href="#home" data-toggle="tab">订单支付</a></li> </ul> <div class="tab-content"> @if($order->is_pay == 1) <div class="cart-pay-order mt20"> <span class="block"></span> <span class="chongzhi-title">支付信息</span> <div class="clearfix"></div> <div class="wrap-order-item mt20"> <div class="order-pay">订单编号: <span class="primary">{{$order->order_no}}</span></div> <div class="order-pay"> <a class="layui-btn layui-btn-xs comfirmSlip" href="{{route("order_contract",["id"=>$order->id])}}" target="_blank">下载合同</a> </div> <div class="pay-money">已付金额:<span class="red pay-money-num">¥{{$order->total_price}}</span></div> </div> </div> <div class="clearfix"></div> @else <div class="cart-pay-order mt20"> <span class="block"></span> <span class="chongzhi-title">待支付订单</span> <div class="clearfix"></div> <div class="wrap-order-item mt20"> <div class="order-pay">订单编号: <span class="primary">{{$order->order_no}}</span></div> <div class="order-pay"> <a class="layui-btn layui-btn-xs comfirmSlip" href="{{route("order_contract",["id"=>$order->id])}}" target="_blank">下载合同</a> </div> <div class="pay-money">总金额:<span class="red pay-money-num">¥{{$order->total_price}}</span> 已付金额:<span class="red pay-money-num">¥{{$order->user_price_pay}}</span> 应付金额:<span class="red pay-money-num">¥{{sprintf("%.2f",($order->total_price-$order->user_price_pay))}}</span></div> </div> </div> <div class="clearfix"></div> <div class="ctn-wrap-chongzhipanel mt20"> <span class="block"></span> <span class="chongzhi-title">支付</span> <div class="clearfix"></div> <div class="pay mt20"> <ul class="pay_method"> @if(auth('member')->user()->is_deposit == 1) <li pay_method_id="0">账户额度支付 <i></i> </li> @endif <li pay_method_id="1">支付宝 <i></i> </li> <li pay_method_id="2">微信 <i></i> </li> <li pay_method_id="3">线下付款 <i></i> </li> </ul> <div class="pay-tab-content"> @if(auth('member')->user()->is_deposit == 1) <div class="pay-tab-item show" tab_index="0"> <div class="payway-content"> <div class="wrap-yuer"> <img src="/static/new/images/member/yuer.png" class="yuerimg" style="width: 80px; height: 80px;" alt=""> <span class="keyongerdu">可用额度: <span class="red keyongerdu-num">¥{{auth('member')->user()->deposit}}</span></span> </div> <div class="wrap-offlinepay"></div> </div> </div> @endif <div class="pay-tab-item" tab_index="1"></div> <div class="pay-tab-item" tab_index="2"></div> <div class="pay-tab-item" tab_index="3"> <div class="payway-content"> <div class="wrap-offlinepay-left"> <div class="paynote-title">付款账户信息</div> <p class="order-pay-info">公司名称:江苏**研发有限公司</p> <p class="order-pay-info">税号:913501166023181985</p> <p class="order-pay-info">开户银行:中国银行南京六合开发区支行</p> <p class="order-pay-info">银行帐户:970264565219</p> <p class="order-pay-info">地址:南京市六合区</p> <p class="order-pay-info">电话:025-67811055</p> <p class="order-pay-info">传真:025-88637475</p> <p class="order-pay-info">您可以通过国内任何一家银行、ATM机向实验谷指定账户汇款。</p> <p class="order-pay-info">向**网指定帐户汇款(到账时间:同行1—2个工作日,跨行2—5个工作日。</p> </div> </div> </div> </div> </div> <div class="pay-footer"> @if(auth('member')->user()->is_deposit == 1) <input type="hidden" name="payment_id" value="0"> @else <input type="hidden" name="payment_id" value="1"> @endif <a href="javascript:void(0);" class="paybtn" id="ConfirmPay">确认支付</a> </div> </div> @endif <form class="simple_form " id="order_payment_form" novalidate="novalidate" action="{{route("confirm_order_payment")}}" accept-charset="UTF-8" method="post"> <input name="utf8" type="hidden" value="✓"> @csrf <input type="hidden" name="order_id" value="{{$order->id}}"> <input type="hidden" name="platform" value=""> </form> </div> @endsection @section('js') <script language="javascript"> $(".pay_method li").eq(0).addClass('active'); $(".pay_method li i").eq(0).show(); $(".pay-tab-content .pay-tab-item").eq(0).show(); $(".pay_method li").click(function () { var index = $(".pay_method li").index(this); //console.log(index); var pay_method_id = $(this).attr('pay_method_id'); $(".pay_method li").removeClass('active'); $(this).addClass("active"); $(".pay_method li i").hide(); $(this).children('i').show(); $(".pay-tab-content .pay-tab-item").hide(); $(".pay-tab-content .pay-tab-item").eq(index).show(); $("input[name='payment_id']").val(pay_method_id); }); function go_payment(e) { if(null==$("input[name=platform]:checked",e).val()){ return alert_message("提示","请选择支付方式!",null,function(){ close_alert_div() }); } $("body").append(loading),$(e).submit(); } $("#ConfirmPay").click(function () { var payment_id = $("input[name='payment_id']").val(); if(payment_id==2){ //微信支付 $("input[name='platform']").val("wechat"); $("body").append(loading); $("#order_payment_form").submit(); }else if(payment_id==1){ //支付宝 $("input[name='platform']").val("alipay"); $("body").append(loading); $("#order_payment_form").submit(); }else if(payment_id==0){ //余额支付 alert_confirm_message('提示','确定余额支付吗?',null,function(){ close_alert_div(); $("input[name='platform']").val("deposit"); $.ajax({ url: $("#order_payment_form").attr('action'), data: $("#order_payment_form").serializeArray(), type: 'post', cache: false, dataType: 'json', success: function (data) { close_loading_div(); if(data.data.code == "SUCCESS"){ alert_message('提示', data.msg, '500px', function () { close_alert_div(); window.location.href="{{route('list_order')}}"; }) }else{ alert_message('提示', data.msg, '500px', function () { close_alert_div(); }) return false; } }, error: function () { close_loading_div(); alert_message('提示','系统异常,请联系客服人员!',null,function(){ close_alert_div(); }) } }) }, function(){ close_alert_div(); }); } }); </script> @endsection
Member\OrderController 选择不同支付方式对应的逻辑
public function confirm_order_payment(Request $request){ $user_id = isset(auth('member')->user()->id) ?auth('member')->user()->id : 0; $order_id = $request->get('order_id'); $platform = $request->get('platform'); $order = Order::find($order_id); if(!$order){ return Redirect::to('list_order')->with('message', '没有订单,支付错误'); } if($order->user_id !=$user_id){ return Redirect::to('list_order')->with('message', '你没有权限,支付错误'); } if($order->is_pay == 1){ return Redirect::to('list_order')->with('message', '订单已经支付过,请不要重复支付'); } //因为可能订单支付成功后,又去改订单金额,所以out_trade_no 不能仅仅是订单号,不然支付会重复 $out_trade_no = $order_id."_".$order->pay_version; //支付金额 $total_fee = sprintf("%.2f", ($order['total_price'] - $order['user_price_pay'])); if($platform == 'alipay'){ $order = [ 'out_trade_no' => $out_trade_no, 'total_amount' => $total_fee, 'subject' => '**网订单支付', ]; return Pay::alipay($this->ali_config)->web($order)->send(); } if($platform == 'wechat'){ $currentTab = 'list_order'; $crumbsName = "采购中心 > 求购管理 > 采购订单 >微信支付"; $info = [ 'order_no' => $order['order_no'], 'order_price' => $total_fee, ]; $order = [ //order_id' => $order_id, 'out_trade_no' => $out_trade_no, 'total_fee' => ($total_fee*100), 'body' => '**网订单支付', ]; $result = Pay::wechat($this->wechat_config)->scan($order); $qr = $result->code_url; return view('new_home.member.order.wechat_scan',compact('qr','order','currentTab','crumbsName','info')); } //余额支付 if($platform == "deposit"){ // $user = Auth::guard('member')->user(); $deposit = auth('member')->user()->deposit; if($deposit < $total_fee){ return Y::error('余额不够支付!',["code"=>"LESS_MONEY"]); } //事务处理 DB::transaction(function() use($order,$user_id, $total_fee){ Member::where("id","=",$user_id)->decrement('deposit', $total_fee); $depositArr = array( 'user_id' =>$user_id, 'price' =>$total_fee, 'is_pay' =>1, 'status' =>3, 'operation' =>2, 'pay_method' =>'账户', ); $deposit = Deposit::create($depositArr); //更新订单状态 Order::where('id','=',$order->id)->update(['status'=>2,'is_pay'=>1,'pay_method'=>'账户','trade_no'=>$deposit->id]); Order::where('id','=',$order->id)->increment('user_price_pay', $total_fee); SaleOrder::where('order_id','=',$order->id)->update(['is_pay'=>1]); }); return Y::success('支付成功!',["code"=>"SUCCESS"]); } }
wechat_scan.blade.php 调出微信二维码
@extends('new_home.member.base') @section('content') <div style="text-align: center;padding: 10px 0px;font-weight: bold;font-size: 16px;">订单号:{{$info['order_no']}} 订单金额:¥{{$info['order_price']}} 付款码</div> <div style="text-align: center;">{!! QrCode::size(300)->generate($qr) !!}</div> <div style="text-align: center;">请用微信扫描二位码支付</div> @endsection @section('js') <script type="text/javascript"> function pay_status(){ $.ajax({ url:"{{route("find_order")}}", dataType:'json', type:'get', data:{'id':"{{$order['out_trade_no']}}"}, success:function(data){ if(data == '1' ){ window.clearInterval(int); //销毁定时器 setTimeout(function(){ close_alert_div(); alert_message('提示', "支付成功", '500px', function () { window.location.href = "{{route('list_order')}}"; }); },1000) } }, }); } //启动定时器 var int=self.setInterval(function(){pay_status()},2000); </script> @endsection