first commit
This commit is contained in:
@@ -0,0 +1,111 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Controllers\Pay;
|
||||
|
||||
use App\Exceptions\RuleValidationException;
|
||||
use App\Http\Controllers\PayController;
|
||||
use Illuminate\Http\Request;
|
||||
use Yansongda\Pay\Pay;
|
||||
|
||||
class AlipayController extends PayController
|
||||
{
|
||||
|
||||
/**
|
||||
* 支付宝支付网关
|
||||
*
|
||||
* @param string $payway
|
||||
* @param string $orderSN
|
||||
*/
|
||||
public function gateway(string $payway, string $orderSN)
|
||||
{
|
||||
try {
|
||||
// 加载网关
|
||||
$this->loadGateWay($orderSN, $payway);
|
||||
$config = [
|
||||
'app_id' => $this->payGateway->merchant_id,
|
||||
'ali_public_key' => $this->payGateway->merchant_key,
|
||||
'private_key' => $this->payGateway->merchant_pem,
|
||||
'notify_url' => url($this->payGateway->pay_handleroute . '/notify_url'),
|
||||
'return_url' => url('detail-order-sn', ['orderSN' => $this->order->order_sn]),
|
||||
'http' => [ // optional
|
||||
'timeout' => 10.0,
|
||||
'connect_timeout' => 10.0,
|
||||
],
|
||||
];
|
||||
$order = [
|
||||
'out_trade_no' => $this->order->order_sn,
|
||||
'total_amount' => (float)$this->order->actual_price,
|
||||
'subject' => $this->order->order_sn
|
||||
];
|
||||
switch ($payway){
|
||||
case 'zfbf2f':
|
||||
case 'alipayscan':
|
||||
try{
|
||||
$result = Pay::alipay($config)->scan($order)->toArray();
|
||||
$result['payname'] = $this->order->order_sn;
|
||||
$result['actual_price'] = (float)$this->order->actual_price;
|
||||
$result['orderid'] = $this->order->order_sn;
|
||||
$result['jump_payuri'] = $result['qr_code'];
|
||||
return $this->render('static_pages/qrpay', $result, __('dujiaoka.scan_qrcode_to_pay'));
|
||||
} catch (\Exception $e) {
|
||||
return $this->err(__('dujiaoka.prompt.abnormal_payment_channel') . $e->getMessage());
|
||||
}
|
||||
case 'aliweb':
|
||||
try{
|
||||
$result = Pay::alipay($config)->web($order);
|
||||
return $result;
|
||||
} catch (\Exception $e) {
|
||||
return $this->err(__('dujiaoka.prompt.abnormal_payment_channel') . $e->getMessage());
|
||||
}
|
||||
case 'aliwap':
|
||||
try{
|
||||
$result = Pay::alipay($config)->wap($order);
|
||||
return $result;
|
||||
} catch (\Exception $e) {
|
||||
return $this->err(__('dujiaoka.prompt.abnormal_payment_channel') . $e->getMessage());
|
||||
}
|
||||
}
|
||||
} catch (RuleValidationException $exception) {
|
||||
return $this->err($exception->getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 异步通知
|
||||
*/
|
||||
public function notifyUrl(Request $request)
|
||||
{
|
||||
$orderSN = $request->input('out_trade_no');
|
||||
$order = $this->orderService->detailOrderSN($orderSN);
|
||||
if (!$order) {
|
||||
return 'error';
|
||||
}
|
||||
$payGateway = $this->payService->detail($order->pay_id);
|
||||
if (!$payGateway) {
|
||||
return 'error';
|
||||
}
|
||||
if($payGateway->pay_handleroute != '/pay/alipay'){
|
||||
return 'fail';
|
||||
}
|
||||
$config = [
|
||||
'app_id' => $payGateway->merchant_id,
|
||||
'ali_public_key' => $payGateway->merchant_key,
|
||||
'private_key' => $payGateway->merchant_pem,
|
||||
];
|
||||
$pay = Pay::alipay($config);
|
||||
try{
|
||||
// 验证签名
|
||||
$result = $pay->verify();
|
||||
if ($result->trade_status == 'TRADE_SUCCESS' || $result->trade_status == 'TRADE_FINISHED') {
|
||||
$this->orderProcessService->completedOrder($result->out_trade_no, $result->total_amount, $result->trade_no);
|
||||
}
|
||||
return 'success';
|
||||
} catch (\Exception $exception) {
|
||||
return 'fail';
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
@@ -0,0 +1,143 @@
|
||||
<?php
|
||||
namespace App\Http\Controllers\Pay;
|
||||
|
||||
use App\Exceptions\RuleValidationException;
|
||||
use App\Http\Controllers\PayController;
|
||||
use Illuminate\Http\Request;
|
||||
|
||||
class CoinbaseController extends PayController
|
||||
{
|
||||
|
||||
public function gateway(string $payway, string $orderSN)
|
||||
{
|
||||
try {
|
||||
// 加载网关
|
||||
$this->loadGateWay($orderSN, $payway);
|
||||
//构造要请求的参数数组,无需改动
|
||||
switch ($payway) {
|
||||
case 'coinbase':
|
||||
default:
|
||||
try {
|
||||
$createOrderUrl="https://api.commerce.coinbase.com/charges";
|
||||
$price_amount = sprintf('%.2f', (float)$this->order->actual_price);// 只取小数点后两位
|
||||
$fees = (double)$this->payGateway->merchant_id;//手续费费率 比如 0.05
|
||||
if($fees>0.00)
|
||||
{
|
||||
$price_amount =(double)$price_amount * (1.00+$fees);// 价格 * (1 + 0.05)
|
||||
}
|
||||
|
||||
|
||||
$redirect_url = url('detail-order-sn', ['orderSN' => $this->order->order_sn]); //同步地址
|
||||
$cancel_url = url('detail-order-sn', ['orderSN' => $this->order->order_sn]); //同步地址
|
||||
$config = [
|
||||
'name'=>$this->order->title,
|
||||
'description'=>$this->order->title.'需付款'.$price_amount.'元',
|
||||
'pricing_type' => 'fixed_price',
|
||||
'local_price' => [
|
||||
'amount' => $price_amount,
|
||||
'currency' => 'CNY'
|
||||
],
|
||||
'metadata' => [
|
||||
'customer_id' => $this->order->order_sn,
|
||||
'customer_name' => $this->order->title
|
||||
],
|
||||
'redirect_url' =>$redirect_url,
|
||||
'cancel_url'=> $cancel_url
|
||||
];
|
||||
$header = array();
|
||||
$header[] = 'Content-Type:application/json';
|
||||
$header[] = 'X-CC-Api-Key:'.$this->payGateway->merchant_key; //APP key
|
||||
$header[] = 'X-CC-Version: 2018-03-22';
|
||||
|
||||
$ch = curl_init(); //使用curl请求
|
||||
curl_setopt($ch, CURLOPT_URL, $createOrderUrl);
|
||||
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
|
||||
curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, 5);
|
||||
curl_setopt($ch, CURLOPT_HTTPHEADER, $header);
|
||||
curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($config));
|
||||
$coinbase_json = curl_exec($ch);
|
||||
curl_close($ch);
|
||||
|
||||
$coinbase_date=json_decode($coinbase_json,true);
|
||||
if(is_array($coinbase_date))
|
||||
{
|
||||
$payment_url = $coinbase_date['data']['hosted_url'];
|
||||
}
|
||||
else
|
||||
{
|
||||
return 'fail|Coinbase支付接口请求失败';
|
||||
}
|
||||
return redirect()->away($payment_url);
|
||||
} catch (\Exception $e) {
|
||||
throw new RuleValidationException(__('dujiaoka.prompt.abnormal_payment_channel') . $e->getMessage());
|
||||
}
|
||||
break;
|
||||
}
|
||||
} catch (RuleValidationException $exception) {
|
||||
return $this->err($exception->getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
public function notifyUrl(Request $request)
|
||||
{
|
||||
$payload = file_get_contents( 'php://input' );
|
||||
$sig = $_SERVER['HTTP_X_CC_WEBHOOK_SIGNATURE'];
|
||||
$data = json_decode( $payload, true );
|
||||
$event_data = $data['event']['data'];
|
||||
$order = $this->orderService->detailOrderSN($event_data['metadata']['customer_id']);//
|
||||
if (!$order) {
|
||||
return 'fail';
|
||||
}
|
||||
$payGateway = $this->payService->detail($order->pay_id);
|
||||
if (!$payGateway) {
|
||||
return 'fail';
|
||||
}
|
||||
if($payGateway->pay_handleroute != 'pay/coinbase'){
|
||||
return 'fail';
|
||||
}
|
||||
$secret = $payGateway->merchant_pem;//共享密钥
|
||||
$sig2 = hash_hmac( 'sha256', $payload, $secret );
|
||||
$result_str=array("confirmed","resolved");//返回的结果字符串数组
|
||||
if (!empty( $payload ) && ($sig === $sig2))
|
||||
{
|
||||
|
||||
foreach ($event_data['payments'] as $payment) {
|
||||
//if ((strtolower($payment['status']) === 'confirmed')||(strtolower($payment['status']) === 'resolved')) {
|
||||
if(in_array(strtolower($payment['status']),$result_str)){
|
||||
$return_pay_amount = $payment['value']['local']['amount'];
|
||||
$return_currency=$payment['value']['local']['currency'];
|
||||
$return_status=strtolower($payment['status']);
|
||||
}
|
||||
}
|
||||
if($return_currency !== 'CNY')
|
||||
{
|
||||
return 'error|Notify: Wrong currency:'.$return_currency;
|
||||
}
|
||||
|
||||
$bccomp = bccomp($order->actual_price, $return_pay_amount, 2); //如果订单金额 大于 实际支付金额 返回1,抛出异常
|
||||
if ($bccomp == 1) {
|
||||
throw new \Exception(__('Coinbase付款金额不足'));
|
||||
}
|
||||
$return_merchant_order_id = $event_data['metadata']['customer_id'];//卡网订单号
|
||||
$tradeid = $event_data['code'];//Coinbase订单号
|
||||
//if($return_status === 'confirmed'||$return_status === 'resolved')
|
||||
if(in_array(strtolower($payment['status']),$result_str)) {
|
||||
$this->orderProcessService->completedOrder($return_merchant_order_id, $order->actual_price, $tradeid);// 卡网订单号,订单金额(不能传入支付金额,否则抛出订单金额不一致异常),收款平台订单号
|
||||
return "{\"status\": 200}";
|
||||
} else {
|
||||
//不合法的数据
|
||||
return 'fail';
|
||||
//返回失败 继续补单
|
||||
}
|
||||
|
||||
} else {
|
||||
//不合法的数据
|
||||
return 'fail|wrong sig';
|
||||
//返回失败 继续补单
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -0,0 +1,104 @@
|
||||
<?php
|
||||
/**
|
||||
* The file was created by Assimon.
|
||||
*
|
||||
* @author assimon<ashang@utf8.hk>
|
||||
* @copyright assimon<ashang@utf8.hk>
|
||||
* @link http://utf8.hk/
|
||||
*/
|
||||
|
||||
namespace App\Http\Controllers\Pay;
|
||||
|
||||
|
||||
use App\Exceptions\RuleValidationException;
|
||||
use App\Http\Controllers\PayController;
|
||||
use GuzzleHttp\Client;
|
||||
use GuzzleHttp\Exception\GuzzleException;
|
||||
use Illuminate\Http\Request;
|
||||
|
||||
class EpusdtController extends PayController
|
||||
{
|
||||
public function gateway(string $payway, string $orderSN)
|
||||
{
|
||||
try {
|
||||
// 加载网关
|
||||
$this->loadGateWay($orderSN, $payway);
|
||||
//构造要请求的参数数组,无需改动
|
||||
$parameter = [
|
||||
"amount" => (float)$this->order->actual_price,//原价
|
||||
"order_id" => $this->order->order_sn, //可以是用户ID,站内商户订单号,用户名
|
||||
'redirect_url' => route('epusdt-return', ['order_id' => $this->order->order_sn]),
|
||||
'notify_url' => url($this->payGateway->pay_handleroute . '/notify_url'),
|
||||
];
|
||||
$parameter['signature'] = $this->epusdtSign($parameter, $this->payGateway->merchant_id);
|
||||
$client = new Client([
|
||||
'headers' => [ 'Content-Type' => 'application/json' ]
|
||||
]);
|
||||
$response = $client->post($this->payGateway->merchant_pem, ['body' => json_encode($parameter)]);
|
||||
$body = json_decode($response->getBody()->getContents(), true);
|
||||
if (!isset($body['status_code']) || $body['status_code'] != 200) {
|
||||
return $this->err(__('dujiaoka.prompt.abnormal_payment_channel') . $body['message']);
|
||||
}
|
||||
return redirect()->away($body['data']['payment_url']);
|
||||
} catch (RuleValidationException $exception) {
|
||||
} catch (GuzzleException $exception) {
|
||||
return $this->err($exception->getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private function epusdtSign(array $parameter, string $signKey)
|
||||
{
|
||||
ksort($parameter);
|
||||
reset($parameter); //内部指针指向数组中的第一个元素
|
||||
$sign = '';
|
||||
$urls = '';
|
||||
foreach ($parameter as $key => $val) {
|
||||
if ($val == '') continue;
|
||||
if ($key != 'signature') {
|
||||
if ($sign != '') {
|
||||
$sign .= "&";
|
||||
$urls .= "&";
|
||||
}
|
||||
$sign .= "$key=$val"; //拼接为url参数形式
|
||||
$urls .= "$key=" . urlencode($val); //拼接为url参数形式
|
||||
}
|
||||
}
|
||||
$sign = md5($sign . $signKey);//密码追加进入开始MD5签名
|
||||
return $sign;
|
||||
}
|
||||
|
||||
public function notifyUrl(Request $request)
|
||||
{
|
||||
$data = $request->all();
|
||||
$order = $this->orderService->detailOrderSN($data['order_id']);
|
||||
if (!$order) {
|
||||
return 'fail';
|
||||
}
|
||||
$payGateway = $this->payService->detail($order->pay_id);
|
||||
if (!$payGateway) {
|
||||
return 'fail';
|
||||
}
|
||||
if($payGateway->pay_handleroute != 'pay/epusdt'){
|
||||
return 'fail';
|
||||
}
|
||||
$signature = $this->epusdtSign($data, $payGateway->merchant_id);
|
||||
if ($data['signature'] != $signature) { //不合法的数据
|
||||
return 'fail'; //返回失败 继续补单
|
||||
} else {
|
||||
//合法的数据
|
||||
//业务处理
|
||||
$this->orderProcessService->completedOrder($data['order_id'], $data['amount'], $data['trade_id']);
|
||||
return 'ok';
|
||||
}
|
||||
}
|
||||
|
||||
public function returnUrl(Request $request)
|
||||
{
|
||||
$oid = $request->get('order_id');
|
||||
// 异步通知还没到就跳转了,所以这里休眠2秒
|
||||
sleep(2);
|
||||
return redirect(url('detail-order-sn', ['orderSN' => $oid]));
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,83 @@
|
||||
<?php
|
||||
namespace App\Http\Controllers\Pay;
|
||||
|
||||
|
||||
use App\Exceptions\RuleValidationException;
|
||||
use App\Http\Controllers\PayController;
|
||||
use Illuminate\Http\Request;
|
||||
|
||||
class MapayController extends PayController
|
||||
{
|
||||
|
||||
public function gateway(string $payway, string $orderSN)
|
||||
{
|
||||
try {
|
||||
// 加载网关
|
||||
$this->loadGateWay($orderSN, $payway);
|
||||
//构造要请求的参数数组,无需改动
|
||||
$parameter = array(
|
||||
"id" => (int)$this->payGateway->merchant_id,//平台ID号
|
||||
"price" => (float)$this->order->actual_price,//原价
|
||||
"pay_id" => $this->order->order_sn, //可以是用户ID,站内商户订单号,用户名
|
||||
"param" => $this->payGateway->pay_check,//自定义参数
|
||||
"act" => 0,//是否开启认证版的免挂机功能
|
||||
"outTime" => 120,//二维码超时设置
|
||||
"page" => 1,//付款页面展示方式
|
||||
'return_url' => url('detail-order-sn', ['orderSN' => $this->order->order_sn]),
|
||||
'notify_url' => url($this->payGateway->pay_handleroute . '/notify_url'),
|
||||
"pay_type" => 0,//支付宝使用官方接口
|
||||
"chart" => 'utf-8'//字符编码方式
|
||||
//其他业务参数根据在线开发文档,添加参数.文档地址:https://codepay.fateqq.com/apiword/
|
||||
//如"参数名"=>"参数值"
|
||||
);
|
||||
switch ($payway){
|
||||
case 'mqq':
|
||||
$parameter['type'] = 2;
|
||||
break;
|
||||
case 'mzfb':
|
||||
$parameter['type'] = 1;
|
||||
break;
|
||||
case 'mwx':
|
||||
default:
|
||||
$parameter['type'] = 3;
|
||||
break;
|
||||
}
|
||||
$quri = md5_signquery($parameter, $this->payGateway->merchant_pem);
|
||||
$payurl = $this->payGateway->merchant_key . $quri; //支付页面
|
||||
return redirect()->away($payurl);
|
||||
} catch (RuleValidationException $exception) {
|
||||
return $this->err($exception->getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public function notifyUrl(Request $request)
|
||||
{
|
||||
$data = $request->post();
|
||||
$order = $this->orderService->detailOrderSN($data['pay_id']);
|
||||
if (!$order) {
|
||||
return 'fail';
|
||||
}
|
||||
$payGateway = $this->payService->detail($order->pay_id);
|
||||
if (!$payGateway) {
|
||||
return 'fail';
|
||||
}
|
||||
if($payGateway->pay_handleroute != '/pay/mapay'){
|
||||
return 'fail';
|
||||
}
|
||||
$query = signquery_string($data);
|
||||
if (!$data['pay_no'] || md5($query . $payGateway->merchant_pem ) != $data['sign']) { //不合法的数据
|
||||
return 'fail'; //返回失败 继续补单
|
||||
} else { //合法的数据
|
||||
//业务处理
|
||||
$this->orderProcessService->completedOrder($data['pay_id'], $data['money'], $data['pay_id']);
|
||||
return 'success';
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,70 @@
|
||||
<?php
|
||||
namespace App\Http\Controllers\Pay;
|
||||
|
||||
use App\Exceptions\RuleValidationException;
|
||||
use App\Http\Controllers\PayController;
|
||||
use Illuminate\Http\Request;
|
||||
use Xhat\Payjs\Facades\Payjs;
|
||||
|
||||
|
||||
class PayjsController extends PayController
|
||||
{
|
||||
|
||||
public function gateway(string $payway, string $orderSN)
|
||||
{
|
||||
try {
|
||||
// 加载网关
|
||||
$this->loadGateWay($orderSN, $payway);
|
||||
// 构造订单基础信息
|
||||
$data = [
|
||||
'body' => $this->order->order_sn, // 订单标题
|
||||
'total_fee' => bcmul($this->order->actual_price, 100, 0), // 订单金额
|
||||
'out_trade_no' => $this->order->order_sn, // 订单号
|
||||
'notify_url' => url($this->payGateway->pay_handleroute . '/notify_url'),
|
||||
];
|
||||
config(['payjs.mchid' => $this->payGateway->merchant_id, 'payjs.key' => $this->payGateway->merchant_pem]);
|
||||
switch ($payway){
|
||||
case 'payjswescan':
|
||||
try{
|
||||
$payres = Payjs::native($data);
|
||||
if ($payres['return_code'] != 1) {
|
||||
throw new RuleValidationException($payres['return_msg']);
|
||||
}
|
||||
$result['payname'] = $this->payGateway->pay_name;
|
||||
$result['actual_price'] = (float)$this->order->actual_price;
|
||||
$result['orderid'] = $this->order->order_sn;
|
||||
$result['qr_code'] = $payres['code_url'];
|
||||
return $this->render('static_pages/qrpay', $result, __('dujiaoka.scan_qrcode_to_pay'));
|
||||
} catch (\Exception $e) {
|
||||
throw new RuleValidationException(__('dujiaoka.prompt.abnormal_payment_channel') . $e->getMessage());
|
||||
}
|
||||
break;
|
||||
}
|
||||
} catch (RuleValidationException $exception) {
|
||||
return $this->err($exception->getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public function notifyUrl(Request $request)
|
||||
{
|
||||
$orderSN = $request->input('out_trade_no');
|
||||
$order = $this->orderService->detailOrderSN($orderSN);
|
||||
if (!$order) {
|
||||
return 'error';
|
||||
}
|
||||
$payGateway = $this->payService->detail($order->pay_id);
|
||||
if (!$payGateway) {
|
||||
return 'error';
|
||||
}
|
||||
if($payGateway->pay_handleroute != '/pay/payjs'){
|
||||
return 'fail';
|
||||
}
|
||||
config(['payjs.mchid' => $payGateway->merchant_id, 'payjs.key' => $payGateway->merchant_pem]);
|
||||
$notify_info = Payjs::notify();
|
||||
$totalFee = bcdiv($notify_info['total_fee'], 100, 2);
|
||||
$this->orderProcessService->completedOrder($notify_info['out_trade_no'], $totalFee, $notify_info['payjs_order_id']);
|
||||
return 'success';
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,148 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Controllers\Pay;
|
||||
|
||||
|
||||
use AmrShawky\LaravelCurrency\Facade\Currency;
|
||||
use App\Exceptions\RuleValidationException;
|
||||
use App\Http\Controllers\PayController;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Support\Facades\Log;
|
||||
use PayPal\Api\Amount;
|
||||
use PayPal\Api\Details;
|
||||
use PayPal\Api\Item;
|
||||
use PayPal\Api\ItemList;
|
||||
use PayPal\Api\Payer;
|
||||
use PayPal\Api\Payment;
|
||||
use PayPal\Api\PaymentExecution;
|
||||
use PayPal\Api\RedirectUrls;
|
||||
use PayPal\Api\Transaction;
|
||||
use PayPal\Auth\OAuthTokenCredential;
|
||||
use PayPal\Exception\PayPalConnectionException;
|
||||
use PayPal\Rest\ApiContext;
|
||||
|
||||
class PaypalPayController extends PayController
|
||||
{
|
||||
|
||||
const Currency = 'USD'; //货币单位
|
||||
|
||||
public function gateway(string $payway, string $orderSN)
|
||||
{
|
||||
try {
|
||||
// 加载网关
|
||||
$this->loadGateWay($orderSN, $payway);
|
||||
$paypal = new ApiContext(
|
||||
new OAuthTokenCredential(
|
||||
$this->payGateway->merchant_key,
|
||||
$this->payGateway->merchant_pem
|
||||
)
|
||||
);
|
||||
$paypal->setConfig(['mode' => 'live']);
|
||||
$product = $this->order->title;
|
||||
// 得到汇率
|
||||
$total = Currency::convert()
|
||||
->from('CNY')
|
||||
->to('USD')
|
||||
->amount($this->order->actual_price)
|
||||
->round(2)
|
||||
->get();
|
||||
$shipping = 0;
|
||||
$description = $this->order->title;
|
||||
$payer = new Payer();
|
||||
$payer->setPaymentMethod('paypal');
|
||||
$item = new Item();
|
||||
$item->setName($product)->setCurrency(self::Currency)->setQuantity(1)->setPrice($total);
|
||||
$itemList = new ItemList();
|
||||
$itemList->setItems([$item]);
|
||||
$details = new Details();
|
||||
$details->setShipping($shipping)->setSubtotal($total);
|
||||
$amount = new Amount();
|
||||
$amount->setCurrency(self::Currency)->setTotal($total)->setDetails($details);
|
||||
$transaction = new Transaction();
|
||||
$transaction->setAmount($amount)->setItemList($itemList)->setDescription($description)->setInvoiceNumber($this->order->order_sn);
|
||||
$redirectUrls = new RedirectUrls();
|
||||
$redirectUrls->setReturnUrl(route('paypal-return', ['success' => 'ok', 'orderSN' => $this->order->order_sn]))->setCancelUrl(route('paypal-return', ['success' => 'no', 'orderSN' => $this->order->order_sn]));
|
||||
$payment = new Payment();
|
||||
$payment->setIntent('sale')->setPayer($payer)->setRedirectUrls($redirectUrls)->setTransactions([$transaction]);
|
||||
$payment->create($paypal);
|
||||
$approvalUrl = $payment->getApprovalLink();
|
||||
return redirect($approvalUrl);
|
||||
} catch (PayPalConnectionException $payPalConnectionException) {
|
||||
return $this->err($payPalConnectionException->getMessage());
|
||||
} catch (RuleValidationException $exception) {
|
||||
return $this->err($exception->getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
*paypal 同步回调
|
||||
*/
|
||||
public function returnUrl(Request $request)
|
||||
{
|
||||
$success = $request->input('success');
|
||||
$paymentId = $request->input('paymentId');
|
||||
$payerID = $request->input('PayerID');
|
||||
$orderSN = $request->input('orderSN');
|
||||
if ($success == 'no' || empty($paymentId) || empty($payerID)) {
|
||||
// 取消支付
|
||||
redirect(url('detail-order-sn', ['orderSN' => $payerID]));
|
||||
}
|
||||
$order = $this->orderService->detailOrderSN($orderSN);
|
||||
if (!$order) {
|
||||
return 'error';
|
||||
}
|
||||
$payGateway = $this->payService->detail($order->pay_id);
|
||||
if (!$payGateway) {
|
||||
return 'error';
|
||||
}
|
||||
if($payGateway->pay_handleroute != '/pay/paypal'){
|
||||
return 'error';
|
||||
}
|
||||
$paypal = new ApiContext(
|
||||
new OAuthTokenCredential(
|
||||
$payGateway->merchant_key,
|
||||
$payGateway->merchant_pem
|
||||
)
|
||||
);
|
||||
$paypal->setConfig(['mode' => 'live']);
|
||||
$payment = Payment::get($paymentId, $paypal);
|
||||
$execute = new PaymentExecution();
|
||||
$execute->setPayerId($payerID);
|
||||
try {
|
||||
$payment->execute($execute, $paypal);
|
||||
$this->orderProcessService->completedOrder($orderSN, $order->actual_price, $paymentId);
|
||||
Log::info("paypal支付成功", ['支付成功,支付ID【' . $paymentId . '】,支付人ID【' . $payerID . '】']);
|
||||
} catch (\Exception $e) {
|
||||
Log::error("paypal支付失败", ['支付失败,支付ID【' . $paymentId . '】,支付人ID【' . $payerID . '】']);
|
||||
}
|
||||
return redirect(url('detail-order-sn', ['orderSN' => $orderSN]));
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 异步通知
|
||||
* TODO: 暂未实现,但是好像只实现同步回调即可。这个可以放在后面实现
|
||||
*/
|
||||
public function notifyUrl(Request $request)
|
||||
{
|
||||
//获取回调结果
|
||||
$json_data = $this->get_JsonData();
|
||||
if(!empty($json_data)){
|
||||
Log::debug("paypal notify info:\r\n" . json_encode($json_data));
|
||||
}else{
|
||||
Log::debug("paypal notify fail:参加为空");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private function get_JsonData()
|
||||
{
|
||||
$json = file_get_contents('php://input');
|
||||
if ($json) {
|
||||
$json = str_replace("'", '', $json);
|
||||
$json = json_decode($json,true);
|
||||
}
|
||||
return $json;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,113 @@
|
||||
<?php
|
||||
namespace App\Http\Controllers\Pay;
|
||||
|
||||
|
||||
use App\Exceptions\RuleValidationException;
|
||||
use App\Http\Controllers\PayController;
|
||||
use Illuminate\Http\Request;
|
||||
|
||||
class PaysapiController extends PayController
|
||||
{
|
||||
|
||||
const PAY_URI = 'https://pay.bearsoftware.net.cn/';
|
||||
|
||||
public function gateway(string $payway, string $orderSN)
|
||||
{
|
||||
try {
|
||||
// 加载网关
|
||||
$this->loadGateWay($orderSN, $payway);
|
||||
//从网页传入price:支付价格, istype:支付渠道:1-支付宝;2-微信支付
|
||||
$price = (float)$this->order->actual_price;
|
||||
$orderuid = $this->order->email; //此处传入您网站用户的用户名,方便在paysapi后台查看是谁付的款,强烈建议加上。可忽略。
|
||||
//校验传入的表单,确保价格为正常价格(整数,1位小数,2位小数都可以),支付渠道只能是1或者2,orderuid长度不要超过33个中英文字。
|
||||
//此处就在您服务器生成新订单,并把创建的订单号传入到下面的orderid中。
|
||||
$goodsname = $this->order->order_sn;
|
||||
$orderid = $this->order->order_sn; //每次有任何参数变化,订单号就变一个吧。
|
||||
$uid = $this->payGateway->merchant_id; //"此处填写PaysApi的uid";
|
||||
$token = $this->payGateway->merchant_pem; //"此处填写PaysApi的Token";
|
||||
$return_url = route('paysapi-return', ['order_id' => $this->order->order_sn]);
|
||||
$notify_url = url($this->payGateway->pay_handleroute . '/notify_url');
|
||||
switch ($payway){
|
||||
case 'pszfb':
|
||||
$istype = 1;
|
||||
break;
|
||||
case 'pswx':
|
||||
default:
|
||||
$istype = 2;
|
||||
break;
|
||||
}
|
||||
$key = md5($goodsname. $istype . $notify_url . $orderid . $orderuid . $price . $return_url . $token . $uid);
|
||||
//经常遇到有研发问为啥key值返回错误,大多数原因:1.参数的排列顺序不对;2.上面的参数少传了,但是这里的key值又带进去计算了,导致服务端key算出来和你的不一样。
|
||||
$html = "
|
||||
<html><head>
|
||||
<meta http-equiv=\"Content-Type\" content=\"text/html; charset=utf-8\">
|
||||
<title>loading pay...</title>
|
||||
<style type=\"text/css\">
|
||||
body {margin:0;padding:0;}
|
||||
p {position:absolute;
|
||||
left:50%;top:50%;
|
||||
width:330px;height:30px;
|
||||
margin:-35px 0 0 -160px;
|
||||
padding:20px;font:bold 14px/30px \"宋体\", Arial;
|
||||
text-indent:22px;border:1px solid #c5d0dc;}
|
||||
#waiting {font-family:Arial;}
|
||||
</style>
|
||||
<script>
|
||||
function open_without_referrer(link){
|
||||
document.body.appendChild(document.createElement('iframe')).src='javascript:\"<script>top.location.replace(\''+link+'\')<\/script>\"';
|
||||
}
|
||||
</script>
|
||||
</head>
|
||||
<body style=\"\">
|
||||
<form id=\"alipaysubmit\" name=\"alipaysubmit\" action=\"".self::PAY_URI."\" method=\"post\">
|
||||
<input type=\"hidden\" name=\"goodsname\" value=\"".$goodsname."\">
|
||||
<input type=\"hidden\" name=\"istype\" value=\"".$istype."\">
|
||||
<input type=\"hidden\" name=\"key\" value=\"".$key."\">
|
||||
<input type=\"hidden\" name=\"notify_url\" value=\"".$notify_url."\">
|
||||
<input type=\"hidden\" name=\"orderid\" value=\"".$orderid."\">
|
||||
<input type=\"hidden\" name=\"orderuid\" value=\"".$orderuid."\">
|
||||
<input type=\"hidden\" name=\"price\" value=\"".$price."\">
|
||||
<input type=\"hidden\" name=\"return_url\" value=\"".$return_url."\">
|
||||
<input type=\"hidden\" name=\"uid\" value=\"".$uid."\">
|
||||
<input type=\"submit\" value=\"正在跳转\">
|
||||
</form><script>document.forms['alipaysubmit'].submit();</script></body></html>
|
||||
";
|
||||
return $html;
|
||||
} catch (RuleValidationException $exception) {
|
||||
return $this->err($exception->getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
public function notifyUrl(Request $request)
|
||||
{
|
||||
$data = $request->post();
|
||||
$order = $this->orderService->detailOrderSN($data['orderid']);
|
||||
if (!$order) {
|
||||
return 'error';
|
||||
}
|
||||
$payGateway = $this->payService->detail($order->pay_id);
|
||||
if (!$payGateway) {
|
||||
return 'error';
|
||||
}
|
||||
if($payGateway->pay_handleroute != '/pay/paysapi'){
|
||||
return 'error';
|
||||
}
|
||||
$temps = md5($data['orderid'] . $data['orderuid'] . $data['paysapi_id'] . $data['price'] . $data['realprice'] . $payGateway->merchant_pem);
|
||||
if ($temps != $data['key']){
|
||||
return 'fail';
|
||||
}else{
|
||||
//校验key成功,是自己人。执行自己的业务逻辑:加余额,订单付款成功,装备购买成功等等。
|
||||
//业务处理
|
||||
$this->orderProcessService->completedOrder($data['orderid'], $data['price'], $data['paysapi_id']);
|
||||
return 'success';
|
||||
}
|
||||
}
|
||||
|
||||
public function returnUrl(Request $request)
|
||||
{
|
||||
$oid = $request->input('order_id');
|
||||
sleep(1);
|
||||
return redirect(url('detail-order-sn', ['orderSN' => $oid]));
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,540 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Controllers\Pay;
|
||||
|
||||
use App\Exceptions\RuleValidationException;
|
||||
use App\Http\Controllers\PayController;
|
||||
use Illuminate\Http\Request;
|
||||
use GuzzleHttp\Client;
|
||||
use Illuminate\Support\Facades\Redis;
|
||||
use URL;
|
||||
|
||||
class StripeController extends PayController
|
||||
{
|
||||
|
||||
public function gateway(string $payway, string $orderSN)
|
||||
{
|
||||
|
||||
|
||||
// 加载网关
|
||||
$this->loadGateWay($orderSN, $payway);
|
||||
//构造要请求的参数数组,无需改动
|
||||
switch ($payway) {
|
||||
case 'wx':
|
||||
case 'alipay':
|
||||
default:
|
||||
try {
|
||||
\Stripe\Stripe::setApiKey($this->payGateway->merchant_id);
|
||||
$amount = bcmul($this->order->actual_price, 100, 2);
|
||||
$price = $this->order->actual_price;
|
||||
$usd = bcmul($this->getUsdCurrency($this->order->actual_price), 100, 2);
|
||||
$orderid = $this->order->order_sn;
|
||||
$pk = $this->payGateway->merchant_id;
|
||||
$return_url = site_url() . $this->payGateway->pay_handleroute . '/return_url/?orderid=' . $this->order->order_sn;
|
||||
$html = "<html class=\"js cssanimations\">
|
||||
<head lang=\"en\">
|
||||
<meta charset=\"UTF-8\">
|
||||
<title>收银台</title>
|
||||
<meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">
|
||||
<meta name=\"viewport\" content=\"width=device-width, initial-scale=1\">
|
||||
<meta name=\"format-detection\" content=\"telephone=no\">
|
||||
<meta name=\"renderer\" content=\"webkit\">
|
||||
<meta http-equiv=\"Cache-Control\" content=\"no-siteapp\">
|
||||
<link rel=\"stylesheet\" href=\"https://cdn.jsdelivr.net/npm/amazeui@2.7.2/dist/css/amazeui.min.css\">
|
||||
<script src=\"https://cdn.jsdelivr.net/npm/jquery@2.1.4/dist/jquery.min.js\"></script>
|
||||
<script src=\"https://cdn.jsdelivr.net/npm/jquery.qrcode@1.0.3/jquery.qrcode.min.js\"></script>
|
||||
<script src=\"https://cdn.jsdelivr.net/npm/amazeui@2.7.2/dist/js/amazeui.min.js\"></script>
|
||||
<script src=\"https://js.stripe.com/v3/\"></script>
|
||||
<style>
|
||||
@media only screen and (min-width: 641px) {
|
||||
.am-offcanvas {
|
||||
display: block;
|
||||
position: static;
|
||||
background: none;
|
||||
}
|
||||
|
||||
.am-offcanvas-bar {
|
||||
position: static;
|
||||
width: auto;
|
||||
background: none;
|
||||
-webkit-transform: translate3d(0, 0, 0);
|
||||
-ms-transform: translate3d(0, 0, 0);
|
||||
transform: translate3d(0, 0, 0);
|
||||
}
|
||||
|
||||
.am-offcanvas-bar:after {
|
||||
content: none;
|
||||
}
|
||||
}
|
||||
|
||||
@media only screen and (max-width: 640px) {
|
||||
.am-offcanvas-bar .am-nav > li > a {
|
||||
color: #ccc;
|
||||
border-radius: 0;
|
||||
border-top: 1px solid rgba(0, 0, 0, .3);
|
||||
box-shadow: inset 0 1px 0 rgba(255, 255, 255, .05)
|
||||
}
|
||||
|
||||
.am-offcanvas-bar .am-nav > li > a:hover {
|
||||
background: #404040;
|
||||
color: #fff
|
||||
}
|
||||
|
||||
.am-offcanvas-bar .am-nav > li.am-nav-header {
|
||||
color: #777;
|
||||
background: #404040;
|
||||
box-shadow: inset 0 1px 0 rgba(255, 255, 255, .05);
|
||||
text-shadow: 0 1px 0 rgba(0, 0, 0, .5);
|
||||
border-top: 1px solid rgba(0, 0, 0, .3);
|
||||
font-weight: 400;
|
||||
font-size: 75%
|
||||
}
|
||||
|
||||
.am-offcanvas-bar .am-nav > li.am-active > a {
|
||||
background: #1a1a1a;
|
||||
color: #fff;
|
||||
box-shadow: inset 0 1px 3px rgba(0, 0, 0, .3)
|
||||
}
|
||||
|
||||
.am-offcanvas-bar .am-nav > li + li {
|
||||
margin-top: 0;
|
||||
}
|
||||
}
|
||||
|
||||
.my-head {
|
||||
margin-top: 40px;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.am-tab-panel {
|
||||
text-align: center;
|
||||
margin-top: 50px;
|
||||
margin-bottom: 50px;
|
||||
}
|
||||
|
||||
.my-footer {
|
||||
border-top: 1px solid #eeeeee;
|
||||
padding: 10px 0;
|
||||
margin-top: 10px;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.panel-title {
|
||||
display: inline;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.display-table {
|
||||
display: table;
|
||||
}
|
||||
|
||||
.display-tr {
|
||||
display: table-row;
|
||||
}
|
||||
|
||||
.display-td {
|
||||
display: table-cell;
|
||||
vertical-align: middle;
|
||||
width: 61%;
|
||||
}
|
||||
|
||||
.StripeElement {
|
||||
box-sizing: border-box;
|
||||
|
||||
height: 40px;
|
||||
|
||||
padding: 10px 12px;
|
||||
|
||||
border: 1px solid transparent;
|
||||
border-radius: 4px;
|
||||
background-color: white;
|
||||
|
||||
box-shadow: 0 1px 3px 0 #e6ebf1;
|
||||
-webkit-transition: box-shadow 150ms ease;
|
||||
transition: box-shadow 150ms ease;
|
||||
}
|
||||
|
||||
.StripeElement--focus {
|
||||
box-shadow: 0 1px 3px 0 #cfd7df;
|
||||
}
|
||||
|
||||
.StripeElement--invalid {
|
||||
border-color: #fa755a;
|
||||
}
|
||||
|
||||
.StripeElement--webkit-autofill {
|
||||
background-color: #fefde5 !important;
|
||||
}
|
||||
.form-row {
|
||||
width: 70%;
|
||||
float: left;
|
||||
}
|
||||
.wrapper {
|
||||
width: 670px;
|
||||
margin: 0 auto;
|
||||
}
|
||||
label {
|
||||
font-weight: 500;
|
||||
font-size: 14px;
|
||||
display: block;
|
||||
margin-bottom: 8px;
|
||||
}
|
||||
.button {
|
||||
border: none;
|
||||
border-radius: 4px;
|
||||
outline: none;
|
||||
text-decoration: none;
|
||||
color: #fff;
|
||||
background: #32325d;
|
||||
white-space: nowrap;
|
||||
display: inline-block;
|
||||
height: 40px;
|
||||
line-height: 40px;
|
||||
padding: 0 14px;
|
||||
box-shadow: 0 4px 6px rgba(50, 50, 93, .11), 0 1px 3px rgba(0, 0, 0, .08);
|
||||
border-radius: 4px;
|
||||
font-size: 16px;
|
||||
font-weight: 600;
|
||||
letter-spacing: 0.025em;
|
||||
text-decoration: none;
|
||||
-webkit-transition: all 150ms ease;
|
||||
transition: all 150ms ease;
|
||||
margin-top: 10px;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<header class=\"am-g my-head\">
|
||||
<div class=\"am-u-sm-12 am-article\">
|
||||
<h1 class=\"am-article-title\">收银台</h1>
|
||||
</div>
|
||||
</header>
|
||||
<hr class=\"am-article-divider\">
|
||||
<div class=\"am-container\">
|
||||
<h2>付款信息
|
||||
<div class=\"am-topbar-right\">¥{$price}</div>
|
||||
</h2>
|
||||
<p><small>订单编号:$orderid</small></p>
|
||||
<div class=\"am-tabs\" data-am-tabs=\"\">
|
||||
<ul class=\"am-tabs-nav am-nav am-nav-tabs\">
|
||||
<li class=\"am-active\"><a href=\"#alipay\">Alipay 支付宝</a></li>
|
||||
<li class=\"request-wechat-pay\"><a href=\"#wcpay\">微信支付</a></li>
|
||||
<li class=\"request-card-pay\"><a href=\"#cardpay\">银行卡支付</a></li>
|
||||
</ul>
|
||||
<div class=\"am-tabs-bd am-tabs-bd-ofv\"
|
||||
style=\"touch-action: pan-y; user-select: none; -webkit-user-drag: none; -webkit-tap-highlight-color: rgba(0, 0, 0, 0);\">
|
||||
<div class=\"am-tab-panel am-active\" id=\"alipay\">
|
||||
<a class=\"am-btn am-btn-lg am-btn-warning am-btn-primary\" id=\"alipaybtn\" href=\"#\">进入支付宝付款</a>
|
||||
<p></p>
|
||||
</div>
|
||||
<div class=\"am-tab-panel am-fade\" id=\"wcpay\">
|
||||
<div class=\"text-align:center; margin:0 auto; width:60%\">
|
||||
<div class=\"wcpay-qrcode\" style=\"text-align: center; \" data-requested=\"0\">
|
||||
正在加载中...
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class=\"am-tab-panel am-fade\" id=\"cardpay\">
|
||||
<div class=\"text-align:center; margin:0 auto; width:60%\">
|
||||
<div class=\"wrapper cardpay_content\" style=\"max-width:500px\">
|
||||
<div class=\"am-alert am-alert-danger\" style=\"display:none\">支付失败,请更换卡片或检查输入信息</div>
|
||||
<form action=\"/pay/stripe/charge\" method=\"post\" id=\"payment-form\">
|
||||
<div class=\"form-row\">
|
||||
<label for=\"card-element\">
|
||||
<p class='am-alert am-alert-secondary'>借记卡或信用卡</p>
|
||||
</label>
|
||||
<div id=\"card-element\">
|
||||
<!-- A Stripe Element will be inserted here. -->
|
||||
</div>
|
||||
<!-- Used to display form errors. -->
|
||||
<div id=\"card-errors\" role=\"alert\"></div>
|
||||
</div>
|
||||
<div class=\"form-row\">
|
||||
<button class=\"button\">支付</button>
|
||||
</div>
|
||||
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<script>
|
||||
var stripe = Stripe('$pk');
|
||||
var source = '';
|
||||
// Create a Stripe client.
|
||||
|
||||
// Create an instance of Elements.
|
||||
var elements = stripe.elements();
|
||||
|
||||
// Custom styling can be passed to options when creating an Element.
|
||||
// (Note that this demo uses a wider set of styles than the guide below.)
|
||||
var style = {
|
||||
base: {
|
||||
color: '#32325d',
|
||||
fontFamily: '\"Helvetica Neue\", Helvetica, sans-serif',
|
||||
fontSmoothing: 'antialiased',
|
||||
fontSize: '16px',
|
||||
'::placeholder': {
|
||||
color: '#aab7c4'
|
||||
}
|
||||
},
|
||||
invalid: {
|
||||
color: '#fa755a',
|
||||
iconColor: '#fa755a'
|
||||
}
|
||||
};
|
||||
|
||||
// Create an instance of the card Element.
|
||||
var card = elements.create('card', {style: style});
|
||||
|
||||
// Add an instance of the card Element into the `card-element` <div>.
|
||||
card.mount('#card-element');
|
||||
|
||||
// Handle real-time validation errors from the card Element.
|
||||
card.on('change', function (event) {
|
||||
var displayError = document.getElementById('card-errors');
|
||||
if (event.error) {
|
||||
displayError.textContent = event.error.message;
|
||||
} else {
|
||||
displayError.textContent = '';
|
||||
}
|
||||
});
|
||||
|
||||
// Handle form submission.
|
||||
var form = document.getElementById('payment-form');
|
||||
form.addEventListener('submit', function (event) {
|
||||
event.preventDefault();
|
||||
$(\".button\").attr(\"disabled\",\"true\");
|
||||
$(\".button\").html(\"请稍后\");
|
||||
stripe.createToken(card).then(function (result) {
|
||||
if (result.error) {
|
||||
// Inform the user if there was an error.
|
||||
var errorElement = document.getElementById('card-errors');
|
||||
errorElement.textContent = result.error.message;
|
||||
} else {
|
||||
// Send the token to your server.
|
||||
stripeTokenHandler(result.token);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
// Submit the form with the token ID.
|
||||
function stripeTokenHandler(token) {
|
||||
// Insert the token ID into the form so it gets submitted to the server
|
||||
var form = document.getElementById('payment-form');
|
||||
var hiddenInput = document.createElement('input');
|
||||
var hiddenInput1 = document.createElement('input');
|
||||
hiddenInput.setAttribute('type', 'hidden');
|
||||
hiddenInput.setAttribute('name', 'stripeToken');
|
||||
hiddenInput.setAttribute('value', token.id);
|
||||
hiddenInput1.setAttribute('type', 'hidden');
|
||||
hiddenInput1.setAttribute('name', 'orderid');
|
||||
hiddenInput1.setAttribute('value', '$orderid');
|
||||
form.appendChild(hiddenInput);
|
||||
form.appendChild(hiddenInput1);
|
||||
// Submit the form
|
||||
//form.submit();
|
||||
$.ajax({
|
||||
url: '/pay/stripe/charge/?orderid=$orderid&stripeToken=' + token.id,
|
||||
type: 'GET',
|
||||
success: function (result) {
|
||||
if (result == \"success\") {
|
||||
$(\".cardpay_content\").html(\"\");
|
||||
$(\".cardpay_content\").html(\"<p class='am-alert am-alert-success'>支付成功,正在跳转页面</p>\");
|
||||
window.setTimeout(function () {
|
||||
location.href = \"/detail-order-sn/$orderid\"
|
||||
}, 800);
|
||||
} else {
|
||||
$(\".am-alert\").show();
|
||||
$(\".button\").removeAttr(\"disabled\");
|
||||
$(\".button\").html(\"支付\");
|
||||
setTimeout(\" $('.am-alert').hide();\", 3000);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
(function () {
|
||||
stripe.createSource({
|
||||
type: 'alipay',
|
||||
amount: $amount,
|
||||
currency: 'cny',
|
||||
// 这里你需要渲染出一些用户的信息,不然后期没法知道是谁在付钱
|
||||
owner: {
|
||||
name: '$orderid',
|
||||
},
|
||||
redirect: {
|
||||
return_url: '$return_url',
|
||||
},
|
||||
}).then(function (result) {
|
||||
$(\"#alipaybtn\").attr(\"href\", result.source.redirect.url);
|
||||
});
|
||||
})();
|
||||
|
||||
function paymentcheck() {
|
||||
$.ajax({
|
||||
url: '/pay/stripe/check/?orderid=$orderid&source=' + source,
|
||||
type: 'GET',
|
||||
success: function (result) {
|
||||
if (result == \"success\") {
|
||||
$(\".wcpay-qrcode\").html(\"\");
|
||||
$(\".wcpay-qrcode\").html(\"<p class='am-alert am-alert-success'>支付成功,正在跳转页面</p>\");
|
||||
window.setTimeout(function () {
|
||||
location.href = \"/detail-order-sn/$orderid\"
|
||||
}, 800);
|
||||
} else {
|
||||
setTimeout(\"paymentcheck()\", 1000);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
$(\".request-wechat-pay\").click(function () {
|
||||
if ($(\".wcpay-qrcode\").data(\"requested\") == 0) {
|
||||
stripe.createSource({
|
||||
type: 'wechat',
|
||||
amount: $usd,
|
||||
currency: 'usd',
|
||||
owner: {
|
||||
name: '$orderid'
|
||||
},
|
||||
}).then(function (result) {
|
||||
if (result.source.id) {
|
||||
$(\".wcpay-qrcode\").html(\"<p class='am-alert am-alert-success'>打开微信 - 扫一扫</p>\");
|
||||
$(\".wcpay-qrcode\").qrcode(result.source.wechat.qr_code_url);
|
||||
$(\".wcpay-qrcode\").data(\"requested\", 1);
|
||||
$(\".wcpay-qrcode\").data(\"sid\", result.source.id);
|
||||
$(\".wcpay-qrcode\").data(\"scs\", result.source.client_secret);
|
||||
source = result.source.id;
|
||||
setTimeout(\"paymentcheck()\", 3000);
|
||||
} else {
|
||||
alert(\"微信支付加载失败\");
|
||||
$(\".wcpay-qrcode\").html(\"<p class='am-alert am-alert-danger'>加载失败,请刷新页面。</p>\");
|
||||
}
|
||||
// handle result.error or result.source
|
||||
});
|
||||
}
|
||||
});
|
||||
</script>
|
||||
</body>
|
||||
</html>";
|
||||
|
||||
return $html;
|
||||
} catch (\Exception $e) {
|
||||
throw new RuleValidationException(__('dujiaoka.prompt.abnormal_payment_channel') . $e->getMessage());
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
public function returnUrl(Request $request)
|
||||
{
|
||||
|
||||
$data = $request->all();
|
||||
$cacheord = $this->orderService->detailOrderSN($data['orderid']);
|
||||
if (!$cacheord) {
|
||||
return redirect(url('detail-order-sn', ['orderSN' => $data['orderid']]));
|
||||
}
|
||||
$payGateway = $this->payService->detail($cacheord->pay_id);
|
||||
\Stripe\Stripe::setApiKey($payGateway -> merchant_pem);
|
||||
$source_object = \Stripe\Source::retrieve($data['source']);
|
||||
//die($source_object);
|
||||
if ($source_object->status == 'chargeable') {
|
||||
\Stripe\Charge::create([
|
||||
'amount' => $source_object->amount,
|
||||
'currency' => $source_object->currency,
|
||||
'source' => $data['source'],
|
||||
]);
|
||||
if ($source_object->owner->name == $data['orderid']) {
|
||||
$this->orderProcessService->completedOrder($data['orderid'], $source_object->amount / 100, $source_object->id);
|
||||
}
|
||||
}
|
||||
return redirect(url('detail-order-sn', ['orderSN' => $data['orderid']]));
|
||||
}
|
||||
|
||||
public function check(Request $request)
|
||||
{
|
||||
|
||||
$data = $request->all();
|
||||
$cacheord = $this->orderService->detailOrderSN($data['orderid']);
|
||||
if (!$cacheord) {
|
||||
//可能已异步回调成功,跳转
|
||||
return 'fail';
|
||||
} else {
|
||||
$payGateway = $this->payService->detail($cacheord->pay_id);
|
||||
\Stripe\Stripe::setApiKey($payGateway -> merchant_pem);
|
||||
$source_object = \Stripe\Source::retrieve($data['source']);
|
||||
if ($source_object->status == 'chargeable') {
|
||||
\Stripe\Charge::create([
|
||||
'amount' => $source_object->amount,
|
||||
'currency' => $source_object->currency,
|
||||
'source' => $data['source'],
|
||||
]);
|
||||
}
|
||||
if ($source_object->status == 'consumed' && $source_object->owner->name == $data['orderid']) {
|
||||
$this->orderProcessService->completedOrder($data['orderid'], $cacheord->actual_price, $source_object->id);
|
||||
return 'success';
|
||||
} else {
|
||||
return 'fail';
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public function charge(Request $request)
|
||||
{
|
||||
$data = $request->all();
|
||||
$cacheord = $this->orderService->detailOrderSN($data['orderid']);
|
||||
if (!$cacheord) {
|
||||
//可能已异步回调成功,跳转
|
||||
return 'fail';
|
||||
} else {
|
||||
try {
|
||||
$payGateway = $this->payService->detail($cacheord->pay_id);
|
||||
\Stripe\Stripe::setApiKey($payGateway -> merchant_pem);
|
||||
$result = \Stripe\Charge::create([
|
||||
'amount' => bcmul($this->getUsdCurrency($cacheord->actual_price), 100,0),
|
||||
'currency' => 'usd',
|
||||
'source' => $data['stripeToken'],
|
||||
]);
|
||||
if ($result->status == 'succeeded') {
|
||||
$this->orderProcessService->completedOrder($data['orderid'], $cacheord->actual_price, $data['stripeToken']);
|
||||
return 'success';
|
||||
}
|
||||
return $result;
|
||||
} catch (\Exception $e) {
|
||||
return $e->getMessage();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据RMB获取美元
|
||||
* @param $cny
|
||||
* @return float|int
|
||||
* @throws \Exception
|
||||
*/
|
||||
public function getUsdCurrency($cny)
|
||||
{
|
||||
$client = new Client();
|
||||
$res = $client->get('https://m.cmbchina.com/api/rate/fx-rate');
|
||||
$fxrate = json_decode($res->getBody(), true);
|
||||
$data = $fxrate['body']['data'];
|
||||
if (!isset($data)) {
|
||||
throw new \Exception('汇率接口异常');
|
||||
}
|
||||
$dfFxrate = 0.13;
|
||||
foreach ($data as $item) {
|
||||
if ($item['ccyNbr'] == "美元") {
|
||||
$dfFxrate = bcdiv(100, $item['rtcOfr'], 2);
|
||||
break;
|
||||
}
|
||||
}
|
||||
return bcmul($cny , $dfFxrate , 2);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -0,0 +1,105 @@
|
||||
<?php
|
||||
/**
|
||||
* The file was created by LightCountry.
|
||||
*
|
||||
* @author https://github.com/LightCountry
|
||||
* @copyright https://github.com/LightCountry
|
||||
* @link https://github.com/LightCountry/TokenPay
|
||||
*/
|
||||
|
||||
namespace App\Http\Controllers\Pay;
|
||||
|
||||
|
||||
use App\Exceptions\RuleValidationException;
|
||||
use App\Http\Controllers\PayController;
|
||||
use GuzzleHttp\Client;
|
||||
use GuzzleHttp\Exception\GuzzleException;
|
||||
use Illuminate\Http\Request;
|
||||
|
||||
class TokenPayController extends PayController
|
||||
{
|
||||
public function gateway(string $payway, string $orderSN)
|
||||
{
|
||||
try {
|
||||
// 加载网关
|
||||
$this->loadGateWay($orderSN, $payway);
|
||||
//构造要请求的参数数组,无需改动
|
||||
$parameter = [
|
||||
"ActualAmount" => (float)$this->order->actual_price,//原价
|
||||
"OutOrderId" => $this->order->order_sn,
|
||||
"OrderUserKey" => $this->order->email,
|
||||
"Currency" => $this->payGateway->merchant_id,
|
||||
'RedirectUrl' => route('tokenpay-return', ['order_id' => $this->order->order_sn]),
|
||||
'NotifyUrl' => url($this->payGateway->pay_handleroute . '/notify_url'),
|
||||
];
|
||||
$parameter['Signature'] = $this->VerifySign($parameter, $this->payGateway->merchant_key);
|
||||
$client = new Client([
|
||||
'headers' => [ 'Content-Type' => 'application/json' ]
|
||||
]);
|
||||
$response = $client->post($this->payGateway->merchant_pem.'/CreateOrder', ['body' => json_encode($parameter)]);
|
||||
$body = json_decode($response->getBody()->getContents(), true);
|
||||
if (!isset($body['success']) || $body['success'] != true) {
|
||||
return $this->err(__('dujiaoka.prompt.abnormal_payment_channel') . $body['message']);
|
||||
}
|
||||
return redirect()->away($body['data']);
|
||||
} catch (RuleValidationException $exception) {
|
||||
} catch (GuzzleException $exception) {
|
||||
return $this->err($exception->getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
private function VerifySign(array $parameter, string $signKey)
|
||||
{
|
||||
ksort($parameter);
|
||||
reset($parameter); //内部指针指向数组中的第一个元素
|
||||
$sign = '';
|
||||
$urls = '';
|
||||
foreach ($parameter as $key => $val) {
|
||||
if ($key != 'Signature') {
|
||||
if ($sign != '') {
|
||||
$sign .= "&";
|
||||
$urls .= "&";
|
||||
}
|
||||
$sign .= "$key=$val"; //拼接为url参数形式
|
||||
$urls .= "$key=" . urlencode($val); //拼接为url参数形式
|
||||
}
|
||||
}
|
||||
$sign = md5($sign . $signKey);//密码追加进入开始MD5签名
|
||||
return $sign;
|
||||
}
|
||||
|
||||
public function notifyUrl(Request $request)
|
||||
{
|
||||
$data = $request->all();
|
||||
$order = $this->orderService->detailOrderSN($data['OutOrderId']);
|
||||
if (!$order) {
|
||||
return 'fail';
|
||||
}
|
||||
$payGateway = $this->payService->detail($order->pay_id);
|
||||
if (!$payGateway) {
|
||||
return 'fail';
|
||||
}
|
||||
if($payGateway->pay_handleroute != 'pay/tokenpay'){
|
||||
return 'fail';
|
||||
}
|
||||
//合法的数据
|
||||
$signature = $this->VerifySign($data, $payGateway->merchant_key);
|
||||
if ($data['Signature'] != $signature) { //不合法的数据
|
||||
return 'fail'; //返回失败 继续补单
|
||||
} else {
|
||||
//合法的数据
|
||||
//业务处理
|
||||
$this->orderProcessService->completedOrder($data['OutOrderId'], $data['ActualAmount'], $data['Id']);
|
||||
return 'ok';
|
||||
}
|
||||
}
|
||||
|
||||
public function returnUrl(Request $request)
|
||||
{
|
||||
$oid = $request->get('order_id');
|
||||
// 异步通知还没到就跳转了,所以这里休眠2秒
|
||||
sleep(2);
|
||||
return redirect(url('detail-order-sn', ['orderSN' => $oid]));
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,94 @@
|
||||
<?php
|
||||
/**
|
||||
* VpayController.php
|
||||
* V免签
|
||||
* Author iLay1678
|
||||
* Created on 2020/5/1 11:59
|
||||
*/
|
||||
|
||||
namespace App\Http\Controllers\Pay;
|
||||
|
||||
use App\Exceptions\RuleValidationException;
|
||||
use App\Http\Controllers\PayController;
|
||||
use Illuminate\Http\Request;
|
||||
|
||||
class VpayController extends PayController
|
||||
{
|
||||
|
||||
|
||||
public function gateway(string $payway, string $orderSN)
|
||||
{
|
||||
try {
|
||||
// 加载网关
|
||||
$this->loadGateWay($orderSN, $payway);
|
||||
|
||||
//构造要请求的参数数组,无需改动
|
||||
$parameter = array(
|
||||
"payId" => date('YmdHis') . rand(1, 65535),//平台ID号
|
||||
"price" => (float)$this->order->actual_price,//原价
|
||||
'param' => $this->order->order_sn,
|
||||
'returnUrl' => route('vpay-return', ['order_id' => $this->order->order_sn]),
|
||||
'notifyUrl' => url($this->payGateway->pay_handleroute . '/notify_url'),
|
||||
"isHtml" => 1,
|
||||
);
|
||||
switch ($payway) {
|
||||
case 'vzfb':
|
||||
$parameter['type'] = 2;
|
||||
break;
|
||||
case 'vwx':
|
||||
default:
|
||||
$parameter['type'] = 1;
|
||||
break;
|
||||
}
|
||||
$parameter['sign'] = md5($parameter['payId'] . $parameter['param'] . $parameter['type'] . $parameter['price'] . $this->payGateway->merchant_id);
|
||||
$payurl = $this->payGateway->merchant_pem . 'createOrder?' . http_build_query($parameter); //支付页面
|
||||
return redirect()->away($payurl);
|
||||
} catch (RuleValidationException $exception) {
|
||||
return $this->err($exception->getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public function notifyUrl(Request $request)
|
||||
{
|
||||
$data = $request->all();
|
||||
$order = $this->orderService->detailOrderSN($data['param']);
|
||||
if (!$order) {
|
||||
return 'fail';
|
||||
}
|
||||
$payGateway = $this->payService->detail($order->pay_id);
|
||||
|
||||
if($payGateway->pay_handleroute != 'pay/vpay'){
|
||||
return 'fail';
|
||||
}
|
||||
if (!$payGateway) {
|
||||
return 'fail';
|
||||
}
|
||||
|
||||
$key = $payGateway->merchant_id;//通讯密钥
|
||||
$payId = $data['payId'];//商户订单号
|
||||
$param = $data['param'];//创建订单的时候传入的参数
|
||||
$type = $data['type'];//支付方式 :微信支付为1 支付宝支付为2
|
||||
$price = $data['price'];//订单金额
|
||||
$reallyPrice = $data['reallyPrice'];//实际支付金额
|
||||
$sign = $data['sign'];//校验签名,计算方式 = md5(payId + param + type + price + reallyPrice + 通讯密钥)
|
||||
//开始校验签名
|
||||
$_sign = md5($payId . $param . $type . $price . $reallyPrice . $key);
|
||||
if ($_sign != $sign) { //不合法的数据
|
||||
return 'fail'; //返回失败 继续补单
|
||||
} else { //合法的数据
|
||||
//业务处理
|
||||
$this->orderProcessService->completedOrder($param, $price, $payId);
|
||||
return 'success';
|
||||
}
|
||||
}
|
||||
|
||||
public function returnUrl(Request $request)
|
||||
{
|
||||
$oid = $request->get('order_id');
|
||||
// 异步通知还没到就跳转了,所以这里休眠2秒
|
||||
sleep(2);
|
||||
return redirect(url('detail-order-sn', ['orderSN' => $oid]));
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,89 @@
|
||||
<?php
|
||||
namespace App\Http\Controllers\Pay;
|
||||
|
||||
|
||||
use App\Exceptions\RuleValidationException;
|
||||
use App\Http\Controllers\PayController;
|
||||
use Yansongda\Pay\Pay;
|
||||
|
||||
class WepayController extends PayController
|
||||
{
|
||||
|
||||
public function gateway(string $payway, string $orderSN)
|
||||
{
|
||||
try {
|
||||
// 加载网关
|
||||
$this->loadGateWay($orderSN, $payway);
|
||||
$config = [
|
||||
'app_id' => $this->payGateway->merchant_id,
|
||||
'mch_id' => $this->payGateway->merchant_key,
|
||||
'key' => $this->payGateway->merchant_pem,
|
||||
'notify_url' => url($this->payGateway->pay_handleroute . '/notify_url'),
|
||||
'return_url' => url('detail-order-sn', ['orderSN' => $this->order->order_sn]),
|
||||
'http' => [ // optional
|
||||
'timeout' => 10.0,
|
||||
'connect_timeout' => 10.0,
|
||||
],
|
||||
];
|
||||
$order = [
|
||||
'out_trade_no' => $this->order->order_sn,
|
||||
'total_fee' => bcmul($this->order->actual_price, 100, 0),
|
||||
'body' => $this->order->order_sn
|
||||
];
|
||||
switch ($payway){
|
||||
case 'wescan':
|
||||
try{
|
||||
$result = Pay::wechat($config)->scan($order)->toArray();
|
||||
$result['qr_code'] = $result['code_url'];
|
||||
$result['payname'] =$this->payGateway->pay_name;
|
||||
$result['actual_price'] = (float)$this->order->actual_price;
|
||||
$result['orderid'] = $this->order->order_sn;
|
||||
return $this->render('static_pages/qrpay', $result, __('dujiaoka.scan_qrcode_to_pay'));
|
||||
} catch (\Exception $e) {
|
||||
throw new RuleValidationException(__('dujiaoka.prompt.abnormal_payment_channel') . $e->getMessage());
|
||||
}
|
||||
break;
|
||||
|
||||
}
|
||||
} catch (RuleValidationException $exception) {
|
||||
return $this->err($exception->getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 异步通知
|
||||
*/
|
||||
public function notifyUrl()
|
||||
{
|
||||
$xml = file_get_contents('php://input');
|
||||
$arr = json_decode(json_encode(simplexml_load_string($xml, 'SimpleXMLElement', LIBXML_NOCDATA)), true);
|
||||
$oid = $arr['out_trade_no'];
|
||||
$order = $this->orderService->detailOrderSN($oid);
|
||||
if (!$order) {
|
||||
return 'error';
|
||||
}
|
||||
$payGateway = $this->payService->detail($order->pay_id);
|
||||
if (!$payGateway) {
|
||||
return 'error';
|
||||
}
|
||||
if($payGateway->pay_handleroute != '/pay/wepay'){
|
||||
return 'error';
|
||||
}
|
||||
$config = [
|
||||
'app_id' => $payGateway->merchant_id,
|
||||
'mch_id' => $payGateway->merchant_key,
|
||||
'key' => $payGateway->merchant_pem,
|
||||
];
|
||||
$pay = Pay::wechat($config);
|
||||
try{
|
||||
// 验证签名
|
||||
$result = $pay->verify();
|
||||
$total_fee = bcdiv($result->total_fee, 100, 2);
|
||||
$this->orderProcessService->completedOrder($result->out_trade_no, $total_fee, $result->transaction_id);
|
||||
return 'success';
|
||||
} catch (\Exception $exception) {
|
||||
return 'fail';
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,103 @@
|
||||
<?php
|
||||
namespace App\Http\Controllers\Pay;
|
||||
|
||||
use App\Exceptions\RuleValidationException;
|
||||
use App\Http\Controllers\PayController;
|
||||
use Illuminate\Http\Request;
|
||||
|
||||
class YipayController extends PayController
|
||||
{
|
||||
|
||||
public function gateway(string $payway, string $orderSN)
|
||||
{
|
||||
try {
|
||||
// 加载网关
|
||||
$this->loadGateWay($orderSN, $payway);
|
||||
//组装支付参数
|
||||
$parameter = [
|
||||
'pid' => $this->payGateway->merchant_id,
|
||||
'type' => $payway,
|
||||
'out_trade_no' => $this->order->order_sn,
|
||||
'return_url' => route('yipay-return', ['order_id' => $this->order->order_sn]),
|
||||
'notify_url' => url($this->payGateway->pay_handleroute . '/notify_url'),
|
||||
'name' => $this->order->order_sn,
|
||||
'money' => (float)$this->order->actual_price,
|
||||
'sign' => $this->payGateway->merchant_pem,
|
||||
'sign_type' =>'MD5'
|
||||
];
|
||||
ksort($parameter); //重新排序$data数组
|
||||
reset($parameter); //内部指针指向数组中的第一个元素
|
||||
$sign = '';
|
||||
foreach ($parameter as $key => $val) {
|
||||
if ($key == "sign" || $key == "sign_type" || $val == "") continue;
|
||||
if ($key != 'sign') {
|
||||
if ($sign != '') {
|
||||
$sign .= "&";
|
||||
}
|
||||
$sign .= "$key=$val"; //拼接为url参数形式
|
||||
}
|
||||
}
|
||||
|
||||
$sign = md5($sign . $this->payGateway->merchant_pem);//密码追加进入开始MD5签名
|
||||
$parameter['sign'] = $sign;
|
||||
//待请求参数数组
|
||||
$sHtml = "<form id='alipaysubmit' name='alipaysubmit' action='" . $this->payGateway->merchant_key . "' method='get'>";
|
||||
|
||||
foreach($parameter as $key => $val) {
|
||||
$sHtml.= "<input type='hidden' name='".$key."' value='".$val."'/>";
|
||||
}
|
||||
|
||||
//submit按钮控件请不要含有name属性
|
||||
$sHtml = $sHtml."<input type='submit' value=''></form>";
|
||||
$sHtml = $sHtml."<script>document.forms['alipaysubmit'].submit();</script>";
|
||||
return $sHtml;
|
||||
} catch (RuleValidationException $exception) {
|
||||
return $this->err($exception->getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
public function notifyUrl(Request $request)
|
||||
{
|
||||
$data = $request->all();
|
||||
$order = $this->orderService->detailOrderSN($data['out_trade_no']);
|
||||
if (!$order) {
|
||||
return 'fail';
|
||||
}
|
||||
$payGateway = $this->payService->detail($order->pay_id);
|
||||
if (!$payGateway) {
|
||||
return 'fail';
|
||||
}
|
||||
if($payGateway->pay_handleroute != '/pay/yipay'){
|
||||
return 'fail';
|
||||
}
|
||||
ksort($data); //重新排序$data数组
|
||||
reset($data); //内部指针指向数组中的第一个元素
|
||||
$sign = '';
|
||||
foreach ($data as $key => $val) {
|
||||
if ($key == "sign" || $key == "sign_type" || $val == "") continue;
|
||||
if ($key != 'sign') {
|
||||
if ($sign != '') {
|
||||
$sign .= "&";
|
||||
}
|
||||
$sign .= "$key=$val"; //拼接为url参数形式
|
||||
}
|
||||
}
|
||||
if (!$data['trade_no'] || md5($sign . $payGateway->merchant_pem) != $data['sign']) { //不合法的数据
|
||||
return 'fail'; //返回失败 继续补单
|
||||
} else {
|
||||
//合法的数据
|
||||
//业务处理
|
||||
$this->orderProcessService->completedOrder($data['out_trade_no'], $data['money'], $data['trade_no']);
|
||||
return 'success';
|
||||
}
|
||||
}
|
||||
|
||||
public function returnUrl(Request $request)
|
||||
{
|
||||
$oid = $request->get('order_id');
|
||||
// 有些易支付太垃了,异步通知还没到就跳转了,导致订单显示待支付,其实已经支付了,所以这里休眠2秒
|
||||
sleep(2);
|
||||
return redirect(url('detail-order-sn', ['orderSN' => $oid]));
|
||||
}
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user