diff --git a/src/Services/Cron.php b/src/Services/Cron.php index d52fb98c..eaff7d4d 100755 --- a/src/Services/Cron.php +++ b/src/Services/Cron.php @@ -22,6 +22,7 @@ use App\Models\Ducks; use App\Models\Visitor; use App\Models\CountVisitor; use App\Models\CountUser; +use App\Models\Product; use App\Services\TomTool\TgSendFormat; use App\Services\IM\Telegram; use App\Services\Tg\ReportUser; @@ -74,7 +75,6 @@ final class Cron $sPrevTimeStart = strtotime($sPrevDateStart); $sPrevTimeEnd = strtotime($sPrevDateEnd); $sPrevDate30 = date("Y-m-d", strtotime("-30 day")); -// echo "
";
         
         //// 访客统计 start
         $aVisitorCount = Visitor::select('from', DB::raw('count(*) as count'))
@@ -322,6 +322,7 @@ final class Cron
                 }
                 
                 // todo 反水
+                // 这里返水的话,等于是直接覆盖的用户不返水,自然过期的用户返水,这到合理,自然过期的才是好用户
 
                 try {
                     Notification::notifyUser($user, $_ENV['appName'] . '-您的套餐已经过期', $text);
@@ -336,30 +337,52 @@ final class Cron
                 $user->save();
             }
             
-            //// 流量到期处理
+            //// 流量到期处理 | 不重置了,默认暂停就行
             // 这里,只重置付费用户,不重置免费用户。那么假如免费用户领了60g流量,他就真的能用到没。付费用户则会连带套餐一起重置掉。
             // 应该问题不大,赠送流量有关时,区分免费付费用户,对付费大方(陷阱),对免费抠门。
             // 其实压根就不叠加,套餐流量直接覆盖免费流量。
             // 再者,免费流量
             // 总之,免费流量就是零头,无所谓重置的。
-            $ud = $user->u + $user->d;
-            if ($ud >= $user->transfer_enable && $user->class > 0) {
-                
-                $sText = "你好,系统发现您的流量已用完,已转为免费体验帐户,可用每日签到获取免费流量。";
-                
-                try {
-                    Notification::notifyUser($user, $_ENV['appName'] . '-您的流量已用完', $sText);
-                } catch (GuzzleException|ClientExceptionInterface|TelegramSDKException $e) {
-                    echo $e->getMessage() . PHP_EOL;
-                }
-                
-                $user->u = 0;
-                $user->d = 0;
-                $user->transfer_today = 0;
-                $user->class = 0;
-                $user->save();
-                
-            }
+            
+            // 用户流量用光,或者用户等级到期,就重置。
+            // 流量用光时顺便标记订单。在这里标记不容易埋坑。
+//            $ud = $user->u + $user->d;
+//            if ($ud >= $user->transfer_enable) {
+//                
+//                // 订单标记为过期
+//                // 既然class大于0,就说明肯定有激活的套餐,对吧
+//                $activated_order = (new Order())->where('user_id', $user->id)
+//                    ->where('status', 'activated')
+//                    ->where('product_type', 'tabp')
+//                    ->orderBy('id')
+//                    ->first();
+//                
+//                // 以防万一,判断一下
+//                if (!$activated_order) {
+//                    $activated_order->status = 'expired';
+//                    $activated_order->update_time = time();
+//                    $activated_order->save();
+//                }
+//                
+////                tomd($activated_order, 1);
+//                // 用户流量重置
+//                $user->u = 0;
+//                $user->d = 0;
+//                $user->class = 0;
+//                $user->transfer_today = 0;
+//                $user->transfer_enable = 0;
+//                $user->class_expire = date("Y-m-d H:i:s"); // 用户等级时间到当前,注意订单没变,应该合理
+//                $user->save();
+//                
+//                $sText = "你好,系统发现您的流量已用完,已转为免费体验帐户,可用每日签到获取免费流量。";
+//                
+//                try {
+//                    Notification::notifyUser($user, $_ENV['appName'] . '-您的流量已用完', $sText);
+//                } catch (GuzzleException|ClientExceptionInterface|TelegramSDKException $e) {
+//                    echo $e->getMessage() . PHP_EOL;
+//                }
+//                
+//            }
             
             //// end
         }
@@ -418,6 +441,20 @@ final class Cron
         }
     }
 
