290 lines
9.3 KiB
PHP
290 lines
9.3 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;
|
||
use Omnipay;
|
||
|
||
class UnionpayServices 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 $result_data;
|
||
public static $result;
|
||
|
||
//支付发起第一步:取得通道getGateway,随机通道,第二部配置支付信息,payConfig,第三部发起支付
|
||
//取得通道getGateway
|
||
public function getGateway($pay_type, $custom_gateways = [])
|
||
{
|
||
//取得支付方法和类型
|
||
$pay_config = $this->payMethod($pay_type);
|
||
$this->pay_type = $pay_config['pay_type'];
|
||
$this->pay_method = $pay_config['method'];
|
||
//取得配置通道文件
|
||
$this->gateway_list = config('gateway.' . $this->pay_type);
|
||
|
||
$this->checkGatewayConfig();
|
||
if (count(self::$errorArr) > 0) {
|
||
return false;
|
||
}
|
||
//当前的支付类型方法的通道,比如扫码支付,有多个这样子
|
||
$all_gateways = $this->gateway_list[$this->pay_method];
|
||
//当前用户是否指定了支付通道
|
||
try {
|
||
if (!is_array($custom_gateways)) {
|
||
return false;
|
||
}
|
||
if (count($custom_gateways) > 0) {
|
||
$this->pay_gateway = $this->randomCustomGateways($all_gateways, $custom_gateways);
|
||
} else {
|
||
$this->pay_gateway = $this->randomAllGateways($all_gateways);
|
||
}
|
||
//dump($this->pay_gateway);
|
||
return $this->pay_gateway;//支付数据库信息
|
||
|
||
|
||
} catch (\Exception $e) {
|
||
return false;
|
||
}
|
||
}
|
||
|
||
/**
|
||
* 检查通道是否存在错误
|
||
*/
|
||
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' => '通道支付类型不存在']);
|
||
}
|
||
|
||
}
|
||
|
||
|
||
//第二部配置支付信息,payConfig
|
||
public function payConfig($type, $setConfig = [])
|
||
{
|
||
//将支付配置模型赋值给$this->pay_model,发起支付的时候使用
|
||
$gateway = Omnipay\Omnipay::create('UnionPay_Express');
|
||
$gateway->setMerId($this->pay_gateway['app_id']); //商户号
|
||
//to_linux_path(public_path()) .
|
||
$cert_key = to_linux_path(public_path()) . $this->pay_gateway['cert_key'];
|
||
//dd($cert_key);
|
||
$gateway->setCertPath($cert_key); // 商户私钥证书
|
||
//$gateway->setCertDir( $this->pay_gateway['cert_pub']); //测试环境银联公钥证书
|
||
//$gateway->setCertPath(to_linux_path(public_path()) . '/certs/700000000000001_acp.p12'); // 商户私钥证书
|
||
$gateway->setCertDir(to_linux_path(app_path()) . '/certs/verify_sign_acp.cer'); //测试环境银联公钥证书
|
||
//dump($this->pay_gateway['cert_pub']);
|
||
$gateway->setPublicKey(to_linux_path(public_path()) . $this->pay_gateway['cert_pub']); // path or content
|
||
|
||
$gateway->setReturnUrl(action('Pay\PayController@returnNotify', ['type' => $type])); // 支付后同步通知页面地址
|
||
$gateway->setNotifyUrl(action('Pay\PayController@notify', ['type' => $type]));
|
||
// dd($this->pay_gateway['app_key']);
|
||
$gateway->setCertPassword($this->pay_gateway['app_key']); // 密码
|
||
|
||
|
||
$this->pay_model = $gateway;
|
||
|
||
}
|
||
|
||
//统一下单支付
|
||
public function pay($pay_data)
|
||
{
|
||
//dd($pay_data);
|
||
$response = $this->pay_model->purchase($pay_data)->send();
|
||
$response->redirect(); // 发起银联支付请求
|
||
}
|
||
|
||
//统一验证签名
|
||
public function verify()
|
||
{
|
||
$response = $this->pay_model->completePurchase(['request_params' => $this->request->all()])->send();
|
||
$this->result_data = $response->getData();
|
||
|
||
return $response->isPaid();
|
||
}
|
||
|
||
//返回给支付商的成功
|
||
public function success()
|
||
{
|
||
return 'success';
|
||
}
|
||
|
||
//统一回调处理
|
||
|
||
/**
|
||
* 回调第一部,如果是同步,直接回传
|
||
* @param $return
|
||
* @param $pay_type
|
||
* @param $request
|
||
* @return bool|\Illuminate\Http\RedirectResponse
|
||
*/
|
||
public function notify($return, $pay_type, $request)
|
||
{
|
||
$this->request = $request;
|
||
$this->pay_type = $pay_type;
|
||
$this->setLogName($this->pay_type);
|
||
// self::$result = $request->all();
|
||
// self::$result['pay_order_sn'] = $request->input('queryId');
|
||
//取得订单
|
||
$this->getOrder($this->request->input('orderId'));
|
||
if ($return) {
|
||
//return $this->unionPayNotify();
|
||
return $this->returnUnionPay();
|
||
}
|
||
return $this->unionPayNotify();
|
||
}
|
||
|
||
/**
|
||
* 取得订单,支付宝和微信返回的订单号都有差异,需要分开处理
|
||
* @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);
|
||
}
|
||
|
||
/**
|
||
* 同步回调
|
||
* @return \Illuminate\Http\RedirectResponse
|
||
*/
|
||
public function returnUnionPay()
|
||
{
|
||
|
||
//判断是否是商户id
|
||
if ($this->order->merchant_id == 0) {
|
||
return redirect()->route('web.user.index');
|
||
}
|
||
//
|
||
return $this->merchantReturnSend();
|
||
}
|
||
|
||
//异步回调
|
||
|
||
/**
|
||
* 获得通道信息,取得支付配置模型,验证签名,
|
||
* @return bool|void
|
||
*/
|
||
public function unionPayNotify()
|
||
{
|
||
//取得通道信息内容
|
||
$this->gateway = $this->pay_gateway = config('gateway.config')[$this->gateway_id];
|
||
//加载通道的支付配置信息
|
||
//这里取得支付实例化$this->pay_model
|
||
$this->payConfig($this->pay_type);
|
||
|
||
//验证签名
|
||
if (!$this->verify()) {
|
||
|
||
$this->debugLog('订单验证签名失败', $this->request->all());
|
||
return false;
|
||
}
|
||
$data = $this->result_data;
|
||
$this->pay_data = $this->result_data;
|
||
//如果应答状态不是01/A6表示支付失败
|
||
if (!in_array($data['respCode'], ['00', 'A6'])) {
|
||
$this->debugLog('订单支付失败', $this->request->all());
|
||
return false;//支付失败
|
||
}
|
||
|
||
$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 = '';
|
||
//统一格式化
|
||
$this->unionHandle($data);
|
||
|
||
//支付返回信息
|
||
$this->pay_data = $data;
|
||
$this->debugLog('验证签名成功,数据', $data);
|
||
//更新订单
|
||
$this->updateOrder();
|
||
$this->debugLog('updateOrder Ok');
|
||
} catch (\Exception $exception) {
|
||
$this->debugLog('失败异常内容:' . $exception->getMessage());
|
||
if (!in_array($data['respCode'], ['00', 'A6'])) {
|
||
$this->debugLog('订单支付失败', $this->request->all());
|
||
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)]);
|
||
|
||
}
|
||
|
||
}
|
||
|
||
/**
|
||
* 统一格式化
|
||
*/
|
||
public function unionHandle($data)
|
||
{
|
||
|
||
$result = [
|
||
'order_sn' => $data['orderId'],
|
||
'pay_order_sn' => $data['queryId'],
|
||
'pay_money' => $data['settleAmt'] / 100,//单位分需要/100等于元
|
||
'pay_type' => 'unionpay',
|
||
'account' => $data['accNo']
|
||
];
|
||
// dd($result);
|
||
$this->setResult($result);
|
||
Log::channel('pay_success')->info('银联支付成功', [
|
||
'pay_type' => $result['pay_type'], 'pay_money' => $result['pay_money'],
|
||
'account' => $result['account'], 'order_sn' => $result['order_sn'],
|
||
'pay_order_sn' => $result['pay_order_sn']]);
|
||
|
||
}
|
||
|
||
|
||
/**
|
||
* 这个调试需要配置在config/logging.php
|
||
* @param $pay_type
|
||
*/
|
||
public function setLogName($pay_type)
|
||
{
|
||
$name = '';
|
||
switch ($pay_type) {
|
||
|
||
case 'unionpay':
|
||
$name = 'unionpay_';
|
||
break;
|
||
|
||
}
|
||
$this->log_name = $name;
|
||
}
|
||
|
||
|
||
|
||
|
||
|
||
|
||
} |