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