+    // 激活订单
+    /**
+     逻辑:
+        查询,遍历所有用户
+            根据uid,找待激活订单
+            根据uid,找已激活订单
+                判断:当有待激活订单时:
+                    判断:无已激活订单,激活
+                    判断:此用户流量满了,激活。就加了这个。
+                        无待激活订单时,确定不激活
+                        流量没满时,走原来的逻辑,无已激活时激活
+                判断:有已激活订单
+                    判断:订单的等级时间过期,标记过期
+     */
     public static function processTabpOrderActivation(): void
     {
         $users = User::all();
@@ -436,12 +473,129 @@ final class Cron
                 ->where('product_type', 'tabp')
                 ->orderBy('id')
                 ->first();
+            /*
+             添加条件,当流量用满时,可以直接激活新套餐。
+             那如果,没有新套餐,就等于旧套餐被暂停了,等到用户等级过期时,走原有的重置,没错。
+             那如果,有新套餐,那就是直接覆盖,刷新。
+                也就是说,用户流量不满时,就是当前套餐到期再激活新套餐。
+                而用户流量满时,就是直接激活新套餐。
+                这里是有点怪,两个玩法。何不直接叠加?
+                    如果都直接叠加,会怎样?
+                        连充12个月会员,直接是一年,好像没问题?之前为什么否了?
+                            好像是因为续流量比较亏,因为时间是虚的而流量是实的。
+                                但这其实没办法,不管用什么方案,流量满了总得允许人家续,没得变。
+                    根本区别就是,叠加有粘性,不叠加省成本。
+                        用户流量满了,他就叠流量,最后时间剩很多,流量没有,套餐就成了流量包。
+                            “我套餐还没到期,但是流量已经没了,无所谓”,所以这里不是留住客户的理由。
+                        用户时间到了,他就叠时间,最后流量用不完,时间快到期了。
+                            那基本上他会狂用,看4k被。
+                                “我流量还没用完呢,续一下”
+                                    “这么多流量,看高清”
+                        理想情况,时间叠褶叠着,流量用不完,然后时间到期,一下清空。
+                            这种情况,应该不会太多,他流量多自然就不会省着用了。
+                    所以,还是别叠加,留住客户可以返水之类的,而不是在这里暗着给他们实惠。
+                        不叠加指的是时间不叠加,流量还是要叠的,这没有其他办法。
+                            顶多是流量满了直接重置时间,但这想想没必要。时间是虚的,重置不重置没什么区别,倒是产生业务上的混乱感。
+                                完全没必要,流量满了其实就暂停了,再买套餐就覆盖。重置也相当于暂停,再买套餐也是覆盖,都一样。
+             之前的逻辑怪圈,就是他原本用户等级到期会重置,我就想当然的做成流量满了也重置。
+                首先他为什么原本到期重置
+                    因为订单function只影响订单状态,不影响用户状态,他俩是独立的。
+                        if订单到期,修改。if用户等级到期,修改。代码上是各玩各的,只是刚好订单和用户等级的时间是一致的,所以会同时处理。
+                            你被误导的地方是有可激活订单时,会去覆盖用户。就仿佛他俩是直接关联的。
+                                但要是没有可激活订单呢?用户就一直不重置了,到流量用完暂停。这就是要有用户重置的原因。
+                                    用户重置是基础,订单的重置是补偿。
+                那流量为什么不能重置
+                    因为没必要,反而导致业务逻辑奇怪。
+                        为什么奇怪,用户原本是20号到期,流量用光变成了10号到期,他会迷茫。
+                            用户10号到期也就算了,订单状态也跟着变了,提前到期了。就很怪。
+                    所以就不重置它,保持暂停就行了。等待时间到期走原本的重置。
+             还有一个点,webapi那边会判断流量满了暂停,而不会判断等级到期暂停,所以要有用户时间重置,不然就会跑到流量用光为止。
+                所以流量满了可以不重置,会自然暂停。
+             最后确定一下,到底行不行,别又弄错了。
+                现在就是说,只要流量满了,就直接激活待激活套餐,即便还存在已激活订单。
+                    就会同时会出现两个激活套餐,这倒没事,只要代码没有要求只读一个激活套餐。到时检查一下。
+                其他地方都不用动,爱加就加个流量提醒(本来就有)。对吗?
+                    对,就是这样,流量满了就允许直接激活覆盖新套餐,就这个逻辑。
+                        实在不放心,就把当前订单标记成过期。
+             没问题,确实没问题,就这么干。
+             再缕一次
+                起初,发现流量满了不能激活套餐(原本是用流量包续)
+                    我最初是重置了套餐满了的用户流量,但没重置订单状态。幸亏,是只重置class大于0,不会有大的损失。
+                然后想到应该标记订单,当前订单标记成过期,下一个订单就能激活了。
+                    至于用户function那边,应该不用重置,它自然暂停即可。
+                然后又想到,那会导致业务逻辑怪异,所以就在这加个判断,流量满时直接激活下一个订单,不考虑是否有已激活。这个问题也就解决了。
+             所以就是说,我要解决《用户流量满了不能激活新套餐的问题》,我就在这里加个判断,逻辑是《流量满了直接激活新套餐,即便存在已激活订单》。
+                订单状态有几种?
+                    待激活 - 必须条件
+                    已激活 - 附加条件A(反向)
+                    取消 - 不相关,必然不进
+                    等待付款 - 不相关,必然不进
+                也就是
+                    如果有待激活,就直接激活,不管是否有已激活
+                    如果没有待激活,不管。自然暂停,自然重置。
+                没有其他情况,对吗?
+                    两种条件会激活:
+                        没有已激活订单,只有待激活订单
+                        有激活订单,用户流量满了
+                    其他条件不会激活?
+                那如果,没有已激活订单,同时用户流量满了呢?
+                    也会走进来
+                        那无所谓,是按原有逻辑激活
+                    没有待激活是肯定不会进来的
+                换个说法就是,有待激活,并且没有已激活或者用户流量满了,就进来
+                    激活的必须条件是有待激活订单
+                        然后没有已激活,或者用户流量满了
+                可能的条件(情况):
+                    有待激活订单,用户流量满 - 已测试
+                    有待激活订单,无已激活订单 - 已测试
+                        假如用户没有已激活套餐,却有等级流量呢
+                            当然是不用管他,活动获取的呗
+                    有待激活订单,用户流量满,无已激活订单
+                        没问题,等于走原来的逻辑
+                不可能的情况:
+                    有待激活套餐,有激活套餐,用户流量不满 - 已测试
+                    没有待激活套餐 - 不可能
+             */
             // 如果用户账户中没有已激活的TABP订单,且有等待激活的TABP订单,则激活最早的等待激活TABP订单
-            if ($activated_order === null && count($pending_activation_orders) > 0) {
+            // * 如果用户流量已满,就直接激活待激活订单,不考虑是否有已激活。(之前想的是流量满时把订单标记成过期,这虽然也可以,但是业务逻辑会显得奇怪)
+            $ud = $user->u + $user->d;
+            // 待激活订单 > 0 && (没有已激活订单 || 用户流量满)
+             if (count($pending_activation_orders) > 0 && ($activated_order === null || $ud >= $user->transfer_enable)) {
+//            if ($activated_order === null && count($pending_activation_orders) > 0) {
+//             if (($activated_order === null && count($pending_activation_orders) > 0) || ($ud > $user->transfer_enable && count($pending_activation_orders) > 0)) {
                 $order = $pending_activation_orders[0];
                 // 获取TABP订单内容准备激活
                 $content = json_decode($order->product_content);
+                 
+                 //// * 是用户流量满时,主动标记订单过期
+                 // 按理说可以有多个已激活,但是以防万一,标记掉
+                 // 假如等级还过期了,就是标记两次,无所谓
+                 if ($ud >= $user->transfer_enable) {
+                     $activated_order->status = 'expired';
+                     $activated_order->update_time = time();
+                     $activated_order->save();
+                     echo "TABP订单 #{$activated_order->id} 已过期(流量满了)。\n";
+//                     tomd($activated_order->status);
+                 }
+                 //// end
+                 
+                //// * 特别活动追加,季套餐赠月套餐,年套餐赠季套餐
+//                if ($order->huodong_class && $order->huodong_class == "A") {
+//                    
+//                    $oProduct = Product::where("name", $order->product_name)
+//                                    ->where("type_by_time", "<", $content->class_time)
+//                                    ->orderBy("type_by_time", "desc")
+//                                    ->first();
+//                    $oProductContent = json_decode($oProduct->content);
+//                    
+//                    $content->class_time += $oProductContent->class_time;
+//                    $content->bandwidth += $oProductContent->bandwidth;
+//                    
+//                }
+                //// end
+                
                 // 激活TABP
+                // 等级时间,流量,都是覆盖刷新,不是叠加
                 $user->u = 0;
                 $user->d = 0;
                 $user->transfer_today = 0;
@@ -449,7 +603,7 @@ final class Cron
                 $user->class = $content->class;
                 $old_class_expire = new DateTime();
                 $user->class_expire = $old_class_expire
-                    ->modify('+' . $content->class_time . ' days')->format('Y-m-d H:i:s');
+                    ->modify('+' . $content->class_time . ' days')->format('Y-m-d H:i:s'); // 当前时间+订单等级时间
                 $user->node_group = $content->node_group;
                 $user->node_speedlimit = $content->speed_limit;
                 $user->node_iplimit = $content->ip_limit;
@@ -464,12 +618,14 @@ final class Cron
             if ($activated_order !== null) {
                 $content = json_decode($activated_order->product_content);
 
+                // 原来用的是$content->time
                 if ($activated_order->update_time + $content->class_time * 86400 < time()) {
                     $activated_order->status = 'expired';
                     $activated_order->update_time = time();
                     $activated_order->save();
                     echo "TABP订单 #{$activated_order->id} 已过期。\n";
                 }
+                
             }
         }
 
@@ -546,6 +702,7 @@ final class Cron
         echo Tools::toDateTime(time()) . ' 时间包订单激活处理完成' . PHP_EOL;
     }
 
+    // 标记订单
     public static function processPendingOrder(): void
     {
         $pending_payment_orders = (new Order())->where('status', 'pending_payment')->get();
diff --git a/src/Services/Tg/Hook/Mod/Order.php b/src/Services/Tg/Hook/Mod/Order.php
index cf15b229..bec26cac 100644
--- a/src/Services/Tg/Hook/Mod/Order.php
+++ b/src/Services/Tg/Hook/Mod/Order.php
@@ -10,6 +10,31 @@ use App\Services\DB;
 final class Order
 {
     
+    private function format($v)
+    {
+        $v['create_time'] = date("Y-m-d H:i:m", $v['create_time']);
+        $v['update_time'] = date("Y-m-d H:i:m", $v['update_time']);
+        $v['product_content'] = json_decode($v['product_content']);
+        
+        return $v;
+    }
+    
+    public function Limit($aParam)
+    {
+        $iLimit = $aParam['aArg'][1] ?? 1;
+        
+        $aOrder = Order::orderBy('id', 'desc')->limit($iLimit)->get()->toArray();
+        
+        foreach ($aOrder as $v) {
+            $aOrderSingle = $this->format($v);
+            $sMsg = json_encode($aOrderSingle, JSON_UNESCAPED_UNICODE | JSON_PRETTY_PRINT);
+            $this->oTGHttp->sendToTG($sMsg);
+        }
+        
+        $this->oHttp::response(200, 'ok');
+        
+    }
+    
     public function Find($aParam)
     {
         
@@ -20,10 +45,7 @@ final class Order
         if ($aOrder) {
             $aOrderNew = [];
             foreach ($aOrder as $k => $v) {
-                $v['create_time'] = date("Y-m-d H:i:m", $v['create_time']);
-                $v['update_time'] = date("Y-m-d H:i:m", $v['update_time']);
-                $v['product_content'] = json_decode($v['product_content']);
-                $aOrderNew[] = $v;
+                $aOrderNew[] = $this->format($v);
             }
         } else {
             $aOrderNew = ["not have id" => $iUserId];
diff --git a/src/Services/Tg/Hook/Mod/User.php b/src/Services/Tg/Hook/Mod/User.php
index dbf5e792..de55756b 100644
--- a/src/Services/Tg/Hook/Mod/User.php
+++ b/src/Services/Tg/Hook/Mod/User.php
@@ -39,7 +39,7 @@ final class User extends Base
     public function Limit($aParam)
     {
 //        $sField = $aParam['aOption'][1];
-        $iLimit = $aParam['aArg'][1] ?? 5; // 默认五条
+        $iLimit = $aParam['aArg'][1] ?? 1; // 默认五条
         
         $aUser = ModelUser::where("class", '>', 0)->orderBy("id", "desc")->limit($iLimit)->get()->toArray();