Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
0.00% covered (danger)
0.00%
0 / 1238
0.00% covered (danger)
0.00%
0 / 17
CRAP
0.00% covered (danger)
0.00%
0 / 1
ClientManagementUsersService
0.00% covered (danger)
0.00%
0 / 1238
0.00% covered (danger)
0.00%
0 / 17
7656
0.00% covered (danger)
0.00%
0 / 1
 __construct
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 getUsersPaginated
0.00% covered (danger)
0.00%
0 / 473
0.00% covered (danger)
0.00%
0 / 1
600
 categorizeUsersByEmailDomain
0.00% covered (danger)
0.00%
0 / 19
0.00% covered (danger)
0.00%
0 / 1
6
 getAllUsers
0.00% covered (danger)
0.00%
0 / 23
0.00% covered (danger)
0.00%
0 / 1
12
 getUsersGroupByEmailForReportingsFilterdddddd
0.00% covered (danger)
0.00%
0 / 32
0.00% covered (danger)
0.00%
0 / 1
12
 getUsersGroupByEmailForReportingsFilter
0.00% covered (danger)
0.00%
0 / 41
0.00% covered (danger)
0.00%
0 / 1
20
 getUsersGroupByEmailForReportingsFilter2
0.00% covered (danger)
0.00%
0 / 40
0.00% covered (danger)
0.00%
0 / 1
30
 getFiltersForReportings
0.00% covered (danger)
0.00%
0 / 192
0.00% covered (danger)
0.00%
0 / 1
2
 getCompaniesWithDeactivatedUsers
0.00% covered (danger)
0.00%
0 / 49
0.00% covered (danger)
0.00%
0 / 1
2
 getActiveCompanies
0.00% covered (danger)
0.00%
0 / 51
0.00% covered (danger)
0.00%
0 / 1
6
 categorizeUsers
0.00% covered (danger)
0.00%
0 / 24
0.00% covered (danger)
0.00%
0 / 1
6
 createUserManually
0.00% covered (danger)
0.00%
0 / 50
0.00% covered (danger)
0.00%
0 / 1
2
 createUserByEmails
0.00% covered (danger)
0.00%
0 / 62
0.00% covered (danger)
0.00%
0 / 1
20
 resendInvitations
0.00% covered (danger)
0.00%
0 / 58
0.00% covered (danger)
0.00%
0 / 1
72
 resetPassword
0.00% covered (danger)
0.00%
0 / 19
0.00% covered (danger)
0.00%
0 / 1
12
 moveToInvitedUsers
0.00% covered (danger)
0.00%
0 / 59
0.00% covered (danger)
0.00%
0 / 1
380
 moveToUsers
