From 1e0a52edad70b8aa32b0657c9df116f6be5a6521 Mon Sep 17 00:00:00 2001 From: Dennis Eichhorn Date: Sun, 12 May 2024 00:06:28 +0000 Subject: [PATCH] bug fixes --- .github/workflows/greetings.yml | 2 +- Admin/Install/db.json | 75 ++++- Admin/Install/types.json | 121 +++++++ Admin/Installer.php | 89 +++++ Controller/ApiClockingTypeController.php | 405 +++++++++++++++++++++++ Controller/ApiController.php | 15 +- Models/ClockingType.php | 109 ++++-- Models/ClockingTypeL11nMapper.php | 69 ++++ Models/ClockingTypeMapper.php | 86 +++++ Models/NullClockingType.php | 47 +++ Models/Session.php | 3 +- Models/SessionMapper.php | 13 + 12 files changed, 1001 insertions(+), 33 deletions(-) create mode 100644 Admin/Install/types.json create mode 100644 Controller/ApiClockingTypeController.php create mode 100644 Models/ClockingTypeL11nMapper.php create mode 100644 Models/ClockingTypeMapper.php create mode 100644 Models/NullClockingType.php diff --git a/.github/workflows/greetings.yml b/.github/workflows/greetings.yml index adb8716..75cb759 100755 --- a/.github/workflows/greetings.yml +++ b/.github/workflows/greetings.yml @@ -9,5 +9,5 @@ jobs: - uses: actions/first-interaction@v1 with: repo-token: ${{ secrets.GITHUB_TOKEN }} - issue-message: 'Thank you for createing this issue. We will check it as soon as possible.' + issue-message: 'Thank you for creating this issue. We will check it as soon as possible.' pr-message: 'Thank you for your pull request. We will check it as soon as possible.' diff --git a/Admin/Install/db.json b/Admin/Install/db.json index d630406..97c8001 100755 --- a/Admin/Install/db.json +++ b/Admin/Install/db.json @@ -1,4 +1,73 @@ { + "hr_timerecording_type": { + "name": "hr_timerecording_type", + "fields": { + "hr_timerecording_type_id": { + "name": "hr_timerecording_type_id", + "type": "INT", + "null": false, + "primary": true, + "autoincrement": true + }, + "hr_timerecording_type_name": { + "name": "hr_timerecording_type_name", + "type": "VARCHAR(50)", + "null": false + }, + "hr_timerecording_type_custom_future": { + "name": "hr_timerecording_type_custom_future", + "type": "TINYINT(1)", + "null": false + }, + "hr_timerecording_type_custom_past": { + "name": "hr_timerecording_type_custom_past", + "type": "TINYINT(1)", + "null": false + }, + "hr_timerecording_type_correction": { + "name": "hr_timerecording_type_correction", + "type": "TINYINT(1)", + "null": false + }, + "hr_timerecording_type_work": { + "name": "hr_timerecording_type_work", + "type": "TINYINT(1)", + "null": false + } + } + }, + "hr_timerecording_type_l11n": { + "name": "hr_timerecording_type_l11n", + "fields": { + "hr_timerecording_type_l11n_id": { + "name": "hr_timerecording_type_l11n_id", + "type": "INT", + "null": false, + "primary": true, + "autoincrement": true + }, + "hr_timerecording_type_l11n_title": { + "name": "hr_timerecording_type_l11n_title", + "type": "VARCHAR(255)", + "null": false + }, + "hr_timerecording_type_l11n_type": { + "name": "hr_timerecording_type_l11n_type", + "type": "INT", + "null": false, + "foreignTable": "hr_timerecording_type", + "foreignKey": "hr_timerecording_type_id" + }, + "hr_timerecording_type_l11n_language": { + "name": "hr_timerecording_type_l11n_language", + "type": "VARCHAR(2)", + "default": null, + "null": true, + "foreignTable": "language", + "foreignKey": "language_639_1" + } + } + }, "hr_timerecording_session": { "name": "hr_timerecording_session", "fields": { @@ -11,8 +80,10 @@ }, "hr_timerecording_session_type": { "name": "hr_timerecording_session_type", - "type": "TINYINT", - "null": false + "type": "INT", + "null": false, + "foreignTable": "hr_timerecording_type", + "foreignKey": "hr_timerecording_type_id" }, "hr_timerecording_session_start": { "name": "hr_timerecording_session_start", diff --git a/Admin/Install/types.json b/Admin/Install/types.json new file mode 100644 index 0000000..e7b6109 --- /dev/null +++ b/Admin/Install/types.json @@ -0,0 +1,121 @@ +[ + { + "name": "office", + "is_work": true, + "l11n": { + "en": "Office", + "de": "Büro" + } + }, + { + "name": "home", + "is_work": true, + "l11n": { + "en": "Home", + "de": "Zuhause" + } + }, + { + "name": "remote", + "is_work": true, + "l11n": { + "en": "Remote", + "de": "Mobil" + } + }, + { + "name": "vacation", + "is_work": false, + "l11n": { + "en": "Vacation", + "de": "Urlaub" + } + }, + { + "name": "sick", + "l11n": { + "en": "Sick", + "de": "Krank" + } + }, + { + "name": "travelling", + "is_work": true, + "l11n": { + "en": "Travelling", + "de": "Dienstreise" + } + }, + { + "name": "paid_leave", + "is_work": false, + "l11n": { + "en": "Paid leave", + "de": "Bezahlte Abwesenheit" + } + }, + { + "name": "unpaid_leave", + "is_work": false, + "l11n": { + "en": "Unpaid leave", + "de": "Unbezahlte Abwesenheit" + } + }, + { + "name": "maternity_leave", + "is_work": false, + "l11n": { + "en": "Maternity leave", + "de": "Mutterschutzurlaub" + } + }, + { + "name": "parental_leave", + "is_work": false, + "l11n": { + "en": "Parental leave", + "de": "Elternzeit" + } + }, + { + "name": "dr_visit", + "is_work": false, + "l11n": { + "en": "Dr visit", + "de": "Arztbesuch" + } + }, + { + "name": "education", + "is_work": true, + "l11n": { + "en": "Education", + "de": "Fortbildung" + } + }, + { + "name": "training", + "is_work": true, + "l11n": { + "en": "Training", + "de": "Training" + } + }, + { + "name": "holiday", + "is_work": true, + "l11n": { + "en": "Holiday", + "de": "Feiertag" + } + }, + { + "name": "no_data", + "is_work": false, + "l11n": { + "en": "No data", + "de": "Keine Daten" + } + } +] \ No newline at end of file diff --git a/Admin/Installer.php b/Admin/Installer.php index b686cf3..cd07774 100755 --- a/Admin/Installer.php +++ b/Admin/Installer.php @@ -14,7 +14,12 @@ declare(strict_types=1); namespace Modules\HumanResourceTimeRecording\Admin; +use phpOMS\Application\ApplicationAbstract; +use phpOMS\Config\SettingsInterface; +use phpOMS\Message\Http\HttpRequest; +use phpOMS\Message\Http\HttpResponse; use phpOMS\Module\InstallerAbstract; +use phpOMS\Module\ModuleInfo; /** * Installer class. @@ -33,4 +38,88 @@ final class Installer extends InstallerAbstract * @since 1.0.0 */ public const PATH = __DIR__; + + /** + * {@inheritdoc} + */ + public static function install(ApplicationAbstract $app, ModuleInfo $info, SettingsInterface $cfgHandler) : void + { + parent::install($app, $info, $cfgHandler); + + /* Clocking types */ + $fileContent = \file_get_contents(__DIR__ . '/Install/types.json'); + if ($fileContent === false) { + return; + } + + /** @var array $types */ + $types = \json_decode($fileContent, true); + if ($types === false) { + return; + } + + self::createClockingTypes($app, $types); + } + + /** + * Install default bill types + * + * @param ApplicationAbstract $app Application + * @param array $types Clocking types + * + * @return array + * + * @since 1.0.0 + */ + private static function createClockingTypes(ApplicationAbstract $app, array $types) : array + { + $billTypes = []; + + /** @var \Modules\HumanResourceTimeRecording\Controller\ApiClockingTypeController $module */ + $module = $app->moduleManager->get('HumanResourceTimeRecording', 'ApiClockingType'); + + foreach ($types as $type) { + $response = new HttpResponse(); + $request = new HttpRequest(); + + $request->header->account = 1; + $request->setData('name', $type['name'] ?? ''); + $request->setData('is_work', $type['is_work'] ?? false); + $request->setData('title', \reset($type['l11n'])); + $request->setData('language', \array_keys($type['l11n'])[0] ?? 'en'); + + $module->apiClockingTypeCreate($request, $response); + + $responseData = $response->getData(''); + if (!\is_array($responseData)) { + continue; + } + + $billType = \is_array($responseData['response']) + ? $responseData['response'] + : $responseData['response']->toArray(); + + $billTypes[] = $billType; + + $isFirst = true; + foreach ($type['l11n'] as $language => $l11n) { + if ($isFirst) { + $isFirst = false; + continue; + } + + $response = new HttpResponse(); + $request = new HttpRequest(); + + $request->header->account = 1; + $request->setData('title', $l11n); + $request->setData('language', $language); + $request->setData('type', $billType['id']); + + $module->apiClockingTypeL11nCreate($request, $response); + } + } + + return $billTypes; + } } diff --git a/Controller/ApiClockingTypeController.php b/Controller/ApiClockingTypeController.php new file mode 100644 index 0000000..0141346 --- /dev/null +++ b/Controller/ApiClockingTypeController.php @@ -0,0 +1,405 @@ +validateClockingTypeCreate($request))) { + $response->header->status = RequestStatusCode::R_400; + $this->createInvalidCreateResponse($request, $response, $val); + + return; + } + + $clockingType = $this->createClockingTypeFromRequest($request); + $this->createModel($request->header->account, $clockingType, ClockingTypeMapper::class, 'clocking_type', $request->getOrigin()); + $this->createStandardCreateResponse($request, $response, $clockingType); + } + + /** + * Method to create ClockingType from request. + * + * @param RequestAbstract $request Request + * + * @return ClockingType + * + * @since 1.0.0 + */ + private function createClockingTypeFromRequest(RequestAbstract $request) : ClockingType + { + $clockingType = new ClockingType($request->getDataString('name') ?? ''); + $clockingType->isWork = $request->getDataBool('is_work') ?? false; + $clockingType->customFutureTimeAllowed = $request->getDataBool('custom_future_time_allowed') ?? false; + $clockingType->customPastTimeAllowed = $request->getDataBool('custom_past_time_allowed') ?? false; + $clockingType->correctionAllowed = $request->getDataBool('correction_allowed') ?? false; + $clockingType->setL11n( + $request->getDataString('title') ?? '', + ISO639x1Enum::tryFromValue($request->getDataString('language')) ?? ISO639x1Enum::_EN + ); + + return $clockingType; + } + + /** + * Validate ClockingType create request + * + * @param RequestAbstract $request Request + * + * @return array + * + * @since 1.0.0 + */ + private function validateClockingTypeCreate(RequestAbstract $request) : array + { + $val = []; + if (($val['title'] = !$request->hasData('title')) + || ($val['name'] = !$request->hasData('name')) + ) { + return $val; + } + + return []; + } + + /** + * Api method to create ClockingType l11n + * + * @param RequestAbstract $request Request + * @param ResponseAbstract $response Response + * @param array $data Generic data + * + * @return void + * + * @api + * + * @since 1.0.0 + */ + public function apiClockingTypeL11nCreate(RequestAbstract $request, ResponseAbstract $response, array $data = []) : void + { + if (!empty($val = $this->validateClockingTypeL11nCreate($request))) { + $response->header->status = RequestStatusCode::R_400; + $this->createInvalidCreateResponse($request, $response, $val); + + return; + } + + $clockingTypeL11n = $this->createClockingTypeL11nFromRequest($request); + $this->createModel($request->header->account, $clockingTypeL11n, ClockingTypeL11nMapper::class, 'clocking_type_l11n', $request->getOrigin()); + $this->createStandardCreateResponse($request, $response, $clockingTypeL11n); + } + + /** + * Method to create ClockingType l11n from request. + * + * @param RequestAbstract $request Request + * + * @return BaseStringL11n + * + * @since 1.0.0 + */ + private function createClockingTypeL11nFromRequest(RequestAbstract $request) : BaseStringL11n + { + $clockingTypeL11n = new BaseStringL11n(); + $clockingTypeL11n->ref = $request->getDataInt('type') ?? 0; + $clockingTypeL11n->language = ISO639x1Enum::tryFromValue($request->getDataString('language')) ?? $request->header->l11n->language; + $clockingTypeL11n->content = $request->getDataString('title') ?? ''; + + return $clockingTypeL11n; + } + + /** + * Validate ClockingType l11n create request + * + * @param RequestAbstract $request Request + * + * @return array + * + * @since 1.0.0 + */ + private function validateClockingTypeL11nCreate(RequestAbstract $request) : array + { + $val = []; + if (($val['title'] = !$request->hasData('title')) + || ($val['type'] = !$request->hasData('type')) + ) { + return $val; + } + + return []; + } + + /** + * Api method to update ClockingType + * + * @param RequestAbstract $request Request + * @param ResponseAbstract $response Response + * @param array $data Generic data + * + * @return void + * + * @api + * + * @since 1.0.0 + */ + public function apiClockingTypeUpdate(RequestAbstract $request, ResponseAbstract $response, array $data = []) : void + { + if (!empty($val = $this->validateClockingTypeUpdate($request))) { + $response->header->status = RequestStatusCode::R_400; + $this->createInvalidUpdateResponse($request, $response, $val); + + return; + } + + /** @var ClockingType $old */ + $old = ClockingTypeMapper::get()->where('id', (int) $request->getData('id')); + $new = $this->updateClockingTypeFromRequest($request, clone $old); + + $this->updateModel($request->header->account, $old, $new, ClockingTypeMapper::class, 'clocking_type', $request->getOrigin()); + $this->createStandardUpdateResponse($request, $response, $new); + } + + /** + * Method to update ClockingType from request. + * + * @param RequestAbstract $request Request + * @param ClockingType $new Model to modify + * + * @return ClockingType + * + * @todo Implement API update function + * + * @since 1.0.0 + */ + public function updateClockingTypeFromRequest(RequestAbstract $request, ClockingType $new) : ClockingType + { + return $new; + } + + /** + * Validate ClockingType update request + * + * @param RequestAbstract $request Request + * + * @return array + * + * @todo Implement API validation function + * + * @since 1.0.0 + */ + private function validateClockingTypeUpdate(RequestAbstract $request) : array + { + $val = []; + if (($val['id'] = !$request->hasData('id'))) { + return $val; + } + + return []; + } + + /** + * Api method to delete ClockingType + * + * @param RequestAbstract $request Request + * @param ResponseAbstract $response Response + * @param array $data Generic data + * + * @return void + * + * @api + * + * @since 1.0.0 + */ + public function apiClockingTypeDelete(RequestAbstract $request, ResponseAbstract $response, array $data = []) : void + { + if (!empty($val = $this->validateClockingTypeDelete($request))) { + $response->header->status = RequestStatusCode::R_400; + $this->createInvalidDeleteResponse($request, $response, $val); + + return; + } + + /** @var \Modules\HumanResourceTimeRecording\Models\ClockingType $clockingType */ + $clockingType = ClockingTypeMapper::get()->where('id', (int) $request->getData('id'))->execute(); + $this->deleteModel($request->header->account, $clockingType, ClockingTypeMapper::class, 'clocking_type', $request->getOrigin()); + $this->createStandardDeleteResponse($request, $response, $clockingType); + } + + /** + * Validate ClockingType delete request + * + * @param RequestAbstract $request Request + * + * @return array + * + * @since 1.0.0 + */ + private function validateClockingTypeDelete(RequestAbstract $request) : array + { + $val = []; + if (($val['id'] = !$request->hasData('id'))) { + return $val; + } + + return []; + } + + /** + * Api method to update ClockingTypeL11n + * + * @param RequestAbstract $request Request + * @param ResponseAbstract $response Response + * @param array $data Generic data + * + * @return void + * + * @api + * + * @since 1.0.0 + */ + public function apiClockingTypeL11nUpdate(RequestAbstract $request, ResponseAbstract $response, array $data = []) : void + { + if (!empty($val = $this->validateClockingTypeL11nUpdate($request))) { + $response->header->status = RequestStatusCode::R_400; + $this->createInvalidUpdateResponse($request, $response, $val); + + return; + } + + /** @var BaseStringL11n $old */ + $old = ClockingTypeL11nMapper::get()->where('id', (int) $request->getData('id')); + $new = $this->updateClockingTypeL11nFromRequest($request, clone $old); + + $this->updateModel($request->header->account, $old, $new, ClockingTypeL11nMapper::class, 'clocking_type_l11n', $request->getOrigin()); + $this->createStandardUpdateResponse($request, $response, $new); + } + + /** + * Method to update ClockingTypeL11n from request. + * + * @param RequestAbstract $request Request + * @param BaseStringL11n $new Model to modify + * + * @return BaseStringL11n + * + * @since 1.0.0 + */ + public function updateClockingTypeL11nFromRequest(RequestAbstract $request, BaseStringL11n $new) : BaseStringL11n + { + $new->ref = $request->getDataInt('type') ?? $new->ref; + $new->language = ISO639x1Enum::tryFromValue($request->getDataString('language')) ?? $new->language; + $new->content = $request->getDataString('title') ?? $new->content; + + return $new; + } + + /** + * Validate ClockingTypeL11n update request + * + * @param RequestAbstract $request Request + * + * @return array + * + * @since 1.0.0 + */ + private function validateClockingTypeL11nUpdate(RequestAbstract $request) : array + { + $val = []; + if (($val['id'] = !$request->hasData('id'))) { + return $val; + } + + return []; + } + + /** + * Api method to delete ClockingTypeL11n + * + * @param RequestAbstract $request Request + * @param ResponseAbstract $response Response + * @param array $data Generic data + * + * @return void + * + * @api + * + * @since 1.0.0 + */ + public function apiClockingTypeL11nDelete(RequestAbstract $request, ResponseAbstract $response, array $data = []) : void + { + if (!empty($val = $this->validateClockingTypeL11nDelete($request))) { + $response->header->status = RequestStatusCode::R_400; + $this->createInvalidDeleteResponse($request, $response, $val); + + return; + } + + /** @var BaseStringL11n $clockingTypeL11n */ + $clockingTypeL11n = ClockingTypeL11nMapper::get()->where('id', (int) $request->getData('id'))->execute(); + $this->deleteModel($request->header->account, $clockingTypeL11n, ClockingTypeL11nMapper::class, 'clocking_type_l11n', $request->getOrigin()); + $this->createStandardDeleteResponse($request, $response, $clockingTypeL11n); + } + + /** + * Validate ClockingTypeL11n delete request + * + * @param RequestAbstract $request Request + * + * @return array + * + * @since 1.0.0 + */ + private function validateClockingTypeL11nDelete(RequestAbstract $request) : array + { + $val = []; + if (($val['id'] = !$request->hasData('id'))) { + return $val; + } + + return []; + } +} diff --git a/Controller/ApiController.php b/Controller/ApiController.php index 7f673d8..6b86f5d 100755 --- a/Controller/ApiController.php +++ b/Controller/ApiController.php @@ -19,6 +19,7 @@ use Modules\Admin\Models\NullAccount; use Modules\HumanResourceManagement\Models\EmployeeMapper; use Modules\HumanResourceTimeRecording\Models\ClockingStatus; use Modules\HumanResourceTimeRecording\Models\ClockingType; +use Modules\HumanResourceTimeRecording\Models\NullClockingType; use Modules\HumanResourceTimeRecording\Models\PermissionCategory; use Modules\HumanResourceTimeRecording\Models\Session; use Modules\HumanResourceTimeRecording\Models\SessionElement; @@ -55,7 +56,9 @@ final class ApiController extends Controller */ public function apiSessionCreate(RequestAbstract $request, ResponseAbstract $response, array $data = []) : void { - if (!$this->app->accountManager->get($request->header->account)->hasPermission( + if ($request->hasData('account') + && $request->getDataInt('account') !== $request->header->account + && !$this->app->accountManager->get($request->header->account)->hasPermission( PermissionType::CREATE, $this->app->unitId, $this->app->appId, self::NAME, PermissionCategory::SESSION_FOREIGN )) { $response->header->status = RequestStatusCode::R_403; @@ -95,10 +98,11 @@ final class ApiController extends Controller $account = $request->getDataInt('account') ?? $request->header->account; $session = new Session(new NullAccount($account)); - $session->type = ClockingType::tryFromValue($request->getDataInt('type')) ?? ClockingType::OFFICE; + $session->type = new NullClockingType((int) $request->getDataInt('type')); - // a custom datetime can only be set if the user is allowed to create a session for a foreign account or if the session is a vacation - $dt = $request->hasData('account') || $session->type === ClockingType::VACATION + // @security check if custom datetime is allowed to be set + + $dt = $request->hasData('account') ? ($request->getDataDateTime('datetime') ?? new \DateTime('now')) : new \DateTime('now'); @@ -208,8 +212,7 @@ final class ApiController extends Controller return null; } - // a custom datetime can only be set if the user is allowed to create a session for a foreign account or if the session is a vacation - $dt = $request->hasData('account') || $session->type === ClockingType::VACATION + $dt = $request->hasData('account') ? ($request->getDataDateTime('datetime') ?? new \DateTime('now')) : new \DateTime('now'); diff --git a/Models/ClockingType.php b/Models/ClockingType.php index acacaaa..fa25678 100755 --- a/Models/ClockingType.php +++ b/Models/ClockingType.php @@ -14,48 +14,111 @@ declare(strict_types=1); namespace Modules\HumanResourceTimeRecording\Models; -use phpOMS\Stdlib\Base\Enum; +use Modules\Media\Models\Collection; +use phpOMS\Localization\BaseStringL11n; +use phpOMS\Localization\ISO639x1Enum; /** - * ClockingType enum. + * Bill type enum. * * @package Modules\HumanResourceTimeRecording\Models * @license OMS License 2.0 * @link https://jingga.app * @since 1.0.0 - * - * @todo Make ClockingTypes a DB model instead of an enum - * https://github.com/Karaka-Management/oms-HumanResourceTimeRecording/issues/16 */ -abstract class ClockingType extends Enum +class ClockingType implements \JsonSerializable { - public const OFFICE = 1; + /** + * Id + * + * @var int + * @since 1.0.0 + */ + public int $id = 0; - public const HOME = 2; + public string $name = ''; - public const REMOTE = 3; + public bool $customFutureTimeAllowed = false; - public const VACATION = 4; + public bool $customPastTimeAllowed = false; - public const SICK = 5; + public bool $correctionAllowed = false; - public const ON_THE_MOVE = 6; + public bool $isWork = true; - public const PAID_LEAVE = 7; + /** + * Localization + * + * @var string|BaseStringL11n + */ + public string | BaseStringL11n $l11n; - public const UNPAID_LEAVE = 8; + /** + * Constructor. + * + * @param string $name Name + * + * @since 1.0.0 + */ + public function __construct(string $name = '') + { + $this->name = $name; + } - public const MATERNITY_LEAVE = 9; + /** + * Set l11n + * + * @param string|BaseStringL11n $l11n Tag article l11n + * @param string $lang Language + * + * @return void + * + * @since 1.0.0 + */ + public function setL11n(string | BaseStringL11n $l11n, string $lang = ISO639x1Enum::_EN) : void + { + if ($l11n instanceof BaseStringL11n) { + $this->l11n = $l11n; + } elseif (isset($this->l11n) && $this->l11n instanceof BaseStringL11n) { + $this->l11n->content = $l11n; + $this->l11n->language = $lang; + } else { + $this->l11n = new BaseStringL11n(); + $this->l11n->content = $l11n; + $this->l11n->ref = $this->id; + $this->l11n->language = $lang; + } + } - public const PARENTAL_LEAVE = 10; + /** + * @return string + * + * @since 1.0.0 + */ + public function getL11n() : string + { + if (!isset($this->l11n)) { + return ''; + } - public const DR_VISIT = 11; + return $this->l11n instanceof BaseStringL11n ? $this->l11n->content : $this->l11n; + } - public const EDUCATION = 12; + /** + * {@inheritdoc} + */ + public function toArray() : array + { + return [ + 'id' => $this->id, + ]; + } - public const TRAINING = 13; - - public const HOLIDAY = 14; - - public const NO_DATA = -1; + /** + * {@inheritdoc} + */ + public function jsonSerialize() : mixed + { + return $this->toArray(); + } } diff --git a/Models/ClockingTypeL11nMapper.php b/Models/ClockingTypeL11nMapper.php new file mode 100644 index 0000000..27845a1 --- /dev/null +++ b/Models/ClockingTypeL11nMapper.php @@ -0,0 +1,69 @@ + + */ +final class ClockingTypeL11nMapper extends DataMapperFactory +{ + /** + * Columns. + * + * @var array + * @since 1.0.0 + */ + public const COLUMNS = [ + 'hr_timerecording_type_l11n_id' => ['name' => 'hr_timerecording_type_l11n_id', 'type' => 'int', 'internal' => 'id'], + 'hr_timerecording_type_l11n_title' => ['name' => 'hr_timerecording_type_l11n_title', 'type' => 'string', 'internal' => 'content', 'autocomplete' => true], + 'hr_timerecording_type_l11n_type' => ['name' => 'hr_timerecording_type_l11n_type', 'type' => 'int', 'internal' => 'ref'], + 'hr_timerecording_type_l11n_language' => ['name' => 'hr_timerecording_type_l11n_language', 'type' => 'string', 'internal' => 'language'], + ]; + + /** + * Primary table. + * + * @var string + * @since 1.0.0 + */ + public const TABLE = 'hr_timerecording_type_l11n'; + + /** + * Primary field name. + * + * @var string + * @since 1.0.0 + */ + public const PRIMARYFIELD = 'hr_timerecording_type_l11n_id'; + + /** + * Model to use by the mapper. + * + * @var class-string + * @since 1.0.0 + */ + public const MODEL = BaseStringL11n::class; +} diff --git a/Models/ClockingTypeMapper.php b/Models/ClockingTypeMapper.php new file mode 100644 index 0000000..c65ca2b --- /dev/null +++ b/Models/ClockingTypeMapper.php @@ -0,0 +1,86 @@ + + */ +final class ClockingTypeMapper extends DataMapperFactory +{ + /** + * Columns. + * + * @var array + * @since 1.0.0 + */ + public const COLUMNS = [ + 'hr_timerecording_type_id' => ['name' => 'hr_timerecording_type_id', 'type' => 'int', 'internal' => 'id'], + 'hr_timerecording_type_name' => ['name' => 'hr_timerecording_type_name', 'type' => 'string', 'internal' => 'name'], + 'hr_timerecording_type_custom_future' => ['name' => 'hr_timerecording_type_custom_future', 'type' => 'bool', 'internal' => 'customFutureTimeAllowed'], + 'hr_timerecording_type_custom_past' => ['name' => 'hr_timerecording_type_custom_past', 'type' => 'bool', 'internal' => 'customPastTimeAllowed'], + 'hr_timerecording_type_correction' => ['name' => 'hr_timerecording_type_correction', 'type' => 'bool', 'internal' => 'correctionAllowed'], + 'hr_timerecording_type_work' => ['name' => 'hr_timerecording_type_work', 'type' => 'bool', 'internal' => 'isWork'], + ]; + + /** + * Has many relation. + * + * @var array + * @since 1.0.0 + */ + public const HAS_MANY = [ + 'l11n' => [ + 'mapper' => ClockingTypeL11nMapper::class, + 'table' => 'hr_timerecording_type_l11n', + 'self' => 'hr_timerecording_type_l11n_type', + 'column' => 'content', + 'external' => null, + ], + ]; + + /** + * Model to use by the mapper. + * + * @var class-string + * @since 1.0.0 + */ + public const MODEL = ClockingType::class; + + /** + * Primary table. + * + * @var string + * @since 1.0.0 + */ + public const TABLE = 'hr_timerecording_type'; + + /** + * Primary field name. + * + * @var string + * @since 1.0.0 + */ + public const PRIMARYFIELD = 'hr_timerecording_type_id'; +} diff --git a/Models/NullClockingType.php b/Models/NullClockingType.php new file mode 100644 index 0000000..91da897 --- /dev/null +++ b/Models/NullClockingType.php @@ -0,0 +1,47 @@ +id = $id; + parent::__construct(); + } + + /** + * {@inheritdoc} + */ + public function jsonSerialize() : mixed + { + return ['id' => $this->id]; + } +} diff --git a/Models/Session.php b/Models/Session.php index d8d8b7b..bd5ccc8 100755 --- a/Models/Session.php +++ b/Models/Session.php @@ -69,7 +69,7 @@ class Session implements \JsonSerializable * @var int * @since 1.0.0 */ - public int $type = ClockingType::NO_DATA; + public ClockingType $type; /** * Session elements. @@ -107,6 +107,7 @@ class Session implements \JsonSerializable $this->start = new \DateTime('now'); $this->employee = $employee ?? new NullAccount(); $this->createdAt = new \DateTimeImmutable('now'); + $this->type = new NullClockingType(); } /** diff --git a/Models/SessionMapper.php b/Models/SessionMapper.php index a62dfb5..7004179 100755 --- a/Models/SessionMapper.php +++ b/Models/SessionMapper.php @@ -76,6 +76,19 @@ final class SessionMapper extends DataMapperFactory ], ]; + /** + * Has one relation. + * + * @var array + * @since 1.0.0 + */ + public const OWNS_ONE = [ + 'type' => [ + 'mapper' => ClockingTypeMapper::class, + 'external' => 'hr_timerecording_session_type', + ], + ]; + /** * Primary table. *