408 lines
14 KiB
PHP
408 lines
14 KiB
PHP
<?php
|
||
|
||
namespace app\command;
|
||
|
||
use app\admin\controller\AdminController;
|
||
use app\model\Admins;
|
||
use app\model\Blacks;
|
||
use app\model\Finances;
|
||
use app\model\Logs;
|
||
use app\model\Orders;
|
||
use app\server\Douyin;
|
||
use app\server\Meituan;
|
||
use app\server\Kuaishou;
|
||
use app\server\Orders as ServerOrders;
|
||
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 08:20'));
|
||
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 = 6;
|
||
$page = 1;
|
||
while (true) {
|
||
if ($page > $pages) break;
|
||
$list = [];
|
||
|
||
switch ($k) {
|
||
case 6:
|
||
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('os', $order->os)->where('sn', $order->sn)->find();
|
||
|
||
if (empty($item)) {
|
||
$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);
|
||
}
|
||
|
||
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);
|
||
}
|
||
//新获得一个用户的,提示管理员有新的订单
|
||
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 (count($list) < 50) {
|
||
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) {
|
||
echo "发送短信\n";
|
||
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 {
|
||
echo "黑名单不发送短信\n";
|
||
sleep(10);
|
||
}
|
||
|
||
} else {
|
||
echo "不发送短信\n";
|
||
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
|
||
// ]);
|
||
// }
|
||
}
|
||
}
|