Kaynağa Gözat

Merge branch 'priority' into dev/test

shensong00 23 saat önce
ebeveyn
işleme
a9661ecfdc

+ 7 - 6
app/Console/Commands/ChatGroup/GroupBasicInfo.php

@@ -84,12 +84,13 @@ class GroupBasicInfo extends Command
84 84
     private function getGroupInfo($corpid, $userIds, $source)
85 85
     {
86 86
         # owner_filter参数处理
87
-        $userIdList = DjUser::select(['user_id'])->where('corpid', $corpid)->where('enable', 1)
88
-            ->where(function($query) use($userIds) {
89
-                if($userIds) $query->whereIn('user_id', $userIds);
90
-            })
91
-            ->where('status', 1)->orderBy('id')
92
-            ->distinct()->pluck('user_id')->toArray();
87
+//        $userIdList = DjUser::select(['user_id'])->where('corpid', $corpid)->where('enable', 1)
88
+//            ->where(function($query) use($userIds) {
89
+//                if($userIds) $query->whereIn('user_id', $userIds);
90
+//            })
91
+//            ->where('status', 1)->orderBy('id')
92
+//            ->distinct()->pluck('user_id')->toArray();
93
+        $userIdList = DjUser::getActiveUserListById($corpid, $userIds);
93 94
 
94 95
         $userCount = count($userIdList);
95 96
         # 需要截取的段数

+ 219 - 0
app/Console/Commands/CorpInformation/BatchMarkTagDeal.php

@@ -0,0 +1,219 @@
1
+<?php
2
+
3
+namespace App\Console\Commands\CorpInformation;
4
+
5
+use App\Log;
6
+use App\Models\AuthorizeCorp;
7
+use App\Models\BatchMarkTag;
8
+use App\Models\BatchMarkTagRecord;
9
+use App\Models\CustomerDetails;
10
+use App\Models\DjUser;
11
+use App\Models\Tag;
12
+use App\RedisModel;
13
+use App\Service\TagService;
14
+use App\Support\EmailQueue;
15
+use App\Support\qyApi\QyCommon;
16
+use Illuminate\Console\Command;
17
+
18
+class BatchMarkTagDeal extends Command
19
+{
20
+    protected $signature = 'BatchMarkTagDeal';
21
+    protected $description = '客户批量打标签处理';
22
+
23
+    protected $emailSender = '猎羽-批量打标签';
24
+    protected $emailReceiver = ['song.shen@kuxuan-inc.com'];
25
+    protected $logName = 'BatchMarkTagDeal';
26
+
27
+    public function handle()
28
+    {
29
+        \DB::connection()->disableQueryLog();
30
+
31
+        $beginTime = time();
32
+        $this->info(date('m-d H:i:s') . ' 开始整理');
33
+
34
+        while(true) {
35
+            $result = $this->taskDeal();
36
+            if(!$result) sleep(1);
37
+            $now = time();
38
+            // 超过10分钟,主动停止循环
39
+            if ($now - $beginTime > 600) {
40
+                break;
41
+            }
42
+
43
+            sleep(1);
44
+        }
45
+
46
+        $this->info(date('Y-m-d H:i:s') . ' 整理结束');
47
+    }
48
+
49
+    private function taskDeal()
50
+    {
51
+        # 取出数据
52
+        $redisVal = RedisModel::rPop(BatchMarkTagRecord::BATCH_MARK_TAG_RECORD);
53
+        if(empty($redisVal))
54
+            return false;
55
+        try {
56
+            $this->createTask($redisVal);
57
+        } catch (\Exception $e) {
58
+            EmailQueue::rPush('客户批量打标签处理任务出现异常', $e->getTraceAsString(), $this->emailReceiver, $this->emailSender);
59
+            Log::logError('程序异常', [
60
+                'line'  => $e->getLine(), 'msg'   => $e->getMessage(), 'param' => $redisVal
61
+            ], $this->logName);
62
+
63
+            return false;
64
+        }
65
+
66
+        return true;
67
+    }
68
+
69
+    private function createTask($redisVal) {
70
+        $redisData = json_decode($redisVal, 1);
71
+        if(empty($redisData) || empty($redisData['task_id']) || empty($redisData['record_id'])) {
72
+            Log::logError('队列数据异常', [$redisData], $this->logName);
73
+            EmailQueue::rPush('处理客户批量打标签 - 队里数据异常', $redisVal, $this->emailReceiver, $this->emailSender);
74
+            return false;
75
+        }
76
+
77
+        $taskId = $redisData['task_id'];
78
+        $recordId = $redisData['record_id'];
79
+        $taskInfo = BatchMarkTag::getTaskInfoById($redisData['task_id']);
80
+        if(empty($taskInfo)) {
81
+            Log::logError('根据任务ID查询任务信息失败', ['task_id' => $taskId], $this->logName);
82
+            EmailQueue::rPush('处理客户批量打标签 - 根据任务ID查询任务信息失败', $redisVal, $this->emailReceiver, $this->emailSender);
83
+            $status = -1;
84
+            BatchMarkTagRecord::updateData($recordId, ['status' => $status]);
85
+            return false;
86
+        }
87
+
88
+        $taskInfo = json_decode(json_encode($taskInfo), 1);
89
+
90
+        $recordInfo = BatchMarkTagRecord::getInfoById($recordId);
91
+        if(empty($recordInfo)) {
92
+            Log::logError('根据记录ID查询记录信息失败', ['record_id' => $recordId], $this->logName);
93
+            EmailQueue::rPush('处理客户批量打标签 - 根据记录ID查询记录信息失败', $redisVal, $this->emailReceiver, $this->emailSender);
94
+            $status = -1;
95
+            BatchMarkTagRecord::updateData($recordId, ['status' => $status]);
96
+            return false;
97
+        }
98
+
99
+        $recordInfo = json_decode(json_encode($recordInfo), 1);
100
+
101
+        $this->dealTask($taskInfo, $recordInfo);
102
+    }
103
+
104
+    private function dealTask($taskInfo, $recordInfo) {
105
+        $externalUserIdList = explode(',', $recordInfo['external_userid']);
106
+        if(empty($externalUserIdList)) {
107
+            Log::logError('根据记录ID查询记录信息失败', ['record_id' => $recordInfo['id']], $this->logName);
108
+            EmailQueue::rPush('处理客户批量打标签 - 根据记录ID查询记录信息失败', 'task_id:'.$taskInfo['id'].'; record_id:'.$recordInfo['id'], $this->emailReceiver, $this->emailSender);
109
+            $status = -1;
110
+            BatchMarkTagRecord::updateData($recordInfo['id'], ['status' => $status]);
111
+            return false;
112
+        }
113
+
114
+        $tagList = json_decode($taskInfo['task_list'], 1);
115
+        // 标签转化
116
+        $newTagList = Tag::query()->where('corpid', $taskInfo['corpid'])->where('enable', 1)
117
+            ->whereIn('tag_md5', $tagList)->get();
118
+        $newTagList = $newTagList->isNotEmpty() ? array_column($newTagList->toArray(), 'tag_id') : [];
119
+
120
+        $update = ['exec_success' => 0, 'exec_fail' => 0];
121
+        foreach ($externalUserIdList as $externalUserId) {
122
+            if(1 == $taskInfo['type']) {
123
+                $newAddTagIdList = $newTagList;
124
+                $newRemoveTagIdList = [];
125
+            } else if(2 == $taskInfo['type']) {
126
+                $newAddTagIdList = [];
127
+                $newRemoveTagIdList = $newTagList;
128
+            }
129
+
130
+            $res = $this->markTag($taskInfo['corpid'], $recordInfo['user_id'], $externalUserId, $newAddTagIdList, $newRemoveTagIdList);
131
+            if($res) {
132
+                $update['exec_success']++;
133
+            } else {
134
+                $update['exec_fail']++;
135
+            }
136
+        }
137
+
138
+        # 验证总数
139
+        if($update['success'] + $update['exec_fail'] != $recordInfo['exec_total']) {
140
+            Log::logError('程序异常', ['record_id' => $recordInfo['id'], 'stat' => $update], $this->logName);
141
+            EmailQueue::rPush('客户批量打标签 - 处理数据总数与待处理数据总数不一致', json_encode(['record_id' => $recordInfo['id'], 'stat' => $update]), $this->emailReceiver, $this->emailSender);
142
+        }
143
+
144
+        # 更新任务状态
145
+        if($update['fail'] == $recordInfo['exec_total']) {
146
+            $update['status'] = -1;
147
+        } else {
148
+            $update['status'] = 1;
149
+        }
150
+        $res = BatchMarkTagRecord::updateData($recordInfo['id'], $update);
151
+        if(!$res) {
152
+            Log::logError('数据更新失败', ['record_id' => $recordInfo['id'], 'update' => $update], $this->logName);
153
+        }
154
+
155
+        # 判断总体任务是否执行完成
156
+        $this->chargeTaskStatus($taskInfo['id']);
157
+    }
158
+
159
+    private function markTag($corpid, $userId, $externalUserId, $newAddTagIdList, $newRemoveTagIdList, $retry = 0) {
160
+        $responseData = QyCommon::mark_tag($corpid, $userId, $externalUserId, $newAddTagIdList, $newRemoveTagIdList);
161
+
162
+        if(isset($responseData['errcode']) && $responseData['errcode'] == 0) {
163
+            // 编辑成功了
164
+            TagService::updateLocalCustomerTagSecond($corpid, $userId, $externalUserId, $newAddTagIdList, $newRemoveTagIdList);
165
+
166
+            $state = $data['state'] ?? null;
167
+            if (!is_null($state)) {
168
+                // 客户详情10s同步一遍
169
+                RedisModel::lPush(CustomerDetails::CUSTOMER_DATA_SYNC_RDS, json_encode([
170
+                    'corpid' => $corpid,
171
+                    'user_id' => $userId,
172
+                    'external_userid' => $externalUserId,
173
+                    'exec_time' => time() + 10
174
+                ]));
175
+            }
176
+
177
+            return true;
178
+        } else {
179
+           if( $responseData['errcode'] != 84061 ) { # 无法处理的状态码:没有好友关系
180
+                // 判断重试次数
181
+                if($retry <= 5) {
182
+                    $retry++;
183
+                    return $this->markTag($corpid, $userId, $externalUserId, $newAddTagIdList, $newRemoveTagIdList, $retry);
184
+                } else {
185
+                    $params = ['corpid' => $corpid, 'user_id' => $userId, 'external_userid' => $externalUserId, 'add_tag_id_list' => $newAddTagIdList, 'remove_tag_id_list' => $newRemoveTagIdList];
186
+                    // 还是一直失败,则不再请求,日志记录一下
187
+                    Log::logError('请求企微打标签接口3次重试均失败', [
188
+                        'param' => $params,
189
+                        'response' => $responseData,
190
+                    ], $this->logName);
191
+                    EmailQueue::rPush('请求企微打标签接口3次重试均失败', json_encode(['params' => $params, 'res' => $responseData], 256), $this->emailReceiver, $this->emailSender);
192
+                    return false;
193
+                }
194
+            } else {
195
+               //todo 隔1小时报警一次
196
+
197
+               return false;
198
+           }
199
+        }
200
+    }
201
+
202
+    private function chargeTaskStatus($taskId) {
203
+        $countData = BatchMarkTagRecord::recordCount($taskId);
204
+        $total = 0; $exec = 0;
205
+        if($countData->isNotEmpty()) {
206
+            foreach ($countData as $countInfo) {
207
+                if(0 == $countInfo->status) {
208
+                    $exec += $countInfo->count;
209
+                }
210
+
211
+                $total += $countInfo->count;
212
+            }
213
+        }
214
+
215
+        if($exec == 0) {
216
+            BatchMarkTag::updateStatus($taskId, 3);
217
+        }
218
+    }
219
+}

+ 22 - 37
app/Console/Commands/CorpInformation/BatchMarkTagNew.php

@@ -75,40 +75,28 @@ class BatchMarkTagNew extends Command
75 75
         }
