bug fixes

This commit is contained in:
Dennis Eichhorn 2024-05-12 00:06:28 +00:00
parent 492eb38e22
commit 1e0a52edad
12 changed files with 1001 additions and 33 deletions

View File

@ -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.'

View File

@ -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",

121
Admin/Install/types.json Normal file
View File

@ -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"
}
}
]

View File

@ -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;
}
}

View File

@ -0,0 +1,405 @@
<?php
/**
* Jingga
*
* PHP Version 8.2
*
* @package Modules\HumanResourceTimeRecording
* @copyright Dennis Eichhorn
* @license OMS License 2.0
* @version 1.0.0
* @link https://jingga.app
*/
declare(strict_types=1);
namespace Modules\HumanResourceTimeRecording\Controller;
use Modules\HumanResourceTimeRecording\Models\ClockingType;
use Modules\HumanResourceTimeRecording\Models\ClockingTypeL11nMapper;
use Modules\HumanResourceTimeRecording\Models\ClockingTypeMapper;
use phpOMS\Localization\BaseStringL11n;
use phpOMS\Localization\ISO639x1Enum;
use phpOMS\Message\Http\RequestStatusCode;
use phpOMS\Message\RequestAbstract;
use phpOMS\Message\ResponseAbstract;
/**
* HumanResourceTimeRecording class.
*
* @package Modules\HumanResourceTimeRecording
* @license OMS License 2.0
* @link https://jingga.app
* @since 1.0.0
*/
final class ApiClockingTypeController extends Controller
{
/**
* Api method to create clocking type
*
* @param RequestAbstract $request Request
* @param ResponseAbstract $response Response
* @param array $data Generic data
*
* @return void
*
* @api
*
* @since 1.0.0
*/
public function apiClockingTypeCreate(RequestAbstract $request, ResponseAbstract $response, array $data = []) : void
{
if (!empty($val = $this->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<string, bool>
*
* @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<string, bool>
*
* @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<string, bool>
*
* @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<string, bool>
*
* @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<string, bool>
*
* @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<string, bool>
*
* @since 1.0.0
*/
private function validateClockingTypeL11nDelete(RequestAbstract $request) : array
{
$val = [];
if (($val['id'] = !$request->hasData('id'))) {
return $val;
}
return [];
}
}

View File

@ -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');

View File

@ -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();
}
}

View File

@ -0,0 +1,69 @@
<?php
/**
* Jingga
*
* PHP Version 8.2
*
* @package Modules\HumanResourceTimerecording\Models
* @copyright Dennis Eichhorn
* @license OMS License 2.0
* @version 1.0.0
* @link https://jingga.app
*/
declare(strict_types=1);
namespace Modules\HumanResourceTimerecording\Models;
use phpOMS\DataStorage\Database\Mapper\DataMapperFactory;
use phpOMS\Localization\BaseStringL11n;
/**
* Clocking type l11n mapper class.
*
* @package Modules\HumanResourceTimerecording\Models
* @license OMS License 2.0
* @link https://jingga.app
* @since 1.0.0
*
* @template T of BaseStringL11n
* @extends DataMapperFactory<T>
*/
final class ClockingTypeL11nMapper extends DataMapperFactory
{
/**
* Columns.
*
* @var array<string, array{name:string, type:string, internal:string, autocomplete?:bool, readonly?:bool, writeonly?:bool, annotations?: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<T>
* @since 1.0.0
*/
public const MODEL = BaseStringL11n::class;
}

View File

@ -0,0 +1,86 @@
<?php
/**
* Jingga
*
* PHP Version 8.2
*
* @package Modules\HumanResourceTimeRecording\Models
* @copyright Dennis Eichhorn
* @license OMS License 2.0
* @version 1.0.0
* @link https://jingga.app
*/
declare(strict_types=1);
namespace Modules\HumanResourceTimeRecording\Models;
use phpOMS\DataStorage\Database\Mapper\DataMapperFactory;
/**
* Clocking type mapper class.
*
* @package Modules\HumanResourceTimeRecording\Models
* @license OMS License 2.0
* @link https://jingga.app
* @since 1.0.0
*
* @template T of ClockingType
* @extends DataMapperFactory<T>
*/
final class ClockingTypeMapper extends DataMapperFactory
{
/**
* Columns.
*
* @var array<string, array{name:string, type:string, internal:string, autocomplete?:bool, readonly?:bool, writeonly?:bool, annotations?: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<string, array{mapper:class-string, table:string, self?:?string, external?:?string, column?:string}>
* @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<T>
* @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';
}

View File

@ -0,0 +1,47 @@
<?php
/**
* Jingga
*
* PHP Version 8.2
*
* @package Modules\HumanResourceTimeRecording\Models
* @copyright Dennis Eichhorn
* @license OMS License 2.0
* @version 1.0.0
* @link https://jingga.app
*/
declare(strict_types=1);
namespace Modules\HumanResourceTimeRecording\Models;
/**
* Null model
*
* @package Modules\HumanResourceTimeRecording\Models
* @license OMS License 2.0
* @link https://jingga.app
* @since 1.0.0
*/
final class NullClockingType extends ClockingType
{
/**
* Constructor
*
* @param int $id Model id
*
* @since 1.0.0
*/
public function __construct(int $id = 0)
{
$this->id = $id;
parent::__construct();
}
/**
* {@inheritdoc}
*/
public function jsonSerialize() : mixed
{
return ['id' => $this->id];
}
}

View File

@ -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();
}
/**

View File

@ -76,6 +76,19 @@ final class SessionMapper extends DataMapperFactory
],
];
/**
* Has one relation.
*
* @var array<string, array{mapper:class-string, external:string, by?:string, column?:string, conditional?:bool}>
* @since 1.0.0
*/
public const OWNS_ONE = [
'type' => [
'mapper' => ClockingTypeMapper::class,
'external' => 'hr_timerecording_session_type',
],
];
/**
* Primary table.
*