Code Coverage |
||||||||||
Lines |
Functions and Methods |
Classes and Traits |
||||||||
Total | |
0.00% |
0 / 130 |
|
0.00% |
0 / 6 |
CRAP | |
0.00% |
0 / 1 |
CompanyUsersService | |
0.00% |
0 / 130 |
|
0.00% |
0 / 6 |
702 | |
0.00% |
0 / 1 |
__construct | |
0.00% |
0 / 1 |
|
0.00% |
0 / 1 |
2 | |||
userEmailsExists | |
0.00% |
0 / 19 |
|
0.00% |
0 / 1 |
20 | |||
addByEmail | |
0.00% |
0 / 61 |
|
0.00% |
0 / 1 |
90 | |||
addExistentUserByEmail | |
0.00% |
0 / 10 |
|
0.00% |
0 / 1 |
12 | |||
addNewUserByEmail | |
0.00% |
0 / 28 |
|
0.00% |
0 / 1 |
20 | |||
createInstancyUser | |
0.00% |
0 / 11 |
|
0.00% |
0 / 1 |
30 |
1 | <?php |
2 | |
3 | namespace App\Http\Services\Admin\Companies; |
4 | |
5 | use App\Http\Models\Admin\AdminUserInvitation; |
6 | use App\Http\Models\Admin\Company; |
7 | use App\Http\Models\Admin\CompanyGroup; |
8 | use App\Http\Models\Admin\CompanyLicenses; |
9 | use App\Http\Models\Auth\User; |
10 | use App\Http\Models\Plans; |
11 | use App\Http\Services\InstancyServiceV2; |
12 | use App\Jobs\Emails\AddExistentUserJob; |
13 | use App\Jobs\Emails\AddNewUserNotification; |
14 | use App\Jobs\Emails\AddNewUserReminder; |
15 | use App\Mail\AdminCenterAddNewUser; |
16 | use App\Services\Email\EmailService; |
17 | use App\Traits\CompanyTrait; |
18 | use Carbon\Carbon; |
19 | use Illuminate\Support\Facades\Log; |
20 | use Illuminate\Support\Str; |
21 | |
22 | class 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 | } |