76 76
 
77 77
         $taskInfo = json_decode(json_encode($taskInfo), 1);
78
+        BatchMarkTag::updateStatus($taskId, 2);
78 79
 
79
-        # 客服许可(兼容新授权到系统的企微,此种企微的客服没有许可,但是会有75天的试用期)
80
-        $corpInfo = AuthorizeCorp::getCorpInfo($taskInfo['corpid']);
81
-        if(!empty($corpInfo)) {
82
-            $chargeActiveType = 1;
83
-            $activeUserList = [];
84
-            if (strtotime($corpInfo->created_at) <= strtotime('-75 days')) {
85
-                $chargeActiveType = 2;
86
-                $activeUserList = DjUser::getActiveUserListById($taskInfo['corpid'], []);
87
-                $activeUserList = json_decode(json_encode($activeUserList), 1);
88
-                if(empty($activeUserList)) {
89
-                    # 选择的客服列表全部没有许可,不去查询客户列表,直接更新状态
90
-                    $status = -1;
91
-                    BatchMarkTag::updateStatus($taskId, $status);
92
-                    Log::logError('所属企微的客服全部没有许可信息', ['task_id' => $taskId, 'corpid' => $taskInfo['corpid']], $this->logName);
93
-                    return false;
94
-                }
95
-            }
96
-
97
-            # 直接筛选出要处理的客户列表,方便生成记录表数据
98
-            if(0 == $taskInfo['select_all']) {
99
-                $this->dealSelectTask($taskInfo, $chargeActiveType, $activeUserList);
100
-            } else {
101
-                $this->dealFilterTask($taskInfo, $chargeActiveType, $activeUserList);
102
-            }
103
-        } else {
80
+        $activeUserList = DjUser::getActiveUserListById($taskInfo['corpid']);
81
+        if(empty($activeUserList)) {
82
+            # 选择的客服列表全部没有许可,不去查询客户列表,直接更新状态
104 83
             $status = -1;
105 84
             BatchMarkTag::updateStatus($taskId, $status);
106
-            Log::logError('企微信息异常', ['task_id' => $taskId], $this->logName);
107
-            EmailQueue::rPush('客户批量打标签-企微信息查询异常', 'task_id:'.$taskId, $this->emailReceiver, $this->emailSender);
85
+            Log::logError('所属企微的客服全部没有许可信息', ['task_id' => $taskId, 'corpid' => $taskInfo['corpid']], $this->logName);
86
+            return false;
108 87
         }
88
+
89
+
90
+        # 直接筛选出要处理的客户列表,方便生成记录表数据
91
+        if(0 == $taskInfo['select_all']) {
92
+            $this->dealSelectTask($taskInfo, $activeUserList);
93
+        } else {
94
+            $this->dealFilterTask($taskInfo, $activeUserList);
95
+        }
96
+
109 97
     }
