travel/service/app/command/SpiderDy.php

547 lines
20 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\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 SpiderDy extends Command
{
protected static $defaultName = 'spider:dy';
protected static $defaultDescription = '抖音订单拉取器';
protected $_users = [];
protected function configure()
{
$this->setName('spider:dy')
->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);
$routeType = AdminController::ROUTE_LISTS[mb_substr($categoryDesc, 0, 2)] ?? 10;
$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;
}
/**
* @param InputInterface $input
* @param OutputInterface $output
* @return int
*/
protected function execute(InputInterface $input, OutputInterface $output): int
{
// $name = $input->getArgument('name');
$output->writeln('START spider:dy:'.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);
// }
$start = date('Y-m-d 00:00:00', strtotime("-{$d} days"));
$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:dy:'.date('Y-m-d H:i:s'));
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();
echo "订单在自己名下";
} else {
// echo "订单在自己名下2 $order_id";
$order = Orders::where('sn', $order_id)->find();
// print_r($order->toArray());
if (!empty($order) && $order->admin_id == 0) {
echo '订单不在自己的名下,并且没有分人。';
$order->is_check = 1;
$order->check_sn = $json->check_sn;
$order->admin_id = $json->admin_id;
$back = $order->save();
} elseif (!empty($order) && $order->admin_id !== $json->admin_id) {
echo '订单不在自己的名下,并且分人了。';
$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;
$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 = 6;
$page = 1;
while (true) {
if ($page > $pages) break;
$list = [];
switch ($k) {
/*case 1:
try {
$mei = new Meituan();
$list = $mei->get($page, $start, $end);
$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:
// echo '==========pages='.$pages;
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) {
// 过滤一日游
if (strpos('一日游', $order->category_desc) !== false) {
continue;
}
$item = Orders::where('os', $order->os)->where('sn', $order->sn)->find();
if (empty($item)) {
$order->is_zhibo = $this->zhibo($order->product_name, $order->os);
$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();
//判断是否需要发短信
if (($order->os == 1 && array_key_exists($order->order_status, [1 => 1, 3 => 3])) ||
($order->os == 2 && array_key_exists($order->order_status, [2 => 2, 3 => 3, 4 => 4])) ||
($order->os == 3 && $order->order_status == 1)) {
// $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);
}
}
$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', 3)->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('没有找到订单');
}
$it = null;
switch ($item->os) {
/*case 1:
$m = new Meituan();
$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) {
echo "发送短信\n";
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 {
echo "黑名单不发送短信\n";
sleep(10);
}
} else {
echo "不发送短信\n";
print_r([$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
// ]);
// }
}
}