Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
11.54% covered (danger)
11.54%
21 / 182
0.00% covered (danger)
0.00%
0 / 13
CRAP
0.00% covered (danger)
0.00%
0 / 1
StatisticsService
11.54% covered (danger)
11.54%
21 / 182
0.00% covered (danger)
0.00%
0 / 13
2723.01
0.00% covered (danger)
0.00%
0 / 1
 getDateFromNow
0.00% covered (danger)
0.00%
0 / 15
0.00% covered (danger)
0.00%
0 / 1
42
 getDateFromNowInMonthYear
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 getWagePerHour
53.33% covered (warning)
53.33%
16 / 30
0.00% covered (danger)
0.00%
0 / 1
33.92
 getCompanyWagePerHour
0.00% covered (danger)
0.00%
0 / 16
0.00% covered (danger)
0.00%
0 / 1
42
 getCostSaved
0.00% covered (danger)
0.00%
0 / 2
0.00% covered (danger)
0.00%
0 / 1
2
 getWordsPerMinute
62.50% covered (warning)
62.50%
5 / 8
0.00% covered (danger)
0.00%
0 / 1
11.38
 getCompanyDefaultSetting
0.00% covered (danger)
0.00%
0 / 12
0.00% covered (danger)
0.00%
0 / 1
2
 getTimeSaved
0.00% covered (danger)
0.00%
0 / 3
0.00% covered (danger)
0.00%
0 / 1
2
 getOldTimeSaved
0.00% covered (danger)
0.00%
0 / 9
0.00% covered (danger)
0.00%
0 / 1
12
 getOldCharactersTyped
0.00% covered (danger)
0.00%
0 / 9
0.00% covered (danger)
0.00%
0 / 1
6
 getOldChart
0.00% covered (danger)
0.00%
0 / 44
0.00% covered (danger)
0.00%
0 / 1
110
 transformHubSpotRecord
0.00% covered (danger)
0.00%
0 / 11
0.00% covered (danger)
0.00%
0 / 1
20
 transformHubSpotRecordToRawChartData
