laravel 支付 微信 支付宝 yansongda插件 流程使用详解
使用yansongda 开发的 ali wechat pay
1 | composer require yansongda /laravel-pay |
routes\web.php 涉及的路由
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | 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
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 | <?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 回调处理逻辑
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 | /** * @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 订单支付页面
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 | @ 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 选择不同支付方式对应的逻辑
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 | 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 调出微信二维码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 | @ 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 |