Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
0.09% covered (danger)
0.09%
1 / 1098
5.00% covered (danger)
5.00%
1 / 20
CRAP
0.00% covered (danger)
0.00%
0 / 1
MagoCommand
0.09% covered (danger)
0.09%
1 / 1098
5.00% covered (danger)
5.00%
1 / 20
23192.93
0.00% covered (danger)
0.00%
0 / 1
 __construct
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 handle
0.00% covered (danger)
0.00%
0 / 4
0.00% covered (danger)
0.00%
0 / 1
2
 fixDuplicates
0.00% covered (danger)
0.00%
0 / 98
0.00% covered (danger)
0.00%
0 / 1
90
 fixShortcuts
0.00% covered (danger)
0.00%
0 / 53
0.00% covered (danger)
0.00%
0 / 1
72
 fixDaily
0.00% covered (danger)
0.00%
0 / 67
0.00% covered (danger)
0.00%
0 / 1
90
 fixWagePerHour
0.00% covered (danger)
0.00%
0 / 47
0.00% covered (danger)
0.00%
0 / 1
72
 fixPlans
0.00% covered (danger)
0.00%
0 / 69
0.00% covered (danger)
0.00%
0 / 1
90
 fixCorporateUsersOnHubspot
0.00% covered (danger)
0.00%
0 / 81
0.00% covered (danger)
0.00%
0 / 1
132
 fixEnterpriseUsersEndDate
0.00% covered (danger)
0.00%
0 / 63
0.00% covered (danger)
0.00%
0 / 1
90
 fixDeleteUsers
0.00% covered (danger)
0.00%
0 / 80
0.00% covered (danger)
0.00%
0 / 1
132
 fixPricing
0.00% covered (danger)
0.00%
0 / 99
0.00% covered (danger)
0.00%
0 / 1
420
 fixAppsumoLifePlan
0.00% covered (danger)
0.00%
0 / 51
0.00% covered (danger)
0.00%
0 / 1
42
 fixUserEmailDomainCount
0.00% covered (danger)
0.00%
0 / 51
0.00% covered (danger)
0.00%
0 / 1
42
 fixUserEmailDomain
0.00% covered (danger)
0.00%
0 / 51
0.00% covered (danger)
0.00%
0 / 1
42
 fixUserStatus
0.00% covered (danger)
0.00%
0 / 52
0.00% covered (danger)
0.00%
0 / 1
42
 fixUserAccountCreationDate
0.00% covered (danger)
0.00%
0 / 52
0.00% covered (danger)
0.00%
0 / 1
42
 fixUserUpdatedAt
0.00% covered (danger)
0.00%
0 / 52
0.00% covered (danger)
0.00%
0 / 1
42
 fixUserCreatedAt
0.00% covered (danger)
0.00%
0 / 52
0.00% covered (danger)
0.00%
0 / 1
42
 fixUserLastLogin
0.00% covered (danger)
0.00%
0 / 52
0.00% covered (danger)
0.00%
0 / 1
42
 cleanShortcutHtml
