Completed
Push — api/develop ( ceb0fc...52cb6e )
by Bertrand
25:03
created

TimelogController::timeOut()   B

Complexity

Conditions 4
Paths 14

Size

Total Lines 29
Code Lines 18

Duplication

Lines 0
Ratio 0 %

Importance

Changes 2
Bugs 0 Features 0
Metric Value
c 2
b 0
f 0
dl 0
loc 29
rs 8.5806
cc 4
eloc 18
nc 14
nop 2
1
<?php
2
3
/**
4
 * This file is part of the HRis Software package.
5
 *
6
 * HRis - Human Resource and Payroll System
7
 *
8
 * @link http://github.com/HB-Co/HRis
9
 */
10
namespace HRis\Api\Controllers\Presence;
11
12
use Carbon\Carbon;
13
use Dingo\Api\Http\Request;
14
use HRis\Api\Controllers\BaseController;
15
use HRis\Api\Eloquent\Employee;
16
use HRis\Api\Eloquent\Timelog;
17
use HRis\Api\Repositories\Time\TimelogRepository;
18
use Tymon\JWTAuth\Facades\JWTAuth;
19
20
class TimelogController extends BaseController
21
{
22
    /**
23
     * @var TimelogRepository
24
     */
25
    public $timelog;
26
27
    /**
28
     * @var Employee
29
     */
30
    public $employee;
31
32
    /**
33
     * @var int
34
     */
35
    public $rows_per_page = 10;
36
37
    /**
38
     * TimelogController constructor.
39
     *
40
     * @param Employee $employee
41
     */
42
    public function __construct(Employee $employee)
43
    {
44
        $this->timelog = new TimelogRepository();
45
        $this->employee = $employee;
46
    }
47
48
    /**
49
     * @param Request $request
50
     *
51
     * @return \Dingo\Api\Http\Response
52
     *
53
     * @author Bertrand Kintanar <[email protected]>
54
     */
55
    public function index(Request $request)
56
    {
57
        $query_params = $request->only('start', 'end', 'offset', 'employee_id');
58
        $query_params = array_filter($query_params);
59
60
        $query_params['offset'] = array_key_exists('offset', $query_params) ?: 0;
61
62
        $employee = $this->employee->whereEmployeeId($query_params['employee_id'])->first();
0 ignored issues
show
Documentation Bug introduced by
The method whereEmployeeId does not exist on object<HRis\Api\Eloquent\Employee>? Since you implemented __call, maybe consider adding a @method annotation.

If you implement __call and you know which methods are available, you can improve IDE auto-completion and static analysis by adding a @method annotation to the class.

This is often the case, when __call is implemented by a parent class and only the child class knows which methods exist:

class ParentClass {
    private $data = array();

    public function __call($method, array $args) {
        if (0 === strpos($method, 'get')) {
            return $this->data[strtolower(substr($method, 3))];
        }

        throw new \LogicException(sprintf('Unsupported method: %s', $method));
    }
}

/**
 * If this class knows which fields exist, you can specify the methods here:
 *
 * @method string getName()
 */
class SomeClass extends ParentClass { }
Loading history...
63
64
        $start = $this->startOfMonth($query_params);
65
        $end = $this->endOfMonth($query_params);
66
        $dateRange = $this->dateRangeFormat($start, $end);
67
        $timelogs = $this->timelog->range(
68
            $start->subMinutes($query_params['offset']),
0 ignored issues
show
Bug introduced by
It seems like $query_params['offset'] can also be of type boolean; however, Carbon\Carbon::subMinutes() does only seem to accept integer, maybe add an additional type check?

If a method or function can return multiple different values and unless you are sure that you only can receive a single value in this context, we recommend to add an additional type check:

/**
 * @return array|string
 */
function returnsDifferentValues($x) {
    if ($x) {
        return 'foo';
    }

    return array();
}

$x = returnsDifferentValues($y);
if (is_array($x)) {
    // $x is an array.
}

If this a common case that PHP Analyzer should handle natively, please let us know by opening an issue.

Loading history...
69
            $end->subMinutes($query_params['offset']),
0 ignored issues
show
Bug introduced by
It seems like $query_params['offset'] can also be of type boolean; however, Carbon\Carbon::subMinutes() does only seem to accept integer, maybe add an additional type check?

If a method or function can return multiple different values and unless you are sure that you only can receive a single value in this context, we recommend to add an additional type check:

/**
 * @return array|string
 */
function returnsDifferentValues($x) {
    if ($x) {
        return 'foo';
    }

    return array();
}

$x = returnsDifferentValues($y);
if (is_array($x)) {
    // $x is an array.
}

If this a common case that PHP Analyzer should handle natively, please let us know by opening an issue.

Loading history...
70
            $employee->id,
71
            $this->rows_per_page
72
        );
73
74
        foreach ($query_params as $key => $value) {
75
            $timelogs->appends($key, $value);
76
        }
77
78
        $data = [
79
            'timelogs'       => $timelogs,
80
            'date_range'     => $dateRange,
81
            'summary_report' => [
82
                'total_hours' => $this->totalHours($timelogs),
83
                'late'        => 0,
84
                'undertime'   => 0,
85
                'overtime'    => 0,
86
            ],
87
        ];
88
89
        return $this->responseAPI(200, SUCCESS_RETRIEVE_MESSAGE,
90
            ['data' => $data, 'table' => $this->setupDataTable($timelogs)]);
91
    }
92
93
    /**
94
     * @param        $input
95
     * @param string $format
96
     *
97
     * @return static
98
     *
99
     * @author Bertrand Kintanar <[email protected]>
100
     */
101
    private function startOfMonth($input, $format = 'Y-m-d H:i:s')
102
    {
103
        return isset($input['start']) ?
104
            Carbon::createFromFormat($format, $input['start'].' 00:00:00') :
105
            Carbon::now()->startOfMonth();
106
    }
107
108
    /**
109
     * @param        $input
110
     * @param string $format
111
     *
112
     * @return static
113
     *
114
     * @author Bertrand Kintanar <[email protected]>
115
     */
116
    private function endOfMonth($input, $format = 'Y-m-d H:i:s')
117
    {
118
        return isset($input['end']) ?
119
            Carbon::createFromFormat($format, $input['end'].' 23:59:59') :
120
            Carbon::now()->endOfMonth();
121
    }
122
123
    /**
124
     * @param $start
125
     * @param $end
126
     *
127
     * @return string
128
     *
129
     * @author Bertrand Kintanar <[email protected]>
130
     */
131
    private function dateRangeFormat($start, $end)
132
    {
133
        if ($start->month == $end->month &&
134
            $start->day == 1 &&
135
            $end->day == $end->format('t')
136
        ) {
137
            $this->rows_per_page = cal_days_in_month(CAL_GREGORIAN, $start->month, $start->year);
138
139
            return $start->format('F Y');
140
        } else {
141
            $this->rows_per_page = $start->diffInDays($end);
142
143
            return $start->format('F d, Y').' - '.$end->format('F d, Y');
144
        }
145
    }
146
147
    /**
148
     * @param $timelogs
149
     *
150
     * @return int
151
     *
152
     * @author Bertrand Kintanar <[email protected]>
153
     */
154
    private function totalHours($timelogs)
155
    {
156
        $total = 0;
157
        foreach ($timelogs as $timelog) {
158
            $total += $timelog->rendered_hours;
159
        }
160
161
        return $total;
162
    }
163
164
    /**
165
     * Setup table for timelogs.
166
     *
167
     * @param $timelogs
168
     *
169
     * @return array
170
     *
171
     * @author Bertrand Kintanar <[email protected]>
172
     */
173
    protected function setupDataTable($timelogs)
174
    {
175
        $table = [];
176
177
        $table['div_size'] = 'col-md-9';
178
        $table['title'] = 'Timesheet';
179
        $table['permission'] = '';
180
        $table['headers'] = ['Date', 'Time In', 'Time Out', 'Hours'];
181
        $table['model'] = [
182
            'singular' => 'timelog',
183
            'plural'   => 'timelogs',
184
            'dashed'   => 'timelogs',
185
        ];
186
        $table['items'] = $timelogs;
187
188
        return $table;
189
    }
190
191
    /**
192
     * @return \Dingo\Api\Http\Response
193
     */
194
    public function serverTime()
195
    {
196
        $server = Carbon::now();
197
198
        return $this->responseAPI(200, SUCCESS_RETRIEVE_MESSAGE, ['server' => $server]);
199
    }
200
201
    /**
202
     * Alert configuration of time in.
203
     *
204
     * @return string
205
     *
206
     * @author Harlequin Doyon <[email protected]>
207
     * @author Bertrand Kintanar <[email protected]>
208
     */
209 View Code Duplication
    public function attemptTimeIn()
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
210
    {
211
        $note = '';
212
213
        if (!$this->timelog->hasNoLatestTimein($this->loggedEmployee())) {
214
            $note = "You have an active timelog that doesn't have a time out yet";
215
        }
216
217
        $data = [
218
            'title'              => 'Are you sure?',
219
            'html'               => $this->html('You want to time in!', $note),
220
            'showCancelButton'   => true,
221
            'confirmButtonColor' => '#DD6B55',
222
            'closeOnConfirm'     => false,
223
        ];
224
225
        return $this->responseAPI(200, SUCCESS_RETRIEVE_MESSAGE, $data);
226
    }
227
228
    /**
229
     * Alert HTML helper.
230
     *
231
     * @param string $msg
232
     * @param string $note
233
     *
234
     * @return string
235
     *
236
     * @author Harlequin Doyon <[email protected]>
237
     * @author Bertrand Kintanar <[email protected]>
238
     */
239
    private function html($msg, $note = '')
240
    {
241
        $output = $msg;
242
        $output .= '<br>';
243
244
        if ($note !== '') {
245
            $output .= '<span style="font-size:12px" class="text-muted">';
246
            $output .= 'Note: '.$note;
247
            $output .= '</span>';
248
        }
249
250
        return $output;
251
    }
252
253
    /**
254
     * Alert configuration of time out.
255
     *
256
     * @return string
257
     *
258
     * @author Harlequin Doyon <[email protected]>
259
     * @author Bertrand Kintanar <[email protected]>
260
     */
261 View Code Duplication
    public function attemptTimeOut()
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
262
    {
263
        $note = '';
264
265
        if (!$this->timelog->hasNoLatestTimeout($this->loggedEmployee())) {
266
            $note = "You don't have an active time in log";
267
        }
268
269
        $data = [
270
            'title'              => 'Are you sure?',
271
            'html'               => $this->html('You want to time out!', $note),
272
            'showCancelButton'   => true,
273
            'confirmButtonColor' => '#DD6B55',
274
            'closeOnConfirm'     => false,
275
        ];
276
277
        return $this->responseAPI(200, SUCCESS_RETRIEVE_MESSAGE, $data);
278
    }
279
280
    /**
281
     * Save time in log in the database.
282
     *
283
     * @param Timelog $timelog
284
     *
285
     * @return \Dingo\Api\Http\Response
286
     *
287
     * @author Harlequin Doyon <[email protected]>
288
     * @author Bertrand Kintanar <[email protected]>
289
     */
290
    public function timeIn(Timelog $timelog)
0 ignored issues
show
Unused Code introduced by
The parameter $timelog is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
291
    {
292
        $user = JWTAuth::parseToken()->authenticate();
293
294
        $timelog = Timelog::create([
295
            'employee_id' => $user->employee->id,
296
            'in'          => Carbon::now(),
297
        ]);
298
299
        $data = [
300
            'title'      => 'Punch In',
301
            'text'       => 'You have successfully submitted your timelog.',
302
            'timelog_id' => $timelog->id,
0 ignored issues
show
Documentation introduced by
The property id does not exist on object<HRis\Api\Eloquent\Timelog>. Since you implemented __get, maybe consider adding a @property annotation.

Since your code implements the magic getter _get, this function will be called for any read access on an undefined variable. You can add the @property annotation to your class or interface to document the existence of this variable.

<?php

/**
 * @property int $x
 * @property int $y
 * @property string $text
 */
class MyLabel
{
    private $properties;

    private $allowedProperties = array('x', 'y', 'text');

    public function __get($name)
    {
        if (isset($properties[$name]) && in_array($name, $this->allowedProperties)) {
            return $properties[$name];
        } else {
            return null;
        }
    }

    public function __set($name, $value)
    {
        if (in_array($name, $this->allowedProperties)) {
            $properties[$name] = $value;
        } else {
            throw new \LogicException("Property $name is not defined.");
        }
    }

}

If the property has read access only, you can use the @property-read annotation instead.

Of course, you may also just have mistyped another name, in which case you should fix the error.

See also the PhpDoc documentation for @property.

Loading history...
303
        ];
304
305
        return $this->responseAPI(201, SUCCESS_ADD_MESSAGE, $data);
306
    }
307
308
    /**
309
     * Save time out log in the database.
310
     *
311
     * @param Timelog $timelog
312
     * @param Request $request
313
     *
314
     * @return \Dingo\Api\Http\Response
315
     *
316
     * @author Harlequin Doyon <[email protected]>
317
     * @author Bertrand Kintanar <[email protected]>
318
     */
319
    public function timeOut(Timelog $timelog, Request $request)
320
    {
321
        $id = $request->has('id') ? $request->get('id') : null;
322
        $user = JWTAuth::parseToken()->authenticate();
323
324
        try {
325
            if (is_null($id)) {
326
327
                $timelog->create([
328
                    'employee_id' => $user->employee->id,
329
                    'out'         => Carbon::now(),
330
                ]);
331
            } else {
332
                $t = $timelog->find($id);
0 ignored issues
show
Documentation Bug introduced by
The method find does not exist on object<HRis\Api\Eloquent\Timelog>? Since you implemented __call, maybe consider adding a @method annotation.

If you implement __call and you know which methods are available, you can improve IDE auto-completion and static analysis by adding a @method annotation to the class.

This is often the case, when __call is implemented by a parent class and only the child class knows which methods exist:

class ParentClass {
    private $data = array();

    public function __call($method, array $args) {
        if (0 === strpos($method, 'get')) {
            return $this->data[strtolower(substr($method, 3))];
        }

        throw new \LogicException(sprintf('Unsupported method: %s', $method));
    }
}

/**
 * If this class knows which fields exist, you can specify the methods here:
 *
 * @method string getName()
 */
class SomeClass extends ParentClass { }
Loading history...
333
                $t->out = Carbon::now();
334
                $t->save();
335
            }
336
        } catch (Exception $e) {
0 ignored issues
show
Bug introduced by
The class HRis\Api\Controllers\Presence\Exception does not exist. Did you forget a USE statement, or did you not list all dependencies?

Scrutinizer analyzes your composer.json/composer.lock file if available to determine the classes, and functions that are defined by your dependencies.

It seems like the listed class was neither found in your dependencies, nor was it found in the analyzed files in your repository. If you are using some other form of dependency management, you might want to disable this analysis.

Loading history...
337
            abort(404, 'cannot_update_timelog');
338
        }
339
340
        $data = [
341
            'title' => 'Punch Out',
342
            'text'  => 'You have successfully submitted your timelog.',
343
        ];
344
345
        return $this->responseAPI(201, SUCCESS_ADD_MESSAGE, $data);
346
347
    }
348
}
349