diff --git a/Admin/Install/Application/Timerecording/Routes.php b/Admin/Install/Application/Timerecording/Routes.php index bc97993..3e26a7c 100644 --- a/Admin/Install/Application/Timerecording/Routes.php +++ b/Admin/Install/Application/Timerecording/Routes.php @@ -5,6 +5,7 @@ return [ 0 => [ 'dest' => '\Modules\HumanResourceTimeRecording\Controller\TimerecordingController:viewDashboard', 'verb' => 1, + 'active' => true, 'permission' => [ 'module' => 'HumanResourceTimeRecording', 'type' => 2, @@ -16,6 +17,7 @@ return [ 0 => [ 'dest' => '\Modules\HumanResourceTimeRecording\Controller\TimerecordingController:viewDashboard', 'verb' => 1, + 'active' => true, 'permission' => [ 'module' => 'HumanResourceTimeRecording', 'type' => 2, diff --git a/Admin/Install/Navigation.install.json b/Admin/Install/Navigation.install.json index 04b44f1..845c47f 100755 --- a/Admin/Install/Navigation.install.json +++ b/Admin/Install/Navigation.install.json @@ -18,7 +18,7 @@ "pid": "/humanresource/timerecording", "type": 3, "subtype": 1, - "name": "Today", + "name": "Dashboard", "uri": "{/base}/humanresource/timerecording/dashboard?{?}", "target": "self", "icon": null, diff --git a/Admin/Routes/Web/Api.php b/Admin/Routes/Web/Api.php index 2b2f2cb..d89ad85 100755 --- a/Admin/Routes/Web/Api.php +++ b/Admin/Routes/Web/Api.php @@ -23,6 +23,7 @@ return [ 'dest' => '\Modules\HumanResourceTimeRecording\Controller\ApiController:apiSessionCreate', 'verb' => RouteVerb::PUT, 'csrf' => true, + 'active' => true, 'permission' => [ 'module' => ApiController::NAME, 'type' => PermissionType::CREATE, @@ -35,6 +36,7 @@ return [ 'dest' => '\Modules\HumanResourceTimeRecording\Controller\ApiController:apiSessionElementCreate', 'verb' => RouteVerb::PUT, 'csrf' => true, + 'active' => true, 'permission' => [ 'module' => ApiController::NAME, 'type' => PermissionType::CREATE, diff --git a/Admin/Routes/Web/Backend.php b/Admin/Routes/Web/Backend.php index d84a1d9..0522299 100755 --- a/Admin/Routes/Web/Backend.php +++ b/Admin/Routes/Web/Backend.php @@ -22,6 +22,7 @@ return [ [ 'dest' => '\Modules\HumanResourceTimeRecording\Controller\BackendController:viewDashboard', 'verb' => RouteVerb::GET, + 'active' => true, 'permission' => [ 'module' => BackendController::NAME, 'type' => PermissionType::READ, @@ -33,6 +34,7 @@ return [ [ 'dest' => '\Modules\HumanResourceTimeRecording\Controller\BackendController:viewPrivateDashboard', 'verb' => RouteVerb::GET, + 'active' => true, 'permission' => [ 'module' => BackendController::NAME, 'type' => PermissionType::READ, @@ -44,6 +46,7 @@ return [ [ 'dest' => '\Modules\HumanResourceTimeRecording\Controller\BackendController:viewPrivateSession', 'verb' => RouteVerb::GET, + 'active' => true, 'permission' => [ 'module' => BackendController::NAME, 'type' => PermissionType::READ, diff --git a/Controller/ApiController.php b/Controller/ApiController.php index bb6f709..a38edfb 100755 --- a/Controller/ApiController.php +++ b/Controller/ApiController.php @@ -91,7 +91,8 @@ final class ApiController extends Controller $element = new SessionElement($session, $dt); $element->status = ClockingStatus::tryFromValue($request->getDataInt('status')) ?? ClockingStatus::START; - $session->addSessionElement($element); + $session->sessionElements[] = $element; + $session->recalculate(); return $session; } @@ -111,7 +112,9 @@ final class ApiController extends Controller */ public function apiSessionElementCreate(RequestAbstract $request, ResponseAbstract $response, array $data = []) : void { - if (($request->getDataInt('status') ?? -1) === ClockingStatus::START) { + if (!$request->hasData('session') && + ($request->getDataInt('status') ?? -1) === ClockingStatus::START + ) { $this->apiSessionCreate($request, $response); return; @@ -146,9 +149,12 @@ final class ApiController extends Controller if ($element->status === ClockingStatus::END) { /** @var \Modules\HumanResourceTimeRecording\Models\Session $session */ - $session = SessionMapper::get()->where('id', (int) $request->getData('session'))->execute(); + $session = SessionMapper::get() + ->with('sessionElements') + ->where('id', (int) $request->getData('session')) + ->execute(); - $session->addSessionElement($element); + $session->recalculate(); SessionMapper::update()->execute($session); } diff --git a/Models/Session.php b/Models/Session.php index 69c60c2..17a5c36 100755 --- a/Models/Session.php +++ b/Models/Session.php @@ -105,56 +105,35 @@ class Session implements \JsonSerializable $this->createdAt = new \DateTimeImmutable('now'); } - /** - * Get busy time. - * - * @return int - * - * @since 1.0.0 - */ - public function getBusy() : int + public function recalculate() : void { - return $this->busy; - } - - /** - * Add a session element to the session - * - * @param SessionElement $element Session element - * - * @return void - * - * @since 1.0.0 - */ - public function addSessionElement(SessionElement $element) : void - { - if ($element->status === ClockingStatus::START) { - foreach ($this->sessionElements as $e) { - if ($e->status === ClockingStatus::START) { - return; - } - } - - $this->start = $element->datetime; - } - - if ($element->status === ClockingStatus::END) { - if ($this->end !== null) { - return; - } - - $this->end = $element->datetime; - } - - $this->sessionElements[] = $element; - \usort($this->sessionElements, [$this, 'compareSessionElementTimestamps']); + $start = null; + $end = null; + + foreach ($this->sessionElements as $e) { + if ($e->status === ClockingStatus::START + && ($start === null || $start->getTimestamp() > $e->datetime->getTimestamp()) + ) { + $start = $e->datetime; + } elseif ($e->status === ClockingStatus::END + && ($end === null || $end->getTimestamp() < $e->datetime->getTimestamp()) + ) { + $end = $e->datetime; + } + } + + $this->start = $start; + $this->end = $end; + $busyTime = 0; $lastStart = $this->start; foreach ($this->sessionElements as $e) { if ($e->status === ClockingStatus::START) { + $lastStart = $e->datetime; + continue; } diff --git a/Models/SessionElementMapper.php b/Models/SessionElementMapper.php index f9e8f37..95a19de 100755 --- a/Models/SessionElementMapper.php +++ b/Models/SessionElementMapper.php @@ -17,7 +17,7 @@ namespace Modules\HumanResourceTimeRecording\Models; use phpOMS\DataStorage\Database\Mapper\DataMapperFactory; /** - * Mapper class. + * SessionElement mapper class. * * @package Modules\HumanResourceTimeRecording\Models * @license OMS License 2.0 diff --git a/Models/SessionMapper.php b/Models/SessionMapper.php index 8fa1ac7..a62dfb5 100755 --- a/Models/SessionMapper.php +++ b/Models/SessionMapper.php @@ -20,7 +20,7 @@ use phpOMS\DataStorage\Database\Query\Builder; use phpOMS\Stdlib\Base\SmartDateTime; /** - * Mapper class. + * Session mapper class. * * @package Modules\HumanResourceTimeRecording\Models * @license OMS License 2.0 @@ -105,6 +105,8 @@ final class SessionMapper extends DataMapperFactory * * @return Session[] * + * @performance This is way too slow + * * @since 1.0.0 */ public static function getLastSessionsFromAllEmployees() : array @@ -121,7 +123,7 @@ final class SessionMapper extends DataMapperFactory ->andOn(self::TABLE . '_d1.hr_timerecording_session_start', '=', 'tm.maxDate'); return self::getAll() - ->execute($query); + ->executeGetArray($query); } /** diff --git a/Theme/Backend/Lang/Navigation.de.lang.php b/Theme/Backend/Lang/Navigation.de.lang.php index 4ab0c01..e27aaa8 100755 --- a/Theme/Backend/Lang/Navigation.de.lang.php +++ b/Theme/Backend/Lang/Navigation.de.lang.php @@ -17,5 +17,5 @@ return ['Navigation' => [ 'List' => 'Liste', 'Stats' => 'Statistiken', 'TimeRecording' => 'Zeitaufnahme', - 'Today' => 'Heute', + 'Dashboard' => 'Dashboard', ]]; diff --git a/Theme/Backend/Lang/Navigation.en.lang.php b/Theme/Backend/Lang/Navigation.en.lang.php index 9ec0fc2..9ec8dac 100755 --- a/Theme/Backend/Lang/Navigation.en.lang.php +++ b/Theme/Backend/Lang/Navigation.en.lang.php @@ -17,5 +17,5 @@ return ['Navigation' => [ 'List' => 'List', 'Stats' => 'Stats', 'TimeRecording' => 'Time Recording', - 'Today' => 'Today', + 'Dashboard' => 'Dashboard', ]]; diff --git a/Theme/Backend/dashboard.tpl.php b/Theme/Backend/dashboard.tpl.php index 5d9dc2c..4dbd7c3 100755 --- a/Theme/Backend/dashboard.tpl.php +++ b/Theme/Backend/dashboard.tpl.php @@ -13,6 +13,7 @@ declare(strict_types=1); use Modules\HumanResourceTimeRecording\Models\ClockingType; +use phpOMS\Uri\UriFactory; $date = new \DateTime('now'); @@ -36,17 +37,21 @@ echo $this->data['nav']->render(); ?> data['employees'] as $employee) : $session = $this->data['sessions'][$employee->id] ?? null; + + // @todo Implement clocking view per employee for HR (also to edit clocking) + $employeeUrl = UriFactory::build('{/base}/humanresource/staff/view?id=' . $employee->id); ?> - getStart()->format('Y-m-d') ?? $date->format('Y-m-d H:i:s'); ?> + start->format('Y-m-d H:i:s') ?? $date->format('Y-m-d H:i:s'); ?> getHtml('CT' . ($session?->type ?? ClockingType::NO_DATA)); ?> - + printHtml($employee->profile->account->name1); ?>, printHtml($employee->profile->account->name2); ?> - getStart()->format('H:i:s'); ?> + + start->format('H:i:s'); ?> getBreak() / 3600)) . 'h' : ''; ?> getBreak() / 60) % 60) . 'm' : ''; ?> - getEnd() !== null ? $session->getEnd()->format('H:i') : ''; ?> - getBusy() / 3600)) . 'h' : ''; ?> getBusy() / 60) % 60) . 'm' : ''; ?> + end?->format('H:i') ?? ''; ?> + busy / 3600)) . 'h' : ''; ?> busy / 60) % 60) . 'm' : ''; ?> diff --git a/Theme/Backend/private-dashboard.tpl.php b/Theme/Backend/private-dashboard.tpl.php index 85a1972..6f02250 100755 --- a/Theme/Backend/private-dashboard.tpl.php +++ b/Theme/Backend/private-dashboard.tpl.php @@ -222,9 +222,9 @@ echo $this->data['nav']->render(); ?> start->format('H:i'); ?> getBreak() / 3600); ?>h getBreak() / 60) % 60); ?>m end?->format('H:i'); ?> - getBusy() / 3600); ?>h getBusy() / 60) % 60); ?>m + busy / 3600); ?>h busy / 60) % 60); ?>m getBusy(); + $busy['week'] += $session->busy; if ($session->start->getTimestamp() < $startWeek->getTimestamp() || $count === $sessionCount ) : ?> @@ -238,7 +238,7 @@ echo $this->data['nav']->render(); ?> endif; ?> getBusy(); + $busy['month'] += $session->busy; if ($session->start->getTimestamp() < $startMonth->getTimestamp() || $count === $sessionCount ) : ?> diff --git a/Theme/Timeterminal/overview.tpl.php b/Theme/Timeterminal/overview.tpl.php index d33a60a..444b0de 100755 --- a/Theme/Timeterminal/overview.tpl.php +++ b/Theme/Timeterminal/overview.tpl.php @@ -99,7 +99,7 @@ echo $this->data['nav']->render(); ?> getStart()->format('H:i'); ?> getBreak() / 3600); ?>h getBreak() / 60) % 60); ?>m getEnd() !== null ? $session->getEnd()->format('H:i') : ''; ?> - getBusy() / 3600); ?>h getBusy() / 60) % 60); ?>m + busy / 3600); ?>h busy / 60) % 60); ?>m diff --git a/tests/Models/SessionTest.php b/tests/Models/SessionTest.php index 82819f7..447aa4c 100755 --- a/tests/Models/SessionTest.php +++ b/tests/Models/SessionTest.php @@ -39,7 +39,7 @@ final class SessionTest extends \PHPUnit\Framework\TestCase public function testDefault() : void { self::assertEquals(0, $this->session->id); - self::assertEquals(0, $this->session->getBusy()); + self::assertEquals(0, $this->session->busy); self::assertEquals(0, $this->session->getBreak()); self::assertEquals([], $this->session->getSessionElements()); self::assertEquals(ClockingType::OFFICE, $this->session->type); @@ -104,7 +104,7 @@ final class SessionTest extends \PHPUnit\Framework\TestCase $this->session->addSessionElement($element); self::assertEquals(2 * 60 * 60, $this->session->getBreak()); - self::assertEquals(7 * 60 * 60, $this->session->getBusy()); + self::assertEquals(7 * 60 * 60, $this->session->busy); } #[\PHPUnit\Framework\Attributes\Group('module')]