travel/service/app/server/Tongcheng.php

279 lines
9.4 KiB
PHP
Raw Normal View History

2024-09-02 17:41:24 +08:00
<?php
namespace app\server;
use app\model\Orders;
use Exception;
use support\Log;
use support\Redis;
use think\db\exception\DataNotFoundException;
use think\db\exception\DbException;
use think\db\exception\ModelNotFoundException;
/**
* 同程订单处理
*/
class Tongcheng {
private $os = '';
protected $cookie;
private $gate = 'https://ebk.17u.cn';
public $totalPage = 6;
public function __construct($os = 6)
{
$this->cookie = $this->_cookie();
$this->os = $os;
}
/**
* @throws ModelNotFoundException
* @throws DataNotFoundException
* @throws DbException
* @throws Exception
*/
public function get($page, $start = null, $end = null, $orderId = '')
{
if (empty($start) || empty($end)) {
$start = date('Y-m-d 00:00:00');
$end = date('Y-m-d 23:59:59');
}
if ($orderId) {
$start = $end = null;
}
$_list = [];
$list = $this->_certificateList($start, $end, $page, $orderId);
if (empty($list->data->list) || $list->code != 1000) {
$this->totalPage = 1;
return $_list;
}
Log::info($start . '--' . $end . " 同程 page:{$page} total_count:" . $list->data->totalCount . " page_count:" . $list->data->totalPage);
foreach ($list->data->list as $order) {
Log::info("同程 订单号:{$order->orderId} \n\n");
// $orderDetail = $this->_orderDetail($order->order_id, $order->status);
// if (empty($orderDetail)) {
// Log::info("同程 订单详情拉取失败:{$order->order_id}");
// throw new Exception("同程拉单{$order->order_id}详情获取失败");
// }
2024-09-02 18:58:14 +08:00
$order->orderAmount = $order->orderAmount * 100;
2024-09-02 17:41:24 +08:00
$item = new Orders();
$item->os = $this->os;
$item->sn = $order->orderId;
$item->product_id = $order->lineId;
$item->product_name = $order->title;
$item->category_id = $order->agentFinderId;
$item->category_desc = $order->agentFinderNickname;
$item->create_at = strtotime($order->createTime) * 1000;
$item->mobile = $order->mobile;
$item->travel_date = null;
$item->total_price = $order->orderAmount;
$item->quantity = $order->productCount;
2024-09-02 18:43:16 +08:00
$item->unit_price = $order->orderAmount/$order->productCount;
2024-09-02 17:41:24 +08:00
$item->actual_price = $order->orderAmount;
$item->order_status = $order->orderStatus; // 订单状态(100 - 待付款150-用户取消200-待使用205-预约中抖音210-已预约抖音310-已履约抖音300-已完成400-已关闭)
$item->appointment_status = in_array($order->orderStatus, [210, 310, 300]) ? 1 : 0; // 是否已预约
$item->asset_status = $order->status ?? 0; // 核销状态
$item->asset_price = $order->orderStatus == 300 ? $order->orderAmount : 0; // 核销金额
//抖音的核销金额需要查核销订单
$_list[] = $item;
}
return $_list; //返回半成品
}
/**
* @throws Exception
*/
public function _certificateList($start, $end, $page, $orderId)
{
$params = [
'begin' => $start,// 开始时间,格式2024-09-01 00:00:00
'end' => $end,// 结束时间 格式2024-09-01 00:00:00
'orderStatus' => "",// 订单状态
'current' => $page, // 当前数量
'size' => 50, // 显示数量
'orderId' => $orderId, // 订单号
];
$this->_getRetriesLock();
$list = $this->_curl("/merchant/api/market-live/wxVideoV2/supplierOrderByPage", $params, 'POST');
if (empty($list) || $list->code != 1000) {
$this->_getRetriesLock();
$list = $this->_curl("/merchant/api/market-live/wxVideoV2/supplierOrderByPage", $params, 'POST');
2024-09-10 09:41:07 +08:00
if (empty($list) || $list->code != 1000) {
2024-09-02 17:41:24 +08:00
Log::error('===查询时间:' . $start . '--' . $end . '====certificate_list: ' . json_encode($list));
throw new Exception("同程拉单失败,Err:" . json_encode($list));
}
}
return $list;
}
public function _getRetriesLock(): bool
{
$pattern = 'php webman spider:tc';
$maxProcesses = 8;
$this->_killMiddleProcesses($pattern, $maxProcesses);
$maxRetries = 5;
$retries = 0;
while ($retries < $maxRetries) {
$back = Redis::set('SpiderTc:CertificateList:lock', time(), 'EX', 1, 'NX');
if ($back) {
break;
}
$retries++;
sleep(1);
}
return true;
}
public function _killMiddleProcesses($pattern, $maxProcesses)
{
// 检查操作系统是否为 Linux
if (PHP_OS !== 'Linux') {
return false;
}
// 获取当前进程的 PID
$currentPid = getmypid();
// 获取进程列表
$command = "ps aux | grep '$pattern' | grep -v grep | grep -v '$currentPid' | awk '{print $2,$10}'";
$output = [];
exec($command, $output);
$processList = [];
foreach ($output as $line) {
list($pid, $runtime) = explode(' ', $line);
$runtimeParts = explode(':', $runtime);
$hours = intval($runtimeParts[0]);
$minutes = intval($runtimeParts[1]);
$totalMinutes = $hours * 60 + $minutes;
$processList[] = ['pid' => $pid, 'runtime' => $totalMinutes];
}
// 按运行时间排序
usort($processList, function ($a, $b) {
return $a['runtime'] <=> $b['runtime'];
});
// 过滤掉当前 PID 和运行时间最短的 PID
if (!empty($processList)) {
array_shift($processList); // 移除运行时间最短的
}
$processList = array_filter($processList, function ($process) use ($currentPid) {
return $process['pid'] != $currentPid;
});
$processCount = count($processList);
// 如果进程数量超过最大值,则终止中间部分的进程
if ($processCount > $maxProcesses) {
$processesToKill = $processCount - $maxProcesses;
$processesKilled = 0;
// 杀死运行时间最短的进程
foreach ($processList as $process) {
if ($processesKilled >= $processesToKill) {
break;
}
exec("kill -9 {$process['pid']}");
$processesKilled++;
2024-09-05 10:55:45 +08:00
Log::info("Killed process with PID: {$process['pid']}\n");
2024-09-02 17:41:24 +08:00
}
if ($processesKilled === 0) {
2024-09-05 10:55:45 +08:00
Log::info("No processes to kill.\n");
2024-09-02 17:41:24 +08:00
}
} else {
2024-09-05 10:55:45 +08:00
Log::info("Process count is not over the limit.\n");
2024-09-02 17:41:24 +08:00
}
return true;
}
public function _orderDetail($orderId = null, $status = null)
{
$orderDetail = $this->_curl("/life/trip/v2/travel_agency/book/detail", [
'order_id' => $orderId,
'book_order_id' => '',
'status' => $status,
]);
return $orderDetail->data ?? null;
}
public function _cookie($data = '')
{
$key = 'Tongcheng:cookie-' . $this->os;
if ($data) Redis::set($key, $data);
return Redis::get($key);
}
public function _curl($url, $params, $method = 'GET')
{
// 请求次数统计
$key = sprintf("Tongcheng:ReqiestCount:%s", date('Y-m-d'));
$requestCount = Redis::incrBy($key, 1);
if ($requestCount == 1) {
Redis::expire($key, 604800); // 7天
}
$cookiePath = sprintf(runtime_path() . '%s_tc_cookie.txt', $this->os);
$http = $this->gate . $url;
if ($method == 'GET') {
$http = $http . '?' . http_build_query($params);
}
$ch = curl_init($http);
$header = [
'Content-type: application/json'
];
if ($method == 'GET' || $method == 'POST') {
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
} else {
curl_setopt($ch, CURLOPT_HEADER, 1);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_COOKIEJAR, $cookiePath);
}
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, $method);
curl_setopt($ch, CURLOPT_COOKIE, $this->_cookie());
curl_setopt($ch, CURLOPT_HTTPHEADER, $header);
curl_setopt($ch, CURLOPT_COOKIEFILE, $cookiePath);
if ($method == 'POST') {
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($params));
}
$body = curl_exec($ch);
curl_close($ch);
if (!in_array($method, ['GET', 'POST'])) {
$header_size = curl_getinfo($ch, CURLINFO_HEADER_SIZE);
$header = substr($body, 0, $header_size);
$in = explode("\n", $body);
foreach ($in as $i) {
if (stripos($i, 'x-ware-csrf-token') !== false) {
$inn = explode(',', $i);
return $inn[1];
}
}
return null;
}
2024-09-10 09:41:07 +08:00
$res = json_decode($body);
if (!isset($res['code']) || $res['code'] != 1000) {
Log::info( "同城 body{$body} \n\n");
(new ThirdApiService())->weComNotice($this->os);
}
return $res;
2024-09-02 17:41:24 +08:00
}
}