110 98
 
111
-    private function dealSelectTask($taskInfo, $chargeActiveType, $activeUserList) {
99
+    private function dealSelectTask($taskInfo, $activeUserList) {
112 100
         $customerList = json_decode($taskInfo['customer_list'], 1);
113 101
         $taskId = $taskInfo['id'];
114 102
         $corpid = $taskInfo['corpid'];
@@ -124,7 +112,7 @@ class BatchMarkTagNew extends Command
124 112
         }
125 113
 
126 114
         foreach ($userCustomerList as $userId => $childCustomerIdListArr) {
127
-            if(2 == $chargeActiveType && !in_array($userId, $activeUserList)) {
115
+            if(!in_array($userId, $activeUserList)) {
128 116
                 Log::logInfo('客服无许可,跳过', ['user_id' => $userId, 'customer_list' => $childCustomerIdListArr], $this->logName);
129 117
                 continue;
130 118
             }
@@ -148,7 +136,7 @@ class BatchMarkTagNew extends Command
148 136
                     if(!$result) {
149 137
                         Log::logError('记录写入失败', ['task_info' => $taskInfo], $this->logName);
150 138
                     } else {
151
-                        RedisModel::rPush(BatchMarkTagRecord::BATCH_MARK_TAG_RECORD, $result->id);
139
+                        RedisModel::rPush(BatchMarkTagRecord::BATCH_MARK_TAG_RECORD, json_encode(['task_id' => $taskId, 'record_id' => $result->id]));
152 140
                     }
153 141
                 }
154 142
             }
@@ -179,10 +167,11 @@ class BatchMarkTagNew extends Command
179 167
         return $data;
180 168
     }
