travel/service/app/command/SpiderTc.php

413 lines
14 KiB
PHP
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<?php
namespace app\command;
use app\admin\controller\AdminController;
use app\model\Admins;
use app\model\Blacks;
use app\model\Finances;
use app\model\Orders;
use app\server\SMS;
use app\server\Tongcheng;
use stdClass;
use support\Log;
use support\Redis;
use Symfony\Component\Console\Command\Command;
use Symfony\Component\Console\Input\InputDefinition;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Input\InputOption;
use Symfony\Component\Console\Output\OutputInterface;
/**
* 同程数据拉取
*/
class SpiderTc extends Command
{
protected static $defaultName = 'spider:tc';
protected static $defaultDescription = '同程订单拉取器';
protected $_users = [];
protected function configure()
{
$this->setName('spider:tc')
->setDescription('同程订单拉取器')
->setDefinition(
new InputDefinition(array(
new InputOption('sn', 'sn', InputOption::VALUE_REQUIRED),
new InputOption('os', 'os', InputOption::VALUE_REQUIRED),
new InputOption('day', 'day', InputOption::VALUE_REQUIRED)
))
);
}
protected function users($routeType)
{
// if (count($this->_users) > 0) return $this->_users;
$users = Admins::where('status', 1)->where('is_order', 1)->where('route_type', $routeType)->select();
$us = [];
foreach ($users as $u) {
$ru = Redis::get('CRM:USER:ONLINE:' . $u->id);
if (empty($ru)) continue;
$_u = new stdClass();
$_u->username = $u->id;
$us[] = $_u;
};
$this->_users = $us;
return $this->_users;
}
protected $_redis_pool = [];
protected function poolUser($status = 0, $categoryDesc = '')
{
$routeType = AdminController::ROUTE_LISTS[mb_substr($categoryDesc, 0, 2)] ?? 10;
$status .= $routeType;
if (empty($this->_redis_pool[$status])) {
$this->_redis_pool[$status] = Redis::hGetAll('CRM:Pool:' . $status);
$users = $this->users($routeType);
$_users = [];
if (empty($this->_redis_pool[$status])) {
foreach ($users as $user) {
$_users[$user->username] = 0;
Redis::hSet('CRM:Pool:' . $status, $user->username, 0);
}
$this->_redis_pool[$status] = $_users;
} else {
asort($this->_redis_pool[$status]);
$key_users = array_keys($this->_redis_pool[$status]);
$username = $key_users[0];
$max = $this->_redis_pool[$status][$username];
$_users = [];
foreach ($users as $user) {
$_users[] = $user->username;
if (!in_array($user->username, $key_users)) {
$this->_redis_pool[$status][$username] = $max;
Redis::hSet('CRM:Pool:' . $status, $user->username, $max);
}
}
foreach ($this->_redis_pool[$status] as $username => $val) {
if (!in_array($username, $_users)) {
unset($this->_redis_pool[$status][$username]);
Redis::hDel('CRM:Pool:' . $status, $username);
}
}
}
}
$username = null;
try {
$pool = $this->_redis_pool[$status];
if (empty($pool)) $pool = [];
asort($pool);
$keys = array_keys($pool);
// if(!!config('app.debug', true)) return 1;
if (empty($keys)) {
Log::error(dirname(__FILE__) . __LINE__ . '没有可以分配的用户');
throw new \Exception('没有可以分配的用户');
}
$username = $keys[0];
$this->_redis_pool[$status][$username] += 1;
Redis::hIncrBy('CRM:Pool:' . $status, $username, 1);
} catch (\Exception $e) {
Log::error(dirname(__FILE__) . __LINE__ . '没有可以分配的用户', (array)json_encode($e));
throw new \Exception('没有可以分配的用户');
}
return $username;
}
/** @var InputInterface $output */
protected $output;
/**
* @param InputInterface $input
* @param OutputInterface $output
* @return int
*/
protected function execute(InputInterface $input, OutputInterface $output): int
{
// $name = $input->getArgument('name');
$this->output = $output;
$output->writeln('START spider:tc:'.date('Y-m-d H:i:s'));
$os = $input->getOption('os');
$orderid = $input->getOption('sn');
$d = $input->getOption('day');
if (empty($d)) {
$d = 40;
}
if ($orderid) {
$this->reloadStatus($orderid, $os, $output);
return 1;
}
// echo "状态1\n";
// $this->poolUser(1);
// echo "状态2\n";
// $this->poolUser(2);
// echo "状态3\n";
// $this->poolUser(3);
// echo "状态4\n";
// $this->poolUser(4);
// echo "状态5\n";
// $this->poolUser(5);
// return 1;
// $this->checks($output);
// $output->writeln('CHECK spider:dy');
// $day = new Douyin();
// print_r($day->get(1));
// return 1;
// sleep(5);
// $time = strtotime(date('Y-m-d'));
// for ($i = 0; $i <= $d; $i++) {
// $day = $time - $i * 24 * 3600;
// $start = date('Y-m-d', $day);
// $end = date('Y-m-d 23:59:59', $day);
// $this->orders($start, $end, false);
// // $this->_kuaishouOrder($start, $end, false);
// }
// 8点20 开始分配订单
date_default_timezone_set('Asia/Shanghai');
$startTime = strtotime(date('Y-m-d 09:10'));
if (time() > $startTime) {
$start = date('Y-m-d 00:00:00', strtotime("-{$d} days"));
$output->writeln('END spider:tc:start:'.$start);
$end = date('Y-m-d 23:59:59');
$this->orders($start, $end, false);
}
if (date('H') >= 1 && date('H') <= 7) {
$this->reload($output);
}
$output->writeln('END spider:tc:'.date('Y-m-d H:i:s'));
return self::SUCCESS;
}
private function orders($start = null, $end = null, $order_id = false)
{
foreach (Orders::OSS as $k => $os) {
$pages = 10;
$page = 1;
while (true) {
if ($page > $pages) break;
$list = [];
switch ($k) {
case 6:
case 8:
try {
$dou = new Tongcheng($k);
$list = $dou->get($page, $start, $end, '');
$pages = $dou->totalPage;
} catch (\Exception $e) {
Log::info('同程订单拉取失败:' . dirname(__FILE__) . __LINE__ . $e);
}
break;
default:
# code...
break;
}
foreach ($list as $order) {
$item = Orders::where('sn', $order->sn)->find();
if (empty($item)) {
if ($order->orderStatus == 400) {
continue;
}
$order->is_zhibo = 2;
$oldMobile = orders::where("os", $order->os)->where("mobile", $order->mobile)
->where("create_time", '>=', time() - 24 * 3600 * 3)->find();
if (!empty($oldMobile)) {
$admin_id = $oldMobile->admin_id;
} else {
// $admin_id = $this->poolUser($order->orderStatus, $order->category_desc);
try {
$admin_id = \app\server\Orders::poolUser($order->orderStatus, $order->product_id);
} catch (\Exception $exception) {
Log::info(sprintf('tc create order fail:%s, order_id:%s', $exception->getMessage(), $order->sn));
continue;
}
}
if (empty($admin_id)) return null;
$order->admin_id = $admin_id;
$order->give_time = time();
//判断是否需要发短信 200-待使用205-预约中抖音210-已预约抖音310-已履约抖音300-已完成
if (in_array($order->order_status, [200, 205, 210, 310, 300]) ) {
$this->sms($admin_id, $order);
}
$work = \app\server\Orders::getLiveRoomWork($order->create_at, $order->product_id);
if ($work) {
$order->live_room_work_id = $work->id;
}
//新获得一个用户的,提示管理员有新的订单
Redis::incrBy('CRM:USER:ONLINE:NEW:' . $admin_id, 1);
$item = new Orders();
}
if ($order->travel_date && empty($order->travel_end)) {
$days = $this->_days($order);
if ($days) {
$order->travel_end = date('Y-m-d 00:00:00', strtotime($order->travel_date) + $days * 24 * 3600);
}
}
if ($item->order_status !== 2 && $order->order_status == 2) {
Redis::incrBy('CRM:USER:WRITE:OFF:' . $item->admin_id, 1);
}
$back = $item->save($order->toArray());
if ($back) {
$this->_finance(0, $item->id, $item->asset_price);
}
}
// 数据小于50, 结束
if (empty($list)) {
break;
}
$page++;
}
}
}
private function reload($output)
{
$back = Redis::set('SpiderMt:reload:dy:lock', time(), 'EX', 3600 * 8, 'NX');
if (!$back) return;
$orders = Orders::where('create_at', '<=', (time() - 15 * 24 * 3600) * 1000)->where('os', 6)->wherein('status', [1, 2, 3])->select();
foreach ($orders as $order) {
$this->reloadStatus($order->sn, $order->os, $output);
}
}
/**
* @param $admin_id
* @param $order
* @throws \think\db\exception\DataNotFoundException
* @throws \think\db\exception\DbException
* @throws \think\db\exception\ModelNotFoundException
*/
private function sms($admin_id, $order) {
$user = Admins::cache(true)->where('id', $admin_id)->find();
$templateId = 261607;
if ((!config('app.debug', true) || config('app.debug', true) === 'false') && (time() * 1000 - $order->create_at) / 1000 < 2 * 24 * 3600) {
print_r([$order->mobile, $templateId, ['title' => $order->product_name, 'mobile' => $user->mobile]]);
$has = Blacks::where('mobile', $order->mobile)->find();
if (empty($has) && !empty($order->mobile)) {
SMS::juhe_sms_send($order->mobile, $templateId, ['title' => $order->product_name, 'mobile' => $user->mobile]);
} else {
sleep(10);
}
} else {
print_r([$order->mobile, $templateId, ['title' => $order->product_name, 'mobile' => $user->mobile]]);
}
}
private function reloadStatus($orderid, $os, $output)
{
$w[] = ['sn', '=', $orderid];
if ($os) $w[] = ['os', '=', $os];
$item = Orders::where($w)->find();
if (empty($item)) {
$output->writeln('没有找到订单');
}
$m = new Tongcheng($os);
$it = $m->get(1, null, null, $item->sn);
if ($it) {
$back = $item->save($it[0]);
if ($back) {
$this->_finance(0, $item->id, $item->asset_price);
}
} else {
$output->writeln('没有拉取到数据:' . $orderid);
}
}
private function _days($order)
{
if (stripos($order->product_name, '一日') !== false) {
return 1;
}
preg_match('/(\d)天/', $order->product_name, $all);
if (!empty($all) && intval($all[1]) > 0) {
return $all[1];
}
return 0;
}
private function zhibo($title, $os = 0)
{
if ($os == 3) {
return 2;
}
if (
strlen($title) - 3 == strripos($title, "")
|| strlen($title) - 1 == strripos($title, "!")
) {
return 1;
} elseif (strlen($title) - 3 == strripos($title, "")) {
return 2;
}
return 0;
}
private function _finance($type = 1, $order_id = 0, $price = 0)
{
// $fa = Finances::where('order_id', $order_id)->where('type', $type)->find();
$back = Redis::set('CRM:ORDER:LOCK:' . $order_id, time(), 'EX', 6, 'NX');
if (!$back) return;
$total = Finances::where('order_id', $order_id)->sum('total'); //总的关于这个订单的金额
//如果总金额大于提交上来的核销金额,那就是退费的
//如果提交上来的金额小于总金额,那就是核销的
if ($total > $price) {
$type = 2;
$fee = -($total - $price);
} elseif ($total < $price) {
$type = 1;
$fee = $price - $total;
} else {
return;
}
Finances::create([
'order_id' => $order_id,
'type' => $type,
'total' => $fee,
'status' => 1
]);
return;
// if(empty($fa)) {
// if($type == 2) {
// $has = Finances::where('order_id', $order_id)->where('type', 1)->find();
// if(empty($has)) return;
// }
// Finances::create([
// 'order_id' => $order_id,
// 'type' => $type,
// 'total' => $price,
// 'status' => 1
// ]);
// }
}
}