Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
0.77% covered (danger)
0.77%
1 / 130
16.67% covered (danger)
16.67%
1 / 6
CRAP
0.00% covered (danger)
0.00%
0 / 1
CompanyUsersService
0.77% covered (danger)
0.77%
1 / 130
16.67% covered (danger)
16.67%
1 / 6
686.52
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
 userEmailsExists
0.00% covered (danger)
0.00%
0 / 19
0.00% covered (danger)
0.00%
0 / 1
20
 addByEmail
0.00% covered (danger)
0.00%
0 / 61
0.00% covered (danger)
0.00%
0 / 1
90
 addExistentUserByEmail
0.00% covered (danger)
0.00%
0 / 10
0.00% covered (danger)
0.00%
0 / 1
12
 addNewUserByEmail
0.00% covered (danger)
0.00%
0 / 28
0.00% covered (danger)
0.00%
0 / 1
20
 createInstancyUser
0.00% covered (danger)
0.00%
0 / 11
0.00% covered (danger)
0.00%
0 / 1
30
1<?php
2
3namespace App\Http\Services\Admin\Companies;
4
5use App\Http\Models\Admin\AdminUserInvitation;
6use App\Http\Models\Admin\Company;
7use App\Http\Models\Admin\CompanyGroup;
8use App\Http\Models\Admin\CompanyLicenses;
9use App\Http\Models\Auth\User;
10use App\Http\Models\Plans;
11use App\Http\Services\InstancyServiceV2;
12use App\Jobs\Emails\AddExistentUserJob;
13use App\Jobs\Emails\AddNewUserNotification;
14use App\Jobs\Emails\AddNewUserReminder;
15use App\Mail\AdminCenterAddNewUser;
16use App\Services\Email\EmailService;
17use App\Traits\CompanyTrait;
18use Carbon\Carbon;
19use Illuminate\Support\Facades\Log;
20use Illuminate\Support\Str;
21
22class CompanyUsersService
23{
24    use CompanyTrait;
25
26    public function __construct(
27        private readonly CompanyLicensesService $companyLicensesService,
28        private readonly EmailService $emailService
29    ) {}
30
31    private $instancyPlanIdentifiersApplicable = [
32        Plans::PROFESSIONAL_MONTHLY_IDENTIFIER,
33        Plans::PROFESSIONAL_YEARLY_IDENTIFIER,
34        Plans::ProPlanTeamsSMB,
35        Plans::ProPlanTeamsENT,
36    ];
37
38    public function userEmailsExists(?string $companyId, array $emails)
39    {
40        $usersCount = User::whereIn('email', $emails);
41
42        if ($companyId) {
43            $usersCount = $usersCount->where('company_id', $companyId);
44        }
45
46        $users = $usersCount->get()->pluck('email')->toArray();
47
48        $invitationsCount = AdminUserInvitation::whereIn('email', $emails);
49
50        if ($companyId) {
51            $invitationsCount = $invitationsCount->where('company_id', $companyId);
52        }
53
54        $invitations = $invitationsCount->get()->pluck('email')->toArray();
55
56        $users = array_merge($users, $invitations);
57
58        $message = 'The emails you provided are available.';
59
60        $exists = count($users) > 0;
61
62        if ($exists) {
63            $email = implode(', ', $users);
64            $message = "The emails $email has already been taken.";
65        }
66
67        return [
68            'success' => true,
69            'exists' => $exists,
70            'message' => $message,
71        ];
72    }
73
74    /**
75     * Validate plans availability.
76     *
77     * @param  array{users:array<array{email: string, plan: string}>, group_id: string, subgroup_id: string}  $request
78     * @param  User  $adminUser
79     * @return array{users: array, invitation_sent_count: int}
80     */
81    public function addByEmail(array $request, string $companyId, $adminUser)
82    {
83        $invitation_sent_count = 0;
84        $response_builder = [];
85        $usersToCreate = [];
86
87        $company = Company::find($companyId);
88
89        $this->companyLicensesService->validatePlansAvailability($request, $companyId);
90
91        foreach ($request['users'] as $newUser) {
92            $user = User::where('email', $newUser['email'])
93                ->where('company_id', $companyId)
94                ->first();
95
96            if ($user) {
97                continue;
98            }
99
100            $plan_id = $newUser['plan'];
101            $plan = Plans::where('stripe_id', $plan_id)->first();
102
103            $password = Str::password(16);
104            $hashed_password = bcrypt($password);
105            $password_expiry = Carbon::now()->addDays(7);
106
107            $newUser['plan'] = $plan;
108            $newUser['plan_id'] = $plan->id;
109            $newUser['company_id'] = $companyId;
110            $newUser['company_group_id'] = $request['group_id'];
111            $newUser['company_subgroup_id'] = $request['subgroup_id'];
112            $newUser['temp_password_expiry'] = $password_expiry->toDateTimeString();
113            $newUser['temp_password'] = $hashed_password;
114            $newUser['password'] = $hashed_password;
115            $newUser['admin_email'] = $adminUser->email;
116            $newUser['remove_password'] = $password;
117
118            $usersToCreate[] = $newUser;
119        }
120
121        foreach ($usersToCreate as $newUser) {
122            $user = User::where('email', $newUser['email'])->first();
123
124            if ($user) {
125                $this->addExistentUserByEmail($user, $newUser, $company);
126            } else {
127                $newUser['reminder_job_id'] = $this->addNewUserByEmail($newUser, $password_expiry, $company);
128                $invitation_sent_count++;
129            }
130
131            unset($newUser['remove_password']);
132
133            $invitation = AdminUserInvitation::updateOrCreate(['email' => $newUser['email']], $newUser);
134
135            $group_name = $request['group_id'] ? CompanyGroup::find($request['group_id'])->name : 'Not Assigned';
136            $subgroup_name = $request['subgroup_id'] ? CompanyGroup::find($request['subgroup_id'])->name : 'Not Assigned';
137
138            $response_builder[] = [
139                'id' => $user?->id ?? $invitation?->id,
140                'first_name' => $user?->first_name ?? null,
141                'last_name' => $user?->last_name ?? null,
142                'email' => $newUser['email'],
143                'role' => 'User',
144                'group' => $group_name,
145                'sub_group' => $subgroup_name,
146                'group_subgroup' => $subgroup_name != 'Not Assigned' ? $subgroup_name : $group_name,
147                'licenseType' => $newUser['plan']?->title ?? 'Not Assigned',
148                'status' => 'Invited',
149                'invitation_link' => $invitation->getInvitationLinkForAdminPortal(),
150                'created_at' => $user?->created_at ?? $invitation?->updated_at,
151                'user_id' => $user?->id ?? null,
152                'group_id' => $request['group_id'],
153                'group_subgroup_id' => $request['subgroup_id'],
154                'statusDate' => $invitation?->updated_at?->toFormattedDateString(),
155                'is_invite' => filled($user) ? false : true,
156                'company_slug' => $company->slug,
157            ];
158        }
159
160        return [
161            'users' => $response_builder,
162            'invitation_sent_count' => $invitation_sent_count,
163        ];
164    }
165
166    /**
167     * addExistentUserByEmail.
168     *
169     * @param  array<array{email: string, plan: string}>  $data
170     * @return void
171     */
172    private function addExistentUserByEmail(User $user, array $data, Company $company)
173    {
174        $user->company_id = $data['company_id'];
175        $user->invited_to_company = true;
176        $user->invited_to_company_by_admin = $data['admin_email'];
177        $user->status = 'Invited';
178
179        if (filled($data['company_group_id'])) {
180            $user->company_group_id = $data['company_group_id'];
181        }
182
183        if (filled($data['company_subgroup_id'])) {
184            $user->company_group_id = $data['company_subgroup_id'];
185        }
186
187        $user->save();
188
189        AddExistentUserJob::dispatch($data['email'], $data['admin_email'], $company, $this->emailService)->delay(now()->addSeconds(1));
190    }
191
192    /**
193     * addExistentUserByEmail.
194     *
195     * @param  array{email: string, password: string, admin_email: string}  $data
196     */
197    private function addNewUserByEmail(array $data, Carbon $password_expiry, $company): string
198    {
199        $password_expiry = $password_expiry->format('m/d/Y').' at '.$password_expiry->format('h:i A');
200
201        $this->emailService->send(
202            $data['email'],
203            new AdminCenterAddNewUser(
204                email: $data['email'],
205                password: $data['remove_password'],
206                inviter: $data['admin_email'],
207                password_expiry: $password_expiry,
208            ),
209            'cmc_add_new_user_by_email'
210        );
211
212        $admin = auth()->user();
213        $companyName = $admin->company->name;
214        $companyEmail = $admin->email;
215        if ($company) {
216            $companyLicense = CompanyLicenses::where('company_id', $company->id)->first();
217            $community = $companyLicense->business_pro_enterprise_plus ?? [];
218            $isPro = in_array('yes_dedicated', $community) || in_array('yes_community', $community);
219
220            if ($isPro) {
221                AddNewUserNotification::dispatch($data['email'], $companyEmail, $companyName, $this->emailService)->delay(now()->addSeconds(2));
222            }
223        }
224
225        $addNewUserEmailJob = (new AddNewUserReminder(
226            $data['email'],
227            $data['remove_password'],
228            $data['admin_email'],
229            $password_expiry,
230            $this->emailService
231        ))->delay(now()->addHours(48));
232
233        return app(\Illuminate\Contracts\Bus\Dispatcher::class)->dispatch($addNewUserEmailJob);
234    }
235
236    private function createInstancyUser(Plans $plan, User $user)
237    {
238        if (in_array($plan->identifier, $this->instancyPlanIdentifiersApplicable)) {
239            try {
240                $group = CompanyGroup::find($user->company_group_id);
241                $company = Company::find($user->company_id);
242
243                $groupId = false;
244                if ($company) {
245                    $groupId = $company->instancy_id;
246                } elseif ($group) {
247                    $groupId = $group->instancy_id;
248                }
249
250                (new InstancyServiceV2)->createInstancyUser($user->email, $groupId);
251            } catch (\Throwable $th) {
252                Log::error(__METHOD__, $th);
253            }
254        }
255    }
256}