first commit
This commit is contained in:
@@ -0,0 +1,54 @@
|
||||
<?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;
|
||||
|
||||
class BaseController extends Controller
|
||||
{
|
||||
|
||||
/**
|
||||
* 渲染模板
|
||||
*
|
||||
* @param string $tpl 模板名称
|
||||
* @param array $data 数据
|
||||
* @param array $pageTitle 页面标题
|
||||
*
|
||||
* @return \Illuminate\Contracts\Foundation\Application|\Illuminate\Contracts\View\Factory|\Illuminate\View\View
|
||||
*
|
||||
* @author assimon<ashang@utf8.hk>
|
||||
* @copyright assimon<ashang@utf8.hk>
|
||||
* @link http://utf8.hk/
|
||||
*/
|
||||
protected function render(string $tpl, $data = [], string $pageTitle = '')
|
||||
{
|
||||
$layout = dujiaoka_config_get('template', 'unicorn');
|
||||
$tplPath = $layout . '/' .$tpl;
|
||||
return view($tplPath, $data)->with('page_title', $pageTitle);
|
||||
}
|
||||
|
||||
/**
|
||||
* 错误提示
|
||||
*
|
||||
* @param string $content 提示内容
|
||||
* @param string $jumpUri 跳转url
|
||||
* @return \Illuminate\Contracts\Foundation\Application|\Illuminate\Contracts\View\Factory|\Illuminate\View\View
|
||||
*
|
||||
* @author assimon<ashang@utf8.hk>
|
||||
* @copyright assimon<ashang@utf8.hk>
|
||||
* @link http://utf8.hk/
|
||||
*/
|
||||
protected function err(string $content, $jumpUri = '')
|
||||
{
|
||||
$layout = dujiaoka_config_get('template', 'unicorn');
|
||||
$tplPath = $layout . '/errors/error';
|
||||
return view($tplPath, ['title' => __('dujiaoka.error_title'), 'content' => $content, 'url' => $jumpUri])
|
||||
->with('page_title', __('dujiaoka.error_title'));
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Controllers;
|
||||
|
||||
use Illuminate\Foundation\Auth\Access\AuthorizesRequests;
|
||||
use Illuminate\Foundation\Bus\DispatchesJobs;
|
||||
use Illuminate\Foundation\Validation\ValidatesRequests;
|
||||
use Illuminate\Routing\Controller as BaseController;
|
||||
|
||||
class Controller extends BaseController
|
||||
{
|
||||
use AuthorizesRequests, DispatchesJobs, ValidatesRequests;
|
||||
}
|
||||
@@ -0,0 +1,189 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Controllers\Home;
|
||||
|
||||
use App\Exceptions\RuleValidationException;
|
||||
use App\Http\Controllers\BaseController;
|
||||
use App\Models\Pay;
|
||||
use Germey\Geetest\Geetest;
|
||||
use Illuminate\Database\DatabaseServiceProvider;
|
||||
use Illuminate\Database\QueryException;
|
||||
use Illuminate\Encryption\Encrypter;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Support\Facades\Auth;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
use Illuminate\Support\Facades\Redis;
|
||||
|
||||
class HomeController extends BaseController
|
||||
{
|
||||
|
||||
/**
|
||||
* 商品服务层.
|
||||
* @var \App\Service\PayService
|
||||
*/
|
||||
private $goodsService;
|
||||
|
||||
/**
|
||||
* 支付服务层
|
||||
* @var \App\Service\PayService
|
||||
*/
|
||||
private $payService;
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
$this->goodsService = app('Service\GoodsService');
|
||||
$this->payService = app('Service\PayService');
|
||||
}
|
||||
|
||||
/**
|
||||
* 首页.
|
||||
*
|
||||
* @param Request $request
|
||||
*
|
||||
* @author assimon<ashang@utf8.hk>
|
||||
* @copyright assimon<ashang@utf8.hk>
|
||||
* @link http://utf8.hk/
|
||||
*/
|
||||
public function index(Request $request)
|
||||
{
|
||||
$goods = $this->goodsService->withGroup();
|
||||
return $this->render('static_pages/home', ['data' => $goods], __('dujiaoka.page-title.home'));
|
||||
}
|
||||
|
||||
/**
|
||||
* 商品详情
|
||||
*
|
||||
* @param int $id
|
||||
* @return \Illuminate\Contracts\Foundation\Application|\Illuminate\Contracts\View\Factory|\Illuminate\View\View
|
||||
*
|
||||
* @author assimon<ashang@utf8.hk>
|
||||
* @copyright assimon<ashang@utf8.hk>
|
||||
* @link http://utf8.hk/
|
||||
*/
|
||||
public function buy(int $id)
|
||||
{
|
||||
try {
|
||||
$goods = $this->goodsService->detail($id);
|
||||
$this->goodsService->validatorGoodsStatus($goods);
|
||||
// 有没有优惠码可以展示
|
||||
if (count($goods->coupon)) {
|
||||
$goods->open_coupon = 1;
|
||||
}
|
||||
$formatGoods = $this->goodsService->format($goods);
|
||||
// 加载支付方式.
|
||||
$client = Pay::PAY_CLIENT_PC;
|
||||
if (app('Jenssegers\Agent')->isMobile()) {
|
||||
$client = Pay::PAY_CLIENT_MOBILE;
|
||||
}
|
||||
$formatGoods->payways = $this->payService->pays($client);
|
||||
return $this->render('static_pages/buy', $formatGoods, $formatGoods->gd_name);
|
||||
} catch (RuleValidationException $ruleValidationException) {
|
||||
return $this->err($ruleValidationException->getMessage());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* 极验行为验证
|
||||
*
|
||||
* @param Request $request
|
||||
*
|
||||
* @author assimon<ashang@utf8.hk>
|
||||
* @copyright assimon<ashang@utf8.hk>
|
||||
* @link http://utf8.hk/
|
||||
*/
|
||||
public function geetest(Request $request)
|
||||
{
|
||||
$data = [
|
||||
'user_id' => @Auth::user()?@Auth::user()->id:'UnLoginUser',
|
||||
'client_type' => 'web',
|
||||
'ip_address' => \Illuminate\Support\Facades\Request::ip()
|
||||
];
|
||||
$status = Geetest::preProcess($data);
|
||||
session()->put('gtserver', $status);
|
||||
session()->put('user_id', $data['user_id']);
|
||||
return Geetest::getResponseStr();
|
||||
}
|
||||
|
||||
/**
|
||||
* 安装页面
|
||||
*
|
||||
* @param Request $request
|
||||
* @return \Illuminate\Contracts\Foundation\Application|\Illuminate\Contracts\View\Factory|\Illuminate\View\View
|
||||
*
|
||||
* @author assimon<ashang@utf8.hk>
|
||||
* @copyright assimon<ashang@utf8.hk>
|
||||
* @link http://utf8.hk/
|
||||
*/
|
||||
public function install(Request $request)
|
||||
{
|
||||
return view('common/install');
|
||||
}
|
||||
|
||||
/**
|
||||
* 执行安装
|
||||
*
|
||||
* @param Request $request
|
||||
*
|
||||
* @author assimon<ashang@utf8.hk>
|
||||
* @copyright assimon<ashang@utf8.hk>
|
||||
* @link http://utf8.hk/
|
||||
*/
|
||||
public function doInstall(Request $request)
|
||||
{
|
||||
try {
|
||||
$dbConfig = config('database');
|
||||
$mysqlDB = [
|
||||
'host' => $request->input('db_host'),
|
||||
'port' => $request->input('db_port'),
|
||||
'database' => $request->input('db_database'),
|
||||
'username' => $request->input('db_username'),
|
||||
'password' => $request->input('db_password'),
|
||||
];
|
||||
$dbConfig['connections']['mysql'] = array_merge($dbConfig['connections']['mysql'], $mysqlDB);
|
||||
// Redis
|
||||
$redisDB = [
|
||||
'host' => $request->input('redis_host'),
|
||||
'password' => $request->input('redis_password', 'null'),
|
||||
'port' => $request->input('redis_port'),
|
||||
];
|
||||
$dbConfig['redis']['default'] = array_merge($dbConfig['redis']['default'], $redisDB);
|
||||
config(['database' => $dbConfig]);
|
||||
DB::purge();
|
||||
// db测试
|
||||
DB::connection()->select('select 1 limit 1');
|
||||
// redis测试
|
||||
Redis::set('dujiaoka_com', 'ok');
|
||||
Redis::get('dujiaoka_com');
|
||||
// 获得文件模板
|
||||
$envExamplePath = base_path() . DIRECTORY_SEPARATOR . '.env.example';
|
||||
$envPath = base_path() . DIRECTORY_SEPARATOR . '.env';
|
||||
$installLock = base_path() . DIRECTORY_SEPARATOR . 'install.lock';
|
||||
$installSql = database_path() . DIRECTORY_SEPARATOR . 'sql' . DIRECTORY_SEPARATOR . 'install.sql';
|
||||
$envTemp = file_get_contents($envExamplePath);
|
||||
$postData = $request->all();
|
||||
// 临时写入key
|
||||
$postData['app_key'] = 'base64:' . base64_encode(
|
||||
Encrypter::generateKey(config('app.cipher'))
|
||||
);
|
||||
foreach ($postData as $key => $item) {
|
||||
$envTemp = str_replace('{' . $key . '}', $item, $envTemp);
|
||||
}
|
||||
// 写入配置
|
||||
file_put_contents($envPath, $envTemp);
|
||||
// 导入sql
|
||||
DB::unprepared(file_get_contents($installSql));
|
||||
// 写入安装锁
|
||||
file_put_contents($installLock, 'install ok');
|
||||
return 'success';
|
||||
} catch (\RedisException $exception) {
|
||||
return 'Redis配置错误 :' . $exception->getMessage();
|
||||
} catch (QueryException $exception) {
|
||||
return '数据库配置错误 :' . $exception->getMessage();
|
||||
} catch (\Exception $exception) {
|
||||
return $exception->getMessage();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -0,0 +1,259 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Controllers\Home;
|
||||
|
||||
use App\Exceptions\RuleValidationException;
|
||||
use App\Http\Controllers\BaseController;
|
||||
use App\Models\Order;
|
||||
use App\Service\OrderProcessService;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Support\Facades\Cookie;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
|
||||
|
||||
/**
|
||||
* 订单控制器
|
||||
*
|
||||
* Class OrderController
|
||||
* @package App\Http\Controllers\Home
|
||||
* @author: Assimon
|
||||
* @email: Ashang@utf8.hk
|
||||
* @blog: https://utf8.hk
|
||||
* Date: 2021/5/30
|
||||
*/
|
||||
class OrderController extends BaseController
|
||||
{
|
||||
|
||||
|
||||
/**
|
||||
* 订单服务层
|
||||
* @var \App\Service\OrderService
|
||||
*/
|
||||
private $orderService;
|
||||
|
||||
/**
|
||||
* 订单处理层.
|
||||
* @var OrderProcessService
|
||||
*/
|
||||
private $orderProcessService;
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
$this->orderService = app('Service\OrderService');
|
||||
$this->orderProcessService = app('Service\OrderProcessService');
|
||||
}
|
||||
|
||||
/**
|
||||
* 创建订单
|
||||
*
|
||||
* @param Request $request
|
||||
* @return \Illuminate\Contracts\Foundation\Application|\Illuminate\Contracts\View\Factory|\Illuminate\View\View
|
||||
* @throws \Illuminate\Validation\ValidationException
|
||||
*
|
||||
* @author assimon<ashang@utf8.hk>
|
||||
* @copyright assimon<ashang@utf8.hk>
|
||||
* @link http://utf8.hk/
|
||||
*/
|
||||
public function createOrder(Request $request)
|
||||
{
|
||||
DB::beginTransaction();
|
||||
try {
|
||||
$this->orderService->validatorCreateOrder($request);
|
||||
$goods = $this->orderService->validatorGoods($request);
|
||||
$this->orderService->validatorLoopCarmis($request);
|
||||
// 设置商品
|
||||
$this->orderProcessService->setGoods($goods);
|
||||
// 优惠码
|
||||
$coupon = $this->orderService->validatorCoupon($request);
|
||||
// 设置优惠码
|
||||
$this->orderProcessService->setCoupon($coupon);
|
||||
$otherIpt = $this->orderService->validatorChargeInput($goods, $request);
|
||||
$this->orderProcessService->setOtherIpt($otherIpt);
|
||||
// 数量
|
||||
$this->orderProcessService->setBuyAmount($request->input('by_amount'));
|
||||
// 支付方式
|
||||
$this->orderProcessService->setPayID($request->input('payway'));
|
||||
// 下单邮箱
|
||||
$this->orderProcessService->setEmail($request->input('email'));
|
||||
// ip地址
|
||||
$this->orderProcessService->setBuyIP($request->getClientIp());
|
||||
// 查询密码
|
||||
$this->orderProcessService->setSearchPwd($request->input('search_pwd', ''));
|
||||
// 创建订单
|
||||
$order = $this->orderProcessService->createOrder();
|
||||
DB::commit();
|
||||
// 设置订单cookie
|
||||
$this->queueCookie($order->order_sn);
|
||||
return redirect(url('/bill', ['orderSN' => $order->order_sn]));
|
||||
} catch (RuleValidationException $exception) {
|
||||
DB::rollBack();
|
||||
return $this->err($exception->getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置订单cookie.
|
||||
* @param string $orderSN 订单号.
|
||||
*/
|
||||
private function queueCookie(string $orderSN) : void
|
||||
{
|
||||
// 设置订单cookie
|
||||
$cookies = Cookie::get('dujiaoka_orders');
|
||||
if (empty($cookies)) {
|
||||
Cookie::queue('dujiaoka_orders', json_encode([$orderSN]));
|
||||
} else {
|
||||
$cookies = json_decode($cookies, true);
|
||||
array_push($cookies, $orderSN);
|
||||
Cookie::queue('dujiaoka_orders', json_encode($cookies));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 结账
|
||||
*
|
||||
* @param string $orderSN
|
||||
* @return \Illuminate\Contracts\Foundation\Application|\Illuminate\Contracts\View\Factory|\Illuminate\View\View
|
||||
*
|
||||
* @author assimon<ashang@utf8.hk>
|
||||
* @copyright assimon<ashang@utf8.hk>
|
||||
* @link http://utf8.hk/
|
||||
*/
|
||||
public function bill(string $orderSN)
|
||||
{
|
||||
$order = $this->orderService->detailOrderSN($orderSN);
|
||||
if (empty($order)) {
|
||||
return $this->err(__('dujiaoka.prompt.order_does_not_exist'));
|
||||
}
|
||||
if ($order->status == Order::STATUS_EXPIRED) {
|
||||
return $this->err(__('dujiaoka.prompt.order_is_expired'));
|
||||
}
|
||||
return $this->render('static_pages/bill', $order, __('dujiaoka.page-title.bill'));
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 订单状态监测
|
||||
*
|
||||
* @param string $orderSN 订单号
|
||||
* @return \Illuminate\Http\JsonResponse
|
||||
*
|
||||
* @author assimon<ashang@utf8.hk>
|
||||
* @copyright assimon<ashang@utf8.hk>
|
||||
* @link http://utf8.hk/
|
||||
*/
|
||||
public function checkOrderStatus(string $orderSN)
|
||||
{
|
||||
$order = $this->orderService->detailOrderSN($orderSN);
|
||||
// 订单不存在或者已经过期
|
||||
if (!$order || $order->status == Order::STATUS_EXPIRED) {
|
||||
return response()->json(['msg' => 'expired', 'code' => 400001]);
|
||||
}
|
||||
// 订单已经支付
|
||||
if ($order->status == Order::STATUS_WAIT_PAY) {
|
||||
return response()->json(['msg' => 'wait....', 'code' => 400000]);
|
||||
}
|
||||
// 成功
|
||||
if ($order->status > Order::STATUS_WAIT_PAY) {
|
||||
return response()->json(['msg' => 'success', 'code' => 200]);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 通过订单号展示订单详情
|
||||
*
|
||||
* @param string $orderSN 订单号.
|
||||
* @return \Illuminate\Contracts\Foundation\Application|\Illuminate\Contracts\View\Factory|\Illuminate\View\View
|
||||
*
|
||||
* @author assimon<ashang@utf8.hk>
|
||||
* @copyright assimon<ashang@utf8.hk>
|
||||
* @link http://utf8.hk/
|
||||
*/
|
||||
public function detailOrderSN(string $orderSN)
|
||||
{
|
||||
$order = $this->orderService->detailOrderSN($orderSN);
|
||||
// 订单不存在或者已经过期
|
||||
if (!$order) {
|
||||
return $this->err(__('dujiaoka.prompt.order_does_not_exist'));
|
||||
}
|
||||
return $this->render('static_pages/orderinfo', ['orders' => [$order]], __('dujiaoka.page-title.order-detail'));
|
||||
}
|
||||
|
||||
/**
|
||||
* 订单号查询
|
||||
*
|
||||
* @param Request $request
|
||||
* @return \Illuminate\Contracts\Foundation\Application|\Illuminate\Contracts\View\Factory|\Illuminate\View\View
|
||||
*
|
||||
* @author assimon<ashang@utf8.hk>
|
||||
* @copyright assimon<ashang@utf8.hk>
|
||||
* @link http://utf8.hk/
|
||||
*/
|
||||
public function searchOrderBySN(Request $request)
|
||||
{
|
||||
return $this->detailOrderSN($request->input('order_sn'));
|
||||
}
|
||||
|
||||
/**
|
||||
* 通过邮箱查询
|
||||
*
|
||||
* @param Request $request
|
||||
* @return \Illuminate\Contracts\Foundation\Application|\Illuminate\Contracts\View\Factory|\Illuminate\View\View
|
||||
*
|
||||
* @author assimon<ashang@utf8.hk>
|
||||
* @copyright assimon<ashang@utf8.hk>
|
||||
* @link http://utf8.hk/
|
||||
*/
|
||||
public function searchOrderByEmail(Request $request)
|
||||
{
|
||||
if (
|
||||
!$request->has('email') ||
|
||||
(
|
||||
dujiaoka_config_get('is_open_search_pwd', \App\Models\BaseModel::STATUS_CLOSE) == \App\Models\BaseModel::STATUS_OPEN &&
|
||||
!$request->has('search_pwd')
|
||||
)
|
||||
) {
|
||||
return $this->err(__('dujiaoka.prompt.server_illegal_request'));
|
||||
}
|
||||
$orders = $this->orderService->withEmailAndPassword($request->input('email'), $request->input('search_pwd',''));
|
||||
if (!$orders) {
|
||||
return $this->err(__('dujiaoka.prompt.no_related_order_found'));
|
||||
}
|
||||
return $this->render('static_pages/orderinfo', ['orders' => $orders], __('dujiaoka.page-title.order-detail'));
|
||||
}
|
||||
|
||||
/**
|
||||
* 通过浏览器缓存查询
|
||||
* @param Request $request
|
||||
* @return \Illuminate\Contracts\Foundation\Application|\Illuminate\Contracts\View\Factory|\Illuminate\View\View
|
||||
*
|
||||
* @author assimon<ashang@utf8.hk>
|
||||
* @copyright assimon<ashang@utf8.hk>
|
||||
* @link http://utf8.hk/
|
||||
*/
|
||||
public function searchOrderByBrowser(Request $request)
|
||||
{
|
||||
$cookies = Cookie::get('dujiaoka_orders');
|
||||
if (empty($cookies)) {
|
||||
return $this->err(__('dujiaoka.prompt.no_related_order_found_for_cache'));
|
||||
}
|
||||
$orderSNS = json_decode($cookies, true);
|
||||
$orders = $this->orderService->byOrderSNS($orderSNS);
|
||||
return $this->render('static_pages/orderinfo', ['orders' => $orders], __('dujiaoka.page-title.order-detail'));
|
||||
}
|
||||
|
||||
/**
|
||||
* 订单查询页
|
||||
*
|
||||
* @param Request $request
|
||||
* @return mixed
|
||||
*
|
||||
* @author assimon<ashang@utf8.hk>
|
||||
* @copyright assimon<ashang@utf8.hk>
|
||||
* @link http://utf8.hk/
|
||||
*/
|
||||
public function orderSearch(Request $request)
|
||||
{
|
||||
return $this->render('static_pages/searchOrder', [], __('dujiaoka.page-title.order-search'));
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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]));
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,130 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Controllers;
|
||||
|
||||
use App\Exceptions\RuleValidationException;
|
||||
use App\Models\Order;
|
||||
use App\Service\OrderProcessService;
|
||||
|
||||
class PayController extends BaseController
|
||||
{
|
||||
|
||||
/**
|
||||
* 支付网关
|
||||
* @var \App\Models\Pay
|
||||
*/
|
||||
protected $payGateway;
|
||||
|
||||
|
||||
/**
|
||||
* 订单
|
||||
* @var \App\Models\Order
|
||||
*/
|
||||
protected $order;
|
||||
|
||||
/**
|
||||
* 订单服务层
|
||||
* @var \App\Service\OrderService
|
||||
*/
|
||||
protected $orderService;
|
||||
|
||||
/**
|
||||
* 支付服务层
|
||||
* @var \App\Service\PayService
|
||||
*/
|
||||
protected $payService;
|
||||
|
||||
/**
|
||||
* 订单处理层.
|
||||
* @var OrderProcessService
|
||||
*/
|
||||
protected $orderProcessService;
|
||||
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
$this->orderService = app('Service\OrderService');
|
||||
$this->payService = app('Service\PayService');
|
||||
$this->orderProcessService = app('Service\OrderProcessService');
|
||||
}
|
||||
|
||||
/**
|
||||
* 订单检测
|
||||
*
|
||||
* @param string $orderSN
|
||||
* @throws RuleValidationException
|
||||
*
|
||||
* @author assimon<ashang@utf8.hk>
|
||||
* @copyright assimon<ashang@utf8.hk>
|
||||
* @link http://utf8.hk/
|
||||
*/
|
||||
public function checkOrder(string $orderSN)
|
||||
{
|
||||
// 订单
|
||||
$this->order = $this->orderService->detailOrderSN($orderSN);
|
||||
if (!$this->order) {
|
||||
throw new RuleValidationException(__('dujiaoka.prompt.order_does_not_exist'));
|
||||
}
|
||||
// 订单过期
|
||||
if ($this->order->status == Order::STATUS_EXPIRED) {
|
||||
throw new RuleValidationException(__('dujiaoka.prompt.order_is_expired'));
|
||||
}
|
||||
// 已经支付了
|
||||
if ($this->order->status > Order::STATUS_WAIT_PAY) {
|
||||
throw new RuleValidationException(__('dujiaoka.prompt.order_already_paid'));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 加载支付网关
|
||||
*
|
||||
* @param string $orderSN 订单号
|
||||
* @param string $payCheck 支付标识
|
||||
* @throws RuleValidationException
|
||||
*
|
||||
* @author assimon<ashang@utf8.hk>
|
||||
* @copyright assimon<ashang@utf8.hk>
|
||||
* @link http://utf8.hk/
|
||||
*/
|
||||
public function loadGateWay(string $orderSN, string $payCheck)
|
||||
{
|
||||
$this->checkOrder($orderSN);
|
||||
// 支付配置
|
||||
$this->payGateway = $this->payService->detailByCheck($payCheck);
|
||||
if (!$this->payGateway) {
|
||||
throw new RuleValidationException(__('dujiaoka.prompt.pay_gateway_does_not_exist'));
|
||||
}
|
||||
// 临时保存支付方式
|
||||
$this->order->pay_id = $this->payGateway->id;
|
||||
$this->order->save();
|
||||
}
|
||||
|
||||
/**
|
||||
* 网关处理.
|
||||
*
|
||||
* @param string $handle 跳转方法
|
||||
* @param string $payway 支付标识
|
||||
* @param string $orderSN 订单.
|
||||
*
|
||||
* @author assimon<ashang@utf8.hk>
|
||||
* @copyright assimon<ashang@utf8.hk>
|
||||
* @link http://utf8.hk/
|
||||
*/
|
||||
public function redirectGateway(string $handle,string $payway, string $orderSN)
|
||||
{
|
||||
try {
|
||||
$this->checkOrder($orderSN);
|
||||
$bccomp = bccomp($this->order->actual_price, 0.00, 2);
|
||||
// 如果订单金额为0 代表无需支付,直接成功
|
||||
if ($bccomp == 0) {
|
||||
$this->orderProcessService->completedOrder($this->order->order_sn, 0.00);
|
||||
return redirect(url('detail-order-sn', ['orderSN' => $this->order->order_sn]));
|
||||
}
|
||||
return redirect(url(urldecode($handle), ['payway' => $payway, 'orderSN' => $orderSN]));
|
||||
} catch (RuleValidationException $exception) {
|
||||
return $this->err($exception->getMessage());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,89 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http;
|
||||
|
||||
use App\Http\Middleware\DujiaoBoot;
|
||||
use App\Http\Middleware\InstallCheck;
|
||||
use App\Http\Middleware\PayGateWay;
|
||||
use Illuminate\Foundation\Http\Kernel as HttpKernel;
|
||||
|
||||
class Kernel extends HttpKernel
|
||||
{
|
||||
/**
|
||||
* The application's global HTTP middleware stack.
|
||||
*
|
||||
* These middleware are run during every request to your application.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $middleware = [
|
||||
\App\Http\Middleware\TrustProxies::class,
|
||||
\App\Http\Middleware\CheckForMaintenanceMode::class,
|
||||
\Illuminate\Foundation\Http\Middleware\ValidatePostSize::class,
|
||||
\App\Http\Middleware\TrimStrings::class,
|
||||
\Illuminate\Foundation\Http\Middleware\ConvertEmptyStringsToNull::class,
|
||||
\App\Http\Middleware\DujiaoSystem::class,
|
||||
];
|
||||
|
||||
/**
|
||||
* The application's route middleware groups.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $middlewareGroups = [
|
||||
'web' => [
|
||||
\App\Http\Middleware\EncryptCookies::class,
|
||||
\Illuminate\Cookie\Middleware\AddQueuedCookiesToResponse::class,
|
||||
\Illuminate\Session\Middleware\StartSession::class,
|
||||
// \Illuminate\Session\Middleware\AuthenticateSession::class,
|
||||
\Illuminate\View\Middleware\ShareErrorsFromSession::class,
|
||||
\App\Http\Middleware\VerifyCsrfToken::class,
|
||||
\Illuminate\Routing\Middleware\SubstituteBindings::class,
|
||||
],
|
||||
|
||||
'api' => [
|
||||
'throttle:60,1',
|
||||
\Illuminate\Routing\Middleware\SubstituteBindings::class,
|
||||
],
|
||||
];
|
||||
|
||||
/**
|
||||
* The application's route middleware.
|
||||
*
|
||||
* These middleware may be assigned to groups or used individually.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $routeMiddleware = [
|
||||
'auth' => \App\Http\Middleware\Authenticate::class,
|
||||
'auth.basic' => \Illuminate\Auth\Middleware\AuthenticateWithBasicAuth::class,
|
||||
'bindings' => \Illuminate\Routing\Middleware\SubstituteBindings::class,
|
||||
'cache.headers' => \Illuminate\Http\Middleware\SetCacheHeaders::class,
|
||||
'can' => \Illuminate\Auth\Middleware\Authorize::class,
|
||||
'guest' => \App\Http\Middleware\RedirectIfAuthenticated::class,
|
||||
'password.confirm' => \Illuminate\Auth\Middleware\RequirePassword::class,
|
||||
'signed' => \Illuminate\Routing\Middleware\ValidateSignature::class,
|
||||
'throttle' => \Illuminate\Routing\Middleware\ThrottleRequests::class,
|
||||
'verified' => \Illuminate\Auth\Middleware\EnsureEmailIsVerified::class,
|
||||
'dujiaoka.boot' => DujiaoBoot::class,
|
||||
'dujiaoka.pay_gate_way' => PayGateWay::class,
|
||||
'install.check' => InstallCheck::class,
|
||||
];
|
||||
|
||||
/**
|
||||
* The priority-sorted list of middleware.
|
||||
*
|
||||
* This forces non-global middleware to always be in the given order.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $middlewarePriority = [
|
||||
\Illuminate\Session\Middleware\StartSession::class,
|
||||
\Illuminate\View\Middleware\ShareErrorsFromSession::class,
|
||||
\App\Http\Middleware\Authenticate::class,
|
||||
\Illuminate\Routing\Middleware\ThrottleRequests::class,
|
||||
\Illuminate\Session\Middleware\AuthenticateSession::class,
|
||||
\Illuminate\Routing\Middleware\SubstituteBindings::class,
|
||||
\Illuminate\Auth\Middleware\Authorize::class,
|
||||
];
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Middleware;
|
||||
|
||||
use Illuminate\Auth\Middleware\Authenticate as Middleware;
|
||||
|
||||
class Authenticate extends Middleware
|
||||
{
|
||||
/**
|
||||
* Get the path the user should be redirected to when they are not authenticated.
|
||||
*
|
||||
* @param \Illuminate\Http\Request $request
|
||||
* @return string|null
|
||||
*/
|
||||
protected function redirectTo($request)
|
||||
{
|
||||
if (! $request->expectsJson()) {
|
||||
return route('login');
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Middleware;
|
||||
|
||||
use Illuminate\Foundation\Http\Middleware\CheckForMaintenanceMode as Middleware;
|
||||
|
||||
class CheckForMaintenanceMode extends Middleware
|
||||
{
|
||||
/**
|
||||
* The URIs that should be reachable while maintenance mode is enabled.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $except = [
|
||||
//
|
||||
];
|
||||
}
|
||||
@@ -0,0 +1,58 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Middleware;
|
||||
|
||||
use App\Models\BaseModel;
|
||||
use Closure;
|
||||
use Germey\Geetest\GeetestServiceProvider;
|
||||
|
||||
class DujiaoBoot
|
||||
{
|
||||
/**
|
||||
* Handle an incoming request.
|
||||
*
|
||||
* @param \Illuminate\Http\Request $request
|
||||
* @param \Closure $next
|
||||
* @return mixed
|
||||
*/
|
||||
public function handle($request, Closure $next)
|
||||
{
|
||||
// 安装检查
|
||||
$installLock = base_path() . DIRECTORY_SEPARATOR . 'install.lock';
|
||||
if (!file_exists($installLock)) {
|
||||
return redirect(url('install'));
|
||||
}
|
||||
// 浏览器检测
|
||||
$userAgent = $request->header('user-agent');
|
||||
$nowUri = site_url() . $request->path();
|
||||
$tplPath = 'common/notencent';
|
||||
if (
|
||||
(strpos($userAgent, 'QQ/')
|
||||
||
|
||||
strpos($userAgent, 'MicroMessenger') !== false)
|
||||
&&
|
||||
dujiaoka_config_get('is_open_anti_red', BaseModel::STATUS_OPEN) == BaseModel::STATUS_OPEN
|
||||
) {
|
||||
return response()->view($tplPath, ['nowUri' => $nowUri]);
|
||||
}
|
||||
// 语言检测
|
||||
$lang = dujiaoka_config_get('language', 'zh_CN');
|
||||
app()->setLocale($lang);
|
||||
// 极验
|
||||
$geetest = dujiaoka_config_get('is_open_geetest', BaseModel::STATUS_CLOSE);
|
||||
if ($geetest == BaseModel::STATUS_OPEN) {
|
||||
$geetestConfig = [
|
||||
'key' => dujiaoka_config_get('geetest_key'),
|
||||
'id' => dujiaoka_config_get('geetest_id'),
|
||||
'lang' => $lang
|
||||
];
|
||||
// 覆盖 配置
|
||||
config([
|
||||
'geetest' => array_merge(config('mail'), $geetestConfig)
|
||||
]);
|
||||
// 重新注册服务
|
||||
(new GeetestServiceProvider(app()))->register();
|
||||
}
|
||||
return $next($request);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Middleware;
|
||||
|
||||
use App\Providers\AppServiceProvider;
|
||||
use Closure;
|
||||
|
||||
class DujiaoSystem
|
||||
{
|
||||
/**
|
||||
* Handle an incoming request.
|
||||
*
|
||||
* @param \Illuminate\Http\Request $request
|
||||
* @param \Closure $next
|
||||
* @return mixed
|
||||
*/
|
||||
public function handle($request, Closure $next)
|
||||
{
|
||||
// 检测https
|
||||
if ($request->getScheme() == 'https') {
|
||||
$httpsConfig = [
|
||||
'https' => true
|
||||
];
|
||||
config([
|
||||
'admin' => array_merge(config('admin'), $httpsConfig)
|
||||
]);
|
||||
(new AppServiceProvider(app()))->register();
|
||||
}
|
||||
return $next($request);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Middleware;
|
||||
|
||||
use Illuminate\Cookie\Middleware\EncryptCookies as Middleware;
|
||||
|
||||
class EncryptCookies extends Middleware
|
||||
{
|
||||
/**
|
||||
* The names of the cookies that should not be encrypted.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $except = [
|
||||
//
|
||||
];
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Middleware;
|
||||
|
||||
use Closure;
|
||||
|
||||
class InstallCheck
|
||||
{
|
||||
/**
|
||||
* Handle an incoming request.
|
||||
*
|
||||
* @param \Illuminate\Http\Request $request
|
||||
* @param \Closure $next
|
||||
* @return mixed
|
||||
*/
|
||||
public function handle($request, Closure $next)
|
||||
{
|
||||
// 安装检查
|
||||
$installLock = base_path() . DIRECTORY_SEPARATOR . 'install.lock';
|
||||
if (file_exists($installLock)) {
|
||||
return redirect(url('/'));
|
||||
}
|
||||
return $next($request);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Middleware;
|
||||
|
||||
use Closure;
|
||||
|
||||
class PayGateWay
|
||||
{
|
||||
|
||||
/**
|
||||
* Handle an incoming request.
|
||||
*
|
||||
* @param \Illuminate\Http\Request $request
|
||||
* @param \Closure $next
|
||||
* @return mixed
|
||||
*/
|
||||
public function handle($request, Closure $next)
|
||||
{
|
||||
return $next($request);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Middleware;
|
||||
|
||||
use App\Providers\RouteServiceProvider;
|
||||
use Closure;
|
||||
use Illuminate\Support\Facades\Auth;
|
||||
|
||||
class RedirectIfAuthenticated
|
||||
{
|
||||
/**
|
||||
* Handle an incoming request.
|
||||
*
|
||||
* @param \Illuminate\Http\Request $request
|
||||
* @param \Closure $next
|
||||
* @param string|null $guard
|
||||
* @return mixed
|
||||
*/
|
||||
public function handle($request, Closure $next, $guard = null)
|
||||
{
|
||||
if (Auth::guard($guard)->check()) {
|
||||
return redirect(RouteServiceProvider::HOME);
|
||||
}
|
||||
|
||||
return $next($request);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Middleware;
|
||||
|
||||
use Illuminate\Foundation\Http\Middleware\TrimStrings as Middleware;
|
||||
|
||||
class TrimStrings extends Middleware
|
||||
{
|
||||
/**
|
||||
* The names of the attributes that should not be trimmed.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $except = [
|
||||
'password',
|
||||
'password_confirmation',
|
||||
];
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Middleware;
|
||||
|
||||
use Fideloper\Proxy\TrustProxies as Middleware;
|
||||
use Illuminate\Http\Request;
|
||||
|
||||
class TrustProxies extends Middleware
|
||||
{
|
||||
/**
|
||||
* The trusted proxies for this application.
|
||||
*
|
||||
* @var array|string
|
||||
*/
|
||||
protected $proxies;
|
||||
|
||||
/**
|
||||
* The headers that should be used to detect proxies.
|
||||
*
|
||||
* @var int
|
||||
*/
|
||||
protected $headers = Request::HEADER_X_FORWARDED_ALL;
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Middleware;
|
||||
|
||||
use Illuminate\Foundation\Http\Middleware\VerifyCsrfToken as Middleware;
|
||||
|
||||
class VerifyCsrfToken extends Middleware
|
||||
{
|
||||
/**
|
||||
* Indicates whether the XSRF-TOKEN cookie should be set on the response.
|
||||
*
|
||||
* @var bool
|
||||
*/
|
||||
protected $addHttpCookie = true;
|
||||
|
||||
/**
|
||||
* The URIs that should be excluded from CSRF verification.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $except = [
|
||||
'pay/*',
|
||||
];
|
||||
}
|
||||
Reference in New Issue
Block a user