Code Coverage |
||||||||||
Lines |
Functions and Methods |
Classes and Traits |
||||||||
Total | |
0.00% |
0 / 489 |
|
0.00% |
0 / 5 |
CRAP | |
0.00% |
0 / 1 |
UsersReportOverviewExport | |
0.00% |
0 / 489 |
|
0.00% |
0 / 5 |
42 | |
0.00% |
0 / 1 |
__construct | |
0.00% |
0 / 1 |
|
0.00% |
0 / 1 |
2 | |||
array | |
0.00% |
0 / 81 |
|
0.00% |
0 / 1 |
6 | |||
headings | |
0.00% |
0 / 15 |
|
0.00% |
0 / 1 |
2 | |||
getCompanyOverview | |
0.00% |
0 / 315 |
|
0.00% |
0 / 1 |
2 | |||
getFlyCutUsageByUser | |
0.00% |
0 / 77 |
|
0.00% |
0 / 1 |
2 |
1 | <?php |
2 | |
3 | namespace App\Exports; |
4 | |
5 | use App\Helpers\CoachLevelHelper; |
6 | use App\Http\Models\Admin\Company; |
7 | use Carbon\Carbon; |
8 | use Carbon\CarbonPeriod; |
9 | use App\Http\Models\Chart; |
10 | use MongoDB\BSON\UTCDateTime; |
11 | use App\Http\Models\Auth\User; |
12 | use App\Http\Models\HubspotProperties; |
13 | use App\Http\Models\Admin\CompanyLicenses; |
14 | use App\Http\Models\FlyCutUsage; |
15 | use Vitorccs\LaravelCsv\Concerns\FromArray; |
16 | use Vitorccs\LaravelCsv\Concerns\Exportable; |
17 | use Vitorccs\LaravelCsv\Concerns\WithHeadings; |
18 | use App\Traits\AccountCenter\Reporting\ChartTrait; |
19 | use MongoDB\BSON\ObjectId; |
20 | |
21 | class UsersReportOverviewExport implements FromArray, WithHeadings |
22 | { |
23 | use Exportable; |
24 | use ChartTrait; |
25 | |
26 | public $company_id; |
27 | |
28 | public function __construct($company_id) |
29 | { |
30 | $this->company_id = $company_id; |
31 | } |
32 | |
33 | public function array(): array |
34 | { |
35 | $flychartTotal = $this->getCompanyOverview($this->company_id, Carbon::now()->subMonths(12)->toDateString(), Carbon::now()->toDateString()); |
36 | |
37 | $users = User::select([ |
38 | "id", |
39 | "first_name", |
40 | "last_name", |
41 | "company_group_id", |
42 | "company_id", |
43 | "deleted_at", |
44 | "avatar" |
45 | ])->where("company_id", "=", $this->company_id); |
46 | |
47 | $users = $users->get(); |
48 | $user_ids = $users->pluck("id")->toArray(); |
49 | |
50 | $period = CarbonPeriod::create(Carbon::now()->subMonths(12)->toDateString(), '1 month', Carbon::now()->toDateString()); |
51 | $data = []; |
52 | |
53 | $startDate = new UTCDateTime(Carbon::now()->subMonths(12)->startOfDay()->getTimestamp() * 1000); |
54 | $endDate = new UTCDateTime(Carbon::now()->endOfDay()->getTimestamp() * 1000); |
55 | $characterUsageTotal = $this->getFlyCutUsageByUser($user_ids, $startDate, $endDate); |
56 | |
57 | foreach ($period as $date) { |
58 | $month_year = $date->format('M Y'); |
59 | $year_month = $date->format('Y-m'); |
60 | |
61 | $purchased_licenses = $flychartTotal[0]->purchased_licenses; |
62 | $assigned_licenses = $flychartTotal[0]->total_active_licenses + $flychartTotal[0]->total_invited_licenses; |
63 | $activate_licenses = $flychartTotal[0]->total_active_licenses; |
64 | $extension_installed = 0; |
65 | |
66 | $extensions_installed_query = HubspotProperties::raw(function ($collection) use ($user_ids, $date) { |
67 | return $collection->aggregate([ |
68 | [ |
69 | '$match' => [ |
70 | 'flymsg_id' => ['$in' => $user_ids], |
71 | '$or' => [ |
72 | [ |
73 | 'flymsg_chrome_extension_installed' => 'Yes', |
74 | 'flymsg_chrome_extension_uninstalled' => 'No' |
75 | ], |
76 | [ |
77 | 'flymsg_edge_extension_installed' => 'Yes', |
78 | 'flymsg_edge_extension_uninstalled' => 'No' |
79 | ] |
80 | ], |
81 | 'created_at' => [ |
82 | '$gte' => new UTCDateTime(strtotime($date->startOfMonth()->toDateString()) * 1000), |
83 | '$lte' => new UTCDateTime(strtotime($date->endOfMonth()->toDateString()) * 1000) |
84 | ] |
85 | ] |
86 | ], |
87 | [ |
88 | '$sort' => [ |
89 | 'created_at' => -1 |
90 | ] |
91 | ], |
92 | [ |
93 | '$group' => [ |
94 | '_id' => '$flymsg_id', |
95 | 'most_recent' => ['$first' => '$$ROOT'] |
96 | ] |
97 | ] |
98 | ]); |
99 | }); |
100 | |
101 | $extension_installed = count($extensions_installed_query); |
102 | |
103 | $flychart = collect($flychartTotal[0]->flycut_usage_aggregated)->firstWhere("month_year", $year_month); |
104 | |
105 | $roi_spotlight = round($flychart->cost_saved_by_flymsg, 2); |
106 | $productivity_spotlight = round($flychart->time_saved_by_flymsg, 2); |
107 | $total_characters_typed = round($flychart->characters_typed_by_flymsg, 2); |
108 | |
109 | $characterUsage = $characterUsageTotal->where("_id", $year_month)->first()?->users ?? []; |
110 | |
111 | $coachLevels = CoachLevelHelper::categorizeCharacterUsage($characterUsage, count($user_ids)); |
112 | |
113 | $data[$month_year] = [ |
114 | 'Month' => $month_year, |
115 | 'Purchased Licenses' => $purchased_licenses, |
116 | 'Assigned Licenses' => $assigned_licenses, |
117 | 'Activate Licenses' => $activate_licenses, |
118 | 'Extension Installed' => $extension_installed, |
119 | |
120 | 'ROI Spotlight' => $roi_spotlight, |
121 | 'Productivity Spotlight' => $productivity_spotlight, |
122 | 'Total Characters Typed' => $total_characters_typed, |
123 | |
124 | 'Coach Level Beginner' => $coachLevels->beginner, |
125 | 'Coach Level Intermediate' => $coachLevels->intermediate, |
126 | 'Coach Level Proficient' => $coachLevels->proficient, |
127 | 'Coach Level Advanced' => $coachLevels->advanced, |
128 | 'Coach Level Expert' => $coachLevels->expert, |
129 | ]; |
130 | } |
131 | |
132 | return $data; |
133 | } |
134 | |
135 | public function headings(): array |
136 | { |
137 | return [ |
138 | 'Months', |
139 | 'Purchased Licenses', |
140 | 'Assigned Licenses', |
141 | 'Activate Licenses', |
142 | 'Extension Installed', |
143 | 'ROI Spotlight', |
144 | 'Productivity Spotlight', |
145 | 'Total Characters Typed', |
146 | 'Coach Level Beginner', |
147 | 'Coach Level Intermediate', |
148 | 'Coach Level Proficient', |
149 | 'Coach Level Advanced', |
150 | 'Coach Level Expert', |
151 | ]; |
152 | } |
153 | |
154 | private function getCompanyOverview(string $companyId, string $startDate, string $endDate) |
155 | { |
156 | $companyId = new ObjectId($companyId); |
157 | $startDate = new UTCDateTime(strtotime($startDate) * 1000); |
158 | $endDate = new UTCDateTime(strtotime($endDate) * 1000); |
159 | |
160 | $aggregation = [ |
161 | [ |
162 | '$match' => [ |
163 | '_id' => $companyId |
164 | ] |
165 | ], |
166 | [ |
167 | '$lookup' => [ |
168 | 'from' => 'company_licenses', |
169 | 'let' => ['companyId' => ['$toString' => '$_id']], |
170 | 'pipeline' => [ |
171 | [ |
172 | '$match' => [ |
173 | '$expr' => ['$and' => [ |
174 | ['$eq' => ['$company_id', '$$companyId']] |
175 | ]] |
176 | ] |
177 | ], |
178 | [ |
179 | '$project' => [ |
180 | 'purchased_licenses' => [ |
181 | '$add' => [ |
182 | '$total_sales_pro_teams_license_count', |
183 | '$total_sales_pro_license_count', |
184 | '$total_growth_license_count', |
185 | '$total_starter_license_count' |
186 | ] |
187 | ] |
188 | ] |
189 | ] |
190 | ], |
191 | 'as' => 'licenses_data' |
192 | ] |
193 | ], |
194 | [ |
195 | '$unwind' => [ |
196 | 'path' => '$licenses_data', |
197 | 'preserveNullAndEmptyArrays' => true |
198 | ] |
199 | ], |
200 | [ |
201 | '$lookup' => [ |
202 | 'from' => 'users', |
203 | 'let' => ['companyId' => ['$toString' => '$_id']], |
204 | 'pipeline' => [ |
205 | [ |
206 | '$match' => [ |
207 | '$expr' => ['$eq' => ['$company_id', '$$companyId']] |
208 | ] |
209 | ], |
210 | [ |
211 | '$lookup' => [ |
212 | 'from' => 'flycut_usage', |
213 | 'let' => ['userId' => ['$toString' => '$_id']], |
214 | 'pipeline' => [ |
215 | [ |
216 | '$match' => [ |
217 | '$expr' => [ |
218 | '$and' => [ |
219 | ['$eq' => ['$user_id', '$$userId']], |
220 | ['$gte' => ['$created_at', $startDate]], |
221 | ['$lte' => ['$created_at', $endDate]] |
222 | ] |
223 | ] |
224 | ] |
225 | ], |
226 | [ |
227 | '$group' => [ |
228 | '_id' => [ |
229 | 'month_year' => [ |
230 | '$dateToString' => [ |
231 | 'format' => '%Y-%m', |
232 | 'date' => '$created_at' |
233 | ] |
234 | ] |
235 | ], |
236 | 'characters_typed_by_flymsg' => ['$sum' => '$characters_typed'], |
237 | 'time_saved_by_flymsg' => ['$sum' => '$time_saved'], |
238 | 'cost_saved_by_flymsg' => ['$sum' => '$cost_saved'] |
239 | ] |
240 | ], |
241 | [ |
242 | '$sort' => ['_id.month_year' => 1] |
243 | ] |
244 | ], |
245 | 'as' => 'monthly_usage_data' |
246 | ] |
247 | ], |
248 | [ |
249 | '$unwind' => [ |
250 | 'path' => '$monthly_usage_data', |
251 | 'preserveNullAndEmptyArrays' => false |
252 | ] |
253 | ], |
254 | [ |
255 | '$group' => [ |
256 | '_id' => '$monthly_usage_data._id.month_year', |
257 | 'characters_typed_by_flymsg' => ['$sum' => '$monthly_usage_data.characters_typed_by_flymsg'], |
258 | 'time_saved_by_flymsg' => ['$sum' => '$monthly_usage_data.time_saved_by_flymsg'], |
259 | 'cost_saved_by_flymsg' => ['$sum' => '$monthly_usage_data.cost_saved_by_flymsg'] |
260 | ] |
261 | ], |
262 | [ |
263 | '$sort' => ['_id' => 1] |
264 | ], |
265 | [ |
266 | '$group' => [ |
267 | '_id' => null, |
268 | 'flycut_usage_aggregated' => [ |
269 | '$push' => [ |
270 | 'month_year' => '$_id', |
271 | 'characters_typed_by_flymsg' => '$characters_typed_by_flymsg', |
272 | 'time_saved_by_flymsg' => '$time_saved_by_flymsg', |
273 | 'cost_saved_by_flymsg' => '$cost_saved_by_flymsg' |
274 | ] |
275 | ] |
276 | ] |
277 | ] |
278 | ], |
279 | 'as' => 'flycut_data' |
280 | ] |
281 | ], |
282 | [ |
283 | '$unwind' => [ |
284 | 'path' => '$flycut_data', |
285 | 'preserveNullAndEmptyArrays' => true |
286 | ] |
287 | ], |
288 | [ |
289 | '$lookup' => [ |
290 | 'from' => 'users', |
291 | 'let' => ['companyId' => ['$toString' => '$_id']], |
292 | 'pipeline' => [ |
293 | [ |
294 | '$match' => [ |
295 | '$expr' => ['$and' => [ |
296 | ['$eq' => ['$company_id', '$$companyId']] |
297 | ]] |
298 | ] |
299 | ], |
300 | [ |
301 | '$lookup' => [ |
302 | 'from' => 'subscriptions', |
303 | 'let' => ['userId' => ['$toString' => '$_id'], 'userStatus' => '$status'], |
304 | 'pipeline' => [ |
305 | [ |
306 | '$match' => [ |
307 | '$expr' => [ |
308 | '$and' => [ |
309 | ['$eq' => ['$user_id', '$$userId']], |
310 | ['$eq' => ['$name', 'main']], |
311 | ['$eq' => ['$stripe_status', 'active']], |
312 | ['$eq' => ['$$userStatus', 'Active']] |
313 | ] |
314 | ] |
315 | ] |
316 | ], |
317 | [ |
318 | '$sort' => ['created_at' => -1] |
319 | ], |
320 | [ |
321 | '$limit' => 1 |
322 | ] |
323 | ], |
324 | 'as' => 'active_users_subscriptions_data' |
325 | ] |
326 | ], |
327 | [ |
328 | '$lookup' => [ |
329 | 'from' => 'subscriptions', |
330 | 'let' => ['userId' => ['$toString' => '$_id'], 'userStatus' => '$status'], |
331 | 'pipeline' => [ |
332 | [ |
333 | '$match' => [ |
334 | '$expr' => [ |
335 | '$and' => [ |
336 | ['$eq' => ['$user_id', '$$userId']], |
337 | ['$eq' => ['$name', 'main']], |
338 | ['$eq' => ['$stripe_status', 'active']], |
339 | ['$eq' => ['$$userStatus', 'Invited']] |
340 | ] |
341 | ] |
342 | ] |
343 | ], |
344 | [ |
345 | '$sort' => ['created_at' => -1] |
346 | ], |
347 | [ |
348 | '$limit' => 1 |
349 | ] |
350 | ], |
351 | 'as' => 'invited_users_subscriptions_data' |
352 | ] |
353 | ], |
354 | [ |
355 | '$addFields' => [ |
356 | 'active_subscription_count' => ['$size' => '$active_users_subscriptions_data'], |
357 | 'invited_subscription_count' => ['$size' => '$invited_users_subscriptions_data'] |
358 | ] |
359 | ], |
360 | [ |
361 | '$group' => [ |
362 | '_id' => null, |
363 | 'total_active_subscriptions' => ['$sum' => '$active_subscription_count'], |
364 | 'total_invited_subscriptions' => ['$sum' => '$invited_subscription_count'] |
365 | ] |
366 | ], |
367 | [ |
368 | '$project' => [ |
369 | '_id' => 0, |
370 | 'total_active_subscriptions' => 1, |
371 | 'total_invited_subscriptions' => 1 |
372 | ] |
373 | ] |
374 | ], |
375 | 'as' => 'sub_data' |
376 | ] |
377 | ], |
378 | [ |
379 | '$unwind' => [ |
380 | 'path' => '$sub_data', |
381 | 'preserveNullAndEmptyArrays' => true |
382 | ] |
383 | ], |
384 | [ |
385 | '$lookup' => [ |
386 | 'from' => 'users', |
387 | 'let' => ['companyId' => ['$toString' => '$_id']], |
388 | 'pipeline' => [ |
389 | [ |
390 | '$match' => [ |
391 | '$expr' => ['$and' => [ |
392 | ['$eq' => ['$company_id', '$$companyId']] |
393 | ]] |
394 | ] |
395 | ], |
396 | [ |
397 | '$lookup' => [ |
398 | 'from' => 'hubspot_properties', |
399 | 'let' => ['userId' => ['$toString' => '$_id']], |
400 | 'pipeline' => [ |
401 | [ |
402 | '$match' => [ |
403 | '$expr' => [ |
404 | '$and' => [ |
405 | ['$eq' => ['$flymsg_id', '$$userId']], |
406 | [ |
407 | '$or' => [ |
408 | [ |
409 | '$and' => [ |
410 | ['$eq' => ['$flymsg_chrome_extension_installed', 'Yes']], |
411 | ['$eq' => ['$flymsg_chrome_extension_uninstalled', 'No']] |
412 | ] |
413 | ], |
414 | [ |
415 | '$and' => [ |
416 | ['$eq' => ['$flymsg_edge_extension_installed', 'Yes']], |
417 | ['$eq' => ['$flymsg_edge_extension_uninstalled', 'No']] |
418 | ] |
419 | ] |
420 | ] |
421 | ] |
422 | ] |
423 | ] |
424 | ] |
425 | ], |
426 | [ |
427 | '$sort' => ['created_at' => -1] |
428 | ], |
429 | [ |
430 | '$limit' => 1 |
431 | ] |
432 | ], |
433 | 'as' => 'hubspot_data' |
434 | ] |
435 | ], |
436 | [ |
437 | '$unwind' => [ |
438 | 'path' => '$hubspot_data', |
439 | 'preserveNullAndEmptyArrays' => true |
440 | ] |
441 | ], |
442 | [ |
443 | '$group' => [ |
444 | '_id' => null, |
445 | 'total_extension_installed' => ['$sum' => ['$cond' => [['$ifNull' => ['$hubspot_data', false]], 1, 0]]] |
446 | ] |
447 | ] |
448 | ], |
449 | 'as' => 'hp_data' |
450 | ] |
451 | ], |
452 | [ |
453 | '$unwind' => [ |
454 | 'path' => '$hp_data', |
455 | 'preserveNullAndEmptyArrays' => true |
456 | ] |
457 | ], |
458 | [ |
459 | '$project' => [ |
460 | 'company_id' => '$_id', |
461 | 'purchased_licenses' => '$licenses_data.purchased_licenses', |
462 | 'total_active_licenses' => '$sub_data.total_active_subscriptions', |
463 | 'total_invited_licenses' => '$sub_data.total_invited_subscriptions', |
464 | 'total_extension_installed' => '$hp_data.total_extension_installed', |
465 | 'flycut_usage_aggregated' => '$flycut_data.flycut_usage_aggregated' |
466 | ] |
467 | ] |
468 | ]; |
469 | |
470 | return Company::withoutGlobalScopes()->raw(function ($collection) use ($aggregation) { |
471 | return $collection->aggregate($aggregation); |
472 | }); |
473 | } |
474 | |
475 | private function getFlyCutUsageByUser($userIds, $startDate, $endDate) |
476 | { |
477 | $aggregation = [ |
478 | [ |
479 | '$match' => [ |
480 | '_id' => ['$in' => array_map(function ($userId) { |
481 | return new \MongoDB\BSON\ObjectId($userId); |
482 | }, $userIds)] |
483 | ] |
484 | ], |
485 | [ |
486 | '$lookup' => [ |
487 | 'from' => 'flycut_usage', |
488 | 'let' => ['userId' => ['$toString' => '$_id']], |
489 | 'pipeline' => [ |
490 | [ |
491 | '$match' => [ |
492 | '$expr' => [ |
493 | '$and' => [ |
494 | ['$eq' => ['$user_id', '$$userId']], |
495 | ['$gte' => ['$created_at', $startDate]], |
496 | ['$lte' => ['$created_at', $endDate]] |
497 | ] |
498 | ] |
499 | ] |
500 | ], |
501 | [ |
502 | '$group' => [ |
503 | '_id' => [ |
504 | 'user_id' => '$user_id', |
505 | 'month_year' => [ |
506 | '$dateToString' => [ |
507 | 'format' => '%Y-%m', |
508 | 'date' => '$created_at' |
509 | ] |
510 | ] |
511 | ], |
512 | 'characters_typed' => ['$sum' => '$characters_typed'], |
513 | 'characters_saved' => ['$sum' => '$characters_saved'], |
514 | 'time_saved' => ['$sum' => '$time_saved'], |
515 | 'cost_saved' => ['$sum' => '$cost_saved'], |
516 | 'flycuts_used' => ['$sum' => 1] |
517 | ] |
518 | ], |
519 | [ |
520 | '$sort' => ['_id.month_year' => 1] |
521 | ] |
522 | ], |
523 | 'as' => 'usage_data' |
524 | ] |
525 | ], |
526 | [ |
527 | '$unwind' => [ |
528 | 'path' => '$usage_data', |
529 | 'preserveNullAndEmptyArrays' => false |
530 | ] |
531 | ], |
532 | [ |
533 | '$group' => [ |
534 | '_id' => '$usage_data._id.month_year', |
535 | 'users' => [ |
536 | '$push' => [ |
537 | 'user_id' => '$_id', |
538 | 'characters_typed' => '$usage_data.characters_typed', |
539 | 'characters_saved' => '$usage_data.characters_saved', |
540 | 'time_saved' => '$usage_data.time_saved', |
541 | 'cost_saved' => '$usage_data.cost_saved', |
542 | 'flycuts_used' => '$usage_data.flycuts_used' |
543 | ] |
544 | ] |
545 | ] |
546 | ], |
547 | [ |
548 | '$sort' => ['_id' => 1] |
549 | ] |
550 | ]; |
551 | |
552 | return User::raw(function ($collection) use ($aggregation) { |
553 | return $collection->aggregate($aggregation); |
554 | }); |
555 | } |
556 | } |