travel/service/app/command/SpiderMt.php

582 lines
22 KiB
PHP
Raw Permalink 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\FilterMobiles;
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 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 SpiderMt extends Command
{
protected static $defaultName = 'spider:mt';
protected static $defaultDescription = '美团订单拉取器';
protected $_users = [];
protected $order_num = 99999999;
protected $page = 20;
protected function configure()
{
$this->setName('spider:mt')
->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),
// 最大页数
new InputOption('max_page', 'max_page', InputOption::VALUE_OPTIONAL)
))
);
}
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;
/*if (!config('app.debug', true)) {
if (empty($ru)) continue;
}*/
//过滤不分配订单的客服用户
/*$isEndWork = Redis::get("CRM:USER:ENDWORK:" . $u->id);
if (empty($isEndWork)) {
$_u = new stdClass();
$_u->username = $u->id;
$us[] = $_u;
}*/
/*if ($u->order_num > 0){
if ($u->order_num !== $this->order_num){
$data = Admins::where('id',$u->id)->find();
$num = $data['order_num'] - 1;
if ($num >= 0){
Admins::where('id',$u->id)->update(['order_num'=>$num]);
}
}
$_u = new stdClass();
$_u->username = $u->id;
$us[] = $_u;
}*/
$_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('没有可以分配的用户' . $status . '--' . $categoryDesc);
}
return $username;
}
/**
* @param InputInterface $input
* @param OutputInterface $output
* @return int
*/
protected function execute(InputInterface $input, OutputInterface $output): int
{
// $name = $input->getArgument('name');
$output->writeln('START spider:mt');
$os = $input->getOption('os');
$orderid = $input->getOption('sn');
$d = $input->getOption('day');
if (empty($d)) {
$d = 90;
}
if ($input->getOption('max_page')) {
$this->page = $input->getOption('max_page');
}
if ($orderid) {
$this->reloadStatus($orderid, $os, $output);
}
// $this->checks($output);
// $output->writeln('CHECK spider:mt');
// $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);
// }
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"));
$end = date('Y-m-d 23:59:59');
$this->orders($start, $end, $orderid);
}
if (date('H') >= 1 && date('H') <= 7) {
$this->reload($output);
}
$output->writeln('END spider:mt');
return self::SUCCESS;
}
private function checks($output)
{
$i = 0;
while (true) {
$i++;
sleep(1);
$val = Redis::Rpop('Travel:Order:check:lits');
if (empty($val) || $i > 100) return;
//{\"id\":35,\"check_sn\":\"1\\u963f\\u8fbe\\u6211\\u7684as\\u7684\"}
$json = json_decode($val);
$res = (new Meituan())->voucher($json->check_sn);
//{"code":0,"message":"成功","data":{"orderId":"4944968014698378527","mobile":"18641285757","categoryId":100602,"travelDate":"2024-03-29","isConsumed":true,"categoryDesc":"出发地参团","travelBeginDate":"2024-03-29","travelEndDate":"2024-03-29"},"texInfo":null,"success":true,"fail":false}
if ($res->code === 0) { //核销成功
$order_id = $res->data->orderId;
$item = Orders::where('os', 1)->where('sn', $order_id)->find();
if (!$item) {
$this->orders($output, $order_id);
$item = Orders::where('os', 1)->where('sn', $order_id)->find();
}
if (empty($item)) {
Redis::Lpush('Travel:Order:check:lits', $val);
continue;
}
//
$checkOrder = Orders::where('check_sn', $json->check_sn)->find();
//不为空表示已经验证过了
if (!empty($checkOrder)) {
continue;
}
//查看订单是否存在
$back = false; //修改数据库成功了没有
if (!empty($json->id)) {
$order = Orders::where('id', $json->id)->find();
if ($order->sn == $order_id) {
$order->is_check = 1;
$order->check_sn = $json->check_sn;
$back = $order->save();
}
} elseif (!empty($json->admin_id)) {
//订单在自己的名下
$order = Orders::where('sn', $order_id)->where('admin_id', $json->admin_id)->find();
if (!empty($order)) {
$order->is_check = 1;
$order->check_sn = $json->check_sn;
$back = $order->save();
} else {
$order = Orders::where('sn', $order_id)->find();
// print_r($order->toArray());
if (!empty($order) && $order->admin_id == 0) {
$order->is_check = 1;
$order->check_sn = $json->check_sn;
$order->admin_id = $json->admin_id;
$order->give_time = time();
$back = $order->save();
} elseif (!empty($order) && $order->admin_id !== $json->admin_id) {
$item = new Orders();
$item->os = 1;
$item->sn = $order->sn;
$item->product_id = $order->product_id;
$item->product_name = $order->product_name;
$item->category_id = $order->category_id;
$item->create_at = $order->create_at;
$item->travel_date = $order->travel_date;
$item->mobile = $order->mobile;
$item->unit_price = $order->unit_price;
$item->total_price = $order->total_price;
$item->actual_price = $order->actual_price;
$item->quantity = $order->quantity;
$item->order_status = $order->order_status;
$item->refund_status = $order->refund_status;
$item->category_desc = $order->category_desc;
$item->admin_id = $json->admin_id;
$item->check_sn = $json->check_sn;
$item->is_check = 1;
$item->give_time = time();
$back = $item->save();
$order->is_change = $json->admin_id;
$back2 = $order->save();
}
}
}
if (!$back) {
Redis::Lpush('Travel:Order:check:lits', $val); //写回去
Redis::Lpush('Travel:Order:check:lits:err', $val);
}
} else {
if ($res->code == 12) {
if ($json->id > 0) {
//核销码无效
$order = Orders::where('id', $json->id)->find();
$order->is_check = 2;
$order->save();
}
Logs::create([
'admin_id' => $json->admin_id ?? 0,
'action' => 11,
'order_id' => $json->id ?? 0,
'check_sn' => $json->check_sn
]);
}
if ($res->code > 0 && $res->code != 12) {
Redis::Lpush('Travel:Order:check:lits', $val);
Redis::Lpush('Travel:Order:check:lits:err', $val);
}
}
}
}
private function orders($start = null, $end = null, $order_id = false)
{
foreach (Orders::OSS as $k => $os) {
$pages = $this->page;
$page = 1;
while (true) {
if ($page > $pages) break;
$list = [];
switch ($k) {
case 1:
case 7:
try {
$mei = new Meituan($k);
$list = $mei->get($page, $start, $end, $order_id);
// $pages = $mei->totalPage;
} catch (\Exception $e) {
Log::error(dirname(__FILE__) . __LINE__ . $e);
}
break;
/*case 2:
try {
$kuai = new Kuaishou();
$list = $kuai->get($page, $start, $end);
$pages = $kuai->totalPage;
} catch (\Exception $e) {
Log::error(dirname(__FILE__) . __LINE__ . $e);
}
break;*/
/*case 3:
try {
$dou = new Douyin();
$list = $dou->get($page, $start, $end);
$pages = $dou->totalPage;
} catch (\Exception $e) {
Log::error(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 = $this->zhibo($order->product_name, $order->os);
// 刷单账号
if (FilterMobiles::isFilterMobile($order->mobile)) {
$admin_id = 0;
} else {
$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 {
try {
// $admin_id = $this->poolUser($order->orderStatus, $order->category_desc);
$admin_id = \app\server\Orders::poolUser($order->orderStatus, $order->product_id);
} catch (\Exception $exception) {
Log::info(sprintf('mt 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();
//判断是否需要发短信
if ((in_array($order->os, [1, 7]) && array_key_exists($order->order_status, [1 => 1, 3 => 3]))) {
if ($admin_id > 0) {
// 发送短信
\app\server\Orders::sendOrderSms($admin_id, $order);
// $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;
}
Log::info(sprintf('mt create order success order_id:%s', $order->sn));
//新获得一个用户的,提示管理员有新的订单
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 !== 4 && $order->order_status == 4) {
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:mt:lock', time(), 'EX', 3600 * 8, 'NX');
if (!$back) return;
$orders = Orders::where('create_at', '<=', (time() - 15 * 24 * 3600) * 1000)->where('os', 1)->wherein('status', [1, 2, 3])->select();
foreach ($orders as $order) {
$this->reloadStatus($order->sn, $order->os, $output);
}
}
private function reloadStatus($orderid, $os, $output)
{
$w[] = ['sn', '=', $orderid];
if ($os) $w[] = ['os', '=', $os];
$item = Orders::where($w)->find();
if (empty($item)) {
$output->writeln('没有找到订单');
return;
}
$it = null;
switch ($item->os) {
case 1:
case 7:
$m = new Meituan($item->os);
$it = $m->get(1, null, null, $item->sn);
break;
/* case 2:
$m = new Kuaishou();
$it = $m->get(1, null, null, $item->sn);
break;
case 3:
$m = new Douyin();
$it = $m->get(1, null, null, $item->sn);
break;*/
default:
# code...
break;
}
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 sms($admin_id, $order)
{
$user = Admins::cache(true)->where('id', $admin_id)->find();
if ((!config('app.debug', true) || config('app.debug', true) === 'false') && (time() * 1000 - $order->create_at) / 1000 < 2 * 24 * 3600) {
print_r([$order->mobile, 261607, ['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, 261607, ['title' => $order->product_name, 'mobile' => $user->mobile]);
} else {
sleep(10);
}
} else {
Log::info('不发送短信' . json_encode([$order->mobile, 261607, ['title' => $order->product_name, 'mobile' => $user->mobile]]));
}
}
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
// ]);
// }
}
}