181 169
 
182
-    private function dealFilterTask($taskInfo, $chargeActiveType, $activeUserList)
170
+    private function dealFilterTask($taskInfo, $activeUserList)
183 171
     {
184 172
         $params = json_decode($taskInfo['params'], 1);
185 173
         $params['corpid'] = $taskInfo['corpid'];
174
+        $params['user_id_list'] = !is_array($params['user_id_list']) ? json_decode($params['user_id_list']) : $params['user_id_list'];
186 175
         $source = 1;
187 176
 
188 177
         $filterCustomerList = json_decode($taskInfo['filter_customer_list'], 1);
@@ -195,11 +184,7 @@ class BatchMarkTagNew extends Command
195 184
         # 先查询出所有需要执行的客服,再按照客服来查询客户列表
196 185
         $userIdList = $params['user_id_list'];
197 186
         if (empty($userIdList)) {
198
-            if (1 == $chargeActiveType) {
199
-                $userIdList = DjUser::query()->where('corpid', $taskInfo['corpid'])->where('enable', 1)->pluck('user_id')->toArray();
200
-            } else {
201
-                $userIdList = $activeUserList;
202
-            }
187
+            $userIdList = $activeUserList;
203 188
         } else {
204 189
             $userIdList = array_intersect($params['user_id_list'], $activeUserList);
205 190
         }
@@ -230,7 +215,7 @@ class BatchMarkTagNew extends Command
230 215
                         if (!$result) {
231 216
                             Log::logError('记录写入失败', ['task_info' => $taskInfo], $this->logName);
232 217
                         } else {
233
-                            RedisModel::rPush(BatchMarkTagRecord::BATCH_MARK_TAG_RECORD, $result->id);
218
+                            RedisModel::rPush(BatchMarkTagRecord::BATCH_MARK_TAG_RECORD, json_encode(['task_id' => $taskInfo['id'], 'record' => $result->id]));
234 219
                         }
235 220
                     }