0.00% covered (danger)
0.00%
0 / 22
0.00% covered (danger)
0.00%
0 / 1
30
1<?php
2
3namespace App\Http\Services;
4
5use App\Http\Models\Auth\User;
6use App\Http\Models\FlyCutUsage;
7use App\Http\Models\Setting;
8use App\Http\Models\ShortcutWithUsage;
9use Carbon\Carbon;
10
11class StatisticsService
12{
13    /**
14     * Get the date whose difference from now is specified in the params.
15     *
16     * @param  string  $type  month|day|hour
17     */
18    public function getDateFromNow(?int $differenceFromNow = 12, ?string $type = 'month'): Carbon
19    {
20        $from = now()->subMonths(12);
21
22        if (empty($differenceFromNow)) {
23            return $from;
24        }
25
26        switch ($type) {
27            case 'month':
28                $from = now()->subMonths($differenceFromNow);
29                break;
30            case 'day':
31                $from = now()->subDays($differenceFromNow);
32                break;
33            case 'hour':
34                $from = now()->subHours($differenceFromNow);
35                break;
36            default:
37                $from = now()->subMonths(12);
38                break;
39        }
40
41        return $from;
42    }
43
44    /**
45     * Get the date in month year format whose difference from now is specified in the params.
46     *
47     * @param  string  $type  month|day|hour
48     */
49    public function getDateFromNowInMonthYear(?int $differenceFromNow = 12, ?string $type = 'month'): string
50    {
51        return $this->getDateFromNow($differenceFromNow, $type)->format('M Y');
52    }
53
54    public function getWagePerHour(User $user, Carbon $date): float
55    {
56        $wagePerHour = FlyCutUsage::WAGE_PER_HOUR;
57
58        if (filled($user->setting)) {
59            $wagePerHourHistory = $user->setting->wage_per_hour_history ?? [];
60
61            $historyWagePerHour = null;
62            if (count($wagePerHourHistory) > 0) {
63                $wagePerHourHistory = array_filter($wagePerHourHistory, function ($item) use ($date) {
64                    return Carbon::parse($item['date'])->lte($date);
65                });
66
67                if (count($wagePerHourHistory) > 0) {
68                    $historyWagePerHour = end($wagePerHourHistory)['wage_per_hour'];
69                }
70            }
71
72            if ($historyWagePerHour) {
73                $wagePerHour = $historyWagePerHour;
74            } elseif (! empty($user->setting->wage_per_hour)) {
75                $wagePerHour = $user->setting->wage_per_hour;
76            }
77        }
78
79        if (! empty($user->company_id) && strtolower($user->status) == 'active') {
80            $companySetting = Setting::where('company_id', $user->company_id)->first();
81            if ($companySetting && $companySetting->override_user_wage_per_hour) {
82                $wagePerHourHistory = $companySetting->wage_per_hour_history ?? [];
83
84                $historyWagePerHour = null;
85                if (count($wagePerHourHistory) > 0) {
86                    $wagePerHourHistory = array_filter($wagePerHourHistory, function ($item) use ($date) {
87                        return Carbon::parse($item['date'])->lte($date);
88                    });
89
90                    if (count($wagePerHourHistory) > 0) {
91                        $historyWagePerHour = end($wagePerHourHistory)['wage_per_hour'];
92                    }
93                }
94
95                if ($historyWagePerHour) {
96                    $wagePerHour = $historyWagePerHour;
97                } elseif (! empty($companySetting->wage_per_hour)) {
98                    $wagePerHour = $companySetting->wage_per_hour;
99                }
100            }
101        }
102
103        return $wagePerHour;
104    }
105
106    public function getCompanyWagePerHour(string $companyId, Carbon $date): float
107    {
108        $wagePerHour = FlyCutUsage::WAGE_PER_HOUR;
109
110        $setting = Setting::where('company_id', $companyId)->first();
111
112        if (filled($setting)) {
113            $wagePerHourHistory = $setting->wage_per_hour_history ?? [];
114
115            $historyWagePerHour = null;
116            if (count($wagePerHourHistory) > 0) {
117                $wagePerHourHistory = array_filter($wagePerHourHistory, function ($item) use ($date) {
118                    return Carbon::parse($item['date'])->lte($date);
119                });
120
121                if (count($wagePerHourHistory) > 0) {
122                    $historyWagePerHour = end($wagePerHourHistory)['wage_per_hour'];
123                }
124            }
125
126            if ($historyWagePerHour) {
127                $wagePerHour = $historyWagePerHour;
128            } elseif (! empty($setting->wage_per_hour)) {
129                $wagePerHour = $setting->wage_per_hour;
130            }
131        }
132
133        return $wagePerHour;
134    }
135
136    /**
137     * Get the time saved in hours.
138     */
139    public function getCostSaved(User $user, float $timeSaved, Carbon $date): float
140    {
141        $wagePerHour = $this->getWagePerHour($user, $date);
142
143        return round($timeSaved * $wagePerHour, 8);
144    }
145
146    public function getWordsPerMinute(User $user): int
147    {
148        $userWordPerMinute = FlyCutUsage::WORDS_PER_MINUTE;
149
150        if (filled($user->setting) && ! empty($user->setting->words_per_minute)) {
151            $userWordPerMinute = $user->setting->words_per_minute;
152        }
153
154        if (! empty($user->company_id) && strtolower($user->status) == 'active') {
155            $companySetting = Setting::where('company_id', $user->company_id)->first();
156            if ($companySetting && $companySetting->override_user_words_per_minute && ! empty($companySetting->words_per_minute)) {
157                $userWordPerMinute = $companySetting->words_per_minute;
158            }
159        }
160
161        return $userWordPerMinute;
162    }
163
164    public function getCompanyDefaultSetting()
165    {
166        return [
167            'wage_per_hour' => FlyCutUsage::WAGE_PER_HOUR,
168            'words_per_minute' => FlyCutUsage::WORDS_PER_MINUTE,
169            'override_user_wage_per_hour' => false,
170            'override_user_typing_style' => false,
171            'override_user_flygrammar' => false,
172            'override_user_flyrewrite' => false,
173            'typing_style' => 'all',
174            'fly_rewrite' => 'enabled',
175            'fly_grammar' => 'enabled',
176            'fly_grammar_default_language' => 'en_US',
177        ];
178    }
179
180    /**
181     * Get the time saved in hours.
182     */
183    public function getTimeSaved(User $user, int $charactersSaved): float
184    {
185        $userWordPerMinute = $this->getWordsPerMinute($user);
186
187        $characterPerHour = $userWordPerMinute * 300;
188
189        return round($charactersSaved / $characterPerHour, 8);
190    }
191
192    /**
193     * Get the time saved in hours for old records.
194     */
195    public function getOldTimeSaved($from, $hubspotRecord): float
196    {
197        $tRecord = $this->transformHubSpotRecord($hubspotRecord);
198
199        if (! $tRecord) {
200            return 0;
201        }
202
203        $user = User::where('id', $hubspotRecord['flymsg_id'])->first();
204        $userWordPerMinute = $this->getWordsPerMinute($user);
205
206        $characterPerHour = $userWordPerMinute * 300;
207
208        // Estimate
209        $difference = $this->getOldCharactersTyped($from, $hubspotRecord) - ($hubspotRecord->number_of_flycuts_created * 5);
210
211        $charactersSaved = $difference > 0 ? $difference : 0;
212
213        return $charactersSaved / $characterPerHour;
214    }
215
216    /**
217     * Get the characters typed for old records.
218     */
219    public function getOldCharactersTyped($from, $hubspotRecord): int
220    {
221        $tRecord = $this->transformHubSpotRecord($hubspotRecord);
222
223        if (! $tRecord) {
224            return 0;
225        }
226
227        $filtered = collect(array_filter($tRecord, function ($key) use ($from) {
228            return Carbon::parse($key)->gte(Carbon::parse($from));
229        }, ARRAY_FILTER_USE_KEY));
230
231        return $filtered->sum(function ($value) {
232            return $value;
233        });
234    }
235
236    /**
237     * Get chart data from old records.
238     */
239    public function getOldChart(string $from, $hubspotRecord)
240    {
241        $tRecord = $this->transformHubSpotRecord($hubspotRecord);
242
243        // Get user avergae charcter count for flycuts
244        $flymsg_id = $hubspotRecord['flymsg_id'] ?? null;
245        $average = 1;
246        $user = User::where('_id', $flymsg_id)->first();
247
248        if (isset($user['average_charactors_count']) && $user['average_charactors_count'] != null) {
249            $average = $user['average_charactors_count'];
250        } else {
251            $shortcuts = ShortcutWithUsage::where('user_id', $flymsg_id)
252                ->where('created_at', '<=', Carbon::createFromFormat('Y-m-d', '2023-1-24'))
253                ->select('text', 'charactors_count')->get();
254            if (isset($shortcuts) && count($shortcuts) > 0) {
255                $charactors_counts = [];
256                foreach ($shortcuts as $shortcutHtmlArray) {
257                    if ($shortcutHtmlArray['charactors_count']) {
258                        $charactors_counts[] = $shortcutHtmlArray['charactors_count'];
259                    } else {
260                        $charactors_counts[] = strlen(strip_tags($shortcutHtmlArray['text']));
261                    }
262                }
263                $a = array_filter($charactors_counts);
264                $average = array_sum($a) / count($a);
265                $user['average_charactors_count'] = $average;
266                $user->save();
267            }
268        }
269
270        if (! $tRecord) {
271            return null;
272        }
273
274        $filtered = array_reverse(array_filter($tRecord, function ($key) use ($from) {
275            return Carbon::parse($key)->gte(Carbon::parse($from));
276        }, ARRAY_FILTER_USE_KEY), true);
277
278        $mutated = [];
279
280        array_map(function ($key, $value) use ($hubspotRecord, &$mutated, $average, $user, $from) {
281            // Estimate
282            $difference = $value - ($hubspotRecord->number_of_flycuts_created * 5);
283
284            $charactersSaved = $difference > 0 ? $difference : 0;
285
286            // old $timeSaved = $charactersSaved / $characterPerHour;
287            $timeSaved = $this->getTimeSaved($user, $charactersSaved);
288            $costSaved = $this->getCostSaved($user, $timeSaved, Carbon::parse($from));
289
290            $keyArray = explode(' ', $key);
291
292            $flycuts_used = $value / ($average * 0.5);
293
294            $mutated[@$keyArray[0]] =
295                [
296                    'flycut_count' => ceil($flycuts_used),
297                    'characters_typed' => $value,
298                    'cost_saved' => $timeSaved,
299                    'time_saved' => $costSaved,
300                ];
301            if (isset($mutated['totalflycuts_used'])) {
302                $mutated['totalflycuts_used'] = $mutated['totalflycuts_used'] + ceil($flycuts_used);
303            } else {
304                $mutated['totalflycuts_used'] = ceil($flycuts_used);
305            }
306        }, array_keys($filtered), array_values($filtered));
307
308        return $mutated;
309    }
310
311    public function transformHubSpotRecord($hubspotRecord)
312    {
313        $monthlyRecord = @$hubspotRecord->total___of_characters_typed_monthly_by_flymsg_by_user;
314
315        // $monthlyRecord = "136050 - Jan 2023.   86228 - Dec 2022.   524720 - Nov 2022.   141441 - Oct 2022.   378095 - Sep 2022.   158766 - Aug 2022.   109886 - Jul 2022.   173300 - Jun 2022.   99031 - May 2022.   175428 - Apr 2022.   0 - Mar 2022.   0 - Feb 2022.   0 - Jan 2022.   ";
316
317        if (! $monthlyRecord || empty($monthlyRecord)) {
318            return null;
319        }
320
321        $record = array_map('trim', explode('.', $monthlyRecord));
322
323        $tRecord = [];
324        array_map(function ($each) use (&$tRecord) {
325            $exploded = explode(' - ', $each);
326
327            if (filled(@$exploded[1])) {
328                $tRecord[@$exploded[1]] = (int) $exploded[0];
329            }
330        }, $record);
331
332        return $tRecord;
333    }
334
335    public function transformHubSpotRecordToRawChartData($hubspotRecord)
336    {
337        $monthlyRecord = @$hubspotRecord->total___of_characters_typed_monthly_by_flymsg_by_user;
338
339        if (! $monthlyRecord || empty($monthlyRecord)) {
340            return null;
341        }
342
343        $user = User::where('id', $hubspotRecord['flymsg_id'])->first();
344        $record = array_map('trim', explode('.', $monthlyRecord));
345
346        return array_map(function ($each) use ($hubspotRecord, $user) {
347            $exploded = explode(' - ', $each);
348
349            if (filled(@$exploded[1])) {
350                // Estimate
351                $charactersSaved = (int) $exploded[0] - ($hubspotRecord->number_of_flycuts_created * 5);
352
353                $charactersSaved = $charactersSaved > 0 ? $charactersSaved : 0;
354
355                // old $timeSaved = $charactersSaved / $characterPerHour;
356                $timeSaved = $this->getTimeSaved($user, $charactersSaved);
357                $costSaved = $this->getCostSaved($user, $timeSaved, now());
358
359                return [
360                    'month_year' => @$exploded[1],
361                    'flycuts_used' => 0,
362                    'characters_typed' => (int) $exploded[0],
363                    'characters_saved' => $charactersSaved,
364                    'time_saved' => $timeSaved,
365                    'cost_saved' => $costSaved,
366                ];
367            }
368
369            return [];
370        }, $record);
371    }
372}