Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
0.22% covered (danger)
0.22%
1 / 459
4.76% covered (danger)
4.76%
1 / 21
CRAP
0.00% covered (danger)
0.00%
0 / 1
AdminUsersService
0.22% covered (danger)
0.22%
1 / 459
4.76% covered (danger)
4.76%
1 / 21
19057.80
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
 getUsersPaginated
0.00% covered (danger)
0.00%
0 / 116
0.00% covered (danger)
0.00%
0 / 1
702
 deleteUsers
0.00% covered (danger)
0.00%
0 / 9
0.00% covered (danger)
0.00%
0 / 1
42
 unassignUsers
0.00% covered (danger)
0.00%
0 / 9
0.00% covered (danger)
0.00%
0 / 1
42
 deleteInvitation
0.00% covered (danger)
0.00%
0 / 5
0.00% covered (danger)
0.00%
0 / 1
30
 delete
0.00% covered (danger)
0.00%
0 / 25
0.00% covered (danger)
0.00%
0 / 1
2
 unassign
0.00% covered (danger)
0.00%
0 / 15
0.00% covered (danger)
0.00%
0 / 1
42
 deleteUser
0.00% covered (danger)
0.00%
0 / 8
0.00% covered (danger)
0.00%
0 / 1
6
 unassignUser
0.00% covered (danger)
0.00%
0 / 8
0.00% covered (danger)
0.00%
0 / 1
6
 deactivateUsers
0.00% covered (danger)
0.00%
0 / 5
0.00% covered (danger)
0.00%
0 / 1
20
 deactivateUser
0.00% covered (danger)
0.00%
0 / 24
0.00% covered (danger)
0.00%
0 / 1
72
 deactivateUserBulk
0.00% covered (danger)
0.00%
0 / 11
0.00% covered (danger)
0.00%
0 / 1
56
 deactivateInvitedUser
0.00% covered (danger)
0.00%
0 / 6
0.00% covered (danger)
0.00%
0 / 1
6
 deleteInvitedUser
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 moveUsersToGroup
0.00% covered (danger)
0.00%
0 / 10
0.00% covered (danger)
0.00%
0 / 1
20
 moveUserToGroup
0.00% covered (danger)
0.00%
0 / 16
0.00% covered (danger)
0.00%
0 / 1
20
 moveInvitationUserToGroup
0.00% covered (danger)
0.00%
0 / 3
0.00% covered (danger)
0.00%
0 / 1
6
 acceptMoveToInvitation
0.00% covered (danger)
0.00%
0 / 40
0.00% covered (danger)
0.00%
0 / 1
90
 acceptUserInvitation
0.00% covered (danger)
0.00%
0 / 82
0.00% covered (danger)
0.00%
0 / 1
702
 rejectUserInvitation
0.00% covered (danger)
0.00%
0 / 45
0.00% covered (danger)
0.00%
0 / 1
240
 createUserForInvitationLogin
