Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
0.16% covered (danger)
0.16%
1 / 620
7.69% covered (danger)
7.69%
1 / 13
CRAP
0.00% covered (danger)
0.00%
0 / 1
UserInfoService
0.16% covered (danger)
0.16%
1 / 620
7.69% covered (danger)
7.69%
1 / 13
62448.07
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
 created
0.00% covered (danger)
0.00%
0 / 18
0.00% covered (danger)
0.00%
0 / 1
30
 updated
0.00% covered (danger)
0.00%
0 / 15
0.00% covered (danger)
0.00%
0 / 1
20
 pushItToHubspot
0.00% covered (danger)
0.00%
0 / 13
0.00% covered (danger)
0.00%
0 / 1
30
 validateHubspotUpdatedFields
0.00% covered (danger)
0.00%
0 / 3
0.00% covered (danger)
0.00%
0 / 1
2
 parseToHubspotFields
0.00% covered (danger)
0.00%
0 / 73
0.00% covered (danger)
0.00%
0 / 1
182
 addExtension
0.00% covered (danger)
0.00%
0 / 29
0.00% covered (danger)
0.00%
0 / 1
30
 removeExtension
0.00% covered (danger)
0.00%
0 / 26
0.00% covered (danger)
0.00%
0 / 1
30
 processUser
0.00% covered (danger)
0.00%
0 / 404
0.00% covered (danger)
0.00%
0 / 1
37830
 parseUserTypeByRoleId
0.00% covered (danger)
0.00%
0 / 4
0.00% covered (danger)
0.00%
0 / 1
6
 parseUserType
0.00% covered (danger)
0.00%
0 / 10
0.00% covered (danger)
0.00%
0 / 1
6
 formatToCarbonDate
0.00% covered (danger)
0.00%
0 / 13
0.00% covered (danger)
0.00%
0 / 1
90
 recalculateFlyCutUsage