0.00% covered (danger)
0.00%
0 / 45
0.00% covered (danger)
0.00%
0 / 1
20
1<?php
2
3namespace App\Http\Services;
4
5use App\Enums\HttpStatusCode;
6use App\Events\User\Registered;
7use App\Http\Models\UserInfo;
8use Illuminate\Support\Str;
9use App\Http\Models\Auth\User;
10use App\Http\Models\Admin\Company;
11use App\Mail\AdminCenterAddExistingUser;
12use Illuminate\Support\Facades\Password;
13use App\Mail\SendResetPasswordRequestedEmail;
14use App\Http\Models\Admin\AdminUserInvitation;
15use App\Http\Models\Admin\CompanyLicenses;
16use App\Http\Models\Admin\CompanyPOC;
17use App\Http\Models\Auth\Role;
18use App\Http\Models\Plans;
19use App\Http\Services\Admin\Companies\CompanyService;
20use App\Jobs\Emails\AddExistentUserJob;
21use App\Jobs\Emails\AddNewUserReminder;
22use App\Mail\AdminCenterAddNewUser;
23use App\Services\Email\EmailService;
24use Illuminate\Foundation\Auth\SendsPasswordResetEmails;
25use Carbon\Carbon;
26use Illuminate\Support\Facades\Cache;
27use MongoDB\BSON\UTCDateTime;
28
29class ClientManagementUsersService
30{
31    use SendsPasswordResetEmails;
32
33    public function __construct(
34        private readonly CompanyService $companyService,
35        private readonly EmailService $emailService
36    ) {}
37
38    public function getUsersPaginated($filter, $deactivated, $perPage, $page, $categories, $sortBy, $sortOrder, $license_types, $account_status)
39    {
40        $account_status = array_filter($account_status);
41        $license_types = array_filter($license_types);
42
43        if (!$sortBy) {
44            $sortBy = 'created_at';
45        }
46
47        if (!$sortOrder) {
48            $sortOrder = 'desc';
49        }
50
51        $sortOrder = $sortOrder == 'desc' ? -1 : 1;
52
53        $skip = ($page - 1) * $perPage;
54        $take = $perPage;
55
56        $emails = array_filter($categories, function ($category) {
57            return str_starts_with($category, '@') && $category !== 'all_individuals';
58        });
59
60        $companyIds = array_filter($categories, function ($category) {
61            return !str_starts_with($category, '@') && $category !== 'all_individuals';
62        });
63
64        $filters = [
65            ["deleted_at" => ['$exists' => false]]
66        ];
67
68        $deactivatedCompanies = Company::whereNotNull('deactivated_at')
69            ->pluck('id')
70            ->toArray();
71
72        if ($deactivated) {
73            $filters[] = [
74                '$or' => [
75                    [
76                        '$and' => [
77                            ['deactivated_at' => ['$exists' => true]],
78                            ['deactivated_at' => ['$ne' => null]],
79                        ]
80                    ],
81                    ['company_id' => ['$in' => $deactivatedCompanies]]
82                ]
83            ];
84        } else {
85            $filters[] = [
86                '$and' => [
87                    [
88                        '$or' => [
89                            ['deactivated_at' => ['$exists' => false]],
90                            ['deactivated_at' => ['$eq' => null]],
91                        ]
92                    ],
93                    ['company_id' => ['$nin' => $deactivatedCompanies]]
94                ]
95            ];
96        }
97
98        if (filled($filter)) {
99            $escapedFilter = preg_quote($filter, '/');
100            $filters[] = ['$or' => [
101                ['email' => ['$regex' => $escapedFilter, '$options' => 'i']],
102                ['first_name' => ['$regex' => $escapedFilter, '$options' => 'i']],
103                ['last_name' => ['$regex' => $escapedFilter, '$options' => 'i']],
104                [
105                    '$expr' => [
106                        '$regexMatch' => [
107                            'input' => ['$concat' => ['$first_name', ' ', '$last_name']],
108                            'regex' => $filter,
109                            'options' => 'i'
110                        ]
111                    ]
112                ]
113            ]];
114        }
115
116        if (count($account_status) > 0) {
117            $statusFilters = [];
118            foreach ($account_status as $st) {
119                if ($st == 'Active') {
120                    $statusFilters[] = [
121                        '$or' => [
122                            ['status' => ['$regex' => $st, '$options' => 'i']],
123                            ['status' => ['$exists' => false]]
124                        ]
125                    ];
126                } else {
127                    $statusFilters[] = [
128                        '$or' => [
129                            ['status' => ['$regex' => $st, '$options' => 'i']]
130                        ]
131                    ];
132                }
133            }
134            $filters[] = [
135                '$or' => $statusFilters
136            ];
137        }
138        $categoriesQuery = [];
139
140        if (in_array('all_individuals', $categories)) {
141            $emailDomains = $this->categorizeUsersByEmailDomain($deactivated ? 'inactive' : 'active')->pluck("id")->toArray();
142            $categoriesQuery = array_map(function ($domain) {
143                return [
144                    '$and' => [
145                        ['email' => ['$regex' => preg_quote(substr($domain, 1)), '$options' => 'i']],
146                        ['company_id' => null]
147                    ]
148                ];
149            }, $emailDomains);
150        } elseif (filled($emails) && count($emails) > 0) {
151            $categoriesQuery = array_map(function ($email) {
152                return [
153                    '$and' => [
154                        ['email' => ['$regex' => preg_quote(substr($email, 1)), '$options' => 'i']],
155                        ['company_id' => null]
156                    ]
157                ];
158            }, $emails);
159        }
160
161        if (filled($companyIds) && count($companyIds) > 0) {
162            $categoriesQuery = array_merge($categoriesQuery, array_map(function ($companyId) {
163                return ['company_id' => $companyId];
164            }, $companyIds));
165        }
166
167        if (filled($categoriesQuery)) {
168            $filters[] = [
169                '$and' => [
170                    ['$or' => $categoriesQuery]
171                ]
172            ];
173        }
174
175        $pipeline = [];
176
177        if (filled($filters)) {
178            $pipeline[] = [
179                '$match' => [
180                    '$and' => $filters
181                ]
182            ];
183        }
184
185        if (count($account_status) === 0 || in_array('Invited', $account_status)) {
186            $pipeline[] = [
187                '$unionWith' => [
188                    "coll" => "admin_user_invitations",
189                    "pipeline" => [
190                        [
191                            '$match' => [
192                                '$and' => $filters
193                            ]
194                        ],
195                        [
196                            '$addFields' => [
197                                'status' => 'Invited',
198                                'is_invite' => true
199                            ]
200                        ]
201                    ]
202                ]
203            ];
204        }
205
206        $pipeline[] = [
207            '$group' => [
208                "_id" => '$email',
209                "data" => [
210                    '$first' => '$$ROOT'
211                ]
212            ]
213        ];
214
215        $pipeline[] = [
216            '$replaceRoot' => [
217                "newRoot" => '$data'
218            ]
219        ];
220
221        $hasLicenseFilter = count($license_types) > 0;
222
223        if (!$hasLicenseFilter) {
224            $totalUsers = User::raw(function ($collection) use ($pipeline) {
225                return $collection->aggregate($pipeline);
226            })->count();
227
228            $totalPages = ceil($totalUsers / $take);
229            $currentPage = $skip / $take + 1;
230
231            $sortPipeline = match (true) {
232                $sortBy == 'name' => ['$sort' => [
233                    'first_name' => $sortOrder,
234                    'last_name' => $sortOrder,
235                    'created_at' => -1
236                ]],
237                default => ['$sort' => ['created_at' => $sortOrder]],
238            };
239
240            $pipeline[] = $sortPipeline;
241
242            $pipeline[] = ['$skip' => $skip];
243            $pipeline[] = ['$limit' => $take];
244        }
245
246        $pipeline[] = [
247            '$project' => [
248                '_id' => 1,
249                'first_name' => 1,
250                'last_name' => 1,
251                'email' => 1,
252                'avatar' => 1,
253                'activation_date' => 1,
254                'created_at' => 1,
255                'updated_at' => 1,
256                'deleted_at' => 1,
257                'deactivated_at' => 1,
258                'company_id' => 1,
259                'company_group_id' => 1,
260                'status' => 1,
261                'is_invite' => 1,
262            ]
263        ];
264
265        $pipeline[] = [
266            '$lookup' => [
267                'from' => 'subscriptions',
268                'let' => ['subscriptionUserId' => ['$toString' => '$_id']],
269                'pipeline' => [
270                    [
271                        '$match' => [
272                            '$expr' => [
273                                '$and' => [
274                                    ['$eq' => ['$name', 'main']],
275                                    ['$eq' => ['$stripe_status', 'active']],
276                                    ['$eq' => ['$user_id', '$$subscriptionUserId']]
277                                ]
278                            ]
279                        ]
280                    ],
281                    [
282                        '$lookup' => [
283                            'from' => 'plans',
284                            'let' => ['planId' => '$stripe_plan'],
285                            'pipeline' => [
286                                [
287                                    '$match' => [
288                                        '$expr' => [
289                                            '$and' => [
290                                                ['$eq' => ['$stripe_id', '$$planId']]
291                                            ]
292                                        ]
293                                    ]
294                                ],
295                                [
296                                    '$project' => [
297                                        "_id" => 0,
298                                        "id" => ['$toString' => '$_id'],
299                                        'title' => 1,
300                                    ]
301                                ]
302                            ],
303                            'as' => 'plan'
304                        ]
305                    ],
306                    [
307                        '$project' => [
308                            "_id" => 0,
309                            'plan' => 1,
310                        ]
311                    ],
312                ],
313                'as' => 'subscription'
314            ]
315        ];
316
317        if ($hasLicenseFilter) {
318            $pipeline[] = [
319                '$addFields' => [
320                    'plan_id' => ['$arrayElemAt' => ['$subscription.plan.id', 0]]
321                ]
322            ];
323
324            $planIdFilters = [
325                ['plan_id' => ['$in' => $license_types]]
326            ];
327
328            $freemiumId = Plans::where('identifier', 'freemium')->first()?->_id;
329
330            if (in_array($freemiumId, $license_types)) {
331                $planIdFilters[] = ['plan_id' => ['$eq' => null]];
332            }
333
334            $pipeline[] = [
335                '$match' => [
336                    '$or' => $planIdFilters
337                ]
338            ];
339
340            $totalUsers = User::raw(function ($collection) use ($pipeline) {
341                return $collection->aggregate($pipeline);
342            })->count();
343
344            $totalPages = ceil($totalUsers / $take);
345            $currentPage = $skip / $take + 1;
346
347            $sortPipeline = match (true) {
348                $sortBy == 'name' => ['$sort' => [
349                    'first_name' => $sortOrder,
350                    'last_name' => $sortOrder,
351                    'created_at' => -1
352                ]],
353                default => ['$sort' => ['created_at' => $sortOrder]],
354            };
355
356            $pipeline[] = $sortPipeline;
357
358            $pipeline[] = ['$skip' => $skip];
359            $pipeline[] = ['$limit' => $take];
360        }
361
362        $pipeline[] = [
363            '$lookup' => [
364                'from' => 'companies',
365                'let' => ['companyId' => ['$toObjectId' => '$company_id']],
366                'pipeline' => [
367                    ['$match' => [
368                        '$expr' => [
369                            '$eq' => ['$$companyId', '$_id']
370                        ]
371                    ]],
372                    ['$lookup' => [
373                        'from' => 'company_groups',
374                        'let' => ['objCompanyId' => ['$toString' => '$_id']],
375                        'pipeline' => [
376                            ['$match' => [
377                                '$expr' => [
378                                    '$eq' => ['$company_id', '$$objCompanyId']
379                                ]
380                            ]],
381                        ],
382                        'as' => 'company_groups'
383                    ]],
384                    [
385                        '$addFields' => [
386                            'groups' => [
387                                '$size' => '$company_groups'
388                            ]
389                        ]
390                    ],
391                    [
392                        '$project' => [
393                            "_id" => 0,
394                            'name' => 1,
395                            'slug' => 1,
396                            'deactivated_at' => 1,
397                            'groups' => 1,
398                        ]
399                    ]
400                ],
401                'as' => 'company_info'
402            ]
403        ];
404
405        $pipeline[] = [
406            '$lookup' => [
407                'from' => 'sales_pro_team_managers',
408                'let' => ['userId' => ['$toString' => '$_id']],
409                'pipeline' => [
410                    ['$match' => [
411                        '$expr' => [
412                            '$eq' => ['$$userId', '$user_id']
413                        ]
414                    ]],
415                    ['$sort' => ['created_at' => -1]],
416                    [
417                        '$project' => [
418                            "_id" => 0,
419                            'company_group_ids' => 1,
420                        ]
421                    ]
422                ],
423                'as' => 'sales_pro_team_manager_info'
424            ]
425        ];
426
427        $pipeline[] = [
428            '$lookup' => [
429                'from' => 'hubspot_properties',
430                'let' => ['id' => ['$toString' => '$_id']],
431                'pipeline' => [
432                    ['$match' => [
433                        '$expr' => [
434                            '$eq' => ['$$id', '$flymsg_id']
435                        ]
436                    ]],
437                    [
438                        '$project' => [
439                            "_id" => 0,
440                            'flymsg_chrome_extension_installed' => 1,
441                            'flymsg_edge_extension_installed' => 1,
442                        ]
443                    ],
444                ],
445                'as' => 'hubspot'
446            ]
447        ];
448
449        $pipeline[] = [
450            '$lookup' => [
451                'from' => 'company_groups',
452                'let' => ['companyGroupId' => ['$toObjectId' => '$company_group_id']],
453                'pipeline' => [
454                    ['$match' => [
455                        '$expr' => [
456                            '$eq' => ['$_id', '$$companyGroupId']
457                        ]
458                    ]],
459                    [
460                        '$lookup' => [
461                            'from' => 'company_groups',
462                            'let' => ['parentCompanyGroupId' => ['$toObjectId' => '$parent_id']],
463                            'pipeline' => [
464                                ['$match' => [
465                                    '$expr' => [
466                                        '$eq' => ['$_id', '$$parentCompanyGroupId']
467                                    ]
468                                ]],
469                                [
470                                    '$project' => [
471                                        "_id" => 0,
472                                        'name' => 1,
473                                    ]
474                                ],
475                            ],
476                            'as' => 'parent_company_group_info'
477                        ]
478                    ],
479                    [
480                        '$project' => [
481                            "_id" => 0,
482                            'name' => 1,
483                        ]
484                    ],
485                ],
486                'as' => 'company_group_info'
487            ]
488        ];
489
490        $pipeline[] = [
491            '$lookup' => [
492                'from' => 'role_user',
493                'let' => ['userId' => ['$toString' => '$_id']],
494                'pipeline' => [
495                    ['$match' => [
496                        '$expr' => [
497                            '$eq' => ['$$userId', '$user_id']
498                        ]
499                    ]],
500                ],
501                'as' => 'user_roles'
502            ]
503        ];
504
505        $pipeline[] = [
506            '$lookup' => [
507                'from' => 'roles',
508                'let' => ['roleIds' => '$user_roles.role_id'],
509                'pipeline' => [
510                    ['$match' => [
511                        '$expr' => [
512                            '$in' => [['$toString' => '$_id'], '$$roleIds']
513                        ]
514                    ]],
515                    [
516                        '$project' => [
517                            "_id" => 0,
518                            'name' => 1,
519                        ]
520                    ],
521                ],
522                'as' => 'roles_info'
523            ]
524        ];
525
526        $pipeline[] = [
527            '$group' => [
528                '_id' => '$_id',
529                'roles' => ['$push' => '$roles_info.name'],
530                'document' => ['$first' => '$$ROOT']
531            ]
532        ];
533
534        $pipeline[] = [
535            '$replaceRoot' => [
536                'newRoot' => [
537                    '$mergeObjects' => ['$document', ['roles' => ['$arrayElemAt' => ['$roles', 0]]]]
538                ]
539            ]
540        ];
541
542        $pipeline[] = [
543            '$project' => [
544                '_id' => 1,
545                'first_name' => 1,
546                'last_name' => 1,
547                'status' => 1,
548                'is_invite' => 1,
549                'email' => 1,
550                'avatar' => 1,
551                'created_at' => 1,
552                'updated_at' => 1,
553                'deactivated_at' => 1,
554                'deleted_at' => 1,
555                'activation_date' => 1,
556                'company_id' => 1,
557                'company_group_id' => 1,
558                'sales_pro_team_manager' => ['$arrayElemAt' => ['$sales_pro_team_manager_info', 0]],
559                'company_info' => ['$arrayElemAt' => ['$company_info', 0]],
560                'hubspot' => ['$arrayElemAt' => ['$hubspot', 0]],
561                'company_group_info' => ['$arrayElemAt' => ['$company_group_info', 0]],
562                'role' => 1,
563                'plan' => ['$arrayElemAt' => ['$subscription.plan.title', 0]]
564            ]
565        ];
566
567        $pipeline[] = ['$match' => ['deleted_at' => ['$eq' => null]]];
568
569        $users = User::raw(function ($collection) use ($pipeline) {
570            return $collection->aggregate($pipeline);
571        });
572
573        return [
574            'users' => $users,
575            'total' => $totalUsers,
576            'total_pages' => $totalPages,
577            'current_page' => $currentPage,
578        ];
579    }
580
581    public function categorizeUsersByEmailDomain($status)
582    {
583        $emails = UserInfo::where('company_id', null)->where('email_domain_count', '>', 1);
584
585        if (!empty($status)) {
586            // uppercase the status first letter to match the database
587            $status = ucfirst($status);
588
589            $emails = $emails->where('status', $status);
590        }
591
592        return UserInfo::raw(function ($collection) {
593            return $collection->aggregate([
594                ['$match' => [
595                    'company_id' => null,
596                    'email_domain_count' => ['$gt' => 1]
597                ]],
598                ['$group' => [
599                    '_id' => '$email_domain',
600                    'email_domain_count' => ['$sum' => 1]
601                ]],
602                ['$sort' => [
603                    'email_domain_count' => -1
604                ]],
605            ]);
606        });
607
608        // return $emails->select([
609        //     'email_domain',
610        //     'email_domain_count',
611        // ])->distinct('email_domain')->get();
612
613        //        return User::raw(function ($collection) use ($status) {
614        //            $match = [
615        //                'company_id' => ['$exists' => false]
616        //            ];
617        //
618        //            if ($status === 'active') {
619        //                $match['deactivated_at'] = ['$exists' => false];
620        //            } elseif ($status === 'inactive') {
621        //                $match['deactivated_at'] = ['$exists' => true];
622        //            }
623        //
624        //            return $collection->aggregate([
625        //                [
626        //                    '$match' => $match
627        //                ],
628        //                [
629        //                    '$group' => [
630        //                        '_id' => [
631        //                            '$toLower' => [
632        //                                '$arrayElemAt' => [
633        //                                    ['$split' => ['$email', '@']],
634        //                                    1
635        //                                ]
636        //                            ]
637        //                        ],
638        //                        'count' => ['$sum' => 1]
639        //                    ]
640        //                ],
641        //                [
642        //                    '$match' => [
643        //                        'count' => ['$gt' => 1] // Filter out domains with only one user
644        //                    ]
645        //                ],
646        //                [
647        //                    '$project' => [
648        //                        '_id' => 0, // Exclude the default _id field
649        //                        'id' => '$_id', // Rename _id to domain
650        //                        'count' => 1
651        //                    ]
652        //                ],
653        //                [
654        //                    '$sort' => ['count' => -1] // Sort by count in descending order
655        //                ]
656        //            ]);
657        //        });
658    }
659
660    public function getAllUsers($resetCache = false)
661    {
662        ini_set("memory_limit", "3072M");
663
664        $pipeline = [];
665
666        $pipeline[] = [
667            '$match' => [
668                '$and' => [
669                    ["deleted_at" => ['$exists' => false]]
670                ]
671            ]
672        ];
673
674        $pipeline[] = ['$sort' => [
675            'first_name' => 1,
676            'last_name' => 1,
677            'created_at' => -1
678        ]];
679
680        if ($resetCache) {
681            Cache::forget('cmc-total-users');
682        }
683
684        $result = Cache::get("cmc-total-users");
685
686        if (!$result) {
687            $result = User::raw(function ($collection) use ($pipeline) {
688                return $collection->aggregate($pipeline);
689            });
690
691            Cache::put('cmc-total-users', $result, 24 * 60 * 60);
692        }
693
694        return $result;
695    }
696
697    public function getUsersGroupByEmailForReportingsFilterdddddd($users, $resetCache = false)
698    {
699        $usersGroupedByDomain = $this->categorizeUsersByEmailDomain(null);
700
701        if ($resetCache) {
702            Cache::forget('cmc-emails-filter');
703        }
704
705        $result = Cache::get("cmc-emails-filter");
706
707        if (!$result) {
708            $usersAlreadyFiltered = [];
709            $usersByEmail = $usersGroupedByDomain->map(function ($item) use ($users, &$usersAlreadyFiltered) {
710                $currentEmailUsers = $users->filter(function ($user) use ($item) {
711                    return preg_match('/' . preg_quote($item['id'], '/') . '/i', $user->email);
712                });
713
714                $usersAlreadyFiltered = array_merge($usersAlreadyFiltered, $currentEmailUsers->pluck('id')->toArray());
715
716                $currentEmailResult = [
717                    'id' => '@' . $item['id'],
718                    'name' => $item['id'],
719                    'count' => $item['count'],
720                    'type' => 'email',
721                ];
722
723                $currentEmailResult['items'] = $currentEmailUsers->map(function ($user) {
724                    return [
725                        'id' => $user->id,
726                        'type' => 'user',
727                        'name' => $user->first_name . ' ' . $user->last_name,
728                    ];
729                })->values()->toArray();
730
731                return $currentEmailResult;
732            });
733
734            $result = [
735                'usersAlreadyFiltered' => $usersAlreadyFiltered,
736                'usersByEmail' => $usersByEmail
737            ];
738
739            Cache::put('cmc-emails-filter', $result, 24 * 60 * 60);
740        }
741
742        return $result;
743    }
744
745    public function getUsersGroupByEmailForReportingsFilter($users, $resetCache = false)
746    {
747        if ($resetCache) {
748            Cache::forget('cmc-emails-filter');
749        }
750
751        $result = Cache::get("cmc-emails-filter");
752
753        if (!$result) {
754            // Pipeline de agregação para agrupar e contar domínios
755            $usersGroupedByDomain = UserInfo::raw(function ($collection) {
756                return $collection->aggregate([
757                    ['$match' => ['company_id' => null]],
758                    ['$group' => [
759                        '_id' => '$email_domain',
760                        'email_domain_count' => ['$sum' => 1]
761                    ]]
762                ]);
763            });
764
765            $usersAlreadyFiltered = [];
766            $usersByEmail = [];
767
768            foreach ($usersGroupedByDomain as $item) {
769                $domain = $item['_id'];
770
771                $currentEmailUsers = $users->filter(function ($user) use ($domain) {
772                    return str_contains(strtolower($user->email), '@' . $domain);
773                });
774
775                $usersAlreadyFiltered = array_merge($usersAlreadyFiltered, $currentEmailUsers->pluck('id')->toArray());
776
777                $currentEmailResult = [
778                    'id' => $domain,
779                    'name' => $domain,
780                    'count' => $item['email_domain_count'],
781                    'type' => 'email',
782                    'items' => $currentEmailUsers->map(function ($user) {
783                        return [
784                            'id' => $user->id,
785                            'type' => 'user',
786                            'name' => $user->first_name . ' ' . $user->last_name,
787                        ];
788                    })->values()->toArray(),
789                ];
790
791                $usersByEmail[] = $currentEmailResult;
792            }
793
794            $result = [
795                'usersAlreadyFiltered' => $usersAlreadyFiltered,
796                'usersByEmail' => $usersByEmail,
797            ];
798
799            Cache::put('cmc-emails-filter', $result, 24 * 60 * 60);
800        }
801
802        return $result;
803    }
804
805    public function getUsersGroupByEmailForReportingsFilter2($users, $resetCache = false)
806    {
807        ini_set("memory_limit", "3072M");
808
809        // Agrupa os domínios usando o método categorizeUsersByEmailDomain()
810        // $usersGroupedByDomain = $this->categorizeUsersByEmailDomain(null);
811
812        $emails = UserInfo::where('company_id', null);
813
814        if (!empty($status)) {
815            $emails = $emails->where('status', $status);
816        }
817
818        $usersGroupedByDomain = $emails->select([
819            'email_domain',
820            'email_domain_count',
821        ])->distinct('email_domain')->get();
822
823        if ($resetCache) {
824            Cache::forget('cmc-emails-filter');
825        }
826
827        $result = Cache::get("cmc-emails-filter");
828
829        if (!$result) {
830            $usersAlreadyFiltered = [];
831            $usersByEmail = [];
832
833            foreach ($usersGroupedByDomain as $item) {
834                // Obtém o domínio atual
835                $domain = $item['id'];
836
837                // Filtra os usuários pelo domínio de e-mail
838                $currentEmailUsers = $users->filter(function ($user) use ($domain) {
839                    return str_contains(strtolower($user->email), '@' . $domain);
840                });
841
842                // Atualiza a lista de IDs de usuários já filtrados
843                $usersAlreadyFiltered = array_merge($usersAlreadyFiltered, $currentEmailUsers->pluck('id')->toArray());
844
845                // Monta o resultado atual para o domínio
846                $currentEmailResult = [
847                    'id' => '@' . $domain,
848                    'name' => $domain,
849                    'count' => $item['count'],
850                    'type' => 'email',
851                    'items' => $currentEmailUsers->map(function ($user) {
852                        return [
853                            'id' => $user->id,
854                            'type' => 'user',
855                            'name' => $user->first_name . ' ' . $user->last_name,
856                        ];
857                    })->values()->toArray()
858                ];
859
860                $usersByEmail[] = $currentEmailResult;
861            }
862
863            $result = [
864                'usersAlreadyFiltered' => $usersAlreadyFiltered,
865                'usersByEmail' => $usersByEmail
866            ];
867
868            Cache::put('cmc-emails-filter', $result, 24 * 60 * 60);
869        }
870
871        return $result;
872    }
873
874    public function getFiltersForReportings()
875    {
876        // Increase memory limit temporary
877        // ini_set('memory_limit', '3072M');
878
879        $pipeline = [
880            [
881                '$facet' => [
882                    'individuals' => [
883                        [
884                            '$match' => [
885                                'company_id' => null,
886                            ],
887                        ],
888                        [
889                            '$group' => [
890                                '_id' => '$email_domain',
891                                'count' => ['$sum' => 1],
892                                'items' => [
893                                    '$push' => [
894                                        'id' => '$user_id',
895                                        'name' => '$full_name',
896                                        'type' => 'user',
897                                    ],
898                                ],
899                            ],
900                        ],
901                        [
902                            '$addFields' => [
903                                'name' => '$_id',
904                                'id' => '$_id',
905                                'type' => 'email',
906                            ],
907                        ],
908                        [
909                            '$match' => [
910                                'count' => ['$gt' => 4],
911                            ],
912                        ],
913                        [
914                            '$sort' => [
915                                'count' => -1,
916                            ],
917                        ],
918                        [
919                            '$group' => [
920                                '_id' => null,
921                                'categories' => ['$push' => '$$ROOT'],
922                                'total' => ['$sum' => '$count'],
923                            ],
924                        ],
925                        [
926                            '$project' => [
927                                '_id' => 0,
928                                'id' => 'individuals',
929                                'name' => 'Individuals',
930                                'count' => '$total',
931                                'items' => '$categories',
932                                'type' => 'main',
933                            ],
934                        ],
935                    ],
936                    'corporate' => [
937                        [
938                            '$match' => [
939                                'company_id' => ['$ne' => null],
940                            ],
941                        ],
942                        [
943                            '$group' => [
944                                '_id' => [
945                                    'company_id' => '$company_id',
946                                    'group_id' => ['$ifNull' => ['$group_id', ['$concat' => ['$company_id', '-1']]]],
947                                    'subgroup_id' => ['$ifNull' => ['$subgroup_id', ['$concat' => ['$company_id', ['$ifNull' => ['$group_id', '-1']], '-1']]]],
948                                ],
949                                'company_name' => ['$first' => '$company_name'],
950                                'group_name' => ['$first' => ['$ifNull' => ['$group_name', 'Not Assigned']]],
951                                'subgroup_name' => ['$first' => ['$ifNull' => ['$subgroup_name', 'Not Assigned']]],
952                                'count' => ['$sum' => 1],
953                                'users' => [
954                                    '$push' => [
955                                        'id' => '$user_id',
956                                        'name' => '$full_name',
957                                        'type' => 'user',
958                                    ],
959                                ],
960                            ],
961                        ],
962                        [
963                            '$group' => [
964                                '_id' => [
965                                    'company_id' => '$_id.company_id',
966                                    'group_id' => '$_id.group_id',
967                                ],
968                                'company_name' => ['$first' => '$company_name'],
969                                'group_name' => ['$first' => '$group_name'],
970                                'subgroups' => [
971                                    '$push' => [
972                                        'id' => '$_id.subgroup_id',
973                                        'name' => '$subgroup_name',
974                                        'count' => '$count',
975                                        'items' => '$users',
976                                        'type' => 'subgroup',
977                                    ],
978                                ],
979                            ],
980                        ],
981                        [
982                            '$group' => [
983                                '_id' => '$_id.company_id',
984                                'company_name' => ['$first' => '$company_name'],
985                                'items' => [
986                                    '$push' => [
987                                        'id' => '$_id.group_id',
988                                        'name' => '$group_name',
989                                        'items' => '$subgroups',
990                                        'count' => ['$sum' => ['$sum' => '$subgroups.count']],
991                                        'type' => 'group',
992                                    ],
993                                ],
994                            ],
995                        ],
996                        [
997                            '$addFields' => [
998                                'name' => '$company_name',
999                                'id' => '$_id',
1000                                'type' => 'company',
1001                                'items' => '$items',
1002                                'count' => ['$sum' => ['$sum' => '$items.count']],
1003                            ],
1004                        ],
1005                        [
1006                            '$project' => [
1007                                '_id' => 0,
1008                                'name' => 1,
1009                                'id' => 1,
1010                                'type' => 1,
1011                                'items' => 1,
1012                                'count' => 1,
1013                            ],
1014                        ],
1015                        [
1016                            '$group' => [
1017                                '_id' => null,
1018                                'categories' => ['$push' => '$$ROOT'],
1019                                'total' => ['$sum' => ['$sum' => '$items.count']],
1020                            ],
1021                        ],
1022                        [
1023                            '$project' => [
1024                                '_id' => 0,
1025                                'id' => 'corporate',
1026                                'name' => 'Corporate',
1027                                'count' => '$total',
1028                                'items' => '$categories',
1029                                'type' => 'main',
1030                            ],
1031                        ],
1032                    ],
1033                ],
1034            ],
1035            [
1036                '$project' => [
1037                    'result' => [
1038                        '$concatArrays' => ['$individuals', '$corporate'],
1039                    ],
1040                ],
1041            ],
1042            [
1043                '$unwind' => '$result',
1044            ],
1045            [
1046                '$replaceRoot' => ['newRoot' => '$result'],
1047            ],
1048        ];
1049
1050        $result = UserInfo::raw(function ($collection) use ($pipeline) {
1051            return $collection->aggregate($pipeline);
1052        });
1053
1054        return $result;
1055
1056        // $users = $this->getAllUsers();
1057
1058        // $companyUsers = $users->whereNotNull('company_id');
1059
1060        // $companies = Company::with(['groupsAndSubgroups' => function ($query) {
1061        //     $query->whereNull("parent_id")->with("subgroups");
1062        // }])->latest()->get();
1063
1064        // $companies = $companies->map(function ($company) use ($companyUsers) {
1065        //     $companyUsers = $companyUsers->where('company_id', $company->id);
1066        //     $companyResult = [
1067        //         'id' => $company->id,
1068        //         'name' => $company->name,
1069        //         'count' => $companyUsers->count(),
1070        //         'type' => 'company',
1071        //     ];
1072
1073        //     $companyResult['items'] = $company->groupsAndSubgroups->map(function ($group) use ($companyUsers) {
1074        //         $subgroupIds = $group->subgroups->pluck('_id')->toArray();
1075        //         $groupUsers = collect($companyUsers)->filter(function ($user) use ($subgroupIds, $group) {
1076        //             return in_array($user->company_group_id, $subgroupIds) || $user->company_group_id === $group->id;
1077        //         });
1078
1079        //         $companyGroupResult = [
1080        //             'id' => $group->id,
1081        //             'name' => $group->name,
1082        //             'type' => 'group',
1083        //             'count' => $groupUsers->count(),
1084        //         ];
1085
1086        //         $companyGroupResult['items'] = $group->subgroups->map(function ($subgroup) use ($groupUsers) {
1087        //             $subgroupUsers = collect($groupUsers)->filter(function ($user) use ($subgroup) {
1088        //                 return $user->company_group_id === $subgroup->id;
1089        //             });
1090
1091        //             $companySubGroupResult = [
1092        //                 'id' => $subgroup->id,
1093        //                 'name' => $subgroup->name,
1094        //                 'type' => 'subgroup',
1095        //                 'count' => $subgroupUsers->count(),
1096        //             ];
1097
1098        //             $companySubGroupResult['items'] = $subgroupUsers->map(function ($user) {
1099        //                 return [
1100        //                     'id' => $user->id,
1101        //                     'type' => 'user',
1102        //                     'name' => $user->first_name . ' ' . $user->last_name,
1103        //                 ];
1104        //             })->values()->toArray();
1105
1106        //             return $companySubGroupResult;
1107        //         })->values()->toArray();
1108
1109        //         $groupUsers = $companyUsers->where('company_subgroup_id', $group->id);
1110
1111        //         $companyGroupUsers = $groupUsers->map(function ($user) {
1112        //             return [
1113        //                 'id' => $user->id,
1114        //                 'type' => 'user',
1115        //                 'name' => $user->first_name . ' ' . $user->last_name,
1116        //             ];
1117        //         })->values()->toArray();
1118
1119        //         $companyGroupResult['items'] = array_merge($companyGroupResult['items'], $companyGroupUsers);
1120
1121        //         return $companyGroupResult;
1122        //     })->values()->toArray();
1123
1124        //     $companyUsers = $companyUsers->whereNull('company_group_id')->map(function ($user) {
1125        //         return [
1126        //             'id' => $user->id,
1127        //             'type' => 'user',
1128        //             'name' => $user->first_name . ' ' . $user->last_name,
1129        //         ];
1130        //     });
1131
1132        //     $companyResult['items'][] = [
1133        //         'id' => -1,
1134        //         'name' => 'Not Assigned',
1135        //         'type' => 'group',
1136        //         'count' => $companyUsers->count(),
1137        //         'items' => $companyUsers->values()->toArray(),
1138        //     ];
1139
1140        //     return $companyResult;
1141        // })->toArray();
1142
1143        // $filterByEmail = $this->getUsersGroupByEmailForReportingsFilter($users);
1144
1145        // $usersAlreadyFiltered = $filterByEmail['usersAlreadyFiltered'];
1146        // $emailUsers = $filterByEmail['usersByEmail'];
1147
1148        // $usersNotFiltered = $users->whereNotIn('id', $usersAlreadyFiltered)->map(function ($user) {
1149        //     return [
1150        //         'id' => $user->id,
1151        //         'name' => $user->first_name . ' ' . $user->last_name,
1152        //         'type' => 'user',
1153        //     ];
1154        // })->values()->toArray();
1155
1156        // $emailUsers = array_merge($emailUsers, $usersNotFiltered);
1157
1158        // $emailUsers = collect($emailUsers)->sortBy(function ($item) {
1159        //     return str_starts_with($item['name'], '@') ? '0' . $item['name'] : '1' . $item['name'];
1160        // })->values()->toArray();
1161
1162        // usort($emailUsers, function ($a, $b) {
1163        //     if (str_starts_with($a['name'], '@') && !str_starts_with($b['name'], '@')) {
1164        //         return -1;
1165        //     }
1166        //     if (!str_starts_with($a['name'], '@') && str_starts_with($b['name'], '@')) {
1167        //         return 1;
1168        //     }
1169
1170        //     return strcmp($a['name'], $b['name']);
1171        // });
1172
1173        $individualUsersCount = User::where('deleted_at', null)->where('company_id', null)->count();
1174
1175        $companyUsersCount = User::where('deleted_at', null)->where('company_id', '!=', null)->count();
1176
1177        return [
1178            [
1179                'id' => 'individuals',
1180                'name' => 'Individuals',
1181                'count' => $individualUsersCount,
1182                'items' => [],
1183                'type' => 'main',
1184            ],
1185            [
1186                'id' => 'companies',
1187                'name' => 'Teams - Custom',
1188                'count' => $companyUsersCount,
1189                'items' => [],
1190                'type' => 'main',
1191            ]
1192        ];
1193    }
1194
1195    private function getCompaniesWithDeactivatedUsers()
1196    {
1197        return Company::raw(function ($collection) {
1198            return $collection->aggregate([
1199                [
1200                    '$match' => [
1201                        'deleted_at' => ['$exists' => false]
1202                    ]
1203                ],
1204                [
1205                    '$lookup' => [
1206                        'from' => 'users',
1207                        'let' => ['companyId' => ['$toString' => '$_id']],
1208                        'pipeline' => [
1209                            [
1210                                '$match' => [
1211                                    '$expr' => [
1212                                        '$and' => [
1213                                            ['$eq' => ['$company_id', '$$companyId']]
1214                                        ]
1215                                    ],
1216                                    'deactivated_at' => ['$exists' => true],
1217                                    'deleted_at' => ['$exists' => false]
1218                                ]
1219                            ]
1220                        ],
1221                        'as' => 'users'
1222                    ]
1223                ],
1224                [
1225                    '$addFields' => [
1226                        'hasDeactivatedUsers' => ['$gt' => [['$size' => '$users'], 0]]
1227                    ]
1228                ],
1229                [
1230                    '$match' => [
1231                        '$or' => [
1232                            ['hasDeactivatedUsers' => true],
1233                            ['deactivated_at' => ['$exists' => true]]
1234                        ]
1235                    ]
1236                ],
1237                [
1238                    '$project' => [
1239                        'id' => 1,
1240                        'name' => 1,
1241                        'count' => ['$size' => '$users']
1242                    ]
1243                ]
1244            ]);
1245        });
1246    }
1247
1248    private function getActiveCompanies($status)
1249    {
1250        return Company::raw(function ($collection) use ($status) {
1251            $match = [
1252                'deleted_at' => ['$exists' => false]
1253            ];
1254
1255            if ($status === 'active') {
1256                $match['deactivated_at'] = ['$exists' => false];
1257            }
1258
1259            return $collection->aggregate([
1260                [
1261                    '$match' => $match
1262                ],
1263                [
1264                    '$lookup' => [
1265                        'from' => 'users',
1266                        'let' => ['company_id' => ['$toString' => '$_id']],
1267                        'pipeline' => [
1268                            [
1269                                '$match' => [
1270                                    '$expr' => [
1271                                        '$eq' => ['$company_id', '$$company_id']
1272                                    ]
1273                                ]
1274                            ]
1275                        ],
1276                        'as' => 'users'
1277                    ]
1278                ],
1279                [
1280                    '$lookup' => [
1281                        'from' => 'admin_user_invitations',
1282                        'let' => ['company_id' => ['$toString' => '$_id']],
1283                        'pipeline' => [
1284                            [
1285                                '$match' => [
1286                                    '$expr' => [
1287                                        '$eq' => ['$company_id', '$$company_id']
1288                                    ]
1289                                ]
1290                            ]
1291                        ],
1292                        'as' => 'invitations'
1293                    ]
1294                ],
1295                [
1296                    '$project' => [
1297                        'id' => 1,
1298                        'name' => 1,
1299                        'count' => ['$add' => [['$size' => '$users'], ['$size' => '$invitations']]]
1300                    ]
1301                ]
1302            ]);
1303        });
1304    }
1305
1306    public function categorizeUsers($status)
1307    {
1308        $usersGroupedByDomain = $this->categorizeUsersByEmailDomain($status);
1309
1310        if ($status === 'inactive') {
1311            $companies = $this->getCompaniesWithDeactivatedUsers();
1312        } else {
1313            $companies = $this->getActiveCompanies($status);
1314        }
1315
1316        return [
1317            [
1318                'id' => 'individuals',
1319                'name' => 'Individuals',
1320                'count' => $usersGroupedByDomain->sum('email_domain_count'),
1321                'items' => $usersGroupedByDomain->map(function ($item) {
1322                    return [
1323                        'id' => $item['id'],
1324                        'name' => $item['id'],
1325                        'count' => $item['email_domain_count'],
1326                    ];
1327                })
1328            ],
1329            [
1330                'id' => 'companies',
1331                'name' => 'Teams - Custom',
1332                'items' => $companies
1333            ],
1334            // ['id' => 'multi_license', 'name' => 'Teams - Self-service', 'items' => $multi_licenses],
1335        ];
1336    }
1337
1338    public function createUserManually(User $admin, array $data)
1339    {
1340        $email = strtolower($data['email']);
1341        $password = Str::password(16);
1342        $hashed_password = bcrypt($password);
1343        $password_expiry = Carbon::now()->addDays(7);
1344
1345        $user = new User();
1346        $user->fill($data);
1347        $user->status = "Invited";
1348        $user->email = $email;
1349        $user->password = $hashed_password;
1350        $user->temp_password_expiry = $password_expiry->toDateTimeString();
1351        $user->temp_password = $hashed_password;
1352        $user->email_verified_at = new UTCDateTime(now()->getTimestamp() * 1000);
1353        $user->onboardingv2_presented = true;
1354
1355        $user->save();
1356
1357        $password_expiry = $password_expiry->format("m/d/Y") . " at " . $password_expiry->format("h:i A");
1358
1359        $data = [
1360            "email" => $email,
1361            "temp_password_expiry" => $user->temp_password_expiry,
1362            "temp_password" => $hashed_password,
1363            "password" => $hashed_password,
1364            "admin_email" => $admin->email
1365        ];
1366
1367        $invitation = AdminUserInvitation::updateOrCreate(['email' => $email], $data);
1368
1369        $data = [
1370            "email" => $user->email,
1371            "first_name" => $user->first_name,
1372            "last_name" => $user->last_name,
1373        ];
1374
1375        Registered::dispatch($user, $data);
1376
1377        $this->emailService->send(
1378            $email,
1379            new AdminCenterAddNewUser(
1380                email: $email,
1381                password: $password,
1382                inviter: $admin->email,
1383                password_expiry: $password_expiry,
1384            ),
1385            'cac_add_new_user_manually'
1386        );
1387
1388
1389        $addNewUserEmailJob = (new AddNewUserReminder(
1390            $email,
1391            $password,
1392            $admin->email,
1393            $password_expiry,
1394            $this->emailService
1395        ))->delay(now()->addHours(48));
1396
1397        $job = app(\Illuminate\Contracts\Bus\Dispatcher::class)->dispatch($addNewUserEmailJob);
1398
1399        $invitation->reminder_job_id = $job;
1400        $invitation->save();
1401
1402        return $user;
1403    }
1404
1405    public function createUserByEmails(User $admin, array $emails)
1406    {
1407        $invitationSentCount = 0;
1408
1409        $responseBuilder = [];
1410
1411        foreach ($emails as $email) {
1412            $email = strtolower($email);
1413            $existing_user = false;
1414            $password = Str::password(16);
1415            $hashed_password = bcrypt($password);
1416            $passwordExpiry = Carbon::now()->addDays(7);
1417
1418            $data = [
1419                "email" => $email,
1420                "temp_password_expiry" => $passwordExpiry->toDateTimeString(),
1421                "temp_password" => $hashed_password,
1422                "password" => $hashed_password,
1423                "admin_email" => $admin->email
1424            ];
1425
1426            $user = User::where("email", $email)->first();
1427
1428            if (!$user) {
1429                $existing_user = false;
1430
1431                $passwordExpiry = $passwordExpiry->format("m/d/Y") . " at " . $passwordExpiry->format("h:i A");
1432
1433                $this->emailService->send(
1434                    $email,
1435                    new AdminCenterAddNewUser(
1436                        email: $email,
1437                        password: $password,
1438                        inviter: $admin->email,
1439                        password_expiry: $passwordExpiry,
1440                    ),
1441                    'cmc_create_users_by_email'
1442                );
1443
1444                $addNewUserEmailJob = (new AddNewUserReminder(
1445                    $email,
1446                    $password,
1447                    $admin->email,
1448                    $passwordExpiry,
1449                    $this->emailService
1450                ))->delay(now()->addHours(48));
1451
1452                $job = app(\Illuminate\Contracts\Bus\Dispatcher::class)->dispatch($addNewUserEmailJob);
1453                $data["reminder_job_id"] = $job;
1454
1455                $invitationSentCount++;
1456            }
1457
1458            $invitation = AdminUserInvitation::updateOrCreate(['email' => $email], $data);
1459
1460            if (!$existing_user) {
1461                $notAssigned = "Not Assigned";
1462
1463                $user_properties = [
1464                    'id' => $invitation->id,
1465                    'first_name' => null,
1466                    'last_name' => null,
1467                    'email' => $email,
1468                    'role' => 'User',
1469                    'group' => $notAssigned,
1470                    'sub_group' => $notAssigned,
1471                    'group_subgroup' => $notAssigned,
1472                    "licenseType" => $notAssigned,
1473                    "status" => "Invited",
1474                    "invitation_link" => $invitation->getInvitationLinkForAdminPortal(),
1475                    "created_at" => $invitation?->updated_at,
1476                    "user_id" => null,
1477                    "group_id" => null,
1478                    "group_subgroup_id" => null,
1479                    "statusDate" => $invitation?->updated_at?->toFormattedDateString(),
1480                ];
1481
1482                $responseBuilder[] = $user_properties;
1483            }
1484        }
1485
1486        return $responseBuilder;
1487    }
1488
1489    public function resendInvitations(User $admin, array $emails)
1490    {
1491        foreach ($emails as $email) {
1492            $invitation = AdminUserInvitation::firstWhere('email', $email);
1493            $email = strtolower($email);
1494            $user = User::where('email', $email)->whereStatus("Invited")->first();
1495            $pocUser = CompanyPOC::where('email', $email)->first();
1496
1497            $password = Str::random(16);
1498            $encrypted_password = bcrypt($password);
1499            $passwordExpiry = now()->addDays(7);
1500            $passwordExpiryLabel = $passwordExpiry->format("m/d/Y") . " at " . $passwordExpiry->format("h:i A");
1501
1502            $existing_user = $user && $user->created_at->diffInMinutes($invitation?->created_at) > 1;
1503
1504            if ($invitation) {
1505                $invitation->email = $email;
1506                $invitation->password = $encrypted_password;
1507                $invitation->temp_password = $encrypted_password;
1508                $invitation->temp_password_expiry = $passwordExpiry->toDateTimeString();
1509                $invitation->save();
1510            }
1511
1512            if (!$existing_user && $user) {
1513                $user->password = $encrypted_password;
1514                $user->temp_password = $encrypted_password;
1515                $user->temp_password_expiry = $passwordExpiry->toDateTimeString();
1516                $user->save();
1517            }
1518
1519            if ($pocUser) {
1520                $this->companyService->sendInvitationMail($email, $user, $existing_user, $password);
1521                continue;
1522            }
1523
1524            if ($existing_user) {
1525                $this->emailService->send(
1526                    $user->email,
1527                    new AdminCenterAddExistingUser(
1528                        admin_email: $admin->email,
1529                        email: $user->email,
1530                        company: $admin->company->name,
1531                    ),
1532                    'cmc_add_existent_user'
1533                );
1534            } else {
1535                $invitation->password = $encrypted_password;
1536                $invitation->temp_password = $encrypted_password;
1537                $invitation->temp_password_expiry = $passwordExpiry->toDateTimeString();
1538                $invitation->admin_email = $admin->email;
1539
1540                $this->emailService->send(
1541                    $email,
1542                    new AdminCenterAddNewUser(
1543                        email: $email,
1544                        password: $password,
1545                        inviter: $admin->email,
1546                        password_expiry: $passwordExpiryLabel,
1547                    ),
1548                    'cmc_resend_invitations'
1549                );
1550
1551                $addNewUserEmailJob = (new AddNewUserReminder(
1552                    $email,
1553                    $password,
1554                    $admin->email,
1555                    $passwordExpiryLabel,
1556                    $this->emailService
1557                ))->delay(now()->addHours(48));
1558
1559                $job = app(\Illuminate\Contracts\Bus\Dispatcher::class)->dispatch($addNewUserEmailJob);
1560                $invitation->reminder_job_id = $job;
1561
1562                $invitation->save();
1563            }
1564        }
1565    }
1566
1567    public function resetPassword(User $admin, array $userIds)
1568    {
1569        $users = User::whereIn('_id', $userIds)->get();
1570
1571        foreach ($users as $user) {
1572            $userEmail = strtolower($user->email);
1573            $request = request()->merge(["email" => $userEmail]);
1574            $token = $this->broker()->sendResetLink($this->credentials($request), function ($user, $token) {
1575                return $token;
1576            });
1577
1578            if (in_array($token, [Password::INVALID_USER, Password::RESET_THROTTLED])) {
1579                continue;
1580            }
1581
1582            $this->emailService->send(
1583                $userEmail,
1584                new SendResetPasswordRequestedEmail(
1585                    name: $user->first_name . ' ' . $user->last_name,
1586                    admin_email: $admin->email,
1587                    email: $userEmail,
1588                    token: $token
1589                ),
1590                'cmc_send_reset_password_requested'
1591            );
1592        }
1593    }
1594
1595    public function moveToInvitedUsers($validatedData)
1596    {
1597        $companyId = $validatedData['company_id'];
1598        $roleName = $validatedData['role_name'];
1599        $plan = Plans::whereNull('pricing_version')->firstWhere('identifier', $validatedData['plan_identifier']);
1600        $groupId = $validatedData['group_id'] ?? null;
1601        $subgroupId = $validatedData['subgroup_id'] ?? null;
1602
1603        $usersInvitation = AdminUserInvitation::whereIn('_id', $validatedData['user_ids'])->get();
1604
1605        if ($usersInvitation->isEmpty()) {
1606            return response()->json([
1607                'success' => false,
1608                'message' => "No invited users found with the provided IDs.",
1609            ], HttpStatusCode::NOT_FOUND->value);
1610        }
1611
1612        if ($usersInvitation) {
1613            foreach ($usersInvitation as $userInvitation) {
1614
1615                $userInvitation->company_id = $companyId;
1616                $userInvitation->role_name = $roleName;
1617                $userInvitation->plan_id = $plan->id;
1618
1619                if (filled($groupId)) {
1620                    $userInvitation->company_group_id = $groupId;
1621                    $userInvitation->company_subgroup_id = null;
1622                }
1623
1624                if (filled($subgroupId)) {
1625                    $userInvitation->company_subgroup_id = $subgroupId;
1626                }
1627
1628                $userInvitation->save();
1629
1630                $user = User::where('email', $userInvitation->email)->first();
1631
1632                if ($user) {
1633
1634                    $user->removeAllRoles();
1635                    $group_ids = [];
1636                    if (($roleName == Role::GROUP_ADMIN || $roleName = Role::REPORTING_ADMIN) && ($groupId || $subgroupId)) {
1637                        $group_ids = [$groupId] ?? [$subgroupId] ?? [];
1638                    }
1639                    $user->assignRole($roleName, $group_ids);
1640
1641
1642                    if ($plan->identifier === Plans::FREEMIUM_IDENTIFIER) {
1643                        $userSub = $user->subscription("main");
1644                        if ($userSub && $userSub->plan->identifier != Plans::FREEMIUM_IDENTIFIER) {
1645                            $userSub->markAsCancelledOnlyInDB();
1646                        }
1647                        continue;
1648                    }
1649
1650                    $companyLicense = CompanyLicenses::where('company_id', $userInvitation->company_id)->active()->first();
1651
1652                    if (!$companyLicense) {
1653                        // Failed to assign plan. The company doesn't have any active license.";
1654                        continue;
1655                    }
1656
1657                    $licenseRemaining = match ($plan->identifier) {
1658                        Plans::STARTER_YEARLY_IDENTIFIER => $companyLicense->total_starter_license_remaining,
1659                        Plans::GROWTH_YEARLY_IDENTIFIER => $companyLicense->total_growth_license_remaining,
1660                        Plans::PROFESSIONAL_YEARLY_IDENTIFIER => $companyLicense->total_sales_pro_license_remaining,
1661                        Plans::ProPlanTeamsSMB => $companyLicense->total_sales_pro_teams_license_remaining,
1662                        default => 0,
1663                    };
1664
1665                    if ($licenseRemaining < 1) {
1666                        // Failed to assign plan. The company doesn't have sufficient licenses for selected plan.";
1667                        continue;
1668                    }
1669
1670                    $userSub = $user->subscription("main");
1671                    if ($userSub && $userSub->plan->identifier != Plans::FREEMIUM_IDENTIFIER) {
1672                        $userSub->markAsCancelledOnlyInDB();
1673                    }
1674
1675                    if ($plan->identifier != Plans::FREEMIUM_IDENTIFIER) {
1676                        $user->subscriptions()->create([
1677                            'name' => 'main',
1678                            'stripe_status' => 'active',
1679                            'stripe_plan' => $plan->stripe_id,
1680                            'quantity' => "1",
1681                            'ends_at' => $companyLicense->contract_end_date,
1682                            'starts_at' => now()->toDateTimeString()
1683                        ]);
1684                    }
1685                }
1686            }
1687        }
1688
1689
1690        return $usersInvitation;
1691    }
1692
1693    /**
1694     * Validate plans availability.
1695     *
1696     */
1697    public function moveToUsers($data, User $adminUser)
1698    {
1699        $companyId = $data['company_id'];
1700        $company = Company::find($companyId);
1701        $userIds = collect($data['users'])->pluck('id')->toArray();
1702        $inputUsers = $data['users'];
1703        $users = User::whereIn('_id', $userIds)->get();
1704
1705        foreach ($users as $user) {
1706            $hasCorporatePlan = (bool) $user->company_id;
1707            $inputUser = collect($inputUsers)->firstWhere('id', $user->id);
1708            $roleName = $inputUser['role'];
1709            $plan = Plans::firstWhere('stripe_id', $inputUser['plan']);
1710            $groupId = $inputUser['group_id'] ?? null;
1711            $subgroupId = $inputUser['subgroup_id'] ?? null;
1712            $userEmail = strtolower($user->email);
1713
1714            $newUser = [
1715                "user_id" => $user->id,
1716                "email" => $userEmail,
1717                "plan" => $plan,
1718                "plan_id" => $plan->id,
1719                "company_id" => $companyId,
1720                "company_group_id" => $groupId,
1721                "company_subgroup_id" => $subgroupId,
1722                "admin_email" => $adminUser->email,
1723                "move_assign" => true,
1724                "role_name" => $roleName,
1725                "has_corporate_plan" => $hasCorporatePlan,
1726            ];
1727
1728            AdminUserInvitation::updateOrCreate(['email' => $userEmail], $newUser);
1729
1730            $user->company_id = $companyId;
1731            $user->invited_to_company = true;
1732            $user->move_assign = true;
1733            $user->invited_to_company_by_admin = $adminUser->email;
1734            $user->status = "Invited";
1735
1736            if (filled($groupId)) {
1737                $user->company_group_id = $groupId;
1738            }
1739
1740            if (filled($subgroupId)) {
1741                $user->company_group_id = $subgroupId;
1742            }
1743
1744            $user->save();
1745
1746            AddExistentUserJob::dispatch(
1747                $newUser['email'],
1748                $adminUser->email,
1749                $company,
1750                $this->emailService
1751            )->delay(now()->addSeconds(1));
1752
1753            $user->refresh();
1754        }
1755
1756        return $users;
1757    }
1758}