417 lines
12 KiB
PHP
417 lines
12 KiB
PHP
<?php
|
||
|
||
namespace App\ServicePay;
|
||
|
||
use App\Models\Merchant;
|
||
use App\Models\Order;
|
||
use App\ServicePay\Citpay\CitPay;
|
||
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 CitPayServices 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 = [])
|
||
{
|
||
|
||
$config = [
|
||
'mid' => $this->pay_gateway['mch_id'],
|
||
'pt_key' => $this->pay_gateway['cert_pub'],
|
||
'app_key' => $this->pay_gateway['app_id'],
|
||
'serct_code' => $this->pay_gateway['app_key'],
|
||
'url' => 'https://www.citpay.com',
|
||
'notify_url' => action('Pay\PayController@notify', ['type' => $type, 'gateway_id' => $this->pay_gateway['id']]),
|
||
'debug' => 1,
|
||
'logDir' => to_linux_path(storage_path() . '/logs/'),
|
||
'pem' => $this->pay_gateway['cert_key'],
|
||
|
||
];
|
||
$citpay = CitPay::make($config);
|
||
|
||
|
||
$this->pay_model = $citpay;
|
||
|
||
}
|
||
|
||
//统一下单支付
|
||
public function pay($pay_data)
|
||
{
|
||
$array = array(
|
||
// 在citpay平台中获取
|
||
"order_no" => "NO" . date('YmdHis') . mt_rand(1, 999),
|
||
"customer_name" => "空气",
|
||
"customer_mobile" => '+86,13420454614',
|
||
|
||
);
|
||
$res = $this->pay_model->orderBuy($pay_data);
|
||
if (!$res) {
|
||
$error = $this->pay_model->getError();
|
||
if (!empty($error)) {
|
||
foreach ($error as $k => $v) {
|
||
echo $v['msg'] . '<br/>';
|
||
exit();
|
||
}
|
||
}
|
||
} else {
|
||
return redirect()->away($res['redirect_url']);//跳转支付
|
||
}
|
||
}
|
||
|
||
//统一验证签名
|
||
public function verify()
|
||
{
|
||
|
||
|
||
$para = [
|
||
'client_key' => $this->result_data['client_key'],
|
||
'request_content' => $this->result_data['request_content'],
|
||
'sign' => $this->result_data['sign'],
|
||
'sign_type' => $this->result_data['sign_type'],
|
||
'message' => null
|
||
];
|
||
|
||
$r = $this->pay_model->checkSign($para);
|
||
|
||
if ($r == 1) {
|
||
return 1;
|
||
} else {
|
||
return false;
|
||
}
|
||
}
|
||
|
||
//返回给支付商的成功
|
||
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->setLogName($pay_type);
|
||
$this->debugLog('回调原始数据', $request->all());
|
||
$this->pay_type = $pay_type;
|
||
$this->request = $request;
|
||
//取得通道id
|
||
$this->gateway_id = $request->input('gateway_id');
|
||
$this->gateway = $this->pay_gateway = config('gateway.config')[$this->gateway_id];
|
||
//dd($this->gateway);
|
||
//取得支付配置
|
||
$this->payConfig($this->pay_type);
|
||
|
||
|
||
//数字货币做不了通道轮询
|
||
//解密数据
|
||
$data = $this->pay_model->decrypt($request->input('request_content'));
|
||
parse_str($data, $data);
|
||
$data['message'] = 'null';
|
||
$this->result_data = $data + $request->all();
|
||
//dump($this->result_data);
|
||
//进行验证签名
|
||
if (!$this->verify()) {
|
||
|
||
$this->debugLog('签名验证失败');
|
||
return false;
|
||
}
|
||
|
||
|
||
//取得订单
|
||
$this->getOrder($data['order_no']);
|
||
|
||
|
||
// self::$result = $request->all();
|
||
// self::$result['pay_order_sn'] = $request->input('queryId');
|
||
|
||
$return = ($return) ? 1 : 0;
|
||
if ($return) {
|
||
|
||
//return $this->unionPayNotify();
|
||
return $this->payNotify();
|
||
}
|
||
|
||
return $this->payNotify();
|
||
}
|
||
|
||
/**
|
||
* 取得订单,支付宝和微信返回的订单号都有差异,需要分开处理
|
||
* @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 returnPay()
|
||
{
|
||
|
||
//判断是否是商户id
|
||
if ($this->order->merchant_id == 0) {
|
||
return redirect()->route('web.user.index');
|
||
}
|
||
//
|
||
return $this->merchantReturnSend();
|
||
}
|
||
|
||
//异步回调
|
||
|
||
/**
|
||
* 获得通道信息,取得支付配置模型,验证签名,
|
||
* @return bool|void
|
||
*/
|
||
public function payNotify()
|
||
{
|
||
//取得通道信息内容
|
||
|
||
//判断有没支付成功先,没有的话,直接就没有下一步了
|
||
$pay_status = $this->result_data['pay_state'];
|
||
//dd($this->result_data);
|
||
|
||
if ($pay_status != 1) {
|
||
$this->debugLog('citpay订单支付失败', $this->request->all());
|
||
return false;
|
||
}
|
||
|
||
$data = $this->result_data;
|
||
$this->pay_data = $this->result_data;
|
||
//如果应答状态不是01/A6表示支付失败
|
||
|
||
|
||
$this->debugLog('-------------' . $this->order->order_sn . '--选择----' . $this->pay_type . '----' . $this->pay_method . '----开始回调处理-------------------------');
|
||
if (empty($data)) {
|
||
return $this->debugLog('验证签名失败', $data);
|
||
}
|
||
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['order_no'],
|
||
'pay_order_sn' => '',
|
||
'pay_money' => $data['legalB_amount'],//单位分需要/100等于元
|
||
'pay_type' => 'citpay',
|
||
'account' => ''
|
||
];
|
||
|
||
$this->setResult($result);
|
||
Log::channel('pay_success')->info('citpay支付成功', [
|
||
'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']]);
|
||
|
||
}
|
||
|
||
/**
|
||
* 更新订单操作
|
||
* @return mixed|void
|
||
*/
|
||
public function updateOrder()
|
||
{
|
||
|
||
$order = $this->order;
|
||
//判断是否本站
|
||
if ($order->merchant_id == 0) {
|
||
//本地订单处理
|
||
return $this->locationOrder();
|
||
} else {
|
||
|
||
//外站订单处理
|
||
|
||
return $this->outOrder();
|
||
}
|
||
|
||
}
|
||
|
||
/**
|
||
* 这个调试需要配置在config/logging.php
|
||
* @param $pay_type
|
||
*/
|
||
public function setLogName($pay_type)
|
||
{
|
||
$name = '';
|
||
switch ($pay_type) {
|
||
|
||
case 'citpay':
|
||
$name = 'citpay_';
|
||
break;
|
||
|
||
}
|
||
$this->log_name = $name;
|
||
}
|
||
|
||
|
||
public function payMethod($pay_type)
|
||
{
|
||
$arr = [];
|
||
$arr['pay_type'] = $pay_type;
|
||
|
||
switch ($pay_type) {
|
||
case 'alipayscan':
|
||
$arr['method'] = 'scan';
|
||
$arr['pay_type'] = 'alipay';
|
||
break;
|
||
case 'weixinscan':
|
||
$arr['method'] = 'scan';
|
||
$arr['pay_type'] = 'weixin';
|
||
break;
|
||
case 'weixinh5':
|
||
$arr['method'] = 'wap';
|
||
$arr['pay_type'] = 'weixin';
|
||
break;
|
||
default:
|
||
$mothod = is_mobile_client() ? 'wap' : 'web';
|
||
$arr['method'] = $mothod;
|
||
break;
|
||
}
|
||
return $arr;
|
||
}
|
||
|
||
/**
|
||
* 全部轮询支付通道,随机切换
|
||
* @param $all_gateways
|
||
* @return mixed
|
||
*/
|
||
public function randomAllGateways($all_gateways)
|
||
{
|
||
$total = count($all_gateways);
|
||
return $all_gateways[mt_rand(0, $total - 1)];
|
||
}
|
||
|
||
/**
|
||
* 随机切换用户选择支付通道
|
||
* @param $all_gateways 所有通道
|
||
* @param $custom_gateways 用户自定义选择通道
|
||
* @return bool|mixed
|
||
*/
|
||
public function randomCustomGateways($all_gateways, $custom_gateways)
|
||
{
|
||
$on_user_gateway_id = [];
|
||
foreach ($all_gateways as $k => $v) {
|
||
if (in_array($v['id'], $custom_gateways)) {
|
||
$on_user_gateway_id[] = $v;
|
||
}
|
||
$total = count($on_user_gateway_id);
|
||
if ($total <= 0) {
|
||
return false;
|
||
}
|
||
return $on_user_gateway_id[mt_rand(0, $total - 1)];
|
||
}
|
||
}
|
||
|
||
} |