最近在開發一個項目包含web端、H5端和App端,在開發支付功能時每個端的情況略有不同在這裡做一下記錄,支付寶支付使用Yangsongda,微信支付使用EasyWeChat,如有不對之處歡迎指正。
安裝Yansongda
composer require yansongda/pay -vvv
安裝EasyWeChat
composer require w7corp/easywechat
下面上代碼,可以直接使用
use EasyWeChat\Factory;
use Yansongda\LaravelPay\Facades\Pay;
class PayController extends BaseController
{
public function buyVip(Request $request)
{
$user_id = $this->getUserId();
$type = $request->input('type', '');
$id = (int)$request->input('id', 0);
$device_type = $this->deviceType;
if (!$type) {
return $this->error('支付類型不能為空');
}
if (!$id) {
return $this->error('商品ID不能為空');
}
$vip = Vip::where('id', $id)->first();
if (!$vip) {
return $this->error('充值金額不存在');
}
if ($type == 'wxpay') {
$order = OrderService::createOrder($user_id, $vip, 'alipay');
$config = config('wechat.payment.default');
$app = Factory::payment($config);
if ($device_type == 'app') {
// APP支付
$result = $app->order->unify([
'body' => $order['subject'],
'out_trade_no' => $order['order_sn'],
'total_fee' => $order['amount'] * 100,
//'notify_url' => 'https://pay.weixin.qq.com/wxpay/pay.action', // 支付結果通知網址,如果不設定則會使用配置裡的預設位址
'trade_type' => 'APP', // 請對應換成你的支付方式對應的值類型
]);
} else {
if (isWechat()) {
$openid = DB::table('user')->where('id', $user_id)->value('wechat_openid');
if (!$openid) {
return $this->error('openid不存在');
}
//h5 微信jssdk
$result = $app->order->unify([
'body' => $order['subject'],
'out_trade_no' => $order['order_sn'],
'total_fee' => $order['amount'] * 100,
//'notify_url' => 'https://pay.weixin.qq.com/wxpay/pay.action', // 支付結果通知網址,如果不設定則會使用配置裡的預設位址
'trade_type' => 'JSAPI', // 請對應換成你的支付方式對應的值類型
'openid' => $openid,
]);
} else {
// web/h5 掃碼支付
$result = $app->order->unify([
'body' => $order['subject'],
'out_trade_no' => $order['order_sn'],
'total_fee' => $order['amount'] * 100,
//'notify_url' => 'https://pay.weixin.qq.com/wxpay/pay.action', // 支付結果通知網址,如果不設定則會使用配置裡的預設位址
'trade_type' => 'NATIVE', // 請對應換成你的支付方式對應的值類型
]);
}
}
if ($result['return_code'] != 'SUCCESS') {
return $this->error('通信失敗:' . $result['return_msg'], $result);
}
if ($result['result_code'] != 'SUCCESS') {
return $this->error('支付失敗:' . $result['err_code'] . ':' . $result['err_code_des'], $result);
}
return $this->success('支付成功', $result);
} elseif ($type == 'alipay') {
$order = OrderService::createOrder($user_id, $vip, 'alipay');
$config = config('pay.alipay');
$alipay = Pay::alipay($config);
$body = [
'subject' => $order['subject'],
'out_trade_no' => $order['order_sn'],
'total_amount' => $order['amount'],
];
if ($device_type == 'app') {
return $alipay->web($body);
} else {
if (isMobile()) {
return $alipay->wap($body);
} else {
return $alipay->app($body);
}
}
} elseif ($type == 'applepay') {
$order = OrderService::createOrder($user_id, $vip, 'applepay');
$data = [
'order_id' => $order['id'],
'order_sn' => $order['order_sn'],
'price' => $order['amount'],
'payment' => $order['payment']
];
return $this->success('操作成功', $data);
}
return $this->error('error');
}
//微信支付異步回調
public function wxpayNotify()
{
$config = config('wechat.payment.default');
$app = Factory::payment($config);
$response = $app->handlePaidNotify(function ($message, $fail) {
// 使用通知裡的 "微信支付訂單号" 或者 "商戶訂單号" 去自己的資料庫找到訂單
$order = Order::where('order_sn', $message['out_trade_no'])->first();
if (!$order || $order->status == 1) { // 如果訂單不存在 或者 訂單已經支付過了
return true; // 告訴微信,我已經處理完了,訂單沒找到,别再通知我了
}
/ <- 建議在這裡調用微信的【訂單查詢】接口查一下該筆訂單的情況,确認是已經支付 /
if ($message['return_code'] != 'SUCCESS') { // return_code 表示通信狀态,不代表支付狀态
return $fail('通信失敗,請稍後再通知我');
}
// 使用者是否支付成功
if (array_get($message, 'result_code') === 'SUCCESS') {
$order->pay_time = time(); // 更新支付時間為目前時間
$order->status = 1;
// 使用者支付失敗
} elseif (array_get($message, 'result_code') === 'FAIL') {
$order->status = 2;
}
$order->save(); // 儲存訂單
return true; // 傳回處理完成
});
return $response;
}
//支付寶支付異步回調
public function alipayNotify(Request $request)
{
$config = config('pay.alipay');
$alipay = Pay::alipay($config);
try {
$data = $alipay->verify(); // 是的,驗簽就這麼簡單!
//以下根據自己業務進行支付校驗
$order = Order::where('order_sn', $data->out_trade_no)->first();
if (!$order || $order->status == 1) {
//如果訂單狀态異常直接退出
return $alipay->success();
}
\Log::debug('Alipay notify', $data->all());
//進行訂單狀态變更等支付成功操作
PayService::handleOrderPaid($order);
return $alipay->success();
} catch (\Exception $e) {
}
return $alipay->success();// laravel 架構中請直接 `return $alipay->success()`
}
//支付寶支付同步接口
public function alipayReturn(Request $request)
{
$config = config('pay.alipay');
$alipay = Pay::alipay($config);
return $alipay->gateway()->verify($request->all());
}
//蘋果支付訂單結果查詢
public function appleNotify(Request $request)
{
$receipt_data = $request->input('receipt-data', '');
$order_sn = $request->input('order_sn', '');
$is_sandbox = (int)$request->input('is_sandbox', 0);
if (!$receipt_data || !$order_sn) {
return $this->error('缺少必要參數');
}
//是否沙箱環境
$sandbox = false;
if ($is_sandbox) {
$sandbox = true;
}
$result = PayService::validateApplePay($receipt_data, $sandbox);
if ($result['status'] == true) {
//通過驗證
$order = Order::where('order_sn', $order_sn)->first();
if (!$order) {
return $this->error('訂單不存在');
}
if ($order['status'] != 1) {
PayService::handleOrderPaid($order);
}
return $this->success('支付成功');
} else {
return $this->error($result['message']);
}
}
}
代碼中有幾個類庫沒有引入,要根據自己實際情況添加。
也可以參考該文章:
可能是我用過的最優雅的 Alipay 和 WeChat 的支付 SDK 擴充包了 — 闫嵩達 | yansongda
Web端調起支付效果
移動端調起支付效果