0.00% covered (danger)
0.00%
0 / 11
0.00% covered (danger)
0.00%
0 / 1
20
1<?php
2
3namespace App\Services\UserInfo;
4
5use App\Http\Models\UserInfo;
6use App\Http\Models\Auth\User;
7use App\Http\Models\Plans;
8use App\Traits\ObjectMapper;
9use Carbon\Carbon;
10use Illuminate\Support\Facades\Log;
11use App\Http\Models\Admin\Company;
12use App\Http\Models\Auth\Role;
13use App\Http\Models\Parameter;
14use App\Http\Services\HubspotServiceV2;
15use App\Http\Models\Admin\AdminUserInvitation;
16use App\Http\Models\Admin\CompanyGroup;
17use App\Http\Models\Auth\LoginHistory;
18use App\Http\Models\Auth\UserRole;
19use App\Http\Models\FlyCutUsage;
20use App\Http\Models\HubspotProperties;
21use App\Http\Models\Setting;
22use App\Http\Models\Shortcut;
23use App\Http\Models\ShortcutCategory;
24use App\Http\Models\ShortcutSubCategoryLv1;
25use App\Http\Models\ShortcutSubCategoryLv2;
26use App\Http\Models\Subscription;
27use App\Http\Services\StatisticsService;
28use App\Services\UserInfo\SubscriptionService;
29use Illuminate\Support\Facades\Cache;
30use Illuminate\Support\Facades\Http;
31use Illuminate\Support\Facades\Config;
32use MongoDB\BSON\UTCDateTime;
33
34class UserInfoService
35{
36    use ObjectMapper;
37
38    public function __construct(
39        private StatisticsService $statisticsService
40    ) {}
41
42    public function created(UserInfo $user): void
43    {
44        if (empty($user->subscription_type) && !empty($user->email_verified_at)) {
45            $subscriptionService = new SubscriptionService();
46            $props = $subscriptionService->initFreemiumSubscription($user->user_id);
47            $user->update($props);
48            $user = $user->fresh();
49        }
50
51        $created = $user->toArray();
52
53        $hubspotFields = $this->validateHubspotUpdatedFields($created);
54
55        if (!empty($hubspotFields)) {
56            $dbUser = User::find($user->user_id);
57            $parsedHubspotFields = $this->parseToHubspotFields($hubspotFields, $dbUser);
58
59            $hubspotService = new HubspotServiceV2();
60
61            $realUser = User::find($user->user_id);
62            if (!$user->hubspot_id) {
63                $hubspotService->createHubspotProperties($realUser);
64
65                $realUser = $realUser->fresh();
66            }
67
68            $hubspotService->batchUpdate($realUser->hubspot_id, $parsedHubspotFields);
69            $realUser->user_info_id = $user->id;
70            $realUser->save();
71        }
72    }
73
74    public function updated(UserInfo $user): void
75    {
76        $updated = $user->getDirty();
77
78        if (!empty($updated)) {
79            $hubspotFields = $this->validateHubspotUpdatedFields($updated);
80
81            if (!empty($hubspotFields)) {
82                $dbUser = User::find($user->user_id);
83
84                $parsedHubspotFields = $this->parseToHubspotFields($hubspotFields, $dbUser);
85
86                $hubspotService = new HubspotServiceV2();
87
88                $realUser = User::find($user->user_id);
89                if (!$user->hubspot_id) {
90                    $hubspotService->createHubspotProperties($realUser);
91                    $realUser = $realUser->fresh();
92                }
93
94                $hubspotService->batchUpdate($realUser->hubspot_id, $parsedHubspotFields);
95                $realUser->user_info_id = $user->id;
96                $realUser->save();
97            }
98        }
99
100        Log::info('User Info updated: ' . $user->email);
101    }
102
103    public function pushItToHubspot(string $userId, bool $safe = true)
104    {
105        $userInfo = UserInfo::where('user_id', $userId)->first();
106        $hpService = new HubspotServiceV2();
107
108        if ($userInfo) {
109            $created = $userInfo->toArray();
110            $hubspotFields = $this->validateHubspotUpdatedFields($created);
111
112            if (!empty($hubspotFields)) {
113                $user = User::withTrashed()->find($userId);
114
115                $parsedHubspotFields = $this->parseToHubspotFields($hubspotFields, $user);
116
117                if ($user) {
118                    if (!$user->hubspot_id) {
119                        $hpService->createHubspotProperties($user);
120
121                        $user = $user->fresh();
122                    }
123
124                    $hpService->sendToHusbpot($user->hubspot_id, $parsedHubspotFields, $safe);
125                }
126            }
127        }
128    }
129
130    public function validateHubspotUpdatedFields(array $updated): array
131    {
132        $parameter = Parameter::where('name', 'hubspot_fields_to_sync')->first();
133
134        $hubspotFields = $parameter->value;
135
136        return array_filter($updated, fn($key) => in_array($key, $hubspotFields), ARRAY_FILTER_USE_KEY);
137    }
138
139    public function parseToHubspotFields(array $fields, User $user): array
140    {
141        $map = array_fill_keys(array_keys($fields), []);
142
143        $map['last_login'] = ['transform' => fn($value) => $this->formatToCarbonDate($value)];
144        $map['account_creation_date'] = ['transform' => fn($value) => $this->formatToCarbonDate($value)];
145        $map['flymsg_chrome_extension_installed__date_'] = ['transform' => fn($value) => $this->formatToCarbonDate($value)];
146        $map['flymsg_chrome_extension_uninstalled__date_'] = ['transform' => fn($value) => $this->formatToCarbonDate($value)];
147        $map['flymsg_edge_extension_installed__date_'] = ['transform' => fn($value) => $this->formatToCarbonDate($value)];
148        $map['flymsg_edge_extension_uninstalled__date_'] = ['transform' => fn($value) => $this->formatToCarbonDate($value)];
149        $map['clicked_help_last_date'] = ['transform' => fn($value) => $this->formatToCarbonDate($value)];
150        $map['clicked_settings_last_date'] = ['transform' => fn($value) => $this->formatToCarbonDate($value)];
151        $map['clicked_download_extension_last_date'] = ['transform' => fn($value) => $this->formatToCarbonDate($value)];
152        $map['clicked_contact_sales_last_date'] = ['transform' => fn($value) => $this->formatToCarbonDate($value)];
153        $map['freemium_subscription_start_date'] = ['transform' => fn($value) => $this->formatToCarbonDate($value)];
154        $map['freemium_subscription_status_updated_on'] = ['transform' => fn($value) => $this->formatToCarbonDate($value)];
155        $map['freemium_subscription_churn_date'] = ['transform' => fn($value) => $this->formatToCarbonDate($value)];
156        $map['freemium_cancel_subscription_date'] = ['transform' => fn($value) => $this->formatToCarbonDate($value)];
157        $map['starter_subscription_status_updated_on'] = ['transform' => fn($value) => $this->formatToCarbonDate($value)];
158        $map['starter_subscription_start_date'] = ['transform' => fn($value) => $this->formatToCarbonDate($value)];
159        $map['starter_subscription_expiration_date'] = ['transform' => fn($value) => $this->formatToCarbonDate($value)];
160        $map['starter_cancel_subscription_date'] = ['transform' => fn($value) => $this->formatToCarbonDate($value)];
161        $map['starter_subscription_churn_date'] = ['transform' => fn($value) => $this->formatToCarbonDate($value)];
162        $map['growth_subscription_status_updated_on'] = ['transform' => fn($value) => $this->formatToCarbonDate($value)];
163        $map['growth_subscription_start_date'] = ['transform' => fn($value) => $this->formatToCarbonDate($value)];
164        $map['growth_subscription_expiration_date'] = ['transform' => fn($value) => $this->formatToCarbonDate($value)];
165        $map['growth_cancel_subscription_date'] = ['transform' => fn($value) => $this->formatToCarbonDate($value)];
166        $map['growth_subscription_churn_date'] = ['transform' => fn($value) => $this->formatToCarbonDate($value)];
167        $map['trail_period_start_date'] = ['transform' => fn($value) => $this->formatToCarbonDate($value)];
168        $map['trail_period_end_date'] = ['transform' => fn($value) => $this->formatToCarbonDate($value)];
169        $map['trail_period_canceled_date'] = ['transform' => fn($value) => $this->formatToCarbonDate($value)];
170        $map['professional_subscription_status_updated_on'] = ['transform' => fn($value) => $this->formatToCarbonDate($value)];
171        $map['professional_subscription_start_date'] = ['transform' => fn($value) => $this->formatToCarbonDate($value)];
172        $map['professional_subscription_expiration_date'] = ['transform' => fn($value) => $this->formatToCarbonDate($value)];
173        $map['professional_cancel_subscription_date'] = ['transform' => fn($value) => $this->formatToCarbonDate($value)];
174        $map['professional_subscription_churn_date'] = ['transform' => fn($value) => $this->formatToCarbonDate($value)];
175        $map['sales_pro_teams_subscription_status_updated_on'] = ['transform' => fn($value) => $this->formatToCarbonDate($value)];
176        $map['sales_pro_teams_subscription_start_date'] = ['transform' => fn($value) => $this->formatToCarbonDate($value)];
177        $map['sales_pro_teams_subscription_expiration_date'] = ['transform' => fn($value) => $this->formatToCarbonDate($value)];
178        $map['sales_pro_teams_cancel_subscription_date'] = ['transform' => fn($value) => $this->formatToCarbonDate($value)];
179        $map['sales_pro_teams_subscription_churn_date'] = ['transform' => fn($value) => $this->formatToCarbonDate($value)];
180        $map['last_date_user_used_a_flycut'] = ['transform' => fn($value) => $this->formatToCarbonDate($value)];
181        $map['last_date_user_used_flyengage'] = ['transform' => fn($value) => $this->formatToCarbonDate($value)];
182        $map['last_date_user_used_sentence_rewrite'] = ['transform' => fn($value) => $this->formatToCarbonDate($value)];
183        $map['last_date_user_used_paragraph_rewrite'] = ['transform' => fn($value) => $this->formatToCarbonDate($value)];
184        $map['last_date_user_used_flyposts'] = ['transform' => fn($value) => $this->formatToCarbonDate($value)];
185        $map['number_of_categories_created_last_date'] = ['transform' => fn($value) => $this->formatToCarbonDate($value)];
186        $map['number_of_flycuts_created_last_date'] = ['transform' => fn($value) => $this->formatToCarbonDate($value)];
187        $map['number_of_flyplates_in_flycuts_last_date'] = ['transform' => fn($value) => $this->formatToCarbonDate($value)];
188        $map['first_name'] = ['rename' => 'firstname'];
189        $map['last_name'] = ['rename' => 'lastname'];
190        $map['job_title'] = ['rename' => 'jobtitle'];
191        $map['user_id'] = ['rename' => 'flymsg_id'];
192        $map['total___of_times_flygrammar_is_used_summarized_monthly_by_user'] = ['rename' => 'total_of_times_flygrammar_is_used_summarized_monthly'];
193        $map['total___of_times_flygrammar_is_used_count'] = ['rename' => 'total_n_of_times_flygrammar_used'];
194        $map['last_date_user_used_flygrammar'] = ['transform' => fn($value) => $this->formatToCarbonDate($value)];
195        $map['company_id'] = ['rename' => 'company', 'transform' => fn($value) => $value ? Company::find($value)->name : null];
196        $map['is_chrome_extension_installed'] = ['rename' => 'flymsg_chrome_extension_installed', 'transform' => fn($value) => $value ? 'Yes' : 'No'];
197        $map['is_chrome_extension_uninstalled'] = ['rename' => 'flymsg_chrome_extension_uninstalled', 'transform' => fn($value) => $value ? 'Yes' : 'No'];
198        $map['is_edge_extension_installed'] = ['rename' => 'flymsg_edge_extension_installed', 'transform' => fn($value) => $value ? 'Yes' : 'No'];
199        $map['is_edge_extension_uninstalled'] = ['rename' => 'flymsg_edge_extension_uninstalled', 'transform' => fn($value) => $value ? 'Yes' : 'No'];
200        $map['which_browser_has_an_extension_been_installed_on'] = ['transform' => function () use ($fields) {
201            $browsers = [];
202            if (!empty($fields['is_chrome_extension_installed'] ?? null)) {
203                $browsers[] = 'Chrome';
204            }
205            if (!empty($fields['is_edge_extension_installed'] ?? null)) {
206                $browsers[] = 'Edge';
207            }
208
209            return implode(';', $browsers);
210        }];
211        $map['plan_id'] = ['rename' => 'subscription_type', 'transform' => fn($value) => $value ? Plans::find($value)->hubspot_name : null];
212
213        $mappedObject = $this->mapObject($fields, $map);
214
215        if (!empty($fields['subscription_type']) && ($fields['subscription_type'] == 'Cancelled Account' || $fields['subscription_type'] == 'Deleted Profile from FlyMSG')) {
216            $mappedObject['subscription_type'] = $fields['subscription_type'];
217        }
218
219        if (empty($user->email_verified_at)) {
220            $mappedObject['subscription_type'] = 'Unverified';
221        }
222
223        return $mappedObject;
224    }
225
226    public function addExtension(UserInfo $userInfo, string $browser, $date)
227    {
228        $prop = 'is_' . $browser . '_extension_installed';
229
230        $userInfo->$prop = true;
231
232        $userInfo->is_any_extension_installed = true;
233        $userInfo->signed_into_flymsg_extension = 'Yes';
234
235        $browsers = [];
236        if ($userInfo->is_chrome_extension_installed) {
237            $browsers[] = 'Chrome';
238        }
239
240        if ($userInfo->is_edge_extension_installed) {
241            $browsers[] = 'Edge';
242        }
243        $userInfo->which_browser_has_an_extension_been_installed_on = implode(';', $browsers);
244        $userInfo->last_browser_used = ucfirst($browser);
245
246        $extensionInstalledProp = 'flymsg_' . $browser . '_extension_installed__date_';
247        $userInfo->$extensionInstalledProp = $date ? new UTCDateTime($date->timestamp * 1000) : now();
248
249        $extensionIsUninstalledProp = 'is_' . $browser . '_extension_uninstalled';
250        $extensionUninstalledDateProp = 'flymsg_' . $browser . '_extension_uninstalled__date_';
251
252        $userInfo->$extensionIsUninstalledProp = false;
253        $userInfo->$extensionUninstalledDateProp = null;
254
255        $userInfo->is_any_extension_uninstalled = $userInfo->is_edge_extension_uninstalled || $userInfo->is_chrome_extension_uninstalled;
256
257        return [
258            $prop => $userInfo->$prop,
259            'is_any_extension_installed' => $userInfo->is_any_extension_installed,
260            'signed_into_flymsg_extension' => $userInfo->signed_into_flymsg_extension,
261            'which_browser_has_an_extension_been_installed_on' => $userInfo->which_browser_has_an_extension_been_installed_on,
262            'last_browser_used' => $userInfo->last_browser_used,
263            $extensionInstalledProp => $userInfo->$extensionInstalledProp,
264            $extensionIsUninstalledProp => $userInfo->$extensionIsUninstalledProp,
265            $extensionUninstalledDateProp => $userInfo->$extensionUninstalledDateProp,
266            'is_any_extension_uninstalled' => $userInfo->is_any_extension_uninstalled,
267        ];
268    }
269
270    public function removeExtension(UserInfo $userInfo, string $browser, $date)
271    {
272        $prop = 'is_' . $browser . '_extension_uninstalled';
273        $userInfo->$prop = true;
274
275        $userInfo->is_any_extension_uninstalled = true;
276        $userInfo->signed_into_flymsg_extension = 'No';
277
278        $extensionUninstalledProp = 'flymsg_' . $browser . '_extension_uninstalled__date_';
279        $userInfo->$extensionUninstalledProp = $date ? new UTCDateTime($date->timestamp * 1000) : now();
280
281        $extensionIsInstalledProp = 'is_' . $browser . '_extension_installed';
282
283        $userInfo->$extensionIsInstalledProp = false;
284
285        $userInfo->is_any_extension_installed = $userInfo->is_edge_extension_installed || $userInfo->is_chrome_extension_installed;
286
287        $browsers = [];
288        if ($userInfo->is_chrome_extension_installed) {
289            $browsers[] = 'Chrome';
290        }
291
292        if ($userInfo->is_edge_extension_installed) {
293            $browsers[] = 'Edge';
294        }
295        $userInfo->which_browser_has_an_extension_been_installed_on = implode(';', $browsers);
296        $userInfo->last_browser_used = ucfirst($browser);
297
298        return [
299            $prop => $userInfo->$prop,
300            'is_any_extension_uninstalled' => $userInfo->is_any_extension_uninstalled,
301            'signed_into_flymsg_extension' => $userInfo->signed_into_flymsg_extension,
302            $extensionUninstalledProp => $userInfo->$extensionUninstalledProp,
303            $extensionIsInstalledProp => $userInfo->$extensionIsInstalledProp,
304            'is_any_extension_installed' => $userInfo->is_any_extension_installed,
305            'which_browser_has_an_extension_been_installed_on' => $userInfo->which_browser_has_an_extension_been_installed_on,
306            'last_browser_used' => $userInfo->last_browser_used,
307        ];
308    }
309
310    public function processUser(User $user): UserInfo
311    {
312        $subscriptionService = new SubscriptionService();
313
314        $user_info = UserInfo::firstOrNew(['user_id' => $user->id]);
315
316        #region Personal Data
317        $user_info->user_id = $user->id;
318        $user_info->first_name = $user->first_name;
319        $user_info->last_name = $user->last_name;
320        $user_info->full_name = $user->first_name . ' ' . $user->last_name;
321        $user_info->email = $user->email;
322
323        $user_info->account_creation_date = new UTCDateTime($user->created_at->timestamp * 1000);
324        $roles = $user->roles();
325
326        if (!in_array(Role::USER, $roles)) {
327            array_push($roles, Role::USER);
328        }
329        $user_info->user_type = implode(',', $roles);
330
331        $words_per_minute = $this->statisticsService->getWordsPerMinute($user);
332        $wage_per_hour = $this->statisticsService->getWagePerHour($user, now());
333        $user_info->typed_words_per_minute = $words_per_minute;
334        $user_info->wage_per_hour = $wage_per_hour;
335        $user_info->email_used_for_login = $user->email;
336        $user_info->signup_source = $user->signup_source;
337        $user_info->signin_source = $user->signup_source;
338        $last_login = LoginHistory::where('user_id', $user->id)->latest()->first();
339        if ($last_login) {
340            $user_info->last_login = new UTCDateTime($last_login->created_at->timestamp * 1000);
341        }
342        $user_info->status = $user->status ?? 'Active';
343        $account_status_date = match (true) {
344            !is_null($user->deactivated_at) => $user->deactivated_at,
345            !is_null($user->activation_date) => Carbon::parse($user->activation_date),
346            !is_null($user->created_at) => $user->created_at,
347            $user->status == 'Invited' => AdminUserInvitation::where("email", $user->email)->first()?->updated_at,
348            default => null,
349        };
350        $user_info->status_date = new UTCDateTime($account_status_date->timestamp * 1000);
351        $user_info->user_created_at = new UTCDateTime($user->created_at->timestamp * 1000);
352        $user_info->user_updated_at = new UTCDateTime($user->updated_at->timestamp * 1000);
353        $user_info->company_id = $user->company_id;
354        $user_info->company_name = $user->company?->name;
355        $user_info->avatar = $user->avatar;
356        $user_info->hubspot_id = $user->hubspot_id;
357        $user_info->stripe_id = $user->stripe_id;
358        $user_info->instancy_id = $user->instancy_id;
359
360        if (!empty($user->company_group_id)) {
361            $group = CompanyGroup::where('id', $user->company_group_id)->first();
362            if ($group) {
363                $parentGroup = CompanyGroup::where('id', $group->parent_id)->first();
364
365                if ($parentGroup) {
366                    $user_info->group_id = $parentGroup->id;
367                    $user_info->group_name = $parentGroup->name;
368                    $user_info->subgroup_id = $user->company_group_id;
369                    $user_info->subgroup_name = $user->company_group?->name;
370                } else {
371                    $user_info->group_id = $user->company_group_id;
372                    $user_info->group_name = $user->company_group?->name;
373                }
374            } else {
375                $user_info->company_group_id = null;
376                $user_info->company_group_name = null;
377            }
378        }
379
380        $userRoles = UserRole::where('user_id', $user->id)->get();
381        $user_info->role_ids = implode(',', $userRoles->pluck('role_id')->toArray());
382        $user_info->role_names = implode(',', $userRoles->pluck('role.name')->toArray());
383        $user_info->is_invite = !LoginHistory::where('user_id', $user->id)->exists();
384        $user_info->email_domain = explode('@', $user->email)[1];
385        $user_info->email_domain_count = User::where('email', 'like', '%' . $user_info->email_domain)->count();
386        #endregion
387
388        if (false) {
389            #region Items from HubspotProperties
390
391            $hubspotProperty = HubspotProperties::where('email', $user->email)->first();
392
393            #region Extension
394            $user_info->is_chrome_extension_installed = $hubspotProperty ? ($hubspotProperty->flymsg_chrome_extension_installed === 'Yes' && $hubspotProperty->flymsg_chrome_extension_uninstalled === 'No') : false;
395            $user_info->is_edge_extension_installed = $hubspotProperty ? ($hubspotProperty->flymsg_edge_extension_installed === 'Yes' && $hubspotProperty->flymsg_edge_extension_uninstalled === 'No') : false;
396
397            $user_info->is_any_extension_installed = $hubspotProperty ? (
398                ($hubspotProperty->flymsg_chrome_extension_installed === 'Yes' && $hubspotProperty->flymsg_chrome_extension_uninstalled === 'No') ||
399                ($hubspotProperty->flymsg_edge_extension_installed === 'Yes' && $hubspotProperty->flymsg_edge_extension_uninstalled === 'No')
400            ) : false;
401            $user_info->is_any_extension_uninstalled = $hubspotProperty ? (
402                ($hubspotProperty->flymsg_chrome_extension_installed === 'No' && $hubspotProperty->flymsg_chrome_extension_uninstalled === 'Yes') ||
403                ($hubspotProperty->flymsg_edge_extension_installed === 'No' && $hubspotProperty->flymsg_edge_extension_uninstalled === 'Yes')
404            ) : false;
405            $user_info->signed_into_flymsg_extension = $hubspotProperty ? $hubspotProperty->signed_into_flymsg_extension : 'No';
406            $user_info->which_browser_has_an_extension_been_installed_on = $hubspotProperty ? $hubspotProperty->which_browser_has_an_extension_been_installed_on : null;
407            $user_info->last_browser_used = $hubspotProperty ? ucfirst($hubspotProperty->last_browser_used) : null;
408            $user_info->is_chrome_extension_uninstalled = $hubspotProperty ? ($hubspotProperty->flymsg_chrome_extension_installed === 'No' && $hubspotProperty->flymsg_chrome_extension_uninstalled === 'Yes') : false;
409            $user_info->flymsg_chrome_extension_installed__date_ = $hubspotProperty ? new UTCDateTime(Carbon::parse($hubspotProperty->flymsg_chrome_extension_installed__date_)->timestamp * 1000) : null;
410            $user_info->flymsg_chrome_extension_uninstalled__date_ = $hubspotProperty ? new UTCDateTime(Carbon::parse($hubspotProperty->flymsg_chrome_extension_uninstalled__date_)->timestamp * 1000) : null;
411            $user_info->flymsg_extension_version_for_chrome = $hubspotProperty ? $hubspotProperty->flymsg_extension_version_for_chrome : null;
412            $user_info->is_edge_extension_uninstalled = $hubspotProperty ? ($hubspotProperty->flymsg_edge_extension_installed === 'No' && $hubspotProperty->flymsg_edge_extension_uninstalled === 'Yes') : false;
413            $user_info->flymsg_edge_extension_installed__date_ = $hubspotProperty ? new UTCDateTime(Carbon::parse($hubspotProperty->flymsg_edge_extension_installed__date_)->timestamp * 1000) : null;
414            $user_info->flymsg_edge_extension_uninstalled__date_ = $hubspotProperty ? new UTCDateTime(Carbon::parse($hubspotProperty->flymsg_edge_extension_uninstalled__date_)->timestamp * 1000) : null;
415            $user_info->flymsg_extension_version_for_edge = $hubspotProperty ? $hubspotProperty->flymsg_extension_version_for_edge : null;
416
417            if (empty($user_info->flymsg_chrome_extension_installed__date_) && empty($user_info->flymsg_chrome_extension_uninstalled__date_)) {
418                $props = [
419                    'is_chrome_extension_installed' => false,
420                    'signed_into_flymsg_extension' => 'No',
421                    'flymsg_chrome_extension_installed__date_' => null,
422                    'is_chrome_extension_uninstalled' => null,
423                    'flymsg_chrome_extension_uninstalled__date_' => null,
424                    'is_any_extension_uninstalled' => false,
425                ];
426                $user_info->fill($props);
427            } elseif ($user_info->flymsg_chrome_extension_installed__date_ && empty($user_info->flymsg_chrome_extension_uninstalled__date_)) {
428                $props = $this->addExtension($user_info, 'chrome', Carbon::instance($user_info->flymsg_chrome_extension_installed__date_->toDateTime()));
429                $user_info->fill($props);
430            } elseif ($user_info->flymsg_chrome_extension_uninstalled__date_ && empty($user_info->flymsg_chrome_extension_installed__date_)) {
431                $uninstallDate = Carbon::instance($user_info->flymsg_chrome_extension_uninstalled__date_->toDateTime());
432                $props = $this->addExtension($user_info, 'chrome', Carbon::instance($user_info->flymsg_chrome_extension_uninstalled__date_->toDateTime()));
433                $user_info->fill($props);
434                $props = $this->removeExtension($user_info, 'chrome', $uninstallDate);
435                $user_info->fill($props);
436            } elseif ($user_info->flymsg_chrome_extension_installed__date_ < $user_info->flymsg_chrome_extension_uninstalled__date_) {
437                $uninstallDate = Carbon::instance($user_info->flymsg_chrome_extension_uninstalled__date_->toDateTime());
438                $props = $this->addExtension($user_info, 'chrome', Carbon::instance($user_info->flymsg_chrome_extension_installed__date_->toDateTime()));
439                $user_info->fill($props);
440                $props = $this->removeExtension($user_info, 'chrome', $uninstallDate);
441                $user_info->fill($props);
442            } else {
443                $installDate = Carbon::instance($user_info->flymsg_chrome_extension_installed__date_->toDateTime());
444                $props = $this->removeExtension($user_info, 'chrome', Carbon::instance($user_info->flymsg_chrome_extension_uninstalled__date_->toDateTime()));
445                $user_info->fill($props);
446                $props = $this->addExtension($user_info, 'chrome', $installDate);
447                $user_info->fill($props);
448            }
449
450            if (empty($user_info->flymsg_edge_extension_installed__date_) && empty($user_info->flymsg_edge_extension_uninstalled__date_)) {
451                $props = [
452                    'is_edge_extension_installed' => false,
453                    'signed_into_flymsg_extension' => 'No',
454                    'flymsg_edge_extension_installed__date_' => null,
455                    'is_edge_extension_uninstalled' => null,
456                    'flymsg_edge_extension_uninstalled__date_' => null,
457                    'is_any_extension_uninstalled' => false,
458                ];
459                $user_info->fill($props);
460            } elseif ($user_info->flymsg_edge_extension_installed__date_ && empty($user_info->flymsg_edge_extension_uninstalled__date_)) {
461                $props = $this->addExtension($user_info, 'edge', Carbon::instance($user_info->flymsg_edge_extension_installed__date_->toDateTime()));
462                $user_info->fill($props);
463            } elseif ($user_info->flymsg_edge_extension_uninstalled__date_ && empty($user_info->flymsg_edge_extension_installed__date_)) {
464                $uninstallDate = Carbon::instance($user_info->flymsg_edge_extension_uninstalled__date_->toDateTime());
465                $props = $this->addExtension($user_info, 'edge', Carbon::instance($user_info->flymsg_edge_extension_uninstalled__date_->toDateTime()));
466                $user_info->fill($props);
467                $props = $this->removeExtension($user_info, 'edge', $uninstallDate);
468                $user_info->fill($props);
469            } elseif ($user_info->flymsg_edge_extension_installed__date_ < $user_info->flymsg_edge_extension_uninstalled__date_) {
470                $uninstallDate = Carbon::instance($user_info->flymsg_edge_extension_uninstalled__date_->toDateTime());
471                $props = $this->addExtension($user_info, 'edge', Carbon::instance($user_info->flymsg_edge_extension_installed__date_->toDateTime()));
472                $user_info->fill($props);
473                $props = $this->removeExtension($user_info, 'edge', $uninstallDate);
474                $user_info->fill($props);
475            } else {
476                $installDate = Carbon::instance($user_info->flymsg_edge_extension_installed__date_->toDateTime());
477                $props = $this->removeExtension($user_info, 'edge', Carbon::instance($user_info->flymsg_edge_extension_uninstalled__date_->toDateTime()));
478                $user_info->fill($props);
479                $props = $this->addExtension($user_info, 'edge', $installDate);
480                $user_info->fill($props);
481            }
482
483            #endregion
484
485            if ($hubspotProperty) {
486                if (!$user_info->df_stripe_customer_id && $hubspotProperty->df_stripe_customer_id) {
487                    $user_info->df_stripe_customer_id = $hubspotProperty->df_stripe_customer_id;
488                }
489                if (!$user_info->subscription_owner && $hubspotProperty->subscription_owner) {
490                    $user_info->subscription_owner = $hubspotProperty->subscription_owner;
491                }
492                if (!$user_info->billing_address_line_1 && $hubspotProperty->billing_address_line_1) {
493                    $user_info->billing_address_line_1 = $hubspotProperty->billing_address_line_1;
494                }
495                if (!$user_info->billing_address_line_2 && $hubspotProperty->billing_address_line_2) {
496                    $user_info->billing_address_line_2 = $hubspotProperty->billing_address_line_2;
497                }
498                if (!$user_info->billing_city && $hubspotProperty->billing_city) {
499                    $user_info->billing_city = $hubspotProperty->billing_city;
500                }
501                if (!$user_info->billing_state && $hubspotProperty->billing_state) {
502                    $user_info->billing_state = $hubspotProperty->billing_state;
503                }
504                if (!$user_info->billing_zip && $hubspotProperty->billing_zip) {
505                    $user_info->billing_zip = $hubspotProperty->billing_zip;
506                }
507                if (!$user_info->billing_country && $hubspotProperty->billing_country) {
508                    $user_info->billing_country = $hubspotProperty->billing_country;
509                }
510                if (!$user_info->number_of_completed_payments && $hubspotProperty->number_of_completed_payments) {
511                    $user_info->number_of_completed_payments = $hubspotProperty->number_of_completed_payments;
512                }
513                if (!$user_info->number_of_expected_payments && $hubspotProperty->number_of_expected_payments) {
514                    $user_info->number_of_expected_payments = $hubspotProperty->number_of_expected_payments;
515                }
516                if (!$user_info->payment_method && $hubspotProperty->payment_method) {
517                    $user_info->payment_method = $hubspotProperty->payment_method;
518                }
519                if (!$user_info->flymsg_last_product_purchased && $hubspotProperty->flymsg_last_product_purchased) {
520                    $user_info->flymsg_last_product_purchased = $hubspotProperty->flymsg_last_product_purchased;
521                }
522                if (!$user_info->last_total_invoice_amount && $hubspotProperty->last_total_invoice_amount) {
523                    $numberInfo = preg_replace('/[^0-9.]/', '', $hubspotProperty->last_total_invoice_amount);
524                    $user_info->last_total_invoice_amount = $numberInfo;
525                }
526                if (!$user_info->flymsg_total_sales && $hubspotProperty->flymsg_total_sales) {
527                    $user_info->flymsg_total_sales = $hubspotProperty->flymsg_total_sales;
528                }
529                if (!$user_info->coupon_name && $hubspotProperty->coupon_name) {
530                    $user_info->coupon_name = $hubspotProperty->coupon_name;
531                }
532                if (!$user_info->coupon_code && $hubspotProperty->coupon_code) {
533                    $user_info->coupon_code = $hubspotProperty->coupon_code;
534                }
535                if (!$user_info->coupon_type && $hubspotProperty->coupon_type) {
536                    $user_info->coupon_type = $hubspotProperty->coupon_type;
537                }
538                if (!$user_info->duration && $hubspotProperty->duration) {
539                    $user_info->duration = $hubspotProperty->duration;
540                }
541                if (!$user_info->coupon_value__discount_ && $hubspotProperty->coupon_value__discount_) {
542                    $user_info->coupon_value__discount_ = $hubspotProperty->coupon_value__discount_;
543                }
544                if (!$user_info->coupon_redemption_limits && $hubspotProperty->coupon_redemption_limits) {
545                    $user_info->coupon_redemption_limits = $hubspotProperty->coupon_redemption_limits;
546                }
547                if (!$user_info->productivity_problems && $hubspotProperty->productivity_problems) {
548                    $user_info->productivity_problems = $hubspotProperty->productivity_problems;
549                }
550                if (!$user_info->type_here_how_flymsg_will_help_you___ && $hubspotProperty->type_here_how_flymsg_will_help_you___) {
551                    $user_info->type_here_how_flymsg_will_help_you___ = $hubspotProperty->type_here_how_flymsg_will_help_you___;
552                }
553                if (!$user_info->flymsg_use_case && $hubspotProperty->flymsg_use_case) {
554                    $user_info->flymsg_use_case = $hubspotProperty->flymsg_use_case;
555                }
556                if (!$user_info->sign_out_reason && $hubspotProperty->sign_out_reason) {
557                    $user_info->sign_out_reason = $hubspotProperty->sign_out_reason;
558                }
559                if (!$user_info->sign_out_text && $hubspotProperty->sign_out_text) {
560                    $user_info->sign_out_text = $hubspotProperty->sign_out_text;
561                }
562            }
563            #endregion
564        }
565        #region Flymsg Simple Usage
566        $last_date_user_used_a_flycut = FlyCutUsage::where('user_id', $user->id)->where('feature', null)->orderBy('created_at', 'desc')->first();
567        if ($last_date_user_used_a_flycut) {
568            $user_info->last_date_user_used_a_flycut = new UTCDateTime($last_date_user_used_a_flycut->created_at->timestamp * 1000);
569        }
570        $last_date_user_used_a_flyengage = FlyCutUsage::where('user_id', $user->id)->where('feature', 'flyengage')->orderBy('created_at', 'desc')->first();
571        if ($last_date_user_used_a_flyengage) {
572            $user_info->last_date_user_used_flyengage = new UTCDateTime($last_date_user_used_a_flyengage->created_at->timestamp * 1000);
573        }
574        $last_date_user_used_a_sentence_rewrite = FlyCutUsage::where('user_id', $user->id)->where('feature', 'sentence_rewrite')->orderBy('created_at', 'desc')->first();
575        if ($last_date_user_used_a_sentence_rewrite) {
576            $user_info->last_date_user_used_sentence_rewrite = new UTCDateTime($last_date_user_used_a_sentence_rewrite->created_at->timestamp * 1000);
577        }
578        $last_date_user_used_a_paragraph_rewrite = FlyCutUsage::where('user_id', $user->id)->where('feature', 'paragraph_rewrite')->orderBy('created_at', 'desc')->first();
579        if ($last_date_user_used_a_paragraph_rewrite) {
580            $user_info->last_date_user_used_paragraph_rewrite = new UTCDateTime($last_date_user_used_a_paragraph_rewrite->created_at->timestamp * 1000);
581        }
582        $last_date_user_used_a_flypost = FlyCutUsage::where('user_id', $user->id)->where('feature', 'flypost')->orderBy('created_at', 'desc')->first();
583        if ($last_date_user_used_a_flypost) {
584            $user_info->last_date_user_used_flyposts = new UTCDateTime($last_date_user_used_a_flypost->created_at->timestamp * 1000);
585        }
586        $lastCategory = ShortcutCategory::where('user_id', $user->id)->latest()->first();
587        $lastSubCategoryLvl1 = ShortcutSubCategoryLv1::where('user_id', $user->id)->latest()->first();
588        $lastSubCategoryLvl2 = ShortcutSubCategoryLv2::where('user_id', $user->id)->latest()->first();
589
590        $number_of_categories_created_last_date = collect([$lastCategory, $lastSubCategoryLvl1, $lastSubCategoryLvl2])->max('created_at');
591        if ($number_of_categories_created_last_date) {
592            $user_info->number_of_categories_created_last_date = new UTCDateTime($number_of_categories_created_last_date->timestamp * 1000);
593        }
594        $user_info->number_of_categories_created_count = ShortcutCategory::where('user_id', $user->id)->count() +
595            ShortcutSubCategoryLv1::where('user_id', $user->id)->count() +
596            ShortcutSubCategoryLv2::where('user_id', $user->id)->count();
597
598        $number_of_flycuts_created_last_date = Shortcut::where('user_id', $user->id)->where('user_defined', true)->latest()->first();
599        if ($number_of_flycuts_created_last_date) {
600            $user_info->number_of_flycuts_created_last_date = new UTCDateTime($number_of_flycuts_created_last_date->created_at->timestamp * 1000);
601        }
602        $user_info->number_of_flycuts_created_count = Shortcut::where('user_id', $user->id)->where('user_defined', true)->count();
603
604        $number_of_flyplates_in_flycuts_last_date = Shortcut::where('user_id', $user->id)->where('user_defined', false)->latest()->first();
605        if ($number_of_flyplates_in_flycuts_last_date) {
606            $user_info->number_of_flyplates_in_flycuts_last_date = new UTCDateTime($number_of_flyplates_in_flycuts_last_date->created_at->timestamp * 1000);
607        }
608        $user_info->number_of_flyplates_in_flycuts_count = Shortcut::where('user_id', $user->id)->where('user_defined', false)->count();
609        #endregion
610
611        #region Licenses
612        #region Inactive Subscriptions
613        $inactiveSubscriptions = Subscription::where('user_id', $user->id)
614            ->where('stripe_status', '!=', 'active')
615            ->orderBy('created_at', 'asc')
616            ->get();
617        foreach ($inactiveSubscriptions as $subscription) {
618            $fields = $subscription->toArray();
619            $result = $subscriptionService->endSubscription($fields, $subscription);
620            $user_info->fill($result);
621        }
622        #endregion
623
624        #region Active Subscriptions
625        $activeSubscriptions = Subscription::where('user_id', $user->id)
626            ->where('stripe_status', 'active')
627            ->orderBy('created_at', 'asc')
628            ->get();
629
630        $haveActiveSubscription = false;
631
632        foreach ($activeSubscriptions as $subscription) {
633            $fields = $subscription->toArray();
634            $result = $subscriptionService->startSubscription($fields, $subscription);
635            $user_info->fill($result);
636            $haveActiveSubscription = true;
637        }
638
639        if (!$haveActiveSubscription) {
640            $user_info->fill($subscriptionService->initFreemiumSubscription($user->id));
641        }
642        #endregion
643        #endregion
644
645        if (false) {
646            #region Direct from Hubspot API
647            // => filled in by onboarding, not available in users table, try to load from hubspot
648
649            $accessToken = Config::get('hubspotconfig.access_token');
650            $url = 'https://api.hubapi.com/crm/v3/objects/contacts/search';
651
652            $data = [
653                'filterGroups' => [
654                    [
655                        'filters' => [
656                            [
657                                'propertyName' => 'email',
658                                'operator' => 'EQ',
659                                'value' => $user->email,
660                            ],
661                        ],
662                    ],
663                ],
664                'properties' => [
665                    'email',
666                    'job_role',
667                    'department',
668                    'jobtitle',
669                    'company',
670                    'phone',
671                    'linkedin_url',
672                    'clicked_help_last_date',
673                    'clicked_help_count',
674                    'clicked_settings_last_date',
675                    'clicked_settings_count',
676                    'clicked_download_extension_last_date',
677                    'clicked_download_extension_count',
678                    'clicked_contact_sales_last_date',
679                    'clicked_contact_sales_count',
680                    'df_stripe_customer_id',
681                    'subscription_owner',
682                    'billing_address_line_1',
683                    'billing_address_line_2',
684                    'billing_city',
685                    'billing_state',
686                    'billing_zip',
687                    'billing_country',
688                    'number_of_completed_payments',
689                    'number_of_expected_payments',
690                    'payment_method',
691                    'flymsg_last_product_purchased',
692                    'last_total_invoice_amount',
693                    'flymsg_total_sales',
694                    'coupon_name',
695                    'coupon_code',
696                    'coupon_type',
697                    'duration',
698                    'coupon_value__discount_',
699                    'coupon_redemption_limits',
700                    'productivity_problems',
701                    'type_here_how_flymsg_will_help_you___',
702                    'flymsg_use_case',
703                    'sign_out_reason',
704                    'sign_out_text',
705                ],
706                'limit' => 1,
707            ];
708
709            $response = Http::withHeaders([
710                'Authorization' => "Bearer {$accessToken}",
711                'Content-Type' => 'application/json',
712            ])->post($url, $data);
713
714            if ($response->successful()) {
715                $contact = $response->json('results.0');
716
717                if ($contact && !empty($contact['properties'])) {
718                    if (!$user_info->job_role && !empty($contact['properties']['job_role'])) {
719                        $user_info->job_role = $contact['properties']['job_role'];
720                    }
721
722                    if (!$user_info->department && !empty($contact['properties']['department'])) {
723                        $user_info->department = $contact['properties']['department'];
724                    }
725
726                    if (!$user_info->job_title && !empty($contact['properties']['jobtitle'])) {
727                        $user_info->job_title = $contact['properties']['jobtitle'];
728                    }
729
730                    if (!$user_info->company && !empty($contact['properties']['company'])) {
731                        $user_info->company = $contact['properties']['company'];
732                    }
733
734                    if (!$user_info->phone && !empty($contact['properties']['phone'])) {
735                        $user_info->phone = $contact['properties']['phone'];
736                    }
737
738                    if (!$user_info->linkedin_url && !empty($contact['properties']['linkedin_url'])) {
739                        $user_info->linkedin_url = $contact['properties']['linkedin_url'];
740                    }
741
742                    if (!$user_info->clicked_help_last_date && !empty($contact['properties']['clicked_help_last_date'])) {
743                        try {
744                            $user_info->clicked_help_last_date = new UTCDateTime(Carbon::parse($contact['properties']['clicked_help_last_date'])->timestamp * 1000);
745                        } catch (\Exception $e) {
746                            $user_info->clicked_help_last_date = $contact['properties']['clicked_help_last_date'];
747                        }
748                    }
749
750                    if (!$user_info->clicked_help_count && !empty($contact['properties']['clicked_help_count'])) {
751                        $user_info->clicked_help_count = $contact['properties']['clicked_help_count'];
752                    }
753
754                    if (!$user_info->clicked_settings_last_date && !empty($contact['properties']['clicked_settings_last_date'])) {
755                        try {
756                            $user_info->clicked_settings_last_date = new UTCDateTime(Carbon::parse($contact['properties']['clicked_settings_last_date'])->timestamp * 1000);
757                        } catch (\Exception $e) {
758                            $user_info->clicked_settings_last_date = $contact['properties']['clicked_settings_last_date'];
759                        }
760                    }
761
762                    if (!$user_info->clicked_settings_count && !empty($contact['properties']['clicked_settings_count'])) {
763                        $user_info->clicked_settings_count = $contact['properties']['clicked_settings_count'];
764                    }
765
766                    if (!$user_info->clicked_download_extension_last_date && !empty($contact['properties']['clicked_download_extension_last_date'])) {
767                        try {
768                            $user_info->clicked_download_extension_last_date = new UTCDateTime(Carbon::parse($contact['properties']['clicked_download_extension_last_date'])->timestamp * 1000);
769                        } catch (\Exception $e) {
770                            $user_info->clicked_download_extension_last_date = $contact['properties']['clicked_download_extension_last_date'];
771                        }
772                    }
773
774                    if (!$user_info->clicked_download_extension_count && !empty($contact['properties']['clicked_download_extension_count'])) {
775                        $user_info->clicked_download_extension_count = $contact['properties']['clicked_download_extension_count'];
776                    }
777
778                    if (!$user_info->clicked_contact_sales_last_date && !empty($contact['properties']['clicked_contact_sales_last_date'])) {
779                        try {
780                            $user_info->clicked_contact_sales_last_date = new UTCDateTime(Carbon::parse($contact['properties']['clicked_contact_sales_last_date'])->timestamp * 1000);
781                        } catch (\Exception $e) {
782                            $user_info->clicked_contact_sales_last_date = $contact['properties']['clicked_contact_sales_last_date'];
783                        }
784                    }
785
786                    if (!$user_info->clicked_contact_sales_count && !empty($contact['properties']['clicked_contact_sales_count'])) {
787                        $user_info->clicked_contact_sales_count = $contact['properties']['clicked_contact_sales_count'];
788                    }
789
790                    if (!$user_info->df_stripe_customer_id && !empty($contact['properties']['df_stripe_customer_id'])) {
791                        $user_info->df_stripe_customer_id = $contact['properties']['df_stripe_customer_id'];
792                    }
793
794                    if (!$user_info->subscription_owner && !empty($contact['properties']['subscription_owner'])) {
795                        $user_info->subscription_owner = $contact['properties']['subscription_owner'];
796                    }
797
798                    if (!$user_info->billing_address_line_1 && !empty($contact['properties']['billing_address_line_1'])) {
799                        $user_info->billing_address_line_1 = $contact['properties']['billing_address_line_1'];
800                    }
801
802                    if (!$user_info->billing_address_line_2 && !empty($contact['properties']['billing_address_line_2'])) {
803                        $user_info->billing_address_line_2 = $contact['properties']['billing_address_line_2'];
804                    }
805
806                    if (!$user_info->billing_city && !empty($contact['properties']['billing_city'])) {
807                        $user_info->billing_city = $contact['properties']['billing_city'];
808                    }
809
810                    if (!$user_info->billing_state && !empty($contact['properties']['billing_state'])) {
811                        $user_info->billing_state = $contact['properties']['billing_state'];
812                    }
813
814                    if (!$user_info->billing_zip && !empty($contact['properties']['billing_zip'])) {
815                        $user_info->billing_zip = $contact['properties']['billing_zip'];
816                    }
817
818                    if (!$user_info->billing_country && !empty($contact['properties']['billing_country'])) {
819                        $user_info->billing_country = $contact['properties']['billing_country'];
820                    }
821
822                    if (!$user_info->number_of_completed_payments && !empty($contact['properties']['number_of_completed_payments'])) {
823                        $user_info->number_of_completed_payments = $contact['properties']['number_of_completed_payments'];
824                    }
825
826                    if (!$user_info->number_of_expected_payments && !empty($contact['properties']['number_of_expected_payments'])) {
827                        $user_info->number_of_expected_payments = $contact['properties']['number_of_expected_payments'];
828                    }
829
830                    if (!$user_info->payment_method && !empty($contact['properties']['payment_method'])) {
831                        $user_info->payment_method = $contact['properties']['payment_method'];
832                    }
833
834                    if (!$user_info->flymsg_last_product_purchased && !empty($contact['properties']['flymsg_last_product_purchased'])) {
835                        $user_info->flymsg_last_product_purchased = $contact['properties']['flymsg_last_product_purchased'];
836                    }
837
838                    if (!$user_info->last_total_invoice_amount && !empty($contact['properties']['last_total_invoice_amount'])) {
839                        $numberInfo = preg_replace('/[^0-9.]/', '', $contact['properties']['last_total_invoice_amount']);
840                        $user_info->last_total_invoice_amount = $numberInfo;
841                    }
842
843                    if (!$user_info->flymsg_total_sales && !empty($contact['properties']['flymsg_total_sales'])) {
844                        $user_info->flymsg_total_sales = $contact['properties']['flymsg_total_sales'];
845                    }
846
847                    if (!$user_info->coupon_name && !empty($contact['properties']['coupon_name'])) {
848                        $user_info->coupon_name = $contact['properties']['coupon_name'];
849                    }
850
851                    if (!$user_info->coupon_code && !empty($contact['properties']['coupon_code'])) {
852                        $user_info->coupon_code = $contact['properties']['coupon_code'];
853                    }
854
855                    if (!$user_info->coupon_type && !empty($contact['properties']['coupon_type'])) {
856                        $user_info->coupon_type = $contact['properties']['coupon_type'];
857                    }
858
859                    if (!$user_info->duration && !empty($contact['properties']['duration'])) {
860                        $user_info->duration = $contact['properties']['duration'];
861                    }
862
863                    if (!$user_info->coupon_value__discount_ && !empty($contact['properties']['coupon_value__discount_'])) {
864                        $user_info->coupon_value__discount_ = $contact['properties']['coupon_value__discount_'];
865                    }
866
867                    if (!$user_info->coupon_redemption_limits && !empty($contact['properties']['coupon_redemption_limits'])) {
868                        $user_info->coupon_redemption_limits = $contact['properties']['coupon_redemption_limits'];
869                    }
870
871                    if (!$user_info->productivity_problems && !empty($contact['properties']['productivity_problems'])) {
872                        $user_info->productivity_problems = $contact['properties']['productivity_problems'];
873                    }
874
875                    if (!$user_info->type_here_how_flymsg_will_help_you___ && !empty($contact['properties']['type_here_how_flymsg_will_help_you___'])) {
876                        $user_info->type_here_how_flymsg_will_help_you___ = $contact['properties']['type_here_how_flymsg_will_help_you___'];
877                    }
878
879                    if (!$user_info->flymsg_use_case && !empty($contact['properties']['flymsg_use_case'])) {
880                        $user_info->flymsg_use_case = $contact['properties']['flymsg_use_case'];
881                    }
882
883                    if (!$user_info->sign_out_reason && !empty($contact['properties']['sign_out_reason'])) {
884                        $user_info->sign_out_reason = $contact['properties']['sign_out_reason'];
885                    }
886
887                    if (!$user_info->sign_out_text && !empty($contact['properties']['sign_out_text'])) {
888                        $user_info->sign_out_text = $contact['properties']['sign_out_text'];
889                    }
890
891                    Log::info("Contact found for email: {$user->email}", [
892                        'id' => $contact['id'],
893                        'properties' => $contact['properties'],
894                    ]);
895                }
896            }
897
898            #endregion
899        }
900
901        $user_info->save();
902
903        return $user_info->fresh();
904    }
905
906    private function parseUserTypeByRoleId(string $role_ids)
907    {
908        if (empty($role_ids)) {
909            return null;
910        }
911
912        $roles = Role::whereIn('id', explode(',', $role_ids))->get();
913
914        return $this->parseUserType($roles->pluck('name')->implode(','));
915    }
916
917    private function parseUserType(string $roles)
918    {
919        if (empty($roles)) {
920            return null;
921        }
922
923        $userRoles = explode(',', $roles);
924
925        return implode(';', array_map(function ($role) {
926            return match ($role) {
927                'Reporting Admin' => 'Reporting POC',
928                'Group Admin' => 'Group Admin Manager',
929                default => $role,
930            };
931        }, $userRoles));
932    }
933
934    private function formatToCarbonDate($value): ?string
935    {
936        if (empty($value)) {
937            return '';
938        }
939
940        if ($value instanceof Carbon) {
941            return $value->toDateString();
942        }
943
944        if ($value instanceof \MongoDB\BSON\UTCDateTime || (is_numeric($value) && strlen($value) >= 13)) {
945            try {
946                return Carbon::createFromTimestampMs($value)->toDateString();
947            } catch (\Exception $e) {
948                return null;
949            }
950        }
951
952        try {
953            return Carbon::parse($value)->toDateString();
954        } catch (\Exception $e) {
955            try {
956                return Carbon::createFromTimestamp($value)->toDateString();
957            } catch (\Exception $e) {
958                return null;
959            }
960        }
961    }
962
963    public function recalculateFlyCutUsage(string $userId)
964    {
965        $flyCutUsages = FlyCutUsage::where('user_id', $userId)->get();
966
967        foreach ($flyCutUsages as $flyCutUsage) {
968            try {
969                if ($flyCutUsage->user) {
970                    $timeSaved = $this->statisticsService->getTimeSaved($flyCutUsage->user, $flyCutUsage->characters_saved);
971                    $carbonDate = Carbon::createFromFormat('Y-m-d H:i:s', $flyCutUsage->created_at);
972                    $costSaved = $this->statisticsService->getCostSaved($flyCutUsage->user, $timeSaved, $carbonDate);
973                    $flyCutUsage->time_saved = $timeSaved;
974                    $flyCutUsage->cost_saved = $costSaved;
975                    $flyCutUsage->recalculated_wage_per_hour = true;
976                    $flyCutUsage->save();
977                }
978            } catch (\Exception $e) {
979                // error
980            }
981        }
982    }
983}