393 lines
12 KiB
PHP
393 lines
12 KiB
PHP
<?php
|
||
|
||
namespace App\ServicePay;
|
||
|
||
use App\Models\Merchant;
|
||
use App\Models\Order;
|
||
use Illuminate\Support\Facades\Log;
|
||
use Yansongda\Pay\Pay;
|
||
use Yansongda\Pay\Gateways\Wechat\Support;
|
||
use Illuminate\Support\Collection;
|
||
use Illuminate\Http\Request;
|
||
use Ixudra\Curl\Facades\Curl;
|
||
|
||
class WeixinAlipayServices implements PayApiInterface
|
||
{
|
||
|
||
use PayTrait;
|
||
public $gateway_list;//当前类型的支付通道列表
|
||
public $pay_type;//支付类型
|
||
public $pay_method;//支付方法
|
||
public $pay_gateway;//当前的支付通道实例
|
||
public $pay_config;//这个通道的支付配置信息
|
||
public $pay_model;//支付接口实例模型
|
||
public $order;
|
||
public $request;
|
||
public $gateway_id;
|
||
public $pay_data;
|
||
public $log_name;
|
||
public static $result;
|
||
|
||
|
||
/**
|
||
* 检查通道是否存在错误
|
||
*/
|
||
public function checkGatewayConfig()
|
||
{
|
||
$pay_method = $this->pay_method;
|
||
if (count($this->gateway_list) <= 0) {
|
||
self::addError(['msg' => '通道支付不存在']);
|
||
}
|
||
if (!isset($this->gateway_list[$pay_method])) {
|
||
self::addError(['msg' => '通道支付类型不存在']);
|
||
}
|
||
|
||
}
|
||
|
||
/**
|
||
* 支付包配置实列化
|
||
* @param $type
|
||
* @param array $setConfig
|
||
* @return $this
|
||
*/
|
||
public function payConfig($type, $setConfig = [])
|
||
{
|
||
$config = $this->getPayAccount($type);
|
||
|
||
$extend_config = [
|
||
'log' => [ // optional
|
||
'file' => to_linux_path(base_path()) . '/paylogs/' . $type . '_pay.log',
|
||
'level' => 'info', // 建议生产环境等级调整为 info,开发环境为 debug
|
||
'type' => 'daily', // optional, 可选 daily.
|
||
'max_file' => 30, // optional, 当 type 为 daily 时有效,默认 30 天
|
||
],
|
||
'return_url' => action('Pay\PayController@returnNotify', ['type' => $type]),
|
||
'notify_url' => action('Pay\PayController@notify', ['type' => $type]),
|
||
'http' => [ // optional
|
||
'timeout' => 5.0,
|
||
'connect_timeout' => 5.0,
|
||
// 更多配置项请参考 [Guzzle](https://guzzle-cn.readthedocs.io/zh_CN/latest/request-options.html)
|
||
]
|
||
|
||
];
|
||
if ($this->pay_gateway['is_dev'] == 1) {
|
||
$extend_config['mode'] = 'dev';//沙箱
|
||
}
|
||
$this->pay_config = $setConfig + $extend_config + $config;
|
||
Log::info(json_encode($this->pay_config));
|
||
switch ($type) {
|
||
case 'alipay':
|
||
$this->pay_model = Pay::alipay($this->pay_config);
|
||
//dump('我用了支付宝');
|
||
break;
|
||
case 'weixin':
|
||
$this->pay_model = Pay::wechat($this->pay_config);
|
||
break;
|
||
}
|
||
return $this;
|
||
}
|
||
|
||
//回调指定通道配置信息gateway
|
||
public function getConfig($gateway_id, $pay_method)
|
||
{
|
||
$this->pay_method = $pay_method;
|
||
|
||
return $this->pay_model = config('gateway.config')[$gateway_id];
|
||
}
|
||
|
||
|
||
public function getPayConfig()
|
||
{
|
||
return $this->pay_config;
|
||
}
|
||
|
||
public function pay($pay_data)
|
||
{
|
||
$method = $this->pay_method;
|
||
$pay = $this->pay_model->$method($pay_data);
|
||
if (in_array($method, ['web', 'wap', 'app'])) {
|
||
return $pay->send();//直接发送支付
|
||
} else {
|
||
//扫码返回
|
||
return $pay;
|
||
}
|
||
}
|
||
|
||
/*
|
||
* 验证签名
|
||
*/
|
||
public function verify()
|
||
{
|
||
|
||
return $this->pay_model->verify();
|
||
|
||
}
|
||
|
||
/**
|
||
* 支付账号信息
|
||
* @param $type
|
||
* @return array
|
||
*/
|
||
public function getPayAccount($type)
|
||
{
|
||
$config = [];
|
||
switch ($type) {
|
||
//支付宝配置
|
||
case 'alipay':
|
||
$config = [
|
||
'app_id' => $this->pay_gateway['app_id'],
|
||
'ali_public_key' => trim($this->pay_gateway['cert_pub']),
|
||
'private_key' => trim($this->pay_gateway['cert_key'])
|
||
];
|
||
break;
|
||
//微信
|
||
case 'weixin':
|
||
$config = [
|
||
'app_id' => $this->pay_gateway['app_id'],
|
||
'mch_id' => $this->pay_gateway['mch_id'],
|
||
'key' => $this->pay_gateway['app_key']
|
||
];
|
||
break;
|
||
//小程序
|
||
case 'mini':
|
||
$config = [
|
||
'miniapp_id' => $this->pay_gateway['app_id'],
|
||
'mch_id' => $this->pay_gateway['mch_id'],
|
||
'key' => $this->pay_gateway['app_key']
|
||
];
|
||
break;
|
||
}
|
||
return $config;
|
||
}
|
||
|
||
public function setLogName($pay_type)
|
||
{
|
||
$name = '';
|
||
switch ($pay_type) {
|
||
case 'alipay':
|
||
$name = 'alipay_';
|
||
break;
|
||
case 'weixin':
|
||
$name = 'weixin_';
|
||
break;
|
||
|
||
}
|
||
$this->log_name = $name;
|
||
}
|
||
|
||
public function notify($return = 1, $pay_type, $request)
|
||
{
|
||
$this->request = $request;
|
||
$this->pay_type = $pay_type;
|
||
$this->setLogName($this->pay_type);
|
||
switch ($this->pay_type) {
|
||
case 'alipay':
|
||
//取得支付宝类型的订单
|
||
$this->getOrder($this->request->input('out_trade_no'));
|
||
if ($return) {
|
||
return $this->returnAlipay();
|
||
}
|
||
return $this->alipayNotify();
|
||
break;
|
||
case 'weixin':
|
||
if ($return) {
|
||
return $this->returnWeixin();
|
||
}
|
||
return $this->weixinNotify();
|
||
break;
|
||
}
|
||
|
||
}
|
||
|
||
/**
|
||
* 支付宝同步回调
|
||
*
|
||
*/
|
||
public function returnAlipay()
|
||
{
|
||
|
||
//判断是否是商户id
|
||
if ($this->order->merchant_id == 0) {
|
||
return redirect()->route('web.user.index');
|
||
}
|
||
//
|
||
return $this->merchantReturnSend();
|
||
}
|
||
|
||
/**
|
||
* 同步回调给微信支付
|
||
* @return \Illuminate\Http\RedirectResponse
|
||
*/
|
||
public function returnWeixin()
|
||
{
|
||
$this->getOrder($this->request->input('out_trade_no'));//取得微信类型的订单
|
||
//判断是否是商户id
|
||
if ($this->order->merchant_id == 0) {
|
||
return redirect()->route('web.user.index');
|
||
}
|
||
//
|
||
return $this->merchantReturnSend();
|
||
}
|
||
|
||
public function weixinNotify()
|
||
{
|
||
//$this->getOrder($this->request->input('out_trade_no'));
|
||
$content = $content ?? $this->request->createFromGlobals()->getContent();
|
||
$data = Support::fromXml($content);
|
||
$order_sn = $data['out_trade_no'];
|
||
$data = new Collection($data);
|
||
Log::info('微信过来参数' . json_encode($data->toArray()));
|
||
|
||
$this->getOrder($order_sn);
|
||
$this->commonNotify();
|
||
}
|
||
|
||
/**
|
||
* 支付宝异步回调
|
||
*/
|
||
public function alipayNotify()
|
||
{
|
||
$this->commonNotify();
|
||
}
|
||
|
||
/**
|
||
* 取得订单,支付宝和微信返回的订单号都有差异,需要分开处理
|
||
* @param $order_sn
|
||
*/
|
||
public function getOrder($order_sn)
|
||
{
|
||
$this->order = Order::where('order_sn', $order_sn)->first();
|
||
$this->pay_method = $this->order->gateway_method;//支付方法
|
||
$this->gateway_id = $this->order->gateway_id;//通道ID
|
||
$this->merchant = Merchant::find($this->order->merchant_id);
|
||
}
|
||
|
||
|
||
/**
|
||
* 支付宝统一设置参数
|
||
* @param $data
|
||
* @return bool
|
||
*/
|
||
public function alipayHandle($data)
|
||
{
|
||
|
||
$result = [
|
||
'order_sn' => $data->out_trade_no,
|
||
'pay_order_sn' => $data->trade_no,
|
||
'pay_money' => $data->total_amount,
|
||
'pay_type' => 'alipay',
|
||
'account' => $data->buyer_logon_id
|
||
];
|
||
$this->setResult($result);
|
||
Log::channel('pay_success')->info('支付宝支付成功', ['pay_type' => 'alipay', 'pay_money' => $data->total_amount, 'account' => $data->buyer_logon_id, 'order_sn' => $data->out_trade_no, 'pay_order_sn' => $data->trade_no]);
|
||
|
||
}
|
||
|
||
public function wechatHandle($data)
|
||
{
|
||
$data = $data->toArray();
|
||
$result = [
|
||
'order_sn' => $data['out_trade_no'],
|
||
'pay_order_sn' => $data['transaction_id'],//微信订单号
|
||
'pay_money' => $data['total_fee'] / 100,//订单金额,单位分/100=元
|
||
'pay_type' => 'weixin',
|
||
'account' => $data['openid'] //openid
|
||
];
|
||
$this->setResult($result);
|
||
Log::channel('pay_success')->info('微信支付成功', ['pay_type' => 'weixin', 'pay_money' => $result['pay_money'], 'account' => $result['account'], 'order_sn' => $result['order_sn'], 'pay_order_sn' => $result['pay_order_sn']]);
|
||
// Log::channel('pay_success')->info('小程序支付成功',['total'=>$data->total_fee,'openid'=>$data->openid,'out_trade_no'=>$data->out_trade_no,'order_type'=>$data->attach]);
|
||
}
|
||
|
||
public function commonNotify()
|
||
{
|
||
//取得通道信息内容
|
||
$this->gateway = $this->pay_gateway = config('gateway.config')[$this->gateway_id];
|
||
//加载通道的支付配置信息
|
||
//这里取得支付实例化$this->pay_model
|
||
$this->payConfig($this->pay_type);
|
||
//验证签名
|
||
$data = $this->verify();
|
||
|
||
$this->debugLog('-------------' . $this->order->order_sn . '--选择----' . $this->pay_type . '----' . $this->pay_method . '----开始回调处理-------------------------');
|
||
if (empty($data)) {
|
||
return $this->debugLog('验证签名失败', $this->request->all());
|
||
}
|
||
try {
|
||
$pay_cn_name = '';
|
||
switch ($this->pay_type) {
|
||
case 'alipay':
|
||
//支付宝异步回掉也是会未支付
|
||
if (!in_array($data->trade_status, ['TRADE_SUCCESS', 'TRADE_FINISHED'])) {
|
||
|
||
return false;
|
||
exit();//终止
|
||
}
|
||
$this->alipayHandle($data);
|
||
$pay_cn_name = '支付宝';
|
||
break;
|
||
case 'weixin':
|
||
$pay_cn_name = '微信';
|
||
$this->wechatHandle($data);
|
||
break;
|
||
}
|
||
$this->debugLog('验证签名成功,准备订单更新');
|
||
//支付返回信息
|
||
$this->pay_data = $data;
|
||
$this->debugLog('验证签名成功,数据', $data);
|
||
//更新订单
|
||
$this->updateOrder();
|
||
$this->debugLog('updateOrder Ok');
|
||
} catch (\Exception $exception) {
|
||
$this->debugLog('失败异常内容:' . $exception->getMessage());
|
||
if ($this->pay_type == 'alipay') {
|
||
//支付宝异步回调也是会有未支付,需要这2个判断
|
||
if (!in_array($data->trade_status, ['TRADE_SUCCESS', 'TRADE_FINISHED'])) {
|
||
return false;
|
||
}
|
||
}
|
||
$this->order->notify_status = 1;//支付回调成功
|
||
$this->order->pay_status = 1;//支付状态
|
||
$this->order->pay_ok_at = date('Y-m-d H:i:s');
|
||
$this->order->save();//保存
|
||
Log::channel('pay_success')->info($pay_cn_name . '支付成功,但处理订单失败', ['data' => json_encode($data)]);
|
||
|
||
}
|
||
|
||
}
|
||
|
||
/**
|
||
* 更新订单操作
|
||
* @return mixed|void
|
||
*/
|
||
public function updateOrder()
|
||
{
|
||
|
||
$order = $this->order;
|
||
//判断是否本站
|
||
if ($order->merchant_id == 0) {
|
||
//本地订单处理
|
||
return $this->locationOrder();
|
||
} else {
|
||
|
||
//外站订单处理
|
||
//支付宝会异步发送未支付的操作
|
||
if ($this->pay_type == 'alipay') {
|
||
$this->debugLog('alipay');
|
||
//支付宝异步回调也是会有未支付,需要这2个判断
|
||
if (!in_array($this->pay_data->trade_status, ['TRADE_SUCCESS', 'TRADE_FINISHED'])) {
|
||
return false;
|
||
}
|
||
}
|
||
|
||
return $this->outOrder();
|
||
}
|
||
|
||
}
|
||
|
||
//成功完成异步回调返回给支付商
|
||
public function success()
|
||
{
|
||
$this->pay_model->success()->send();
|
||
}
|
||
|
||
} |