0.00% covered (danger)
0.00%
0 / 23
0.00% covered (danger)
0.00%
0 / 1
72
1<?php
2
3namespace App\Console\Commands;
4
5use App\Http\Models\Admin\Company;
6use App\Http\Models\Admin\CompanyGroup;
7use App\Http\Models\Admin\CompanyLicenses;
8use App\Http\Models\Auth\User;
9use App\Http\Models\FlyCutUsage;
10use App\Http\Models\FlyMsgUserDailyUsage;
11use App\Http\Models\HubspotProperties;
12use App\Http\Models\Plans;
13use App\Http\Models\Shortcut;
14use App\Http\Models\Subscription;
15use App\Http\Models\UserInfo;
16use App\Http\Services\HubspotServiceV2;
17use App\Http\Services\InstancyServiceV2;
18use App\Http\Services\StatisticsService;
19use App\Services\UserInfo\FlyMsgUserDailyUsageService;
20use App\Services\UserInfo\SubscriptionService;
21use App\Services\UserInfo\UserInfoService;
22use Carbon\Carbon;
23use Illuminate\Console\Command;
24use Illuminate\Support\Facades\Log;
25use MongoDB\BSON\UTCDateTime;
26use Illuminate\Support\Str;
27
28class MagoCommand extends Command
29{
30    public function __construct(
31        public UserInfoService $userInfoService,
32        public FlyMsgUserDailyUsageService $flyMsgUserDailyUsageService,
33        public StatisticsService $statisticsService,
34    ) {
35        parent::__construct();
36    }
37
38    protected $signature = 'mago {perPage} {page}';
39
40    protected $description = 'MagoCommand';
41
42    public function handle(): void
43    {
44        $this->info("MagoCommand started");
45        $totalTimeStartAt = now();
46
47        $this->fixDuplicates();
48        // $this->fixShortcuts();
49        // $this->fixDaily();
50        // $this->fixWagePerHour();
51        // $this->fixPlans();
52        // $this->fixDaily();
53        // $this->fixWagePerHour();
54        // $this->fixPlans();
55        // $this->fixCorporateUsersOnHubspot();
56        // $this->fixEnterpriseUsersEndDate();
57        // $this->fixDeleteUsers();
58        // $this->fixPricing();
59        // $this->fixAppsumoLifePlan();
60        // $this->fixUserLastLogin();
61        // $this->fixUserCreatedAt();
62        // $this->fixUserStatus();
63        // $this->fixUserEmailDomain();
64        // $this->fixUserEmailDomainCount();
65        // $this->fixUserAccountCreationDate();
66        // $this->fixUserUpdatedAt();
67
68        $this->info("MagoCommand ended with duration of " . now()->diffInSeconds($totalTimeStartAt) . " seconds");
69    }
70
71    private function fixDuplicates()
72    {
73        $perPage = $this->argument('perPage');
74        $page = $this->argument('page');
75
76        $this->info("fixDuplicates started");
77        $totalTimeStartAt = now();
78
79        ini_set('memory_limit', '-1');
80
81        $failed_users_count = 0;
82
83        // test $userIds = User::whereIsNotNull('company_id')->pluck('id')->toArray();
84
85        $pipeline = [
86            [
87                '$match' => [
88                    '$or' => [
89                        ['flymsg_freemium_subscription_status' => 'Active'],
90                        ['flymsg_growth_subscription_status' => 'Active'],
91                        ['flymsg_starter_subscription_status' => 'Active'],
92                        ['professional_subscription_status' => 'Active'],
93                        ['sales_pro_teams_subscription_status' => 'Active'],
94                    ],
95                ],
96            ],
97            [
98                '$addFields' => [
99                    'activeCount' => [
100                        '$add' => [
101                            ['$cond' => [['$eq' => ['$flymsg_freemium_subscription_status', 'Active']], 1, 0]],
102                            ['$cond' => [['$eq' => ['$flymsg_growth_subscription_status', 'Active']], 1, 0]],
103                            ['$cond' => [['$eq' => ['$flymsg_starter_subscription_status', 'Active']], 1, 0]],
104                            ['$cond' => [['$eq' => ['$professional_subscription_status', 'Active']], 1, 0]],
105                            ['$cond' => [['$eq' => ['$sales_pro_teams_subscription_status', 'Active']], 1, 0]],
106                        ],
107                    ],
108                ],
109            ],
110            [
111                '$match' => [
112                    'activeCount' => ['$gte' => 2],
113                ],
114            ],
115            [
116                '$project' => [
117                    'email' => '$email',
118                    'hubspot' => '$hubspot_id',
119                    'free' => '$flymsg_freemium_subscription_status',
120                    'growth' => '$flymsg_growth_subscription_status',
121                    'starter' => '$flymsg_starter_subscription_status',
122                    'pro' => '$professional_subscription_status',
123                    'enterprise' => '$sales_pro_teams_subscription_status',
124                    'user_id' => '$user_id',
125                    'end_free' => '$freemium_subscription_churn_date',
126                    '_id' => 0 // To remove the default _id field from the result
127                ],
128            ],
129        ];
130
131        $results = UserInfo::raw(function ($collection) use ($pipeline) {
132            return $collection->aggregate($pipeline);
133        });
134
135        $totalFlyCutUsage = count($results);
136        $this->info("Processing " . $totalFlyCutUsage . " users");
137
138        $shortcutDispatcher = Shortcut::getEventDispatcher();
139        Shortcut::unsetEventDispatcher();
140        $userInfoDispatcher = UserInfo::getEventDispatcher();
141        UserInfo::unsetEventDispatcher();
142        $userDispatcher = User::getEventDispatcher();
143        User::unsetEventDispatcher();
144        $dailyDispatcher = FlyMsgUserDailyUsage::getEventDispatcher();
145        FlyMsgUserDailyUsage::unsetEventDispatcher();
146        $flyCutDispatcher = FlyCutUsage::getEventDispatcher();
147        FlyCutUsage::unsetEventDispatcher();
148
149        foreach ($results as $userInfo) {
150            try {
151                if ($userInfo['free'] === "Active") {
152                    $subscriptionService = new SubscriptionService();
153
154                    $carbonDate = Carbon::parse($userInfo['end_free']);
155
156                    $data = $subscriptionService->endFreemiumSubscription($userInfo['user_id'], $carbonDate);
157
158                    $user = UserInfo::where('user_id', $userInfo['user_id'])->first();
159
160                    $user->update($data);
161
162                    $this->userInfoService->pushItToHubspot($user->user_id, false);
163                }
164            } catch (\Exception $e) {
165                $this->error("Failed to process flyCutUsage {$userInfo->email}" . $e->getMessage());
166                $failed_users_count++;
167            }
168
169            $totalFlyCutUsage--;
170            $this->output->write("\rRemaining flyCut Usage: " . $totalFlyCutUsage . " | Percentage: " . round(($totalFlyCutUsage / count($results)) * 100, 2) . "%", false);
171        }
172        $this->output->writeln('');
173
174        if ($shortcutDispatcher) {
175            Shortcut::setEventDispatcher($shortcutDispatcher);
176        }
177        if ($userInfoDispatcher) {
178            UserInfo::setEventDispatcher($userInfoDispatcher);
179        }
180        if ($userDispatcher) {
181            User::setEventDispatcher($userDispatcher);
182        }
183        if ($dailyDispatcher) {
184            FlyMsgUserDailyUsage::setEventDispatcher($dailyDispatcher);
185        }
186        if ($flyCutDispatcher) {
187            FlyCutUsage::setEventDispatcher($flyCutDispatcher);
188        }
189
190        $totalDurationInMinutes = now()->diffInMinutes($totalTimeStartAt);
191        $totalDurationInSeconds = now()->diffInSeconds($totalTimeStartAt);
192
193        $total = count($results);
194        $this->info("fixDuplicates completed");
195        $this->info("Total items processed: {$total}");
196        $this->info("Total duration in minutes: {$totalDurationInMinutes}");
197        $this->info("Total duration in seconds: {$totalDurationInSeconds}");
198        $this->info("Failed Count: {$failed_users_count}");
199    }
200
201    private function fixShortcuts()
202    {
203        $perPage = $this->argument('perPage');
204        $page = $this->argument('page');
205
206        $this->info("fixShortcuts started");
207        $totalTimeStartAt = now();
208
209        ini_set('memory_limit', '-1');
210
211        $failed_users_count = 0;
212
213        // test $userIds = User::whereIsNotNull('company_id')->pluck('id')->toArray();
214
215        $shortcuts = Shortcut::where('fix_user_group', null)
216            ->skip(($page - 1) * $perPage)
217            ->take($perPage)
218            ->get();
219
220        $totalFlyCutUsage = count($shortcuts);
221        $this->info("Processing " . $totalFlyCutUsage . " users");
222
223        $shortcutDispatcher = Shortcut::getEventDispatcher();
224        Shortcut::unsetEventDispatcher();
225        $userInfoDispatcher = UserInfo::getEventDispatcher();
226        UserInfo::unsetEventDispatcher();
227        $userDispatcher = User::getEventDispatcher();
228        User::unsetEventDispatcher();
229        $dailyDispatcher = FlyMsgUserDailyUsage::getEventDispatcher();
230        FlyMsgUserDailyUsage::unsetEventDispatcher();
231        $flyCutDispatcher = FlyCutUsage::getEventDispatcher();
232        FlyCutUsage::unsetEventDispatcher();
233
234        foreach ($shortcuts as $shortcut) {
235            try {
236                $shortcut->html_backup = $shortcut->html;
237                $shortcut->html = $this->cleanShortcutHtml($shortcut->html);
238                $shortcut->text_backup = $shortcut->text;
239                $shortcut->text = $this->cleanShortcutHtml($shortcut->text);
240                $shortcut->fix_user_group = true;
241                $shortcut->save();
242            } catch (\Exception $e) {
243                $this->error("Failed to process flyCutUsage {$shortcut->id}" . $e->getMessage());
244                $failed_users_count++;
245            }
246
247            $totalFlyCutUsage--;
248            $this->output->write("\rRemaining flyCut Usage: " . $totalFlyCutUsage . " | Percentage: " . round(($totalFlyCutUsage / count($shortcuts)) * 100, 2) . "%", false);
249        }
250        $this->output->writeln('');
251
252        if ($shortcutDispatcher) {
253            Shortcut::setEventDispatcher($shortcutDispatcher);
254        }
255        if ($userInfoDispatcher) {
256            UserInfo::setEventDispatcher($userInfoDispatcher);
257        }
258        if ($userDispatcher) {
259            User::setEventDispatcher($userDispatcher);
260        }
261        if ($dailyDispatcher) {
262            FlyMsgUserDailyUsage::setEventDispatcher($dailyDispatcher);
263        }
264        if ($flyCutDispatcher) {
265            FlyCutUsage::setEventDispatcher($flyCutDispatcher);
266        }
267
268        $totalDurationInMinutes = now()->diffInMinutes($totalTimeStartAt);
269        $totalDurationInSeconds = now()->diffInSeconds($totalTimeStartAt);
270
271        $total = count($shortcuts);
272        $this->info("fixShortcuts completed");
273        $this->info("Total items processed: {$total}");
274        $this->info("Total duration in minutes: {$totalDurationInMinutes}");
275        $this->info("Total duration in seconds: {$totalDurationInSeconds}");
276        $this->info("Failed Count: {$failed_users_count}");
277    }
278
279    private function fixDaily()
280    {
281        $perPage = $this->argument('perPage');
282        $page = $this->argument('page');
283
284        $this->info("fixDaily started");
285        $totalTimeStartAt = now();
286
287        ini_set('memory_limit', '-1');
288
289        $failed_users_count = 0;
290
291        // test $userIds = User::whereIsNotNull('company_id')->pluck('id')->toArray();
292
293        $users = User::where('fix_user_group', null)
294            ->where('company_id', '!=', null)
295            ->skip(($page - 1) * $perPage)
296            ->take($perPage)
297            ->get();
298
299        $totalFlyCutUsage = count($users);
300        $this->info("Processing " . $totalFlyCutUsage . " users");
301
302        $userInfoDispatcher = UserInfo::getEventDispatcher();
303        UserInfo::unsetEventDispatcher();
304        $userDispatcher = User::getEventDispatcher();
305        User::unsetEventDispatcher();
306        $dailyDispatcher = FlyMsgUserDailyUsage::getEventDispatcher();
307        FlyMsgUserDailyUsage::unsetEventDispatcher();
308        $flyCutDispatcher = FlyCutUsage::getEventDispatcher();
309        FlyCutUsage::unsetEventDispatcher();
310
311        foreach ($users as $user) {
312            try {
313                $userInfo = UserInfo::where('user_id', $user->id)->first();
314
315                $group = CompanyGroup::where('id', $userInfo->group_id)->first();
316                if ($group) {
317                    $parentGroup = CompanyGroup::where('id', $group->parent_id)->first();
318
319                    if ($parentGroup) {
320                        $userInfo->subgroup_id = $group->id;
321                        $userInfo->subgroup_name = $group->name;
322
323                        $userInfo->group_id = $parentGroup->id;
324                        $userInfo->group_name = $parentGroup->name;
325                    } else {
326                        $userInfo->group_id = $group->id;
327                        $userInfo->group_name = $group->name;
328                    }
329
330                    $userInfo->save();
331                } else {
332
333                    UserInfo::where('user_id', $user->id)
334                        ->update([
335                            '$unset' => [
336                                'group_id' => 1,
337                                'group_name' => 1,
338                                'subgroup_id' => 1,
339                                'subgroup_name' => 1,
340                            ]
341                        ]);
342                }
343
344                $user->fix_user_group = true;
345                $user->save();
346            } catch (\Exception $e) {
347                $this->error("Failed to process flyCutUsage {$user->user_id}" . $e->getMessage());
348                $failed_users_count++;
349            }
350
351            $totalFlyCutUsage--;
352            $this->output->write("\rRemaining flyCut Usage: " . $totalFlyCutUsage . " | Percentage: " . round(($totalFlyCutUsage / count($users)) * 100, 2) . "%", false);
353        }
354        $this->output->writeln('');
355
356        if ($userInfoDispatcher) {
357            UserInfo::setEventDispatcher($userInfoDispatcher);
358        }
359        if ($userDispatcher) {
360            User::setEventDispatcher($userDispatcher);
361        }
362        if ($dailyDispatcher) {
363            FlyMsgUserDailyUsage::setEventDispatcher($dailyDispatcher);
364        }
365        if ($flyCutDispatcher) {
366            FlyCutUsage::setEventDispatcher($flyCutDispatcher);
367        }
368
369        $totalDurationInMinutes = now()->diffInMinutes($totalTimeStartAt);
370        $totalDurationInSeconds = now()->diffInSeconds($totalTimeStartAt);
371
372        $total = count($users);
373        $this->info("fixDaily completed");
374        $this->info("Total items processed: {$total}");
375        $this->info("Total duration in minutes: {$totalDurationInMinutes}");
376        $this->info("Total duration in seconds: {$totalDurationInSeconds}");
377        $this->info("Failed Count: {$failed_users_count}");
378    }
379
380    private function fixWagePerHour()
381    {
382        $this->info("fixWagePerHour started");
383        $totalTimeStartAt = now();
384
385        ini_set('memory_limit', '-1');
386
387        $failed_users_count = 0;
388
389        // test $userIds = User::whereIsNotNull('company_id')->pluck('id')->toArray();
390
391        $flyCutUsages = FlyCutUsage::where('recalculated_wage_per_hour', null)->get();
392
393        $totalFlyCutUsage = count($flyCutUsages);
394        $this->info("Processing " . $totalFlyCutUsage . " fly cut usage");
395
396        $userInfoDispatcher = UserInfo::getEventDispatcher();
397        UserInfo::unsetEventDispatcher();
398        $userDispatcher = User::getEventDispatcher();
399        User::unsetEventDispatcher();
400        $dailyDispatcher = FlyMsgUserDailyUsage::getEventDispatcher();
401        FlyMsgUserDailyUsage::unsetEventDispatcher();
402        $flyCutDispatcher = FlyCutUsage::getEventDispatcher();
403        FlyCutUsage::unsetEventDispatcher();
404
405        foreach ($flyCutUsages as $flyCutUsage) {
406            try {
407                $user = User::withTrashed()->find($flyCutUsage->user_id);
408                if ($user) {
409                    $timeSaved = $this->statisticsService->getTimeSaved($user, $flyCutUsage->characters_saved);
410                    $carbonDate = Carbon::createFromFormat('Y-m-d H:i:s', $flyCutUsage->created_at);
411                    $costSaved = $this->statisticsService->getCostSaved($user, $timeSaved, $carbonDate);
412                    $flyCutUsage->time_saved = $timeSaved;
413                    $flyCutUsage->cost_saved = $costSaved;
414                    $flyCutUsage->recalculated_wage_per_hour = true;
415                    $flyCutUsage->save();
416                }
417            } catch (\Exception $e) {
418                $this->error("Failed to process flyCutUsage {$flyCutUsage->user_id}" . $e->getMessage());
419                $failed_users_count++;
420            }
421
422            $totalFlyCutUsage--;
423            $this->output->write("\rRemaining flyCut Usage: " . $totalFlyCutUsage . " | Percentage: " . round(($totalFlyCutUsage / count($flyCutUsages)) * 100, 2) . "%", false);
424        }
425        $this->output->writeln('');
426
427        if ($userInfoDispatcher) {
428            UserInfo::setEventDispatcher($userInfoDispatcher);
429        }
430        if ($userDispatcher) {
431            User::setEventDispatcher($userDispatcher);
432        }
433        if ($dailyDispatcher) {
434            FlyMsgUserDailyUsage::setEventDispatcher($dailyDispatcher);
435        }
436        if ($flyCutDispatcher) {
437            FlyCutUsage::setEventDispatcher($flyCutDispatcher);
438        }
439
440        $totalDurationInMinutes = now()->diffInMinutes($totalTimeStartAt);
441        $totalDurationInSeconds = now()->diffInSeconds($totalTimeStartAt);
442
443        $total = count($flyCutUsages);
444        $this->info("fixWagePerHour completed");
445        $this->info("Total items processed: {$total}");
446        $this->info("Total duration in minutes: {$totalDurationInMinutes}");
447        $this->info("Total duration in seconds: {$totalDurationInSeconds}");
448        $this->info("Failed Count: {$failed_users_count}");
449    }
450
451    private function fixPlans()
452    {
453        $this->info("fixPlans started");
454        $totalTimeStartAt = now();
455
456        ini_set('memory_limit', '-1');
457
458        $failed_users = [];
459        $failed_users_count = 0;
460        $added_users_count = 0;
461
462        $subscriptions = Subscription::where('jon_fix_trial_plans', null)->get();
463
464        $totalSubs = count($subscriptions);
465        $this->info("Processing " . $totalSubs . " users");
466
467        $userInfoDispatcher = UserInfo::getEventDispatcher();
468        UserInfo::unsetEventDispatcher();
469        $userDispatcher = User::getEventDispatcher();
470        User::unsetEventDispatcher();
471        $dailyDispatcher = FlyMsgUserDailyUsage::getEventDispatcher();
472        FlyMsgUserDailyUsage::unsetEventDispatcher();
473        $subscriptionService = new SubscriptionService();
474
475        foreach ($subscriptions as $sub) {
476            $userStarted = now();
477            try {
478                $user_info = UserInfo::where('user_id', $sub->user_id)->first();
479                if (!$user_info) {
480                    continue;
481                }
482
483                $fields = $sub->toArray();
484                $result = $subscriptionService->endSubscription($fields, $sub, false, $sub->ends_at);
485                $user_info->fill($result);
486                $fields = $sub->toArray();
487                $result = $subscriptionService->startSubscription($fields, $sub);
488                $user_info->fill($result);
489                $haveActiveSubscription = Subscription::where('user_id', $sub->user_id)->where('stripe_status', 'active')->count() > 0;
490                if (!$haveActiveSubscription) {
491                    $user_info->fill($subscriptionService->initFreemiumSubscription($sub->user_id));
492                }
493
494                $user_info->save();
495                $sub->jon_fix_trial_plans = true;
496                $sub->save();
497                $this->userInfoService->pushItToHubspot($sub->user_id, false);
498                $added_users_count++;
499            } catch (\Exception $e) {
500                $this->error("Failed to process subscription {$sub->stripe_plan}" . $e->getMessage());
501                $failed_users[] = [
502                    'user_id' => $sub->stripe_plan,
503                    'email' => $sub->user_id,
504                    'error' => $e->getMessage(),
505                ];
506                $failed_users_count++;
507            }
508
509            $durationInMilliseconds = now()->diffInMilliseconds($userStarted);
510
511            // if short than 150 milliseconds, sleep until 150 milliseconds
512            if ($durationInMilliseconds < 150) {
513                usleep(150000 - $durationInMilliseconds);
514            }
515
516            $totalSubs--;
517            $this->output->write("\rRemaining subscriptions: " . $totalSubs . " | Percentage: " . round(($totalSubs / count($subscriptions)) * 100, 2) . "%", false);
518        }
519        $this->output->writeln('');
520
521        if ($userInfoDispatcher) {
522            UserInfo::setEventDispatcher($userInfoDispatcher);
523        }
524        if ($userDispatcher) {
525            User::setEventDispatcher($userDispatcher);
526        }
527        if ($dailyDispatcher) {
528            FlyMsgUserDailyUsage::setEventDispatcher($dailyDispatcher);
529        }
530
531        $totalDurationInMinutes = now()->diffInMinutes($totalTimeStartAt);
532        $totalDurationInSeconds = now()->diffInSeconds($totalTimeStartAt);
533
534        Log::info("fixPlans completed", [
535            'completed_subscriptions_count' => $added_users_count,
536            'total_duration_in_minutes' => $totalDurationInMinutes,
537            'total_duration_in_seconds' => $totalDurationInSeconds,
538            'failed_subs_count' => $failed_users_count,
539            'failed_subs' => $failed_users,
540        ]);
541
542        $this->info("fixPlans completed");
543        $this->info("Total duration in minutes: {$totalDurationInMinutes}");
544        $this->info("Total duration in seconds: {$totalDurationInSeconds}");
545        $this->info("Completed subs: {$added_users_count}");
546        $this->info("Failed subs: {$failed_users_count}");
547    }
548
549    private function fixCorporateUsersOnHubspot()
550    {
551        $this->info("fixCorporateUsersOnHubspot started");
552        $totalTimeStartAt = now();
553
554        ini_set('memory_limit', '-1');
555
556        $failed_users = [];
557        $failed_users_count = 0;
558        $added_users_count = 0;
559
560        $users = User::where('company_id', '!=', null)->where('mago_reprocess', null)->get();
561
562        $totalUsers = count($users);
563        $this->info("Processing " . $totalUsers . " users");
564
565        $userInfoDispatcher = UserInfo::getEventDispatcher();
566        UserInfo::unsetEventDispatcher();
567        $userDispatcher = User::getEventDispatcher();
568        User::unsetEventDispatcher();
569        $dailyDispatcher = FlyMsgUserDailyUsage::getEventDispatcher();
570        FlyMsgUserDailyUsage::unsetEventDispatcher();
571        $subscriptionService = new SubscriptionService();
572
573        foreach ($users as $user) {
574            $userStarted = now();
575            try {
576                $user_info = UserInfo::where('user_id', $user->id)->first();
577
578                #region Licenses
579                #region Inactive Subscriptions
580                $inactiveSubscriptions = Subscription::where('user_id', $user->id)
581                    ->where('stripe_status', '!=', 'active')
582                    ->orderBy('created_at', 'asc')
583                    ->get();
584                foreach ($inactiveSubscriptions as $subscription) {
585                    $fields = $subscription->toArray();
586                    $result = $subscriptionService->endSubscription($fields, $subscription);
587                    $user_info->fill($result);
588                }
589                #endregion
590
591                #region Active Subscriptions
592                $activeSubscriptions = Subscription::where('user_id', $user->id)
593                    ->where('stripe_status', 'active')
594                    ->orderBy('created_at', 'asc')
595                    ->get();
596
597                $haveActiveSubscription = false;
598
599                foreach ($activeSubscriptions as $subscription) {
600                    $fields = $subscription->toArray();
601                    $result = $subscriptionService->startSubscription($fields, $subscription);
602                    $user_info->fill($result);
603                    $haveActiveSubscription = true;
604                }
605
606                if (!$haveActiveSubscription) {
607                    $user_info->fill($subscriptionService->initFreemiumSubscription($user->id));
608                }
609                #endregion
610                #endregion
611                if (empty($user->signup_source)) {
612                    $user->signup_source = $user_info->signup_source ?? $user_info->signin_source;
613                }
614                $user_info->signup_source = $user->signup_source;
615                $user_info->save();
616                $user->mago_reprocess = true;
617                $user->save();
618                $this->userInfoService->pushItToHubspot($user->id, false);
619                $added_users_count++;
620            } catch (\Exception $e) {
621                $this->error("Failed to process user {$user->email}" . $e->getMessage());
622                $failed_users[] = [
623                    'user_id' => $user->id,
624                    'email' => $user->email,
625                    'error' => $e->getMessage(),
626                ];
627                $failed_users_count++;
628            }
629
630            $durationInMilliseconds = now()->diffInMilliseconds($userStarted);
631
632            // if short than 150 milliseconds, sleep until 150 milliseconds
633            if ($durationInMilliseconds < 150) {
634                usleep(150000 - $durationInMilliseconds);
635            }
636
637            $totalUsers--;
638            $this->output->write("\rRemaining users: " . $totalUsers . " | Percentage: " . round(($totalUsers / count($users)) * 100, 2) . "%", false);
639        }
640        $this->output->writeln('');
641
642        if ($userInfoDispatcher) {
643            UserInfo::setEventDispatcher($userInfoDispatcher);
644        }
645        if ($userDispatcher) {
646            User::setEventDispatcher($userDispatcher);
647        }
648        if ($dailyDispatcher) {
649            FlyMsgUserDailyUsage::setEventDispatcher($dailyDispatcher);
650        }
651
652        $totalDurationInMinutes = now()->diffInMinutes($totalTimeStartAt);
653        $totalDurationInSeconds = now()->diffInSeconds($totalTimeStartAt);
654
655        Log::info("fixCorporateUsersOnHubspot completed", [
656            'completed_users_count' => $added_users_count,
657            'total_duration_in_minutes' => $totalDurationInMinutes,
658            'total_duration_in_seconds' => $totalDurationInSeconds,
659            'failed_users_count' => $failed_users_count,
660            'failed_users' => $failed_users,
661        ]);
662
663        $this->info("fixCorporateUsersOnHubspot completed");
664        $this->info("Total duration in minutes: {$totalDurationInMinutes}");
665        $this->info("Total duration in seconds: {$totalDurationInSeconds}");
666        $this->info("Completed users: {$added_users_count}");
667        $this->info("Failed users: {$failed_users_count}");
668    }
669
670    private function fixEnterpriseUsersEndDate()
671    {
672        $this->info("fixEnterpriseUsersEndDate started");
673        $totalTimeStartAt = now();
674
675        ini_set('memory_limit', '-1');
676
677        $failed_users = [];
678        $failed_users_count = 0;
679        $added_users_count = 0;
680
681        $users = User::whereNotNull('company_id')->get();
682
683        $totalUsers = count($users);
684        $this->info("Processing " . $totalUsers . " users");
685
686        $userInfoDispatcher = UserInfo::getEventDispatcher();
687        UserInfo::unsetEventDispatcher();
688        $userDispatcher = User::getEventDispatcher();
689        User::unsetEventDispatcher();
690        $dailyDispatcher = FlyMsgUserDailyUsage::getEventDispatcher();
691        FlyMsgUserDailyUsage::unsetEventDispatcher();
692
693        $instancyService = new InstancyServiceV2();
694        foreach ($users as $user) {
695            $userStarted = now();
696            try {
697                $company = Company::find($user->company_id);
698                $companyLicense = CompanyLicenses::where('company_id', $company->id)->first();
699                $endDate = Carbon::parse($companyLicense->contract_end_date); //contract_end_date
700
701                $subscription = Subscription::where('user_id', $user->id)->where('stripe_status', 'active')->first();
702                if ($subscription) {
703                    $subscription->ends_at = new UTCDateTime($endDate->getTimestamp() * 1000);
704                    $subscription->save();
705
706                    $plan = Plans::where('stripe_id', $subscription->stripe_plan)->first();
707
708                    if (Str::contains($plan->identifier, 'pro')) {
709                        $instancyService->updateMembership($user->email, $endDate->subDay()->toDateString());
710                    }
711                }
712
713                $added_users_count++;
714            } catch (\Exception $e) {
715                $this->error("Failed to process user {$user->email}" . $e->getMessage());
716                $failed_users[] = [
717                    'user_id' => $user->id,
718                    'email' => $user->email,
719                    'error' => $e->getMessage(),
720                ];
721                $failed_users_count++;
722            }
723
724            $durationInMilliseconds = now()->diffInMilliseconds($userStarted);
725
726            // if short than 150 milliseconds, sleep until 150 milliseconds
727            if ($durationInMilliseconds < 150) {
728                usleep(150000 - $durationInMilliseconds);
729            }
730
731            $totalUsers--;
732            $this->output->write("\rRemaining users: " . $totalUsers . " | Percentage: " . round(($totalUsers / count($users)) * 100, 2) . "%", false);
733        }
734        $this->output->writeln('');
735
736        if ($userInfoDispatcher) {
737            UserInfo::setEventDispatcher($userInfoDispatcher);
738        }
739        if ($userDispatcher) {
740            User::setEventDispatcher($userDispatcher);
741        }
742        if ($dailyDispatcher) {
743            FlyMsgUserDailyUsage::setEventDispatcher($dailyDispatcher);
744        }
745
746        $totalDurationInMinutes = now()->diffInMinutes($totalTimeStartAt);
747        $totalDurationInSeconds = now()->diffInSeconds($totalTimeStartAt);
748
749        Log::info("fixUserEmailDomainCount completed", [
750            'completed_users_count' => $added_users_count,
751            'total_duration_in_minutes' => $totalDurationInMinutes,
752            'total_duration_in_seconds' => $totalDurationInSeconds,
753            'failed_users_count' => $failed_users_count,
754            'failed_users' => $failed_users,
755        ]);
756
757        $this->info("fixEnterpriseUsersEndDate completed");
758        $this->info("Total duration in minutes: {$totalDurationInMinutes}");
759        $this->info("Total duration in seconds: {$totalDurationInSeconds}");
760        $this->info("Completed users: {$added_users_count}");
761        $this->info("Failed users: {$failed_users_count}");
762    }
763
764    private function fixDeleteUsers()
765    {
766        $this->info("fixDeleteUsers started");
767        $totalTimeStartAt = now();
768
769        ini_set('memory_limit', '-1');
770
771        $failed_users = [];
772        $failed_users_count = 0;
773        $added_users_count = 0;
774
775        $users = User::withTrashed()->whereNotNull('deleted_at')->get();
776
777        $totalUsers = count($users);
778        $this->info("Processing " . $totalUsers . " users");
779
780        $userInfoDispatcher = UserInfo::getEventDispatcher();
781        UserInfo::unsetEventDispatcher();
782        $userDispatcher = User::getEventDispatcher();
783        User::unsetEventDispatcher();
784        $dailyDispatcher = FlyMsgUserDailyUsage::getEventDispatcher();
785        FlyMsgUserDailyUsage::unsetEventDispatcher();
786
787        foreach ($users as $user) {
788            $userStarted = now();
789            try {
790                $cancellation_date = new UTCDateTime($user->deleted_at->getTimestamp() * 1000);
791
792                $userInfo = UserInfo::where('user_id', $user->id)->first();
793
794                if (!$userInfo || !empty($userInfo->deleted_at) || empty($user->hubspot_id)) {
795                    continue;
796                }
797
798                (new HubspotServiceV2())->updateHubspotOptOutProperty($user->email);
799
800                // if not includes delete_from_flymsg_ then add it
801                $delete_from_flymsg_email = $user->email;
802                if (strpos($user->email, 'delete_from_flymsg_') === false) {
803                    $delete_from_flymsg_email = "delete_from_flymsg_$user->email";
804                }
805                $data = [
806                    'deleted_at' => $cancellation_date,
807                    'status' => 'Delete',
808                    'subscription_type' => 'Deleted Profile from FlyMSG',
809                    'email' => $delete_from_flymsg_email,
810                    'first_name' => "",
811                    'last_name' => "",
812                    'full_name' => "",
813                    'email_used_for_login' => "",
814                    'avatar' => "",
815                    'job_role' => "",
816                    'department' => "",
817                    'company' => ""
818                ];
819
820                $subscriptionService = new SubscriptionService();
821
822                $endFreemiumData = $subscriptionService->endFreemiumSubscription($user->id, $user->deleted_at);
823
824                $data = array_merge($data, $endFreemiumData);
825
826                $userInfo->update($data);
827
828                //////////
829
830                $user->save();
831                $this->userInfoService->pushItToHubspot($user->id, false);
832                $added_users_count++;
833            } catch (\Exception $e) {
834                $this->error("Failed to process user {$user->email}" . $e->getMessage());
835                $failed_users[] = [
836                    'user_id' => $user->id,
837                    'email' => $user->email,
838                    'error' => $e->getMessage(),
839                ];
840                $failed_users_count++;
841            }
842
843            $durationInMilliseconds = now()->diffInMilliseconds($userStarted);
844
845            // if short than 150 milliseconds, sleep until 150 milliseconds
846            if ($durationInMilliseconds < 150) {
847                usleep(150000 - $durationInMilliseconds);
848            }
849
850            $totalUsers--;
851            $this->output->write("\rRemaining users: " . $totalUsers . " | Percentage: " . round(($totalUsers / count($users)) * 100, 2) . "%", false);
852        }
853        $this->output->writeln('');
854
855        if ($userInfoDispatcher) {
856            UserInfo::setEventDispatcher($userInfoDispatcher);
857        }
858        if ($userDispatcher) {
859            User::setEventDispatcher($userDispatcher);
860        }
861        if ($dailyDispatcher) {
862            FlyMsgUserDailyUsage::setEventDispatcher($dailyDispatcher);
863        }
864
865        $totalDurationInMinutes = now()->diffInMinutes($totalTimeStartAt);
866        $totalDurationInSeconds = now()->diffInSeconds($totalTimeStartAt);
867
868        Log::info("fixUserEmailDomainCount completed", [
869            'completed_users_count' => $added_users_count,
870            'total_duration_in_minutes' => $totalDurationInMinutes,
871            'total_duration_in_seconds' => $totalDurationInSeconds,
872            'failed_users_count' => $failed_users_count,
873            'failed_users' => $failed_users,
874        ]);
875
876        $this->info("fixUserEmailDomainCount completed");
877        $this->info("Total duration in minutes: {$totalDurationInMinutes}");
878        $this->info("Total duration in seconds: {$totalDurationInSeconds}");
879        $this->info("Completed users: {$added_users_count}");
880        $this->info("Failed users: {$failed_users_count}");
881    }
882
883    private function fixPricing()
884    {
885        $this->info("fixPricing started");
886        $totalTimeStartAt = now();
887
888        ini_set('memory_limit', '-1');
889
890        $failed_users = [];
891        $failed_users_count = 0;
892        $added_users_count = 0;
893
894        $users = UserInfo::where('mago_fixing_prices', null)->get();
895        // $users = UserInfo::where('email', 'steve@executivesalescoaching.com.au')->get();
896
897        $totalUsers = count($users);
898        $this->info("Processing " . $totalUsers . " users");
899
900        $userInfoDispatcher = UserInfo::getEventDispatcher();
901        UserInfo::unsetEventDispatcher();
902        $userDispatcher = User::getEventDispatcher();
903        User::unsetEventDispatcher();
904        $dailyDispatcher = FlyMsgUserDailyUsage::getEventDispatcher();
905        FlyMsgUserDailyUsage::unsetEventDispatcher();
906
907        foreach ($users as $user) {
908            $userStarted = now();
909            try {
910                $hubspotProperties = HubspotProperties::where('flymsg_id', $user->user_id)->first();
911                $result = [];
912
913                #region Inactive Subscriptions
914                $inactiveSubscriptions = Subscription::where('user_id', $user->user_id)
915                    ->where('stripe_status', '!=', 'active')
916                    ->orderBy('created_at', 'asc')
917                    ->get();
918                foreach ($inactiveSubscriptions as $subscription) {
919                    $plan = Plans::where('stripe_id', $subscription->stripe_plan)->first();
920
921                    if (!empty($hubspotProperties) && !empty($hubspotProperties[$plan->hubspot_subscription_monthly_recurring_revenue])) {
922                        $result[$plan->hubspot_subscription_monthly_recurring_revenue] = $hubspotProperties[$plan->hubspot_subscription_monthly_recurring_revenue];
923                    }
924                }
925                #endregion
926
927                #region Active Subscriptions
928                $activeSubscriptions = Subscription::where('user_id', $user->user_id)
929                    ->where('stripe_status', 'active')
930                    ->orderBy('created_at', 'asc')
931                    ->get();
932
933                foreach ($activeSubscriptions as $subscription) {
934                    $useruser = User::find($user->user_id);
935
936                    $trialEndsAt = $subscription->trial_ends_at;
937                    $invoices = $useruser->invoices()->toArray();
938                    $invoices = array_reverse($invoices);
939                    $plan = Plans::where('stripe_id', $subscription->stripe_plan)->first();
940
941                    // Two  diffrent plans handle
942                    foreach ($invoices as $i => $invoice) {
943                        $invoiceDataIndex = $invoice['lines']['total_count'] > 0 ? $invoice['lines']['total_count'] - 1 : 0;
944                        if (empty($invoice['lines']['data'][$invoiceDataIndex]['subscription']) && $invoice['billing_reason'] == 'manual') {
945                            $this->info("No subscription is associated with invoice id: {$invoice['id']}");
946                            continue;
947                        }
948
949                        $interval = $invoice['lines']['data'][$invoiceDataIndex]['plan']['interval'];
950
951                        $price = $invoice['lines']['data'][$invoiceDataIndex]['price']['unit_amount_decimal'] / 100;
952
953                        if ($interval == "month") {
954                            $interval = 'Monthly';
955                            $annual_recurring_revenue = $price * 12;
956                            $monthly_recurring_revenue = $price;
957                        } else {
958                            $interval = 'Annual';
959                            $annual_recurring_revenue = $price;
960                            $monthly_recurring_revenue = $price / 12;
961                        }
962
963                        if (isset($plan->identifier) && $plan->identifier == 'sales-pro-monthly' && isset($trialEndsAt)) {
964                            $annual_recurring_revenue = 0;
965                            $monthly_recurring_revenue = 0;
966                        }
967                    }
968
969                    $result[$plan->hubspot_subscription_monthly_recurring_revenue] = $monthly_recurring_revenue;
970                    $result[$plan->hubspot_subscription_annual_recurring_revenue] = $annual_recurring_revenue;
971
972                    if ($plan->identifier == 'appsumo-growth-lifetime') {
973                        $result['flymsg_growth_subscription_monthly_recurring_revenue'] = 4;
974                        $result['growth_subscription_annual_recurring_revenue'] = 48;
975                    }
976
977                    $user->fill($result);
978                }
979                #endregion
980
981                $user->save();
982                $this->userInfoService->pushItToHubspot($user->user_id, false);
983                $user->mago_fixing_prices = true;
984                $user->save();
985                $added_users_count++;
986            } catch (\Exception $e) {
987                $this->error("Failed to process user {$user->email}" . $e->getMessage());
988                $failed_users[] = [
989                    'user_id' => $user->id,
990                    'email' => $user->email,
991                    'error' => $e->getMessage(),
992                ];
993                $failed_users_count++;
994            }
995
996            $durationInMilliseconds = now()->diffInMilliseconds($userStarted);
997
998            // if short than 150 milliseconds, sleep until 150 milliseconds
999            if ($durationInMilliseconds < 150) {
1000                usleep(150000 - $durationInMilliseconds);
1001            }
1002
1003            $totalUsers--;
1004            $this->output->write("\rRemaining users: " . $totalUsers . " | Percentage: " . round(($totalUsers / count($users)) * 100, 2) . "%", false);
1005        }
1006        $this->output->writeln('');
1007
1008        if ($userInfoDispatcher) {
1009            UserInfo::setEventDispatcher($userInfoDispatcher);
1010        }
1011        if ($userDispatcher) {
1012            User::setEventDispatcher($userDispatcher);
1013        }
1014        if ($dailyDispatcher) {
1015            FlyMsgUserDailyUsage::setEventDispatcher($dailyDispatcher);
1016        }
1017
1018        $totalDurationInMinutes = now()->diffInMinutes($totalTimeStartAt);
1019        $totalDurationInSeconds = now()->diffInSeconds($totalTimeStartAt);
1020
1021        Log::info("fixUserEmailDomainCount completed", [
1022            'completed_users_count' => $added_users_count,
1023            'total_duration_in_minutes' => $totalDurationInMinutes,
1024            'total_duration_in_seconds' => $totalDurationInSeconds,
1025            'failed_users_count' => $failed_users_count,
1026            'failed_users' => $failed_users,
1027        ]);
1028
1029        $this->info("fixUserEmailDomainCount completed");
1030        $this->info("Total duration in minutes: {$totalDurationInMinutes}");
1031        $this->info("Total duration in seconds: {$totalDurationInSeconds}");
1032        $this->info("Completed users: {$added_users_count}");
1033        $this->info("Failed users: {$failed_users_count}");
1034    }
1035
1036    private function fixAppsumoLifePlan()
1037    {
1038        $this->info("fixUserEmailDomainCount started");
1039        $totalTimeStartAt = now();
1040
1041        ini_set('memory_limit', '-1');
1042
1043        $failed_users = [];
1044        $failed_users_count = 0;
1045        $added_users_count = 0;
1046
1047        $users = UserInfo::where('plan_name', 'Growth Lifetime Access Plan - AppSumo')->get();
1048
1049        $totalUsers = count($users);
1050        $this->info("Processing " . $totalUsers . " users");
1051
1052        $userInfoDispatcher = UserInfo::getEventDispatcher();
1053        UserInfo::unsetEventDispatcher();
1054        $userDispatcher = User::getEventDispatcher();
1055        User::unsetEventDispatcher();
1056        $dailyDispatcher = FlyMsgUserDailyUsage::getEventDispatcher();
1057        FlyMsgUserDailyUsage::unsetEventDispatcher();
1058
1059
1060        foreach ($users as $user) {
1061            try {
1062                $user->appsumo_flymsg_lifetime_access = 'true';
1063                // $user['flymsg_growth_subscription_monthly_recurring_revenue'] = 4;
1064                // $user['growth_subscription_annual_recurring_revenue'] = 48;
1065                $user->save();
1066                $this->userInfoService->pushItToHubspot($user->user_id, false);
1067                $added_users_count++;
1068            } catch (\Exception $e) {
1069                $this->error("Failed to process user {$user->email}" . $e->getMessage());
1070                $failed_users[] = [
1071                    'user_id' => $user->id,
1072                    'email' => $user->email,
1073                    'error' => $e->getMessage(),
1074                ];
1075                $failed_users_count++;
1076            }
1077
1078            $totalUsers--;
1079            $this->output->write("\rRemaining users: " . $totalUsers . " | Percentage: " . round(($totalUsers / count($users)) * 100, 2) . "%", false);
1080        }
1081        $this->output->writeln('');
1082
1083        if ($userInfoDispatcher) {
1084            UserInfo::setEventDispatcher($userInfoDispatcher);
1085        }
1086        if ($userDispatcher) {
1087            User::setEventDispatcher($userDispatcher);
1088        }
1089        if ($dailyDispatcher) {
1090            FlyMsgUserDailyUsage::setEventDispatcher($dailyDispatcher);
1091        }
1092
1093        $totalDurationInMinutes = now()->diffInMinutes($totalTimeStartAt);
1094        $totalDurationInSeconds = now()->diffInSeconds($totalTimeStartAt);
1095
1096        Log::info("fixUserEmailDomainCount completed", [
1097            'completed_users_count' => $added_users_count,
1098            'total_duration_in_minutes' => $totalDurationInMinutes,
1099            'total_duration_in_seconds' => $totalDurationInSeconds,
1100            'failed_users_count' => $failed_users_count,
1101            'failed_users' => $failed_users,
1102        ]);
1103
1104        $this->info("fixUserEmailDomainCount completed");
1105        $this->info("Total duration in minutes: {$totalDurationInMinutes}");
1106        $this->info("Total duration in seconds: {$totalDurationInSeconds}");
1107        $this->info("Completed users: {$added_users_count}");
1108        $this->info("Failed users: {$failed_users_count}");
1109    }
1110
1111    private function fixUserEmailDomainCount()
1112    {
1113        $this->info("fixUserEmailDomainCount started");
1114        $totalTimeStartAt = now();
1115
1116        ini_set('memory_limit', '-1');
1117
1118        $failed_users = [];
1119        $failed_users_count = 0;
1120        $added_users_count = 0;
1121
1122        $users = UserInfo::get();
1123
1124        $totalUsers = count($users);
1125        $this->info("Processing " . $totalUsers . " users");
1126
1127        $userInfoDispatcher = UserInfo::getEventDispatcher();
1128        UserInfo::unsetEventDispatcher();
1129        $userDispatcher = User::getEventDispatcher();
1130        User::unsetEventDispatcher();
1131        $dailyDispatcher = FlyMsgUserDailyUsage::getEventDispatcher();
1132        FlyMsgUserDailyUsage::unsetEventDispatcher();
1133
1134        foreach ($users as $user) {
1135            try {
1136                $user->email_domain_count = User::where('email', 'like', '%' . $user->email_domain)->count();
1137                $user->last_update_usage_at = new UTCDateTime(now()->getTimestamp() * 1000);
1138                $user->save();
1139                $added_users_count++;
1140            } catch (\Exception $e) {
1141                $this->error("Failed to process user {$user->email}" . $e->getMessage());
1142                $failed_users[] = [
1143                    'user_id' => $user->id,
1144                    'email' => $user->email,
1145                    'error' => $e->getMessage(),
1146                ];
1147                $failed_users_count++;
1148            }
1149
1150            $totalUsers--;
1151            $this->output->write("\rRemaining users: " . $totalUsers . " | Percentage: " . round(($totalUsers / count($users)) * 100, 2) . "%", false);
1152        }
1153        $this->output->writeln('');
1154
1155        if ($userInfoDispatcher) {
1156            UserInfo::setEventDispatcher($userInfoDispatcher);
1157        }
1158        if ($userDispatcher) {
1159            User::setEventDispatcher($userDispatcher);
1160        }
1161        if ($dailyDispatcher) {
1162            FlyMsgUserDailyUsage::setEventDispatcher($dailyDispatcher);
1163        }
1164
1165        $totalDurationInMinutes = now()->diffInMinutes($totalTimeStartAt);
1166        $totalDurationInSeconds = now()->diffInSeconds($totalTimeStartAt);
1167
1168        Log::info("fixUserEmailDomainCount completed", [
1169            'completed_users_count' => $added_users_count,
1170            'total_duration_in_minutes' => $totalDurationInMinutes,
1171            'total_duration_in_seconds' => $totalDurationInSeconds,
1172            'failed_users_count' => $failed_users_count,
1173            'failed_users' => $failed_users,
1174        ]);
1175
1176        $this->info("fixUserEmailDomainCount completed");
1177        $this->info("Total duration in minutes: {$totalDurationInMinutes}");
1178        $this->info("Total duration in seconds: {$totalDurationInSeconds}");
1179        $this->info("Completed users: {$added_users_count}");
1180        $this->info("Failed users: {$failed_users_count}");
1181    }
1182
1183    private function fixUserEmailDomain()
1184    {
1185        $this->info("fixUserEmailDomain started");
1186        $totalTimeStartAt = now();
1187
1188        ini_set('memory_limit', '-1');
1189
1190        $failed_users = [];
1191        $failed_users_count = 0;
1192        $added_users_count = 0;
1193
1194        $users = UserInfo::get();
1195
1196        $totalUsers = count($users);
1197        $this->info("Processing " . $totalUsers . " users");
1198
1199        $userInfoDispatcher = UserInfo::getEventDispatcher();
1200        UserInfo::unsetEventDispatcher();
1201        $userDispatcher = User::getEventDispatcher();
1202        User::unsetEventDispatcher();
1203        $dailyDispatcher = FlyMsgUserDailyUsage::getEventDispatcher();
1204        FlyMsgUserDailyUsage::unsetEventDispatcher();
1205
1206        foreach ($users as $user) {
1207            try {
1208                $user->email_domain = '@' . substr(strrchr($user->email, "@"), 1);
1209                $user->last_update_usage_at = new UTCDateTime(now()->getTimestamp() * 1000);
1210                $user->save();
1211                $added_users_count++;
1212            } catch (\Exception $e) {
1213                $this->error("Failed to process user {$user->email}" . $e->getMessage());
1214                $failed_users[] = [
1215                    'user_id' => $user->id,
1216                    'email' => $user->email,
1217                    'error' => $e->getMessage(),
1218                ];
1219                $failed_users_count++;
1220            }
1221
1222            $totalUsers--;
1223            $this->output->write("\rRemaining users: " . $totalUsers . " | Percentage: " . round(($totalUsers / count($users)) * 100, 2) . "%", false);
1224        }
1225        $this->output->writeln('');
1226
1227        if ($userInfoDispatcher) {
1228            UserInfo::setEventDispatcher($userInfoDispatcher);
1229        }
1230        if ($userDispatcher) {
1231            User::setEventDispatcher($userDispatcher);
1232        }
1233        if ($dailyDispatcher) {
1234            FlyMsgUserDailyUsage::setEventDispatcher($dailyDispatcher);
1235        }
1236
1237        $totalDurationInMinutes = now()->diffInMinutes($totalTimeStartAt);
1238        $totalDurationInSeconds = now()->diffInSeconds($totalTimeStartAt);
1239
1240        Log::info("fixUserEmailDomain completed", [
1241            'completed_users_count' => $added_users_count,
1242            'total_duration_in_minutes' => $totalDurationInMinutes,
1243            'total_duration_in_seconds' => $totalDurationInSeconds,
1244            'failed_users_count' => $failed_users_count,
1245            'failed_users' => $failed_users,
1246        ]);
1247
1248        $this->info("fixUserEmailDomain completed");
1249        $this->info("Total duration in minutes: {$totalDurationInMinutes}");
1250        $this->info("Total duration in seconds: {$totalDurationInSeconds}");
1251        $this->info("Completed users: {$added_users_count}");
1252        $this->info("Failed users: {$failed_users_count}");
1253    }
1254
1255    private function fixUserStatus()
1256    {
1257        $this->info("fixUserStatus started");
1258        $totalTimeStartAt = now();
1259
1260        ini_set('memory_limit', '-1');
1261
1262        $failed_users = [];
1263        $failed_users_count = 0;
1264        $added_users_count = 0;
1265
1266        $users = UserInfo::whereNull('status')->get();
1267
1268        $totalUsers = count($users);
1269        $this->info("Processing " . $totalUsers . " users");
1270
1271        $userInfoDispatcher = UserInfo::getEventDispatcher();
1272        UserInfo::unsetEventDispatcher();
1273        $userDispatcher = User::getEventDispatcher();
1274        User::unsetEventDispatcher();
1275        $dailyDispatcher = FlyMsgUserDailyUsage::getEventDispatcher();
1276        FlyMsgUserDailyUsage::unsetEventDispatcher();
1277
1278        foreach ($users as $user) {
1279            try {
1280                $realUser = User::find($user->user_id);
1281                $user->status = $realUser->status ?? 'Active';
1282                $user->last_update_usage_at = new UTCDateTime(now()->getTimestamp() * 1000);
1283                $user->save();
1284                $added_users_count++;
1285            } catch (\Exception $e) {
1286                $this->error("Failed to process user {$user->email}" . $e->getMessage());
1287                $failed_users[] = [
1288                    'user_id' => $user->id,
1289                    'email' => $user->email,
1290                    'error' => $e->getMessage(),
1291                ];
1292                $failed_users_count++;
1293            }
1294
1295            $totalUsers--;
1296            $this->output->write("\rRemaining users: " . $totalUsers . " | Percentage: " . round(($totalUsers / count($users)) * 100, 2) . "%", false);
1297        }
1298
1299        $this->output->writeln('');
1300
1301        if ($userInfoDispatcher) {
1302            UserInfo::setEventDispatcher($userInfoDispatcher);
1303        }
1304        if ($userDispatcher) {
1305            User::setEventDispatcher($userDispatcher);
1306        }
1307        if ($dailyDispatcher) {
1308            FlyMsgUserDailyUsage::setEventDispatcher($dailyDispatcher);
1309        }
1310
1311        $totalDurationInMinutes = now()->diffInMinutes($totalTimeStartAt);
1312        $totalDurationInSeconds = now()->diffInSeconds($totalTimeStartAt);
1313
1314        Log::info("fixUserStatus completed", [
1315            'completed_users_count' => $added_users_count,
1316            'total_duration_in_minutes' => $totalDurationInMinutes,
1317            'total_duration_in_seconds' => $totalDurationInSeconds,
1318            'failed_users_count' => $failed_users_count,
1319            'failed_users' => $failed_users,
1320        ]);
1321
1322        $this->info("fixUserStatus completed");
1323        $this->info("Total duration in minutes: {$totalDurationInMinutes}");
1324        $this->info("Total duration in seconds: {$totalDurationInSeconds}");
1325        $this->info("Completed users: {$added_users_count}");
1326        $this->info("Failed users: {$failed_users_count}");
1327    }
1328
1329    private function fixUserAccountCreationDate()
1330    {
1331        $this->info("fixUserAccountCreationDate started");
1332        $totalTimeStartAt = now();
1333
1334        ini_set('memory_limit', '-1');
1335
1336        $failed_users = [];
1337        $failed_users_count = 0;
1338        $added_users_count = 0;
1339
1340        $users = UserInfo::where('account_creation_date', '$type', 'string')->get();
1341
1342        $totalUsers = count($users);
1343        $this->info("Processing " . $totalUsers . " users");
1344
1345        $userInfoDispatcher = UserInfo::getEventDispatcher();
1346        UserInfo::unsetEventDispatcher();
1347        $userDispatcher = User::getEventDispatcher();
1348        User::unsetEventDispatcher();
1349        $dailyDispatcher = FlyMsgUserDailyUsage::getEventDispatcher();
1350        FlyMsgUserDailyUsage::unsetEventDispatcher();
1351
1352        foreach ($users as $user) {
1353            try {
1354                $carbonDate = Carbon::parse($user->account_creation_date);
1355                $user->account_creation_date = new UTCDateTime($carbonDate->getTimestamp() * 1000);
1356                $user->last_update_usage_at = new UTCDateTime(now()->getTimestamp() * 1000);
1357                $user->save();
1358                $added_users_count++;
1359            } catch (\Exception $e) {
1360                $this->error("Failed to process user {$user->email}" . $e->getMessage());
1361                $failed_users[] = [
1362                    'user_id' => $user->id,
1363                    'email' => $user->email,
1364                    'error' => $e->getMessage(),
1365                ];
1366                $failed_users_count++;
1367            }
1368
1369            $totalUsers--;
1370            $this->output->write("\rRemaining users: " . $totalUsers . " | Percentage: " . round(($totalUsers / count($users)) * 100, 2) . "%", false);
1371        }
1372        $this->output->writeln('');
1373
1374        if ($userInfoDispatcher) {
1375            UserInfo::setEventDispatcher($userInfoDispatcher);
1376        }
1377        if ($userDispatcher) {
1378            User::setEventDispatcher($userDispatcher);
1379        }
1380        if ($dailyDispatcher) {
1381            FlyMsgUserDailyUsage::setEventDispatcher($dailyDispatcher);
1382        }
1383
1384        $totalDurationInMinutes = now()->diffInMinutes($totalTimeStartAt);
1385        $totalDurationInSeconds = now()->diffInSeconds($totalTimeStartAt);
1386
1387        Log::info("fixUserAccountCreationDate completed", [
1388            'completed_users_count' => $added_users_count,
1389            'total_duration_in_minutes' => $totalDurationInMinutes,
1390            'total_duration_in_seconds' => $totalDurationInSeconds,
1391            'failed_users_count' => $failed_users_count,
1392            'failed_users' => $failed_users,
1393        ]);
1394
1395        $this->info("fixUserAccountCreationDate completed");
1396        $this->info("Total duration in minutes: {$totalDurationInMinutes}");
1397        $this->info("Total duration in seconds: {$totalDurationInSeconds}");
1398        $this->info("Completed users: {$added_users_count}");
1399        $this->info("Failed users: {$failed_users_count}");
1400    }
1401
1402    private function fixUserUpdatedAt()
1403    {
1404        $this->info("fixUserUpdatedAt started");
1405        $totalTimeStartAt = now();
1406
1407        ini_set('memory_limit', '-1');
1408
1409        $failed_users = [];
1410        $failed_users_count = 0;
1411        $added_users_count = 0;
1412
1413        $users = UserInfo::where('user_updated_at', '$type', 'string')->get();
1414
1415        $totalUsers = count($users);
1416        $this->info("Processing " . $totalUsers . " users");
1417
1418        $userInfoDispatcher = UserInfo::getEventDispatcher();
1419        UserInfo::unsetEventDispatcher();
1420        $userDispatcher = User::getEventDispatcher();
1421        User::unsetEventDispatcher();
1422        $dailyDispatcher = FlyMsgUserDailyUsage::getEventDispatcher();
1423        FlyMsgUserDailyUsage::unsetEventDispatcher();
1424
1425        foreach ($users as $user) {
1426            try {
1427                $carbonDate = Carbon::parse($user->user_updated_at);
1428                $user->user_updated_at = new UTCDateTime($carbonDate->getTimestamp() * 1000);
1429                $user->last_update_usage_at = new UTCDateTime(now()->getTimestamp() * 1000);
1430                $user->save();
1431                $added_users_count++;
1432            } catch (\Exception $e) {
1433                $this->error("Failed to process user {$user->email}" . $e->getMessage());
1434                $failed_users[] = [
1435                    'user_id' => $user->id,
1436                    'email' => $user->email,
1437                    'error' => $e->getMessage(),
1438                ];
1439                $failed_users_count++;
1440            }
1441
1442            $totalUsers--;
1443            $this->output->write("\rRemaining users: " . $totalUsers . " | Percentage: " . round(($totalUsers / count($users)) * 100, 2) . "%", false);
1444        }
1445        $this->output->writeln('');
1446
1447        if ($userInfoDispatcher) {
1448            UserInfo::setEventDispatcher($userInfoDispatcher);
1449        }
1450        if ($userDispatcher) {
1451            User::setEventDispatcher($userDispatcher);
1452        }
1453        if ($dailyDispatcher) {
1454            FlyMsgUserDailyUsage::setEventDispatcher($dailyDispatcher);
1455        }
1456
1457        $totalDurationInMinutes = now()->diffInMinutes($totalTimeStartAt);
1458        $totalDurationInSeconds = now()->diffInSeconds($totalTimeStartAt);
1459
1460        Log::info("fixUserUpdatedAt completed", [
1461            'completed_users_count' => $added_users_count,
1462            'total_duration_in_minutes' => $totalDurationInMinutes,
1463            'total_duration_in_seconds' => $totalDurationInSeconds,
1464            'failed_users_count' => $failed_users_count,
1465            'failed_users' => $failed_users,
1466        ]);
1467
1468        $this->info("fixUserUpdatedAt completed");
1469        $this->info("Total duration in minutes: {$totalDurationInMinutes}");
1470        $this->info("Total duration in seconds: {$totalDurationInSeconds}");
1471        $this->info("Completed users: {$added_users_count}");
1472        $this->info("Failed users: {$failed_users_count}");
1473    }
1474
1475    private function fixUserCreatedAt()
1476    {
1477        $this->info("fixUserCreatedAt started");
1478        $totalTimeStartAt = now();
1479
1480        ini_set('memory_limit', '-1');
1481
1482        $failed_users = [];
1483        $failed_users_count = 0;
1484        $added_users_count = 0;
1485
1486        $users = UserInfo::where('user_created_at', '$type', 'string')->get();
1487
1488        $totalUsers = count($users);
1489        $this->info("Processing " . $totalUsers . " users");
1490
1491        $userInfoDispatcher = UserInfo::getEventDispatcher();
1492        UserInfo::unsetEventDispatcher();
1493        $userDispatcher = User::getEventDispatcher();
1494        User::unsetEventDispatcher();
1495        $dailyDispatcher = FlyMsgUserDailyUsage::getEventDispatcher();
1496        FlyMsgUserDailyUsage::unsetEventDispatcher();
1497
1498        foreach ($users as $user) {
1499            try {
1500                $carbonDate = Carbon::parse($user->user_created_at);
1501                $user->user_created_at = new UTCDateTime($carbonDate->getTimestamp() * 1000);
1502                $user->last_update_usage_at = new UTCDateTime(now()->getTimestamp() * 1000);
1503                $user->save();
1504                $added_users_count++;
1505            } catch (\Exception $e) {
1506                $this->error("Failed to process user {$user->email}" . $e->getMessage());
1507                $failed_users[] = [
1508                    'user_id' => $user->id,
1509                    'email' => $user->email,
1510                    'error' => $e->getMessage(),
1511                ];
1512                $failed_users_count++;
1513            }
1514
1515            $totalUsers--;
1516            $this->output->write("\rRemaining users: " . $totalUsers . " | Percentage: " . round(($totalUsers / count($users)) * 100, 2) . "%", false);
1517        }
1518        $this->output->writeln('');
1519
1520        if ($userInfoDispatcher) {
1521            UserInfo::setEventDispatcher($userInfoDispatcher);
1522        }
1523        if ($userDispatcher) {
1524            User::setEventDispatcher($userDispatcher);
1525        }
1526        if ($dailyDispatcher) {
1527            FlyMsgUserDailyUsage::setEventDispatcher($dailyDispatcher);
1528        }
1529
1530        $totalDurationInMinutes = now()->diffInMinutes($totalTimeStartAt);
1531        $totalDurationInSeconds = now()->diffInSeconds($totalTimeStartAt);
1532
1533        Log::info("fixUserCreatedAt completed", [
1534            'completed_users_count' => $added_users_count,
1535            'total_duration_in_minutes' => $totalDurationInMinutes,
1536            'total_duration_in_seconds' => $totalDurationInSeconds,
1537            'failed_users_count' => $failed_users_count,
1538            'failed_users' => $failed_users,
1539        ]);
1540
1541        $this->info("fixUserCreatedAt completed");
1542        $this->info("Total duration in minutes: {$totalDurationInMinutes}");
1543        $this->info("Total duration in seconds: {$totalDurationInSeconds}");
1544        $this->info("Completed users: {$added_users_count}");
1545        $this->info("Failed users: {$failed_users_count}");
1546    }
1547
1548    private function fixUserLastLogin()
1549    {
1550        $this->info("fixUserLastLogin started");
1551        $totalTimeStartAt = now();
1552
1553        ini_set('memory_limit', '-1');
1554
1555        $failed_users = [];
1556        $failed_users_count = 0;
1557        $added_users_count = 0;
1558
1559        $users = UserInfo::where('last_login', '$type', 'string')->get();
1560
1561        $totalUsers = count($users);
1562        $this->info("Processing " . $totalUsers . " users");
1563
1564        $userInfoDispatcher = UserInfo::getEventDispatcher();
1565        UserInfo::unsetEventDispatcher();
1566        $userDispatcher = User::getEventDispatcher();
1567        User::unsetEventDispatcher();
1568        $dailyDispatcher = FlyMsgUserDailyUsage::getEventDispatcher();
1569        FlyMsgUserDailyUsage::unsetEventDispatcher();
1570
1571        foreach ($users as $user) {
1572            try {
1573                $carbonDate = Carbon::parse($user->last_login);
1574                $user->last_login = new UTCDateTime($carbonDate->getTimestamp() * 1000);
1575                $user->last_update_usage_at = new UTCDateTime(now()->getTimestamp() * 1000);
1576                $user->save();
1577                $added_users_count++;
1578            } catch (\Exception $e) {
1579                $this->error("Failed to process user {$user->email}" . $e->getMessage());
1580                $failed_users[] = [
1581                    'user_id' => $user->id,
1582                    'email' => $user->email,
1583                    'error' => $e->getMessage(),
1584                ];
1585                $failed_users_count++;
1586            }
1587
1588            $totalUsers--;
1589            $this->output->write("\rRemaining users: " . $totalUsers . " | Percentage: " . round(($totalUsers / count($users)) * 100, 2) . "%", false);
1590        }
1591        $this->output->writeln('');
1592
1593        if ($userInfoDispatcher) {
1594            UserInfo::setEventDispatcher($userInfoDispatcher);
1595        }
1596        if ($userDispatcher) {
1597            User::setEventDispatcher($userDispatcher);
1598        }
1599        if ($dailyDispatcher) {
1600            FlyMsgUserDailyUsage::setEventDispatcher($dailyDispatcher);
1601        }
1602
1603        $totalDurationInMinutes = now()->diffInMinutes($totalTimeStartAt);
1604        $totalDurationInSeconds = now()->diffInSeconds($totalTimeStartAt);
1605
1606        Log::info("fixUserLastLogin completed", [
1607            'completed_users_count' => $added_users_count,
1608            'total_duration_in_minutes' => $totalDurationInMinutes,
1609            'total_duration_in_seconds' => $totalDurationInSeconds,
1610            'failed_users_count' => $failed_users_count,
1611            'failed_users' => $failed_users,
1612        ]);
1613
1614        $this->info("fixUserLastLogin completed");
1615        $this->info("Total duration in minutes: {$totalDurationInMinutes}");
1616        $this->info("Total duration in seconds: {$totalDurationInSeconds}");
1617        $this->info("Completed users: {$added_users_count}");
1618        $this->info("Failed users: {$failed_users_count}");
1619    }
1620
1621    private function cleanShortcutHtml($html)
1622    {
1623        if (empty($html)) {
1624            return '';
1625        }
1626
1627        $dom = new \DOMDocument();
1628        // Suppress warnings for malformed HTML
1629        @$dom->loadHTML('<?xml encoding="utf-8" ?>' . $html);
1630
1631        $xpath = new \DOMXPath($dom);
1632
1633        // Remove elements with style containing "display: none"
1634        $hiddenElements = $xpath->query('//*[@style[contains(., "display: none")]]');
1635        foreach ($hiddenElements as $element) {
1636            $element->parentNode->removeChild($element);
1637        }
1638
1639        // Remove elements with class "wsc-element"
1640        $wscElements = $xpath->query('//*[contains(concat(" ", normalize-space(@class), " "), " wsc-element ")]');
1641        foreach ($wscElements as $element) {
1642            $element->parentNode->removeChild($element);
1643        }
1644
1645        // Remove "fms-fly-app" elements
1646        $flyMsgElements = $dom->getElementsByTagName('fms-fly-app');
1647        // The list is live, so we need to iterate backwards or create a temporary array
1648        $nodesToRemove = [];
1649        foreach ($flyMsgElements as $node) {
1650            $nodesToRemove[] = $node;
1651        }
1652        foreach ($nodesToRemove as $node) {
1653            $node->parentNode->removeChild($node);
1654        }
1655
1656        // Get the HTML of the body content
1657        $body = $dom->getElementsByTagName('body')->item(0);
1658        $newHtml = '';
1659        if ($body) {
1660            foreach ($body->childNodes as $child) {
1661                $newHtml .= $dom->saveHTML($child);
1662            }
1663        }
1664
1665        return trim($newHtml);
1666    }
1667}