前言
因为要写个机器人,又不想让机器人直接操作数据库,所以给发卡加了api接口。
修改过程
新增文件
routes/common/api.php
<?php
/**
* The file was created by Virgo.
*
* @author virgo
* @copyright virgo
* @link http://vxv.tw/
*/
use Illuminate\Support\Facades\Route;
Route::group(['middleware' => ['vxv.api'], 'namespace' => 'Api'], function () {
// 首页
Route::get('api/goodsGroups', 'ApiController@goodsGroups');
Route::get('api/goodsGroups/{goodsGroupsId}/goods', 'ApiController@goods');
Route::get('api/goods/{goodsId}', 'ApiController@goods_info');
Route::post('api/createOrder', 'ApiController@create_order');
Route::get('api/epusdt/{payway}/{orderSN}', 'Pay\EpusdtController@gateway');
Route::post('api/epusdt/notify_url', 'EpusdtController@notifyUrl');
Route::get('api/epusdt/return_url', 'EpusdtController@returnUrl')->name('epusdt-return');
});
app/Http/Controllers/Api/ApiController.php
<?php
namespace App\Http\Controllers\Api;
use App\Exceptions\RuleValidationException;
use App\Http\Controllers\Controller;
use App\Models\Carmis;
use App\Models\Goods;
use App\Models\GoodsGroup;
use App\Models\TelegramOrder;
use App\Service\OrderProcessService;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\DB;
class ApiController extends Controller
{
/**
* 商品服务层.
* @var \App\Service\GoodsService
*/
private $goodsService;
/**
* 支付服务层
* @var \App\Service\PayService
*/
private $payService;
/**
* 订单服务层
* @var \App\Service\OrderService
*/
private $orderService;
/**
* 订单处理层.
* @var OrderProcessService
*/
private $orderProcessService;
public function __construct()
{
$this->goodsService = app('Service\GoodsService');
$this->payService = app('Service\PayService');
$this->orderService = app('Service\OrderService');
$this->orderProcessService = app('Service\OrderProcessService');
}
public function goodsGroups(Request $request)
{
$goodsGroups = GoodsGroup::query()->get();
$goodsGroups = $goodsGroups ? $goodsGroups->toArray() : [];
return ["code" => 200, "msg" => 'ok', 'data' => $goodsGroups];
}
public function goods(Request $request, int $goodsGroupsId)
{
$goodsGroups = GoodsGroup::query()->get();
$goods = Goods::query()->where('group_id', $goodsGroupsId)
->withCount(['carmis' => function ($query) {
$query->where('status', Carmis::STATUS_UNSOLD);
}])
->where('is_open', Goods::STATUS_OPEN)
->orderBy('ord', 'DESC')->get();
$goodsGroups = $goodsGroups ? $goodsGroups->toArray() : [];
return ["code" => 200, "msg" => 'ok', 'data' => $goods];
}
public function goods_info(Request $request, int $goodsId)
{
$goods = $this->goodsService->detail($goodsId);
return ["code" => 200, "msg" => 'ok', 'data' => $goods];
}
public function create_order(Request $request)
{
$telegram_user_id = $request->input('telegram_user_id');
DB::beginTransaction();
try {
$goods = $this->orderService->validatorGoods($request);
$this->orderService->validatorLoopCarmis($request);
// 设置商品
$this->orderProcessService->setGoods($goods);
$otherIpt = $this->orderService->validatorChargeInput($goods, $request);
// 数量
$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();
$tgOrder = new TelegramOrder();
$tgOrder->telegram_user_id = $telegram_user_id;
$tgOrder->order_id = $order['id'];
$tgOrder->save();
DB::commit();
return response()->json(['code' => 200, 'msg' => 'ok', 'data' => ['orderSN' => $order->order_sn]]);
} catch (RuleValidationException $exception) {
DB::rollBack();
return $this->err($exception->getMessage());
}
}
protected function render(string $tpl, $data = [], string $pageTitle = '')
{
$layout = dujiaoka_config_get('template', 'unicorn');
$tplPath = $layout . '/' . $tpl;
return response()->json(['code' => 400, 'msg' => 'error']);
}
protected function err(string $content, $jumpUri = '')
{
return ['code' => 400, 'msg' => 'error'];
}
}
app/Http/Controllers/Api/Pay/EpusdtController.php
<?php
namespace App\Http\Controllers\Api\Pay;
use App\Exceptions\RuleValidationException;
use App\Http\Controllers\Api\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 api_response_error(400, $body['message']);
}
return api_response_success("ok", $body);
} catch (RuleValidationException $exception) {
} catch (GuzzleException $exception) {
return api_response_error(400, $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]));
}
}
app/Http/Controllers/Api/PayController.php
<?php
namespace App\Http\Controllers\Api;
use App\Exceptions\RuleValidationException;
use App\Models\Order;
use App\Service\OrderProcessService;
use App\Http\Controllers\Controller;
class PayController extends Controller
{
/**
* 支付网关
* @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());
}
}
}
app/Models/TelegramOrder.php
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\SoftDeletes;
class TelegramOrder extends BaseModel
{
use SoftDeletes;
protected $table = 'telegram_order';
/**
* 关联商品
*
* @return \Illuminate\Database\Eloquent\Relations\BelongsTo
*
* @author assimon<ashang@utf8.hk>
* @copyright assimon<ashang@utf8.hk>
* @link http://utf8.hk/
*/
public function order()
{
return $this->belongsTo(Order::class, 'order_id');
}
}
app/Jobs/TgFakaBot.php
<?php
namespace App\Jobs;
use App\Models\Order;
use App\Models\TelegramOrder;
use GuzzleHttp\Client;
use Illuminate\Bus\Queueable;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Foundation\Bus\Dispatchable;
use Illuminate\Queue\InteractsWithQueue;
use Illuminate\Queue\SerializesModels;
use Illuminate\Support\Facades\Log;
class TgFakaBot implements ShouldQueue
{
use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;
/**
* 任务最大尝试次数。
*
* @var int
*/
public $tries = 1;
/**
* 任务运行的超时时间。
*
* @var int
*/
public $timeout = 30;
/**
* @var Order
*/
private $order;
/**
* 商品服务层.
* @var \App\Service\GoodsService
*/
private $goodsService;
/**
* Create a new job instance.
*
* @return void
*/
public function __construct(Order $order)
{
$this->order = $order;
$this->goodsService = app('Service\GoodsService');
}
/**
* Execute the job.
*
* @return void
*/
public function handle()
{
$tgOrder = TelegramOrder::query()->where('order_id', $this->order['id'])->first();
$goodInfo = $this->goodsService->detail($this->order->goods_id);
$formatText = '*' . '支付成功通知' . '(' . $this->order->actual_price . '元)*%0A'
. __('order.fields.order_id') . ': `' . $this->order->id . '`%0A'
. __('order.fields.order_sn') . ': `' . $this->order->order_sn . '`%0A'
. __('order.fields.pay_id') . ': `' . $this->order->pay->pay_name . '`%0A'
. __('order.fields.title') . ': ' . $this->order->title . '%0A'
. __('order.fields.actual_price') . ': ' . $this->order->actual_price . '%0A'
. __('goods.fields.gd_name') . ': `' . $goodInfo->gd_name . '`%0A'
. __('order.fields.order_created') . ': ' . $this->order->created_at. '%0A'
. "卡密信息". '%0A'
. "```". '%0A'
. $this->order['info']. '%0A'
. "```";
$client = new Client([
'timeout' => 30,
'proxy' => '127.0.0.1:7890'
]);
Log::info(dujiaoka_config_get('telegram_bot_token'));
$apiUrl = 'https://api.telegram.org/bot' . dujiaoka_config_get('telegram_bot_token') .
'/sendMessage?chat_id=' . $tgOrder->telegram_user_id . '&parse_mode=Markdown&text=' . $formatText;
Log::info($apiUrl);
$client->post($apiUrl);
}
}
修改原有代码文件
app/Helpers/functions.php
在代码末尾插入以下代码
if (!function_exists('api_response_build')) {
function api_response_build(int $code, string $msg, $data = null)
{
return response()->json(['code' => $code, 'msg' => $msg, 'data' => $data]);
}
}
if (!function_exists('api_response_success')) {
function api_response_success(string $msg = 'ok', $data = null)
{
return ['code' => 200, 'msg' => $msg, 'data' => $data];
}
}
if (!function_exists('api_response_error')) {
function api_response_error(int $code = 400, string $msg = 'error', $data = null)
{
return response()->json(['code' => $code, 'msg' => $msg, 'data' => $data]);
}
}
app/Exceptions/Handler.php
在红框位置处插入如下代码
if (str_starts_with($request->path(), "api/")) {
return response()->json(['code' => 400, 'msg' => $exception->getMessage()]);
}
app/Service/OrderProcessService.php
在头部加上引用代码
use App\Jobs\TgFakaBot;
然后找到这个函数
在 ApiHook::dispatch($order);
前面添加如下代码
// 发卡机器人推送订单信息
TgFakaBot::dispatch($order);
app/Http/Middleware/VerifyCsrfToken.php
直接在这加一个 'api/*'
接口
[获取全部分类] – GET /api/goodsGroups
[获取分类下商品] – GET /api/goodsGroups/2/goods
2为分组的id
[获取商品详情] – GET /api/goods/2
2为商品的id
[创建订单] – POST /api/createOrder
请求头
key | value |
Content-Type | application/x-www-form-urlencoded |
字段名 | 示例值 | 描述 |
gid | 2 | 商品id |
aaa@gmail.com | 下单邮箱 | |
by_amount | 1 | 固定为1 |
payway | 27 | 支付方式 |
telegram_user_id | 1405597912 | telegram用户id |
[获取支付信息] – GET /api/epusdt/epusdt/K7WQDNWGI2N3DXJ3
K7WQDNWGI2N3DXJ3 替换为上一步创建订单得到的订单号
© 版权声明
文章版权归作者所有,未经允许请勿转载。
THE END
暂无评论内容