Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
0.00% covered (danger)
0.00%
0 / 130
0.00% covered (danger)
0.00%
0 / 6
CRAP
0.00% covered (danger)
0.00%
0 / 1
CompanyUsersService
0.00% covered (danger)
0.00%
0 / 130
0.00% covered (danger)
0.00%
0 / 6
702
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
 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 string $companyId
79     * @param User $adminUser
80     * @return array{users: array, invitation_sent_count: int}
81     */
82    public function addByEmail(array $request, string $companyId, $adminUser)
83    {
84        $invitation_sent_count = 0;
85        $response_builder = [];
86        $usersToCreate = [];
87
88        $company = Company::find($companyId);
89
90        $this->companyLicensesService->validatePlansAvailability($request, $companyId);
91
92        foreach ($request['users'] as $newUser) {
93            $user = User::where("email", $newUser["email"])
94                ->where("company_id", $companyId)
95                ->first();
96
97            if ($user) {
98                continue;
99            }
100
101            $plan_id = $newUser["plan"];
102            $plan = Plans::where('stripe_id', $plan_id)->first();
103
104            $password = Str::password(16);
105            $hashed_password = bcrypt($password);
106            $password_expiry = Carbon::now()->addDays(7);
107
108            $newUser["plan"] = $plan;
109            $newUser["plan_id"] = $plan->id;
110            $newUser["company_id"] = $companyId;
111            $newUser["company_group_id"] = $request["group_id"];
112            $newUser["company_subgroup_id"] = $request["subgroup_id"];
113            $newUser["temp_password_expiry"] = $password_expiry->toDateTimeString();
114            $newUser["temp_password"] = $hashed_password;
115            $newUser["password"] = $hashed_password;
116            $newUser["admin_email"] = $adminUser->email;
117            $newUser["remove_password"] = $password;
118
119            $usersToCreate[] = $newUser;
120        }
121
122        foreach ($usersToCreate as $newUser) {
123            $user = User::where("email", $newUser["email"])->first();
124
125            if ($user) {
126                $this->addExistentUserByEmail($user, $newUser, $company);
127            } else {
128                $newUser["reminder_job_id"] = $this->addNewUserByEmail($newUser, $password_expiry, $company);
129                $invitation_sent_count++;
130            }
131
132            unset($newUser["remove_password"]);
133
134            $invitation = AdminUserInvitation::updateOrCreate(['email' => $newUser["email"]], $newUser);
135
136            $group_name = $request['group_id'] ? CompanyGroup::find($request['group_id'])->name : "Not Assigned";
137            $subgroup_name = $request['subgroup_id'] ? CompanyGroup::find($request['subgroup_id'])->name : "Not Assigned";
138
139            $response_builder[] = [
140                'id' => $user?->id ?? $invitation?->id,
141                'first_name' => $user?->first_name ?? null,
142                'last_name' => $user?->last_name ?? null,
143                'email' => $newUser["email"],
144                'role' => 'User',
145                'group' => $group_name,
146                'sub_group' => $subgroup_name,
147                'group_subgroup' => $subgroup_name != "Not Assigned" ? $subgroup_name : $group_name,
148                'licenseType' => $newUser["plan"]?->title ?? "Not Assigned",
149                'status' => "Invited",
150                'invitation_link' => $invitation->getInvitationLinkForAdminPortal(),
151                'created_at' => $user?->created_at ?? $invitation?->updated_at,
152                'user_id' => $user?->id ?? null,
153                'group_id' => $request['group_id'],
154                'group_subgroup_id' => $request['subgroup_id'],
155                'statusDate' => $invitation?->updated_at?->toFormattedDateString(),
156                'is_invite' => filled($user) ? false : true,
157                'company_slug' => $company->slug,
158            ];
159        }
160
161        return [
162            'users' => $response_builder,
163            'invitation_sent_count' => $invitation_sent_count,
164        ];
165    }
166
167    /**
168     * addExistentUserByEmail.
169     *
170     * @param User $user
171     * @param array<array{email: string, plan: string}> $data
172     * @param Company $company
173     * @return void
174     */
175    private function addExistentUserByEmail(User $user, array $data, Company $company)
176    {
177        $user->company_id = $data['company_id'];
178        $user->invited_to_company = true;
179        $user->invited_to_company_by_admin = $data['admin_email'];
180        $user->status = "Invited";
181
182        if (filled($data['company_group_id'])) {
183            $user->company_group_id = $data['company_group_id'];
184        }
185
186        if (filled($data['company_subgroup_id'])) {
187            $user->company_group_id = $data['company_subgroup_id'];
188        }
189
190        $user->save();
191
192        AddExistentUserJob::dispatch($data['email'], $data['admin_email'], $company, $this->emailService)->delay(now()->addSeconds(1));
193    }
194
195    /**
196     * addExistentUserByEmail.
197     *
198     * @param array{email: string, password: string, admin_email: string} $data
199     * @param Carbon $password_expiry
200     * @return string
201     */
202    private function addNewUserByEmail(array $data, Carbon $password_expiry, $company): string
203    {
204        $password_expiry = $password_expiry->format("m/d/Y") . " at " . $password_expiry->format("h:i A");
205
206        $this->emailService->send(
207            $data['email'],
208            new AdminCenterAddNewUser(
209                email: $data['email'],
210                password: $data['remove_password'],
211                inviter: $data['admin_email'],
212                password_expiry: $password_expiry,
213            ),
214            'cmc_add_new_user_by_email'
215        );
216
217        $admin = auth()->user();
218        $companyName = $admin->company->name;
219        $companyEmail = $admin->email;
220        if ($company) {
221            $companyLicense = CompanyLicenses::where('company_id', $company->id)->first();
222            $community = $companyLicense->business_pro_enterprise_plus ?? [];
223            $isPro = in_array('yes_dedicated', $community) || in_array('yes_community', $community);
224
225            if ($isPro) {
226                AddNewUserNotification::dispatch($data['email'], $companyEmail, $companyName, $this->emailService)->delay(now()->addSeconds(2));
227            }
228        }
229
230        $addNewUserEmailJob = (new AddNewUserReminder(
231            $data['email'],
232            $data['remove_password'],
233            $data['admin_email'],
234            $password_expiry,
235            $this->emailService
236        ))->delay(now()->addHours(48));
237
238        return app(\Illuminate\Contracts\Bus\Dispatcher::class)->dispatch($addNewUserEmailJob);
239    }
240
241    private function createInstancyUser(Plans $plan, User $user)
242    {
243        if (in_array($plan->identifier, $this->instancyPlanIdentifiersApplicable)) {
244            try {
245                $group = CompanyGroup::find($user->company_group_id);
246                $company = Company::find($user->company_id);
247
248                $groupId = false;
249                if ($company) {
250                    $groupId = $company->instancy_id;
251                } elseif ($group) {
252                    $groupId = $group->instancy_id;
253                }
254
255                (new InstancyServiceV2)->createInstancyUser($user->email, $groupId);
256            } catch (\Throwable $th) {
257                Log::error(__METHOD__, $th);
258            }
259        }
260    }
261}