Просмотр исходного кода

新增积分扣费白名单功能,只统计不扣费

lh 1 месяц назад
Родитель
Сommit
905397ac53
1 измененных файлов с 74 добавлено и 9 удалено
  1. 74 9
      app/Services/PointsService.php

+ 74 - 9
app/Services/PointsService.php

@@ -315,6 +315,11 @@ class PointsService
             return;
         }
 
+        // 测试用户(TEST_CPID / TEST_UID 白名单)跳过余额预检:只记录明细,不实际扣费
+        if ($this->isTestUser($uid)) {
+            return;
+        }
+
         $balance = $this->getUserPointsBalance($uid);
         if ($balance < $pointsNeeded) {
             Utils::throwError(ErrorConst::POINTS_NOT_ENOUGH);
@@ -322,6 +327,59 @@ class PointsService
     }
 
     /**
+     * 判断是否为测试用户(TEST_CPID / TEST_UID 白名单)
+     *
+     * TEST_CPID / TEST_UID 在 .env 中为英文逗号分隔的纯字符串(如 "1"、"142857,142858"),
+     * 读取后先转换为数组再判断。uid 命中 TEST_UID 或 cpid 命中 TEST_CPID(任一命中)即视为测试用户:
+     * 预检不再校验余额,扣费只记录明细、不实际扣减积分。
+     *
+     * @param int $uid 用户ID,缺省取当前登录用户
+     * @param int $cpid 公司ID,缺省取当前上下文公司ID
+     * @return bool
+     */
+    public function isTestUser(int $uid = 0, int $cpid = 0): bool
+    {
+        if (!$uid) {
+            $uid = (int)Site::getUid();
+        }
+        if (!$cpid) {
+            $cpid = (int)Site::getCpid();
+        }
+
+        $testUids = $this->parseEnvList(env('TEST_UID'));
+        $testCpids = $this->parseEnvList(env('TEST_CPID'));
+
+        if (!empty($testUids) && in_array((string)$uid, $testUids, true)) {
+            return true;
+        }
+
+        if (!empty($testCpids) && in_array((string)$cpid, $testCpids, true)) {
+            return true;
+        }
+
+        return false;
+    }
+
+    /**
+     * 将 env 中英文逗号分隔的字符串转换为数组
+     *
+     * @param mixed $value
+     * @return array
+     */
+    private function parseEnvList($value): array
+    {
+        if ($value === null || $value === '') {
+            return [];
+        }
+
+        $items = array_map('trim', explode(',', (string)$value));
+
+        return array_values(array_filter($items, function ($item) {
+            return $item !== '';
+        }));
+    }
+
+    /**
      * 视频生成成功后记录计费明细并扣减用户积分
      *
      * 幂等处理:同一任务只允许计费一次(type + task_id 唯一索引兜底)。
@@ -601,9 +659,12 @@ class PointsService
             }
 
             $pointsBefore = (float)getProp($user, 'points', 0);
-            $pointsAfter = $pointsBefore - $points;
 
-            if ($pointsBefore < $points) {
+            // 测试用户(TEST_CPID / TEST_UID 白名单):只记录明细,不实际扣减积分余额
+            $isTestUser = $this->isTestUser($uid, (int)getProp($user, 'cpid', 0));
+            $pointsAfter = $isTestUser ? $pointsBefore : $pointsBefore - $points;
+
+            if (!$isTestUser && $pointsBefore < $points) {
                 dLog('points')->warning('用户积分不足,扣费后积分为负数', [
                     'task_id' => $taskId,
                     'uid' => $uid,
@@ -612,11 +673,13 @@ class PointsService
                 ]);
             }
 
-            // 更新用户积分总额
-            DB::table('mp_manage_users')->where('id', $uid)->update([
-                'points' => $pointsAfter,
-                'updated_at' => date('Y-m-d H:i:s')
-            ]);
+            if (!$isTestUser) {
+                // 更新用户积分总额
+                DB::table('mp_manage_users')->where('id', $uid)->update([
+                    'points' => $pointsAfter,
+                    'updated_at' => date('Y-m-d H:i:s')
+                ]);
+            }
 
             // 记录积分使用明细
             DB::table('mp_user_points_details')->insert([
@@ -641,7 +704,8 @@ class PointsService
                 'uid' => $uid,
                 'points_consumed' => $points,
                 'points_after' => $pointsAfter,
-                'tokens_consumed' => $tokens
+                'tokens_consumed' => $tokens,
+                'test_mode' => $isTestUser
             ]);
 
             return [
@@ -651,7 +715,8 @@ class PointsService
                 'points_consumed' => $points,
                 'points_before' => $pointsBefore,
                 'points_after' => $pointsAfter,
-                'tokens_consumed' => $tokens
+                'tokens_consumed' => $tokens,
+                'test_mode' => $isTestUser
             ];
 
         } catch (\Exception $e) {