0.00% covered (danger)
0.00%
0 / 20
0.00% covered (danger)
0.00%
0 / 1
2
1<?php
2
3namespace App\Http\Services\Admin\Users;
4
5use App\Actions\AccountCenter\Reporting\AccountCenterReporting;
6use App\Actions\Users\CancelUserPlanAction;
7use App\Actions\Users\UpdateUserPlanAction;
8use App\Events\InstancyUserUpdate;
9use App\Events\User\Registered;
10use App\Exceptions\ExpectedException;
11use App\Http\Models\Admin\AdminUserInvitation;
12use App\Http\Models\Admin\Company;
13use App\Http\Models\Admin\CompanyGroup;
14use App\Http\Models\Admin\CompanyLicenses;
15use App\Http\Models\Auth\LinkedSocialAccount;
16use App\Http\Models\Auth\LoginHistory;
17use App\Http\Models\Auth\LogoutHistory;
18use App\Http\Models\Auth\Role;
19use App\Http\Models\Auth\User;
20use App\Http\Models\FlyMsgUserDailyUsage;
21use App\Http\Models\Plans;
22use App\Http\Models\UserInfo;
23use App\Http\Models\UserPasswordReset;
24use App\Http\Repositories\InstancyRepository;
25use App\Http\Repositories\InstancyUserDTO;
26use App\Http\Services\CacheInvalidationService;
27use App\Http\Services\InstancyServiceV2;
28use App\Jobs\Emails\DeactivateUserNotification;
29use App\Services\Email\EmailService;
30use Carbon\Carbon;
31use Illuminate\Support\Facades\Log;
32use Illuminate\Support\Facades\Queue;
33use MongoDB\BSON\UTCDateTime;
34
35class AdminUsersService extends AccountCenterReporting
36{
37    private string $cantDeactivateOwnAccount = 'You cannot deactivate your own account.';
38
39    private string $cantDeleteOwnAccount = 'You cannot delete your own account.';
40
41    private string $cantUnassignOwnAccount = 'You cannot unassign your own account.';
42
43    public function __construct(
44        private CancelUserPlanAction $cancelUserPlanAction,
45        private InstancyRepository $instancyRepository,
46        private readonly UpdateUserPlanAction $updateUserPlanAction,
47        private readonly EmailService $emailService,
48        private readonly CacheInvalidationService $cacheInvalidationService
49    ) {}
50
51    public function getUsersPaginated($filter, $deactivated, $perPage, $page, $categories, $sortBy, $sortOrder, $license_types, $account_status, $extensions)
52    {
53        $account_status = array_filter($account_status);
54        $license_types = array_filter($license_types);
55        $categories = array_filter($categories);
56
57        $usersQuery = UserInfo::select(
58            'user_id',
59            'first_name',
60            'last_name',
61            'full_name',
62            'status',
63            'is_invite',
64            'email',
65            'avatar',
66            'user_created_at',
67            'user_updated_at',
68            'status_date',
69            'company_id',
70            'company_name',
71            'group_id',
72            'group_name',
73            'subgroup_id',
74            'subgroup_name',
75            // 'sales_pro_team_manager',
76            'is_any_extension_installed',
77            'role_names',
78            'plan_name',
79            'created_at'
80        )->where('deleted_at', null);
81
82        if (filled($filter)) {
83            // $escapedFilter = preg_quote($filter, '/');
84            $usersQuery = $usersQuery->where(function ($query) use ($filter) {
85                $query->where('email', 'like', "%$filter%")
86                    ->orWhere('full_name', 'like', "%$filter$")
87                    ->orWhere('user_id', 'like', "%$filter$");
88            });
89        }
90
91        if (count($extensions) > 0) {
92            $string = str_replace('""', 'empty', $extensions[0]);
93            $extensions = array_map('intval', $extensions);
94            if (count($extensions) > 0) {
95                $extensions = array_map('boolval', $extensions);
96                $usersQuery = $usersQuery->whereIn('is_any_extension_installed', $extensions);
97            }
98        }
99
100        $deactivatedCompanies = Company::whereNotNull('deactivated_at')
101            ->pluck('id')
102            ->toArray();
103
104        if (count($account_status) > 0) {
105            $usersQuery = $usersQuery->whereIn('status', $account_status);
106        } elseif ($deactivated) {
107            $usersQuery = $usersQuery->where(function ($query) use ($deactivatedCompanies) {
108                $query->where('status', 'Deactivated')
109                    ->orWhereIn('company_id', $deactivatedCompanies);
110            });
111        } else {
112            $usersQuery = $usersQuery->where(function ($query) use ($deactivatedCompanies) {
113                $query->whereNull('deactivated_at')
114                    ->WhereNotIn('company_id', $deactivatedCompanies);
115            });
116
117            $usersQuery = $usersQuery->whereNotIn('status', ['Deactivated', 'Deleted']);
118        }
119
120        $emails = array_filter($categories, function ($category) {
121            return str_starts_with($category, '@') && $category !== 'all_individuals';
122        });
123
124        $companyIds = array_filter($categories, function ($category) {
125            return ! str_starts_with($category, '@') && $category !== 'all_individuals';
126        });
127        $categoriesQuery = [];
128
129        if (in_array('all_individuals', $categories)) {
130            $categoriesQuery[] = function ($query) {
131                $query->whereNull('company_id')->where('email_domain_count', '>', 1);
132            };
133        } elseif (filled($emails) && count($emails) > 0) {
134            foreach ($emails as $email) {
135                $categoriesQuery[] = function ($query) use ($email) {
136                    $query->where('email_domain', $email)
137                        ->whereNull('company_id');
138                };
139            }
140        }
141
142        if (filled($companyIds) && count($companyIds) > 0) {
143            foreach ($companyIds as $companyId) {
144                $categoriesQuery[] = function ($query) use ($companyId) {
145                    $query->where('company_id', $companyId);
146                };
147            }
148        }
149
150        if (! empty($categoriesQuery)) {
151            $usersQuery = $usersQuery->where(function ($query) use ($categoriesQuery) {
152                foreach ($categoriesQuery as $filterQuery) {
153                    $query->orWhere($filterQuery);
154                }
155            });
156        }
157
158        if (count($license_types) > 0) {
159            $usersQuery = $usersQuery->whereIn('plan_id', $license_types);
160
161            $freemiumId = Plans::where('identifier', 'freemium')->first()?->_id;
162            if (in_array($freemiumId, $license_types)) {
163                $usersQuery = $usersQuery->orWhereNull('plan_id');
164            }
165        }
166
167        $skip = ($page - 1) * $perPage;
168        $take = $perPage;
169        $totalUsers = $usersQuery->count();
170        $currentPage = $skip / $take + 1;
171        $totalPages = ceil($totalUsers / $take);
172
173        if (! $sortBy) {
174            $sortBy = 'created_at';
175        }
176
177        if (! $sortOrder) {
178            $sortOrder = 'desc';
179        }
180
181        $sortOrder = $sortOrder == 'desc' ? -1 : 1;
182
183        $sortPipeline = match (true) {
184            $sortBy == 'name' => [
185                ['column' => 'first_name', 'direction' => $sortOrder == 1 ? 'asc' : 'desc'],
186                ['column' => 'last_name', 'direction' => $sortOrder == 1 ? 'asc' : 'desc'],
187                ['column' => 'created_at', 'direction' => 'desc'],
188            ],
189            default => [
190                ['column' => 'created_at', 'direction' => $sortOrder == 1 ? 'asc' : 'desc'],
191            ],
192        };
193
194        foreach ($sortPipeline as $sort) {
195            $usersQuery->orderBy($sort['column'], $sort['direction']);
196        }
197
198        $users = $usersQuery->skip($skip)
199            ->take($perPage)
200            ->get();
201
202        return [
203            'users' => $users,
204            'total' => $totalUsers,
205            'total_pages' => $totalPages,
206            'current_page' => $currentPage,
207        ];
208    }
209
210    public function deleteUsers(array $userIds, $adminUser, ?string $company_id)
211    {
212        if (isset($userIds) && in_array($adminUser->id, $userIds)) {
213            throw new ExpectedException($this->cantDeleteOwnAccount);
214        }
215
216        $users = User::whereIn('_id', $userIds)->get();
217
218        foreach ($users as $user) {
219            $this->deleteUser($user, $adminUser, $company_id);
220        }
221
222        $invitations = AdminUserInvitation::whereIn('_id', $userIds)->get();
223
224        if (! empty($invitations)) {
225            foreach ($invitations as $invite) {
226                $this->deleteInvitation($invite);
227            }
228        }
229    }
230
231    public function unassignUsers(array $userIds, $adminUser, ?string $company_id)
232    {
233        if (isset($userIds) && in_array($adminUser->id, $userIds)) {
234            throw new ExpectedException($this->cantUnassignOwnAccount);
235        }
236
237        $users = User::whereIn('_id', $userIds)->get();
238
239        foreach ($users as $user) {
240            $this->unassignUser($user, $adminUser, $company_id);
241        }
242
243        $invitations = AdminUserInvitation::whereIn('_id', $userIds)->get();
244
245        if (! empty($invitations)) {
246            foreach ($invitations as $invite) {
247                $this->deleteInvitation($invite);
248            }
249        }
250    }
251
252    public function deleteInvitation(AdminUserInvitation $invitation)
253    {
254        $invitationSubPlan = $invitation->subscription('invitation');
255
256        $plan = (isset($invitationSubPlan->plan)) ? $invitationSubPlan->plan : '';
257
258        if ($invitation->company_id && $plan && $plan->identifier != Plans::FREEMIUM_IDENTIFIER) {
259            $invitationSubPlan->markAsCancelledOnlyInDB();
260        }
261
262        $invitation->delete();
263    }
264
265    public function delete($user)
266    {
267        $user->deleted_at = Carbon::now()->toDateTimeString();
268        $user->status = 'Deleted';
269        $user->save();
270
271        $this->cancelUserPlanAction->execute($user);
272
273        $searchByIdEmail = ['email' => $user->email];
274
275        // force delete for below tables data for the user
276        AdminUserInvitation::where($searchByIdEmail)->forceDelete();
277        LinkedSocialAccount::where($searchByIdEmail)->forceDelete();
278        LoginHistory::where($searchByIdEmail)->forceDelete();
279        LogoutHistory::where($searchByIdEmail)->forceDelete();
280        UserPasswordReset::where($searchByIdEmail)->forceDelete();
281
282        $user->delete();
283
284        // soft delete the users table
285        $user->fill([
286            'first_name' => '',
287            'last_name' => '',
288            'avatar' => '',
289            'email' => "delete_from_flymsg_$user->email",
290            'password' => '',
291            'remember_token' => '',
292            'card_last_four' => '',
293            'card_brand' => '',
294            'team_id' => '',
295            'pm_last_four' => '',
296            'pm_type' => '',
297        ]);
298        $user->save();
299    }
300
301    public function unassign($user)
302    {
303        $userSub = $user->subscription('main');
304        if ($userSub) {
305            $plan = $userSub->plan;
306
307            if (isset($plan->identifier) && $plan->identifier != Plans::FREEMIUM_IDENTIFIER && $userSub->valid()) {
308                if ($user->company_id) {
309                    $userSub->markAsCancelledOnlyInDB();
310                } else {
311                    // Individual subscriptions: cancel with Stripe so billing stops.
312                    $userSub->cancel();
313                }
314            }
315        }
316        $instancyService = new InstancyServiceV2;
317        $instancyService->updateMembership($user->email, now()->toDateString());
318        $user->company_id = '';
319        $user->company_group_id = '';
320        $user->invited_to_company = null;
321        $user->invited_to_company_by_admin = null;
322        $user->status = 'Active';
323        $user->save();
324    }
325
326    public function deleteUser(User $user, $adminUser)
327    {
328        if ($user->id == $adminUser->id) {
329            throw new ExpectedException($this->cantDeleteOwnAccount);
330        }
331
332        Log::info('Deleting user: ', [
333            'user' => $user->email,
334            'admin' => $adminUser->email,
335            'date' => Carbon::now()->toDateTimeString(),
336        ]);
337        $this->delete($user);
338    }
339
340    public function unassignUser(User $user, $adminUser)
341    {
342        if ($user->id == $adminUser->id) {
343            throw new ExpectedException($this->cantUnassignOwnAccount);
344        }
345
346        Log::info('Unassign user: ', [
347            'user' => $user->email,
348            'admin' => $adminUser->email,
349            'date' => Carbon::now()->toDateTimeString(),
350        ]);
351        $this->unassign($user);
352    }
353
354    public function deactivateUsers(array $userIds, string $adminUserId, ?string $company_id)
355    {
356        if (isset($userIds) && in_array($adminUserId, $userIds)) {
357            throw new ExpectedException($this->cantDeactivateOwnAccount);
358        }
359
360        $users = User::whereIn('_id', $userIds)->get();
361
362        foreach ($users as $user) {
363            $this->deactivateUser($user, $adminUserId, $company_id);
364        }
365    }
366
367    public function deactivateUser(User $user, string $adminUserId, ?string $company_id, $cancellation_date = null)
368    {
369        if ($user->id == $adminUserId) {
370            throw new ExpectedException($this->cantDeactivateOwnAccount);
371        }
372
373        $invitation = AdminUserInvitation::where('email', $user->email)->first();
374        if ($invitation) {
375            $invitation->forceDelete();
376        }
377
378        if ($user->status === 'Invited') {
379            $user->company_id = null;
380        }
381
382        $user->status = 'Deactivated';
383        $user->deactivated_at = Carbon::now()->toDateTimeString();
384        if (! empty($cancellation_date)) {
385            $user->deactivated_at = $cancellation_date->toDateTimeString();
386        }
387
388        $user->company_group_id = null;
389        $user->save();
390
391        $admin = auth()->user();
392        $companyName = $admin->company->name;
393        $companyEmail = $admin->email;
394
395        if ($company_id) {
396            $company = Company::find($user->company_id);
397            $companyLicense = CompanyLicenses::where('company_id', $company->id)->first();
398            $community = $companyLicense->business_pro_enterprise_plus ?? [];
399            $isPro = in_array('yes_dedicated', $community) || in_array('yes_community', $community);
400
401            if ($isPro) {
402                DeactivateUserNotification::dispatch($user->email, $companyEmail, $companyName, $this->emailService)->delay(now()->addSeconds(2));
403            }
404        }
405
406        $this->cancelUserPlanAction->execute($user, true, $cancellation_date);
407    }
408
409    public function deactivateUserBulk(array $userIds, string $adminUserId, string $company_id)
410    {
411        if (isset($userIds) && in_array($adminUserId, $userIds)) {
412            throw new ExpectedException('You cannot deactivate your own account.');
413        }
414
415        $users = User::whereIn('_id', $userIds)->get();
416
417        // create the users ids array those available in users table
418        $existingUsers = User::whereIn('_id', $userIds)->pluck('_id')->toArray();
419
420        // users those not found in users table
421        $invitedUsers = array_diff($userIds, $existingUsers);
422
423        foreach ($users as $user) {
424            $this->deactivateUser($user, $adminUserId, empty($company_id) ? $user->company_id : $company_id);
425        }
426
427        // for the invited users those not yet registered
428        if (! empty($invitedUsers)) {
429            $invitedUsers = AdminUserInvitation::whereIn('_id', $invitedUsers)->get();
430            foreach ($invitedUsers as $invitedUser) {
431                $this->deleteInvitedUser($invitedUser);
432            }
433        }
434    }
435
436    public function deactivateInvitedUser(AdminUserInvitation $user, string $adminUserId)
437    {
438        if ($user->id == $adminUserId) {
439            throw new ExpectedException($this->cantDeactivateOwnAccount);
440        }
441
442        $user->status = 'Deactivated';
443        $user->deactivated_at = Carbon::now()->toDateTimeString();
444        $user->company_group_id = null;
445        $user->save();
446    }
447
448    public function deleteInvitedUser(AdminUserInvitation $user)
449    {
450        $user->forceDelete();
451    }
452
453    public function moveUsersToGroup(array $usersId, ?CompanyGroup $group)
454    {
455        $users = User::whereIn('_id', $usersId)->get();
456
457        // create the users ids array those available in users table
458        $existingUsers = User::whereIn('_id', $usersId)->pluck('_id')->toArray();
459
460        // users those not found in users table
461        $invitedUsers = array_diff($usersId, $existingUsers);
462
463        // for main users those are active
464        foreach ($users as $user) {
465            $user = $this->moveUserToGroup($user, $group);
466        }
467
468        // for the invited users those not yet registered
469        if (! empty($invitedUsers)) {
470            $invitedUsers = AdminUserInvitation::whereIn('_id', $invitedUsers)->get();
471            foreach ($invitedUsers as $invitedUser) {
472                $invitedUser = $this->moveInvitationUserToGroup($invitedUser, $group);
473            }
474        }
475
476        return $users;
477    }
478
479    public function moveUserToGroup(User $user, ?CompanyGroup $group)
480    {
481        $user->company_group_id = $group ? $group->id : null;
482        $user->save();
483
484        if ($user->instancy_id) {
485            if ($group) {
486                $newGroup = $group->instancy_id;
487            } else {
488                $newGroup = $user->company->instancy_id;
489            }
490
491            $instancyUser = new InstancyUserDTO(
492                $user->instancy_id,
493                $newGroup,
494                $user->first_name,
495                $user->last_name,
496                $user->email,
497                $user->company->name,
498            );
499
500            // old code
501            // $this->instancyRepository->updateUser($instancyUser);
502            InstancyUserUpdate::dispatch($instancyUser);
503        }
504
505        return $user;
506    }
507
508    public function moveInvitationUserToGroup(AdminUserInvitation $user, ?CompanyGroup $group)
509    {
510        $user->company_group_id = $group ? $group->id : null;
511        $user->save();
512
513        return $user;
514    }
515
516    private function acceptMoveToInvitation(User $user, AdminUserInvitation $invitation)
517    {
518        $user->removeAllRoles();
519        $group_ids = [];
520
521        $planId = $invitation->plan_id;
522        $companyId = $invitation->company_id;
523        $roleName = $invitation->role_name;
524        $groupId = $invitation->company_group_id;
525        $subgroupId = $invitation->company_subgroup_id;
526        $hasCorporatePlan = $invitation->has_corporate_plan;
527        $plan = Plans::find($planId);
528        $companyLicense = CompanyLicenses::where('company_id', $companyId)
529            ->active()
530            ->first();
531
532        if (($roleName == Role::GROUP_ADMIN || $roleName = Role::REPORTING_ADMIN) && ($groupId || $subgroupId)) {
533            $group_ids = [$groupId] ?? [$subgroupId] ?? [];
534        }
535        $user->assignRole($roleName, $group_ids);
536
537        $user->company_id = $companyId;
538        $user->activation_date = Carbon::now()->toDateTimeString();
539        if (filled($groupId)) {
540            $user->company_group_id = $groupId;
541        }
542
543        if (filled($subgroupId)) {
544            $user->company_group_id = $subgroupId;
545        }
546        $user->status = 'Active';
547        $user->unset('invited_to_company');
548        $user->unset('invited_to_company_by_admin');
549
550        FlyMsgUserDailyUsage::where('user_id', $user->id)
551            ->update([
552                'company_id' => $user->company_id,
553                'group_id' => $user->company_group_id,
554                'user_status' => $user->status,
555            ]);
556
557        $this->updateUserPlanAction->execute($user, $plan, $companyLicense->contract_end_date, $hasCorporatePlan);
558
559        if ($invitation) {
560            if ($invitation->reminder_job_id) {
561                Queue::forget($invitation->reminder_job_id);
562                $invitation->reminder_job_id = null;
563                $invitation->save();
564            }
565
566            $invitation->delete();
567        }
568
569        $user->save();
570
571        $user->refresh();
572
573        return $user;
574    }
575
576    public function acceptUserInvitation(User $user, ?string $company_id)
577    {
578        $invitation = AdminUserInvitation::where('email', $user->email)->withTrashed();
579
580        if ($company_id) {
581            $invitation = $invitation->where('company_id', $company_id);
582        }
583
584        $invitation = $invitation->first();
585
586        if ($invitation->move_assign) {
587            return $this->acceptMoveToInvitation($user, $invitation);
588        }
589
590        if ($invitation && $invitation->deleted_at && $company_id == $invitation->company_id) {
591            $user->unset('invited_to_company');
592            $user->unset('invited_to_company_by_admin');
593            $user->save();
594
595            FlyMsgUserDailyUsage::where('user_id', $user->id)
596                ->update([
597                    'company_id' => $user->company_id,
598                    'group_id' => $user->company_group_id,
599                    'user_status' => $user->status,
600                ]);
601
602            return $user;
603        }
604
605        // if (!$invitation) {
606        //     throw new ExpectedException("Invitation not found");
607        // }
608
609        if ($invitation) {
610            $plan = Plans::find($invitation->plan_id);
611            if ($company_id && ! $plan) {
612                throw new ExpectedException("The user was invited without a Plan. This shouldn't have happened.");
613            }
614
615            // Change the users plan to the invited one
616            $useSub = $user->subscription('main');
617
618            $changeSubscription = ! filled($useSub) || ($useSub->stripe_plan != $plan->stripe_id);
619
620            if ($changeSubscription) {
621                if ($user->subscribed('main')) {
622                    $companyLicense = CompanyLicenses::where('company_id', $user->company_id)
623                        ->active()
624                        ->first();
625                    if (filled($useSub->ends_at) && ($useSub->ends_at == $companyLicense?->contract_end_date)) {
626                        $useSub->update([
627                            'stripe_status' => 'canceled',
628                            'ends_at' => Carbon::now()->toDateTimeString(),
629                        ]);
630                    } else {
631                        $useSub->cancel();
632                    }
633                } else {
634                    $subscription = $user->subscriptions()->latest()->first();
635                    if ($subscription) {
636                        $subscription->update([
637                            'ends_at' => Carbon::now()->toDateTimeString(),
638                            'stripe_status' => 'canceled',
639                        ]);
640                    }
641                }
642            }
643
644            $license = CompanyLicenses::where('company_id', $user->company_id)
645                ->active()
646                ->first();
647
648            if ($company_id && ! $license) {
649                throw new ExpectedException("Failed to assign $plan. The company doesn't have any active licenses.");
650            }
651
652            if ($company_id && $changeSubscription) {
653                $user->subscriptions()->create([
654                    'name' => 'main',
655                    'stripe_status' => 'active',
656                    'stripe_plan' => $plan->stripe_id,
657                    'quantity' => '1',
658                    'ends_at' => $license->contract_end_date,
659                    'starts_at' => Carbon::now()->startOfDay()->toDateTimeString(),
660                ]);
661                $license->reduceCompanyLicenseCountForNewUsers($plan);
662            }
663        }
664
665        // Change the users status to Active
666        $user->status = 'Active';
667        $user->activation_date = Carbon::now()->toDateTimeString();
668
669        if ($invitation) {
670            if ($invitation->company_group_id) {
671                $user->company_group_id = $invitation->company_group_id;
672            }
673            if ($invitation->company_subgroup_id) {
674                $user->company_group_id = $invitation->company_subgroup_id;
675            }
676        }
677
678        $user->unset('invited_to_company');
679        $user->unset('invited_to_company_by_admin');
680
681        FlyMsgUserDailyUsage::where('user_id', $user->id)
682            ->update([
683                'company_id' => $user->company_id,
684                'group_id' => $user->company_group_id,
685                'user_status' => $user->status,
686            ]);
687
688        $user->save();
689
690        if ($invitation) {
691            if ($invitation->reminder_job_id) {
692                Queue::forget($invitation->reminder_job_id);
693                $invitation->reminder_job_id = null;
694                $invitation->save();
695            }
696
697            $invitation->delete();
698        }
699
700        if (isset($plan) && ! empty($plan)) {
701            $user->plan = $plan;
702        }
703
704        $user->refresh();
705
706        $this->cacheInvalidationService->invalidateUserSettingsCaches((string) $user->id);
707
708        return $user;
709    }
710
711    public function rejectUserInvitation(User $user, ?string $company_id)
712    {
713        $invitation = AdminUserInvitation::where('email', $user->email)->withTrashed();
714
715        if ($company_id) {
716            $invitation = $invitation->where('company_id', $company_id);
717        }
718
719        $invitation = $invitation->first();
720
721        if ($invitation) {
722            $plan = Plans::find($invitation->plan_id);
723
724            if ($plan) {
725                // Change the users plan to the invited one
726                $useSub = $user->subscription('main');
727
728                $changeSubscription = filled($useSub) && ($useSub->stripe_plan == $plan->stripe_id);
729
730                if ($changeSubscription) {
731                    $companyLicense = CompanyLicenses::where('company_id', $user->company_id)
732                        ->active()
733                        ->first();
734
735                    if ($user->subscribed('main')) {
736                        if (filled($useSub->ends_at) && ($useSub->ends_at == $companyLicense?->contract_end_date)) {
737                            $useSub->update([
738                                'stripe_status' => 'canceled',
739                                'ends_at' => Carbon::now()->toDateTimeString(),
740                            ]);
741                        } else {
742                            $useSub->cancel();
743                        }
744                    } else {
745                        $subscription = $user->subscriptions()->latest()->first();
746                        if ($subscription) {
747                            $subscription->update([
748                                'ends_at' => Carbon::now()->toDateTimeString(),
749                                'stripe_status' => 'canceled',
750                            ]);
751                        }
752                    }
753
754                    if ($changeSubscription && $companyLicense) {
755                        $companyLicense->restoreLicenseCountForDeletedUsers($plan);
756                    }
757                }
758            }
759        }
760
761        // Change the users status to Active
762        $user->status = 'Active';
763        $user->unset('activation_date');
764        $user->unset('company_id');
765        $user->unset('company_group_id');
766        $user->unset('invited_to_company');
767        $user->unset('invited_to_company_by_admin');
768        $user->save();
769        // remove roles
770        $user->removeAllRoles();
771
772        if ($invitation) {
773            if ($invitation->reminder_job_id) {
774                Queue::forget($invitation->reminder_job_id);
775                $invitation->reminder_job_id = null;
776                $invitation->save();
777            }
778
779            if (! $invitation->deleted_at) {
780                $invitation->delete();
781            }
782        }
783
784        $this->cacheInvalidationService->invalidateUserSettingsCaches((string) $user->id);
785
786        return $user;
787    }
788
789    public function createUserForInvitationLogin(AdminUserInvitation $invitation)
790    {
791        $user = new User;
792        $user->status = 'Invited';
793        $user->email = $invitation->email;
794        $user->first_name = '';
795        $user->last_name = '';
796        $user->password = $invitation->password ?? $invitation->temp_password;
797        $user->temp_password = $invitation->password ?? $invitation->temp_password;
798        $user->company_id = $invitation->company_id;
799        $user->email_verified_at = new UTCDateTime(now()->getTimestamp() * 1000);
800        $user->onboardingv2_presented = true;
801
802        $user->save();
803
804        $data = [
805            'email' => $user->email,
806            'first_name' => $user->first_name,
807            'last_name' => $user->last_name,
808            'do_not_send_welcome_notification' => true,
809        ];
810
811        Registered::dispatch($user, $data);
812
813        $user = $this->acceptUserInvitation($user, $invitation->company_id);
814
815        return $user;
816    }
817}