236 221
                 }

+ 3 - 1
app/Console/Kernel.php

@@ -48,6 +48,7 @@ use App\Console\Commands\CleanData;
48 48
 use App\Console\Commands\ContactChangeRecycle;
49 49
 use App\Console\Commands\CorpAccessTokenRefresh;
50 50
 use App\Console\Commands\CorpDataSync;
51
+use App\Console\Commands\CorpInformation\BatchMarkTagDeal;
51 52
 use App\Console\Commands\CorpInformation\BatchMarkTagNew;
52 53
 use App\Console\Commands\CorpInformation\CustomerPayTagDeal;
53 54
 use App\Console\Commands\CorpInformation\LossContactCntStat;
@@ -479,7 +480,8 @@ class Kernel extends ConsoleKernel
479 480
         SyncYunXuanOrder::class,                // 同步云选联盟订单
480 481
         ECommerceUserActionsDataUpload::class,  // 电商直投订单数据回传
481 482
         OrganizationAccountGet::class,          // 查询组织下的广告主信息
482
-        BatchMarkTagNew::class,                 // 客户批量打标签(新)
483
+        BatchMarkTagNew::class,                 // 客户批量打标签任务分发(新)
484
+        BatchMarkTagDeal::class,                // 客户批量打标签任务处理
483 485
     ];
