Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
100.00% covered (success)
100.00%
26 / 26
100.00% covered (success)
100.00%
2 / 2
CRAP
100.00% covered (success)
100.00%
1 / 1
Goodie
100.00% covered (success)
100.00%
26 / 26
100.00% covered (success)
100.00%
2 / 2
5
100.00% covered (success)
100.00%
1 / 1
 shiftScoreQuery
100.00% covered (success)
100.00%
5 / 5
100.00% covered (success)
100.00%
1 / 1
3
 userScore
100.00% covered (success)
100.00%
21 / 21
100.00% covered (success)
100.00%
1 / 1
2
1<?php
2
3declare(strict_types=1);
4
5namespace Engelsystem\Helpers;
6
7use Engelsystem\Database\Database;
8use Engelsystem\Models\User\User;
9use Illuminate\Database\Query\Expression;
10use Illuminate\Database\Query\Grammars\MySqlGrammar;
11
12class Goodie
13{
14    /**
15     * Generates the query to sum night shifts
16     *
17     * Shifts and shift entries must be available via join
18     */
19    public static function shiftScoreQuery(): Expression
20    {
21        $nightShifts = config('night_shifts');
22
23        /** @var Database $db */
24        $db = app(Database::class);
25        $connection = $db->getConnection();
26
27        if (!$connection->getQueryGrammar() instanceof MySqlGrammar) {
28            return $connection->raw('0');
29        }
30
31        // @codeCoverageIgnoreStart
32        // as sqlite does not support TIMESTAMPDIFF
33
34        if (!$nightShifts['enabled']) {
35            return $connection->raw(
36                /** @lang MySQL */
37                'COALESCE(SUM(TIMESTAMPDIFF(MINUTE, shifts.start, shifts.end) * 60), 0)'
38            );
39        }
40
41        /* @see \Engelsystem\Models\Shifts\Shift::isNightShift to keep them in sync */
42        $query =
43            /** @lang MySQL */
44            '
45                COALESCE(SUM(
46                    /* Shift length */
47                    TIMESTAMPDIFF(MINUTE, shifts.start, shifts.end) * 60
48                    /* Is night shift */
49                    * (
50                        CASE WHEN
51                            /* Starts during night */
52                            HOUR(shifts.start) >= %1$d AND HOUR(shifts.start) < %2$d
53                            /* Ends during night */
54                            OR (
55                                HOUR(shifts.end) > %1$d
56                                || HOUR(shifts.end) = %1$d AND MINUTE(shifts.end) > 0
57                            ) AND HOUR(shifts.end) <= %2$d
58                            /* Starts before and ends after night */
59                            OR HOUR(shifts.start) <= %1$d AND HOUR(shifts.end) >= %2$d
60                        /* Use multiplier */
61                        THEN
62                            /* Handle freeloading */
63                            CASE WHEN `shift_entries`.`freeloaded_by` IS NULL
64                            THEN %3$d
65                            ELSE -%3$d
66                            END
67                        ELSE
68                            /* Handle freeloading */
69                            CASE WHEN `shift_entries`.`freeloaded_by` IS NULL
70                            THEN 1
71                            ELSE -2
72                            END
73                        END
74                    )
75                ), 0)
76            ';
77
78        $query = sprintf($query, $nightShifts['start'], $nightShifts['end'], $nightShifts['multiplier']);
79
80        return $connection->raw($query);
81        // @codeCoverageIgnoreEnd
82    }
83
84    /**
85     * Returns the goodie score (number of hours counted for goodie score)
86     * Includes only ended shifts
87     */
88    public static function userScore(User $user): float
89    {
90        /** @var Database $db */
91        $db = app(Database::class);
92        $con = $db->getConnection();
93
94        $state = $con
95            ->query()
96            ->from('users')
97            ->selectRaw(sprintf(
98                /** @lang MySQL */
99                'ROUND((%s) / 3600, 2) AS `goodie_score`',
100                self::shiftScoreQuery()->getValue($con->getQueryGrammar())
101            ))
102            ->where('users.id', $user->id)
103            ->join('shift_entries', 'users.id', 'shift_entries.user_id')
104            ->join('shifts', 'shift_entries.shift_id', 'shifts.id')
105            ->where('shifts.end', '<', Carbon::now())
106            ->groupBy('users.id')
107            ->first();
108
109        $shiftHours = 0;
110        if ($state) {
111            // @codeCoverageIgnoreStart
112            $shiftHours = (float) $state->goodie_score;
113            // @codeCoverageIgnoreEnd
114        }
115
116        $worklogHours = $user->worklogs()
117            ->where('worked_at', '<=', Carbon::Now())
118            ->sum('hours');
119
120        return $shiftHours + $worklogHours;
121    }
122}