484 486
 
485 487
     /**

+ 13 - 0
app/Models/BatchMarkTagRecord.php

@@ -24,4 +24,17 @@ class BatchMarkTagRecord extends Model
24 24
 
25 25
         return $model;
26 26
     }
27
+
28
+    public static function getInfoById($recordId) {
29
+        return self::query()->where('enable', 1)->where('id', $recordId)->first();
30
+    }
31
+
32
+    public static function updateData($recordId, $update) {
33
+        return self::query()->where('id', $recordId)->update($update);
34
+    }
35
+
36
+    public static function recordCount($taskId) {
37
+        $model = self::query()->where('enable', 1)->where('task_id', $taskId);
38
+        return $model->selectRaw('status, count(1) as count')->groupBy(['status'])->get();
39
+    }
27 40
 }

+ 16 - 5
app/Models/DjUser.php

@@ -224,11 +224,22 @@ class DjUser extends Model
224 224
             ->where('corpid', $corpid)->get()->pluck('user_id');
225 225
     }
226 226
 
227
-    public static function getActiveUserListById($corpid, $userIdList)  {
228
-        return self::query()->where('corpid', $corpid)->where(function($query) use($userIdList){
229
-            if(!empty($userIdList)) $query->whereIn('user_id', $userIdList);
230
-        })->where('enable', 1)->where('status', 1)->where('is_active', 1)
231
-            ->pluck('user_id');
227
+    public static function getActiveUserListById($corpid, $userIdList = null)  {
228
+        $corpInfo = AuthorizeCorp::getCorpInfo($corpid);
229
+        # 客服许可(兼容新授权到系统的企微,此种企微的客服没有许可,但是会有75天的试用期)
230
+        if(!empty($corpInfo)) {
231
+            $model = self::query()->where('corpid', $corpid)->where(function ($query) use ($userIdList) {
232
+                if (!empty($userIdList)) $query->whereIn('user_id', $userIdList);
233
+            })->where('enable', 1)->where('status', 1);
234
+
235
+            if (strtotime($corpInfo->created_at) <= strtotime('-75 days')) {
236
+                $model = $model->where('is_active', 1);
237
+            }
238
+
239
+            return $model->pluck('user_id')->toArray();
240
+        } else {
241
+            return [];
242
+        }
232 243
     }
233 244
 
234 245
     public static function getActiveUserListByPage($startId, $limit, $corpid = null) {

+ 4 - 3
app/Service/ChatGroup/ChatGroupService.php

@@ -848,9 +848,10 @@ class ChatGroupService
848 848
         Log::logInfo('start', [time()], 'syncCorpChatGroup');
849 849
         try{
850 850
             # owner_filter参数处理
851
-            $userIdList = DjUser::select(['user_id'])->where('corpid', $corpid)->where('enable', 1)
852
-                ->where('status', 1)->orderBy('id')
853
-                ->distinct()->pluck('user_id')->toArray();
851
+//            $userIdList = DjUser::select(['user_id'])->where('corpid', $corpid)->where('enable', 1)
852
+//                ->where('status', 1)->orderBy('id')
853
+//                ->distinct()->pluck('user_id')->toArray();
854
+            $userIdList = DjUser::getActiveUserListById($corpid);
854 855
 
855 856
             if(empty($userIdList)) {
856 857
                 return ['待同步成员列表为空', 2014];