Initial xentral_oss_20.3.c9ffacf
This commit is contained in:
@@ -0,0 +1,151 @@
|
||||
<?php
|
||||
|
||||
namespace Xentral\Modules\TimeManagement;
|
||||
|
||||
use ApplicationCore;
|
||||
use Mitarbeiterzeiterfassung;
|
||||
use Xentral\Core\DependencyInjection\ContainerInterface;
|
||||
use Xentral\Modules\TimeManagement\Service\GroupGateway;
|
||||
use Xentral\Modules\TimeManagement\Service\HolidayGateway;
|
||||
use Xentral\Modules\TimeManagement\Service\TimeManagementHistoryService;
|
||||
use Xentral\Modules\TimeManagement\Service\TimeManagementSettingGateway;
|
||||
use Xentral\Modules\TimeManagement\Service\TimeManagementTargetHourGateway;
|
||||
use Xentral\Modules\TimeManagement\Service\TimeManagementTargetHourService;
|
||||
use Xentral\Modules\TimeManagement\Wrapper\TimeManagementMailerWrapper;
|
||||
use Xentral\Modules\TimeManagement\Wrapper\TimeManagementTargetHourWrapper;
|
||||
|
||||
|
||||
final class Bootstrap
|
||||
{
|
||||
/**
|
||||
* @return array
|
||||
*/
|
||||
public static function registerServices(): array
|
||||
{
|
||||
return [
|
||||
'TimeManagementModule' => 'onInitTimeManagementModule',
|
||||
'TimeManagementMailer' => 'onInitTimeManagementMailer',
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* @param ContainerInterface $container
|
||||
*
|
||||
* @return TimeManagementModule
|
||||
*/
|
||||
public static function onInitTimeManagementModule(ContainerInterface $container): TimeManagementModule
|
||||
{
|
||||
return new TimeManagementModule(
|
||||
self::onInitTimeManagementTargetHourGateway($container),
|
||||
self::onInitTimeManagementTargetHourService($container),
|
||||
self::onInitTimeManagementSettingGateway($container),
|
||||
self::onInitHolidayGateway($container),
|
||||
self::onInitGroupGateway($container),
|
||||
self::onInitTimeManagementTargetHourWrapper($container),
|
||||
self::onInitTimeManagementHistoryService($container)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param ContainerInterface $container
|
||||
*
|
||||
* @return TimeManagementTargetHourService
|
||||
*/
|
||||
private static function onInitTimeManagementTargetHourService(ContainerInterface $container
|
||||
): TimeManagementTargetHourService {
|
||||
return new TimeManagementTargetHourService(
|
||||
$container->get('Database')
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param ContainerInterface $container
|
||||
*
|
||||
* @return TimeManagementTargetHourGateway
|
||||
*/
|
||||
private static function onInitTimeManagementTargetHourGateway(ContainerInterface $container
|
||||
): TimeManagementTargetHourGateway {
|
||||
return new TimeManagementTargetHourGateway(
|
||||
$container->get('Database')
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param ContainerInterface $container
|
||||
*
|
||||
* @return TimeManagementSettingGateway
|
||||
*/
|
||||
private static function onInitTimeManagementSettingGateway(ContainerInterface $container
|
||||
): TimeManagementSettingGateway {
|
||||
return new TimeManagementSettingGateway(
|
||||
$container->get('Database')
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param ContainerInterface $container
|
||||
*
|
||||
* @return HolidayGateway
|
||||
*/
|
||||
private static function onInitHolidayGateway(ContainerInterface $container): HolidayGateway
|
||||
{
|
||||
return new HolidayGateway(
|
||||
$container->get('Database')
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param ContainerInterface $container
|
||||
*
|
||||
* @return GroupGateway
|
||||
*/
|
||||
private static function onInitGroupGateway(ContainerInterface $container): GroupGateway
|
||||
{
|
||||
return new GroupGateway(
|
||||
$container->get('Database')
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param ContainerInterface $container
|
||||
*
|
||||
* @return TimeManagementTargetHourWrapper
|
||||
*/
|
||||
private static function onInitTimeManagementTargetHourWrapper(ContainerInterface $container
|
||||
): TimeManagementTargetHourWrapper {
|
||||
/** @var ApplicationCore $app */
|
||||
$app = $container->get('LegacyApplication');
|
||||
|
||||
/** @var Mitarbeiterzeiterfassung $timeRecordingModule */
|
||||
$timeRecordingModule = $app->erp->LoadModul('mitarbeiterzeiterfassung');
|
||||
|
||||
return new TimeManagementTargetHourWrapper($timeRecordingModule);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param ContainerInterface $container
|
||||
*
|
||||
* @return TimeManagementHistoryService
|
||||
*/
|
||||
private static function onInitTimeManagementHistoryService(ContainerInterface $container
|
||||
): TimeManagementHistoryService {
|
||||
return new TimeManagementHistoryService(
|
||||
$container->get('Database')
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param ContainerInterface $container
|
||||
*
|
||||
* @return TimeManagementMailerWrapper
|
||||
*/
|
||||
public function onInitTimeManagementMailer(ContainerInterface $container): TimeManagementMailerWrapper
|
||||
{
|
||||
/** @var ApplicationCore $app */
|
||||
$app = $container->get('LegacyApplication');
|
||||
|
||||
return new TimeManagementMailerWrapper(
|
||||
$app->erp
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,108 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Xentral\Modules\TimeManagement\Data;
|
||||
|
||||
use DateTimeImmutable;
|
||||
use Exception;
|
||||
use DateTimeInterface;
|
||||
use Xentral\Modules\TimeManagement\Exception\InvalidDateFormatException;
|
||||
|
||||
final class CalendarData
|
||||
{
|
||||
/** @var int $month */
|
||||
private $month = 0;
|
||||
|
||||
/** @var DateTimeInterface $date */
|
||||
private $date;
|
||||
|
||||
/** @var int $addressId */
|
||||
private $addressId = 0;
|
||||
|
||||
/** @var string $employeeName */
|
||||
private $employeeName = '';
|
||||
|
||||
/** @var string $type */
|
||||
private $type = '';
|
||||
|
||||
/** @var bool $isHalf */
|
||||
private $isHalf = false;
|
||||
|
||||
private function __construct()
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $data
|
||||
*
|
||||
* @return CalendarData
|
||||
*
|
||||
* @throws InvalidDateFormatException
|
||||
*/
|
||||
public static function fromDbState(array $data): CalendarData
|
||||
{
|
||||
$calendarData = new CalendarData();
|
||||
$calendarData->month = (int)$data['month'];
|
||||
try {
|
||||
$calendarData->date = new DateTimeImmutable($data['date']);
|
||||
} catch (Exception $e) {
|
||||
throw new InvalidDateFormatException('Could not convert date: ' . $data['date']);
|
||||
}
|
||||
|
||||
$calendarData->addressId = (int)$data['address_id'];
|
||||
$calendarData->employeeName = (string)$data['name'];
|
||||
$calendarData->type = (string)$data['type'];
|
||||
$calendarData->isHalf = (bool)$data['is_half'];
|
||||
|
||||
return $calendarData;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return int
|
||||
*/
|
||||
public function getMonth(): int
|
||||
{
|
||||
return $this->month;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return DateTimeInterface
|
||||
*/
|
||||
public function getDate(): DateTimeInterface
|
||||
{
|
||||
return $this->date;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return int
|
||||
*/
|
||||
public function getAddressId(): int
|
||||
{
|
||||
return $this->addressId;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function getEmployeeName(): string
|
||||
{
|
||||
return $this->employeeName;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function getType(): string
|
||||
{
|
||||
return $this->type;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return bool
|
||||
*/
|
||||
public function isHalf(): bool
|
||||
{
|
||||
return $this->isHalf;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,97 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Xentral\Modules\TimeManagement\Data;
|
||||
|
||||
use JsonSerializable;
|
||||
|
||||
final class DayInfoData implements JsonSerializable
|
||||
{
|
||||
|
||||
/** @var string $type */
|
||||
private $type = '';
|
||||
|
||||
/** @var int $workMinutes */
|
||||
private $workMinutes = 0;
|
||||
|
||||
/** @var int $vacationMinutes */
|
||||
private $vacationMinutes = 0;
|
||||
|
||||
/** @var string $internalComment */
|
||||
private $internalComment = '';
|
||||
|
||||
private function __construct()
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $data
|
||||
*
|
||||
* @return DayInfoData
|
||||
*/
|
||||
public static function fromDbState($data): DayInfoData
|
||||
{
|
||||
$dayInfoData = new DayInfoData();
|
||||
|
||||
if (isset($data['type'])) {
|
||||
$dayInfoData->type = (string)$data['type'];
|
||||
}
|
||||
if (isset($data['workminutes'])) {
|
||||
$dayInfoData->workMinutes = (int)$data['workminutes'];
|
||||
}
|
||||
if (isset($data['vacationminutes'])) {
|
||||
$dayInfoData->vacationMinutes = (int)$data['vacationminutes'];
|
||||
}
|
||||
if (isset($data['internal_comment'])) {
|
||||
$dayInfoData->internalComment = (string)$data['internal_comment'];
|
||||
}
|
||||
|
||||
return $dayInfoData;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function getType(): string
|
||||
{
|
||||
return $this->type;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return int
|
||||
*/
|
||||
public function getWorkMinutes(): int
|
||||
{
|
||||
return $this->workMinutes;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return int
|
||||
*/
|
||||
public function getVacationMinutes(): int
|
||||
{
|
||||
return $this->vacationMinutes;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function getInternalComment(): string
|
||||
{
|
||||
return $this->internalComment;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array
|
||||
*/
|
||||
public function jsonSerialize(): array
|
||||
{
|
||||
return [
|
||||
'type' => $this->type,
|
||||
'workminutes' => $this->workMinutes,
|
||||
'vacationminutes' => $this->vacationMinutes,
|
||||
'internal_comment' => $this->internalComment,
|
||||
];
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,61 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Xentral\Modules\TimeManagement\Data;
|
||||
|
||||
use DateTimeImmutable;
|
||||
use DateTimeInterface;
|
||||
use Exception;
|
||||
use Xentral\Modules\TimeManagement\Exception\InvalidDateFormatException;
|
||||
|
||||
final class HolidayData
|
||||
{
|
||||
/** @var string $name */
|
||||
private $name = 'Unknown';
|
||||
|
||||
/** @var DateTimeInterface $date */
|
||||
private $date;
|
||||
|
||||
private function __construct()
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $data
|
||||
*
|
||||
* @throws InvalidDateFormatException
|
||||
*
|
||||
* @return HolidayData
|
||||
*
|
||||
*/
|
||||
public static function fromDbState(array $data): HolidayData
|
||||
{
|
||||
$holidayData = new HolidayData();
|
||||
|
||||
$holidayData->name = $data['name'];
|
||||
try {
|
||||
$holidayData->date = new DateTimeImmutable($data['date']);
|
||||
} catch (Exception $e) {
|
||||
throw new InvalidDateFormatException('Could not convert date: ' . $data['date']);
|
||||
}
|
||||
|
||||
return $holidayData;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function getName(): string
|
||||
{
|
||||
return $this->name;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return DateTimeInterface
|
||||
*/
|
||||
public function getDate(): DateTimeInterface
|
||||
{
|
||||
return $this->date;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,170 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Xentral\Modules\TimeManagement\Data;
|
||||
|
||||
use DateTimeInterface;
|
||||
use DateTimeImmutable;
|
||||
use Exception;
|
||||
use JsonSerializable;
|
||||
use Xentral\Modules\TimeManagement\Exception\InvalidDateFormatException;
|
||||
|
||||
final class RequestInfoData implements JsonSerializable
|
||||
{
|
||||
/** @var int $employeeId */
|
||||
private $employeeId = 0;
|
||||
|
||||
/** @var string $employeeNumber */
|
||||
private $employeeNumber = '';
|
||||
|
||||
/** @var string $employeeName */
|
||||
private $employeeName = '';
|
||||
|
||||
/** @var DateTimeInterface $minDate */
|
||||
private $minDate;
|
||||
|
||||
/** @var DateTimeInterface $maxDate */
|
||||
private $maxDate;
|
||||
|
||||
/** @var int $amount */
|
||||
private $amount = 0;
|
||||
|
||||
/** @var string $comment */
|
||||
private $comment = '';
|
||||
|
||||
/** @var string $type */
|
||||
private $type = '';
|
||||
|
||||
/** @var string $internalComment */
|
||||
private $internalComment = '';
|
||||
|
||||
private function __construct()
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* @return int
|
||||
*/
|
||||
public function getEmployeeId(): int
|
||||
{
|
||||
return $this->employeeId;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function getEmployeeNumber(): string
|
||||
{
|
||||
return $this->employeeNumber;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function getEmployeeName(): string
|
||||
{
|
||||
return $this->employeeName;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return DateTimeInterface
|
||||
*/
|
||||
public function getMinDate(): DateTimeInterface
|
||||
{
|
||||
return $this->minDate;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return DateTimeInterface
|
||||
*/
|
||||
public function getMaxDate(): DateTimeInterface
|
||||
{
|
||||
return $this->maxDate;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return int
|
||||
*/
|
||||
public function getAmount(): int
|
||||
{
|
||||
return $this->amount;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function getComment(): string
|
||||
{
|
||||
return $this->comment;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function getType(): string
|
||||
{
|
||||
return $this->type;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function getInternalComment(): string
|
||||
{
|
||||
return $this->internalComment;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $data
|
||||
*
|
||||
* @throws InvalidDateFormatException
|
||||
*
|
||||
* @return RequestInfoData
|
||||
*/
|
||||
public static function fromDbState(array $data): RequestInfoData
|
||||
{
|
||||
$requestInfoData = new RequestInfoData();
|
||||
|
||||
$requestInfoData->employeeId = (int)$data['employee_id'];
|
||||
$requestInfoData->employeeNumber = (string)$data['employee_number'];
|
||||
$requestInfoData->employeeName = (string)$data['employee_name'];
|
||||
|
||||
try {
|
||||
$requestInfoData->minDate = new DateTimeImmutable($data['min_date']);
|
||||
} catch (Exception $e) {
|
||||
throw new InvalidDateFormatException('Could not convert date: ' . $data['date']);
|
||||
}
|
||||
|
||||
try {
|
||||
$requestInfoData->maxDate = new DateTimeImmutable($data['max_date']);
|
||||
} catch (Exception $e) {
|
||||
throw new InvalidDateFormatException('Could not convert date: ' . $data['date']);
|
||||
}
|
||||
|
||||
$requestInfoData->amount = (int)$data['amount'];
|
||||
$requestInfoData->comment = (string)$data['comment'];
|
||||
$requestInfoData->type = (string)$data['type'];
|
||||
$requestInfoData->internalComment = (string)$data['internal_comment'];
|
||||
|
||||
return $requestInfoData;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array
|
||||
*/
|
||||
public function jsonSerialize(): array
|
||||
{
|
||||
return [
|
||||
'employee_id' => $this->employeeId,
|
||||
'employee_number' => $this->employeeNumber,
|
||||
'employee_name' => $this->employeeName,
|
||||
'min_date' => empty($this->minDate) ? '0000-00-00' : $this->minDate->format('Y-m-d'),
|
||||
'max_date' => empty($this->maxDate) ? '0000-00-00' : $this->maxDate->format('Y-m-d'),
|
||||
'amount' => $this->amount,
|
||||
'comment' => $this->comment,
|
||||
'type' => $this->type,
|
||||
'internal_comment' => $this->internalComment,
|
||||
];
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,106 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Xentral\Modules\TimeManagement\Data;
|
||||
|
||||
final class WorkDayData
|
||||
{
|
||||
|
||||
/** @var bool $isMondayWorkDay */
|
||||
private $isMondayWorkDay = false;
|
||||
|
||||
/** @var bool $isTuesdayWorkDay */
|
||||
private $isTuesdayWorkDay = false;
|
||||
|
||||
/** @var bool $isWednesdayWorkDay */
|
||||
private $isWednesdayWorkDay = false;
|
||||
|
||||
/** @var bool $isThursdayWorkDay */
|
||||
private $isThursdayWorkDay = false;
|
||||
|
||||
/** @var bool $isFridayWorkDay */
|
||||
private $isFridayWorkDay = false;
|
||||
|
||||
/** @var bool $isSaturdayWorkDay */
|
||||
private $isSaturdayWorkDay = false;
|
||||
|
||||
/** @var bool $isSundayWorkDay */
|
||||
private $isSundayWorkDay = false;
|
||||
|
||||
private function __construct()
|
||||
{
|
||||
}
|
||||
|
||||
public static function fromDbState(array $data): WorkDayData
|
||||
{
|
||||
$workDayData = new WorkDayData();
|
||||
|
||||
$workDayData->isMondayWorkDay = !empty($data['is_monday_workday']);
|
||||
$workDayData->isTuesdayWorkDay = !empty($data['is_tuesday_workday']);
|
||||
$workDayData->isWednesdayWorkDay = !empty($data['is_wednesday_workday']);
|
||||
$workDayData->isThursdayWorkDay = !empty($data['is_thursday_workday']);
|
||||
$workDayData->isFridayWorkDay = !empty($data['is_friday_workday']);
|
||||
$workDayData->isSaturdayWorkDay = !empty($data['is_saturday_workday']);
|
||||
$workDayData->isSundayWorkDay = !empty($data['is_sunday_workday']);
|
||||
|
||||
return $workDayData;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return bool
|
||||
*/
|
||||
public function isMondayWorkDay(): bool
|
||||
{
|
||||
return $this->isMondayWorkDay;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return bool
|
||||
*/
|
||||
public function isTuesdayWorkDay(): bool
|
||||
{
|
||||
return $this->isTuesdayWorkDay;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return bool
|
||||
*/
|
||||
public function isWednesdayWorkDay(): bool
|
||||
{
|
||||
return $this->isWednesdayWorkDay;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return bool
|
||||
*/
|
||||
public function isThursdayWorkDay(): bool
|
||||
{
|
||||
return $this->isThursdayWorkDay;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return bool
|
||||
*/
|
||||
public function isFridayWorkDay(): bool
|
||||
{
|
||||
return $this->isFridayWorkDay;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return bool
|
||||
*/
|
||||
public function isSaturdayWorkDay(): bool
|
||||
{
|
||||
return $this->isSaturdayWorkDay;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return bool
|
||||
*/
|
||||
public function isSundayWorkDay(): bool
|
||||
{
|
||||
return $this->isSundayWorkDay;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Xentral\Modules\TimeManagement\Exception;
|
||||
|
||||
use RuntimeException as SplRuntimeException;
|
||||
|
||||
final class EmailAccountNotFoundException extends SplRuntimeException implements TimeManagementExceptionInterface
|
||||
{
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Xentral\Modules\TimeManagement\Exception;
|
||||
|
||||
use RuntimeException as SplRuntimeException;
|
||||
|
||||
final class EmailNotFoundException extends SplRuntimeException implements TimeManagementExceptionInterface
|
||||
{
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Xentral\Modules\TimeManagement\Exception;
|
||||
|
||||
use RuntimeException as SplRuntimeException;
|
||||
|
||||
final class EmailNotSentException extends SplRuntimeException implements TimeManagementExceptionInterface
|
||||
{
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Xentral\Modules\TimeManagement\Exception;
|
||||
|
||||
use InvalidArgumentException as SplInvalidArgumentException;
|
||||
|
||||
final class InvalidArgumentException extends SplInvalidArgumentException implements TimeManagementExceptionInterface
|
||||
{
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Xentral\Modules\TimeManagement\Exception;
|
||||
|
||||
final class InvalidDateFormatException extends \InvalidArgumentException implements TimeManagementExceptionInterface
|
||||
{
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Xentral\Modules\TimeManagement\Exception;
|
||||
|
||||
use RuntimeException as SplRuntimeException;
|
||||
|
||||
final class InvalidQueryException extends SplRuntimeException implements TimeManagementExceptionInterface
|
||||
{
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Xentral\Modules\TimeManagement\Exception;
|
||||
|
||||
final class InvalidRequestTokenException extends \InvalidArgumentException implements TimeManagementExceptionInterface
|
||||
{
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Xentral\Modules\TimeManagement\Exception;
|
||||
|
||||
use RuntimeException as SplRuntimeException;
|
||||
|
||||
final class PatternMissingException extends SplRuntimeException implements TimeManagementExceptionInterface
|
||||
{
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Xentral\Modules\TimeManagement\Exception;
|
||||
|
||||
use RuntimeException as SplRuntimeException;
|
||||
|
||||
final class SupervisorNotFoundException extends SplRuntimeException implements TimeManagementExceptionInterface
|
||||
{
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Xentral\Modules\TimeManagement\Exception;
|
||||
|
||||
use Xentral\Core\Exception\ModuleExceptionInterface;
|
||||
|
||||
interface TimeManagementExceptionInterface extends ModuleExceptionInterface
|
||||
{
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
# Time-Management-Module
|
||||
|
||||
## Description
|
||||
|
||||
The time-management module handles all vacation and illness requests off the employees.
|
||||
It is based (and replaces in certain places) the older module 'Mitarbeiterzeiterfassung'.
|
||||
|
||||
### Create new instance
|
||||
|
||||
```php
|
||||
/** @var \Xentral\Modules\TimeManagement\TimeManagementModule $timeManagement */
|
||||
$timeManagement = $container->get('TimeManagementModule');
|
||||
```
|
||||
|
||||
A hook is provided in mitarbeiterzeiterfassung.php to intervene in the process of changing the state of a day:
|
||||
```php
|
||||
$this->app->erp->RunHook(
|
||||
'timemanagement_after_day_status_change',
|
||||
6,
|
||||
$addressId,
|
||||
$fromDate,
|
||||
$tillDate,
|
||||
$halfday,
|
||||
$statusOldType,
|
||||
$statusWishType
|
||||
);
|
||||
```
|
||||
|
||||
## Open issues
|
||||
|
||||
- half days: It is not possible to differentiate between morning and afternoon
|
||||
- the module is designed for vacation and illnesses. It does not handle unpaid vacation or absent days like the old module
|
||||
- it is not designed for shiftworking over more than one day
|
||||
- if someone only works half-days he has to take a whole day of vacation. This seems not to be correct and must be changed in future.
|
||||
@@ -0,0 +1,170 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Xentral\Modules\TimeManagement\Service;
|
||||
|
||||
use Xentral\Components\Database\Database;
|
||||
use Xentral\Modules\TimeManagement\Exception\SupervisorNotFoundException;
|
||||
|
||||
final class GroupGateway
|
||||
{
|
||||
/** @var Database $db */
|
||||
private $db;
|
||||
|
||||
/**
|
||||
* @param Database $db
|
||||
*/
|
||||
public function __construct(Database $db)
|
||||
{
|
||||
$this->db = $db;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $addressId
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function findGroupsByAddressId(int $addressId): array
|
||||
{
|
||||
$sql =
|
||||
'SELECT DISTINCT
|
||||
g.id AS `group_id`,
|
||||
g.name AS `group_name`
|
||||
FROM `gruppen` AS `g`
|
||||
INNER JOIN `adresse_rolle` AS `ar` ON ar.parameter = g.id AND ar.subjekt = \'Mitglied\'
|
||||
WHERE ar.adresse = :address_id
|
||||
AND (ar.bis = \'0000-00-00\' OR ar.bis > CURDATE())';
|
||||
|
||||
return $this->db->fetchAll($sql, ['address_id' => $addressId]);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $addressId
|
||||
* @param int $groupId
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function isAddressInGroup(int $addressId, int $groupId): bool
|
||||
{
|
||||
$sql =
|
||||
'SELECT
|
||||
g.id AS `group_id`,
|
||||
g.name AS `group_name`
|
||||
FROM `gruppen` AS `g`
|
||||
INNER JOIN `adresse_rolle` AS `ar` ON ar.parameter = g.id AND ar.subjekt = \'Mitglied\'
|
||||
WHERE ar.adresse = :address_id
|
||||
AND ar.parameter = :group_id
|
||||
AND (ar.bis = \'0000-00-00\' OR ar.bis > CURDATE())';
|
||||
|
||||
$result = $this->db->fetchAll($sql, ['address_id' => $addressId, 'group_id' => $groupId]);
|
||||
|
||||
return !empty($result);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array
|
||||
*/
|
||||
public function findAllActiveGroupsWithMembers(): array
|
||||
{
|
||||
$sql =
|
||||
'SELECT DISTINCT
|
||||
g.id AS `group_id`,
|
||||
g.name AS `group_name`
|
||||
FROM `gruppen` AS `g`
|
||||
INNER JOIN `adresse_rolle` AS `ar` ON ar.parameter = g.id AND ar.subjekt = \'Mitglied\'
|
||||
WHERE (ar.bis = \'0000-00-00\' OR ar.bis > CURDATE())';
|
||||
|
||||
return $this->db->fetchAll($sql);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $employeeAddressId
|
||||
* @param int $groupId
|
||||
*
|
||||
* @throws SupervisorNotFoundException
|
||||
*
|
||||
* @return int[]
|
||||
*/
|
||||
public function getSupervisorAddressIds(int $employeeAddressId, int $groupId = 0): array
|
||||
{
|
||||
$bindValues = [];
|
||||
$sql =
|
||||
'SELECT a.id AS `id`
|
||||
FROM `userrights` AS `ur`
|
||||
INNER JOIN `user` AS `u` ON u.id = ur.user
|
||||
INNER JOIN `adresse` AS `a` ON a.id = u.adresse
|
||||
INNER JOIN `adresse_rolle` AS `ar_supervisor` ON ar_supervisor.adresse = a.id
|
||||
WHERE ur.action = \'timemanagementhandle\'
|
||||
AND ar_supervisor.subjekt = \'Mitglied\'
|
||||
AND ar_supervisor.objekt = \'Gruppe\'
|
||||
';
|
||||
|
||||
if ($groupId == 0) {
|
||||
$sql .= 'AND ar_supervisor.parameter IN (
|
||||
SELECT ar_employee.parameter
|
||||
FROM `adresse_rolle` AS `ar_employee`
|
||||
WHERE ar_employee.adresse = :employee_address_id
|
||||
AND ar_employee.subjekt = \'Mitglied\'
|
||||
AND ar_employee.objekt = \'Gruppe\'
|
||||
)';
|
||||
$bindValues['employee_address_id'] = $employeeAddressId;
|
||||
} else {
|
||||
$sql .= 'AND ar_supervisor.parameter = :group_id';
|
||||
$bindValues['group_id'] = $groupId;
|
||||
}
|
||||
|
||||
$superVisorAddressIds = $this->db->fetchAll($sql, $bindValues);
|
||||
|
||||
//superprivilege
|
||||
if (empty($superVisorAddressIds)) {
|
||||
$superVisorAddressIds = $this->findSupervisorAddressIdsBySuperPrivilege();
|
||||
}
|
||||
|
||||
//admin
|
||||
if (empty($superVisorAddressIds)) {
|
||||
$superVisorAddressIds = $this->findSupervisorAddressIdByAdminRight();
|
||||
}
|
||||
|
||||
$return = [];
|
||||
if (!empty($superVisorAddressIds)) {
|
||||
foreach ($superVisorAddressIds as $superVisorAddressId) {
|
||||
$return[] = $superVisorAddressId['id'];
|
||||
}
|
||||
} else {
|
||||
throw new SupervisorNotFoundException('No supervisor found for ' . $employeeAddressId);
|
||||
}
|
||||
|
||||
return $return;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array
|
||||
*/
|
||||
private function findSupervisorAddressIdsBySuperPrivilege()
|
||||
{
|
||||
$sql =
|
||||
'SELECT a.id AS `id`
|
||||
FROM `userrights` AS `ur`
|
||||
INNER JOIN `user` AS `u` ON u.id = ur.user
|
||||
INNER JOIN `adresse` AS `a` ON a.id = u.adresse
|
||||
WHERE ur.action = \'timemanagementsuperprivilege\'
|
||||
ORDER BY a.id DESC';
|
||||
|
||||
return $this->db->fetchAll($sql);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array
|
||||
*/
|
||||
private function findSupervisorAddressIdByAdminRight()
|
||||
{
|
||||
$sql =
|
||||
'SELECT u.adresse AS `id`
|
||||
FROM `user` AS `u`
|
||||
WHERE u.type = \'admin\'
|
||||
ORDER BY u.adresse DESC';
|
||||
|
||||
return $this->db->fetchAll($sql);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,53 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Xentral\Modules\TimeManagement\Service;
|
||||
|
||||
use Xentral\Components\Database\Database;
|
||||
use Xentral\Modules\TimeManagement\Data\HolidayData;
|
||||
use Xentral\Modules\TimeManagement\Exception\InvalidDateFormatException;
|
||||
|
||||
final class HolidayGateway
|
||||
{
|
||||
/** @var Database $db */
|
||||
private $db;
|
||||
|
||||
/**
|
||||
* @param Database $db
|
||||
*/
|
||||
public function __construct(Database $db)
|
||||
{
|
||||
$this->db = $db;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $year
|
||||
*
|
||||
* @throws InvalidDateFormatException
|
||||
*
|
||||
* @return array|HolidayData[]
|
||||
*/
|
||||
public function findHolidayDataByYear(int $year): array
|
||||
{
|
||||
$sql =
|
||||
'SELECT
|
||||
af.bezeichnung as `name`,
|
||||
af.datum as `date`
|
||||
FROM `arbeitsfreietage` AS `af`
|
||||
WHERE af.datum >= :first_date_of_year
|
||||
AND af.typ = \'feiertag\'
|
||||
ORDER BY af.datum';
|
||||
|
||||
$holidays = $this->db->fetchAll($sql, ['first_date_of_year' => $year . '-01-01']);
|
||||
|
||||
$holidayData = [];
|
||||
if (!empty($holidays)) {
|
||||
foreach ($holidays as $holiday) {
|
||||
$holidayData[] = HolidayData::fromDbState($holiday);
|
||||
}
|
||||
}
|
||||
|
||||
return $holidayData;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,97 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Xentral\Modules\TimeManagement\Service;
|
||||
|
||||
use DateTimeInterface;
|
||||
use Xentral\Components\Database\Database;
|
||||
use Xentral\Modules\TimeManagement\Exception\InvalidArgumentException;
|
||||
use Xentral\Modules\TimeManagement\Exception\InvalidQueryException;
|
||||
|
||||
final class TimeManagementHistoryService
|
||||
{
|
||||
|
||||
/** @var Database $db */
|
||||
private $db;
|
||||
|
||||
/**
|
||||
* @param Database $db
|
||||
*/
|
||||
public function __construct(Database $db)
|
||||
{
|
||||
$this->db = $db;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $employeeAddressId
|
||||
* @param int $supervisorAddressId
|
||||
* @param string $oldType
|
||||
* @param string $newType
|
||||
* @param string $requestToken
|
||||
* @param DateTimeInterface $from
|
||||
* @param DateTimeInterface $till
|
||||
* @param string $comment
|
||||
*
|
||||
* @throws InvalidArgumentException
|
||||
* @throws InvalidQueryException
|
||||
*/
|
||||
public function saveActivity(
|
||||
int $employeeAddressId,
|
||||
int $supervisorAddressId,
|
||||
string $oldType,
|
||||
string $newType,
|
||||
string $requestToken,
|
||||
DateTimeInterface $from,
|
||||
DateTimeInterface $till,
|
||||
string $comment
|
||||
): void {
|
||||
if ($employeeAddressId === 0 && $supervisorAddressId === 0) {
|
||||
throw new InvalidArgumentException('No addresses given.');
|
||||
}
|
||||
|
||||
if (empty($oldType) && empty($newType)) {
|
||||
throw new InvalidArgumentException('No types given.');
|
||||
}
|
||||
|
||||
$sql =
|
||||
'INSERT INTO `timemanagement_history` (
|
||||
`employee_address_id`,
|
||||
`supervisor_address_id`,
|
||||
`old_day_type`,
|
||||
`new_day_type`,
|
||||
`request_token`,
|
||||
`from`,
|
||||
`till`,
|
||||
`comment`
|
||||
) VALUES (
|
||||
:employee_address_id,
|
||||
:supervisor_address_id,
|
||||
:old_day_type,
|
||||
:new_day_type,
|
||||
:request_token,
|
||||
:from,
|
||||
:till,
|
||||
:comment
|
||||
)';
|
||||
|
||||
$arguments = [
|
||||
'employee_address_id' => $employeeAddressId,
|
||||
'supervisor_address_id' => $supervisorAddressId,
|
||||
'old_day_type' => $oldType,
|
||||
'new_day_type' => $newType,
|
||||
'request_token' => $requestToken,
|
||||
'from' => $from->format('Y-m-d'),
|
||||
'till' => $till->format('Y-m-d'),
|
||||
'comment' => $comment,
|
||||
];
|
||||
|
||||
$numAffected = (int)$this->db->fetchAffected($sql, $arguments);
|
||||
|
||||
if ($numAffected === 0) {
|
||||
throw new InvalidQueryException(
|
||||
'Time management history could not be updated. Arguments: ' . implode(', ', $arguments)
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,55 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Xentral\Modules\TimeManagement\Service;
|
||||
|
||||
use Xentral\Components\Database\Database;
|
||||
use Xentral\Modules\TimeManagement\Data\WorkDayData;
|
||||
use Xentral\Modules\TimeManagement\Exception\InvalidQueryException;
|
||||
|
||||
final class TimeManagementSettingGateway
|
||||
{
|
||||
|
||||
/** @var Database $db */
|
||||
private $db;
|
||||
|
||||
/**
|
||||
* @param Database $db
|
||||
*/
|
||||
public function __construct(Database $db)
|
||||
{
|
||||
$this->db = $db;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $addressId
|
||||
*
|
||||
* @throws InvalidQueryException
|
||||
*
|
||||
* @return WorkDayData
|
||||
*/
|
||||
public function getWorkingDaysForAddress(int $addressId): WorkDayData
|
||||
{
|
||||
$sql =
|
||||
'SELECT
|
||||
e.vorlagemo > 0 AS `is_monday_workday`,
|
||||
e.vorlagedi > 0 AS `is_tuesday_workday`,
|
||||
e.vorlagemi > 0 AS `is_wednesday_workday`,
|
||||
e.vorlagedo > 0 AS `is_thursday_workday`,
|
||||
e.vorlagefr > 0 AS `is_friday_workday`,
|
||||
e.vorlagesa > 0 AS `is_saturday_workday`,
|
||||
e.vorlageso > 0 AS `is_sunday_workday`
|
||||
FROM `mitarbeiterzeiterfassung_einstellungen` AS `e`
|
||||
WHERE e.adresse = :address_id
|
||||
ORDER BY e.id DESC
|
||||
LIMIT 1';
|
||||
|
||||
$result = $this->db->fetchRow($sql, ['address_id' => $addressId]);
|
||||
if (empty($result)) {
|
||||
throw new InvalidQueryException('Address is not valid: ' . $addressId);
|
||||
}
|
||||
|
||||
return WorkDayData::fromDbState($result);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,445 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Xentral\Modules\TimeManagement\Service;
|
||||
|
||||
use DateTimeImmutable;
|
||||
use DateTimeInterface;
|
||||
use Exception;
|
||||
use Xentral\Components\Database\Database;
|
||||
use Xentral\Modules\TimeManagement\Data\CalendarData;
|
||||
use Xentral\Modules\TimeManagement\Data\DayInfoData;
|
||||
use Xentral\Modules\TimeManagement\Data\RequestInfoData;
|
||||
use Xentral\Modules\TimeManagement\Exception\InvalidDateFormatException;
|
||||
use Xentral\Modules\TimeManagement\Exception\InvalidRequestTokenException;
|
||||
|
||||
final class TimeManagementTargetHourGateway
|
||||
{
|
||||
|
||||
/** @var Database $db */
|
||||
private $db;
|
||||
|
||||
/**
|
||||
* @param Database $db
|
||||
*/
|
||||
public function __construct(Database $db)
|
||||
{
|
||||
$this->db = $db;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $year
|
||||
* @param int $addressId
|
||||
* @param int $groupId
|
||||
*
|
||||
* @throws InvalidDateFormatException
|
||||
*
|
||||
* @return array|CalendarData[]
|
||||
*/
|
||||
public function findAnonymisedVacationCalendarDataByYearAndAddressIdAndGroupId(
|
||||
int $year,
|
||||
int $addressId,
|
||||
int $groupId
|
||||
): array {
|
||||
$sql =
|
||||
'SELECT
|
||||
MONTH(days.date) AS `month`,
|
||||
days.date,
|
||||
days.address_id,
|
||||
days.name,
|
||||
days.type,
|
||||
IF(days.urlaubminuten > 0,true,false) AS `is_half`
|
||||
FROM
|
||||
(
|
||||
SELECT
|
||||
ms.datum AS `date`,
|
||||
ms.adresse AS `address_id`,
|
||||
a.name,
|
||||
\'away\' AS `type`,
|
||||
ms.urlaubminuten
|
||||
FROM `mitarbeiterzeiterfassung_sollstunden` AS `ms`
|
||||
INNER JOIN `adresse` AS `a` ON ms.adresse = a.id
|
||||
WHERE (ms.kuerzel LIKE \'%U%\' OR ms.kuerzel LIKE \'%S%\')
|
||||
AND ms.adresse != :address_id
|
||||
AND year(ms.datum) = :year
|
||||
AND ms.datum > CURDATE()
|
||||
UNION
|
||||
SELECT
|
||||
ms.datum AS `date`,
|
||||
ms.adresse AS `address_id`,
|
||||
a.name,
|
||||
(CASE
|
||||
WHEN ms.kuerzel LIKE \'%U%\' THEN \'vacation\'
|
||||
WHEN ms.kuerzel LIKE \'%R%\' THEN \'request-vacation\'
|
||||
WHEN ms.kuerzel LIKE \'%L%\' THEN \'remove-vacation\'
|
||||
WHEN ms.kuerzel LIKE \'%K%\' THEN \'sick\'
|
||||
WHEN ms.kuerzel LIKE \'%S%\' THEN \'request-sick\'
|
||||
WHEN ms.kuerzel LIKE \'%V%\' THEN \'remove-sick\'
|
||||
WHEN ms.kuerzel LIKE \'%X%\' THEN \'absent\'
|
||||
WHEN ms.kuerzel LIKE \'%N%\' THEN \'unpaid\'
|
||||
END) AS `type`,
|
||||
ms.urlaubminuten
|
||||
FROM `mitarbeiterzeiterfassung_sollstunden` AS `ms`
|
||||
INNER JOIN `adresse` AS `a` ON ms.adresse = a.id
|
||||
WHERE ms.kuerzel != \'\' AND ms.kuerzel NOT LIKE \'%C%\' AND ms.kuerzel NOT LIKE \'%J%\'
|
||||
AND ms.adresse = :address_id
|
||||
AND year(ms.datum) = :year
|
||||
) AS `days`
|
||||
INNER JOIN(
|
||||
SELECT DISTINCT
|
||||
ar_groups.adresse
|
||||
FROM `adresse_rolle` AS `ar_groups`
|
||||
WHERE ar_groups.parameter = :group_id
|
||||
AND ar_groups.subjekt = :subject
|
||||
AND (ar_groups.bis = "0000-00-00" OR ar_groups.bis > CURDATE())
|
||||
) AS `ar` ON ar.adresse = days.address_id
|
||||
ORDER BY days.address_id, days.date';
|
||||
|
||||
$results = $this->db->fetchAll(
|
||||
$sql,
|
||||
[
|
||||
'year' => $year,
|
||||
'group_id' => $groupId,
|
||||
'subject' => 'Mitglied',
|
||||
'address_id' => $addressId,
|
||||
]
|
||||
);
|
||||
|
||||
$calendarDatas = [];
|
||||
if (!empty($results)) {
|
||||
foreach ($results as $result) {
|
||||
$calendarDatas[] = CalendarData::fromDbState($result);
|
||||
}
|
||||
}
|
||||
|
||||
return $calendarDatas;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $year
|
||||
* @param int $addressId
|
||||
*
|
||||
* @throws InvalidDateFormatException
|
||||
*
|
||||
* @return array|CalendarData[]
|
||||
*/
|
||||
public function findAnonymisedVacationCalendarDataByYearAndAddressId(int $year, int $addressId): array
|
||||
{
|
||||
$sql =
|
||||
'SELECT
|
||||
MONTH(days.date) AS `month`,
|
||||
days.date,
|
||||
days.address_id,
|
||||
days.name,
|
||||
days.type,
|
||||
IF(days.urlaubminuten > 0,true,false) AS `is_half`
|
||||
FROM
|
||||
(
|
||||
SELECT
|
||||
ms.datum AS `date`,
|
||||
ms.adresse AS `address_id`,
|
||||
a.name,
|
||||
\'away\' AS `type`,
|
||||
ms.urlaubminuten
|
||||
FROM `mitarbeiterzeiterfassung_sollstunden` AS `ms`
|
||||
INNER JOIN `adresse` AS `a` ON ms.adresse = a.id
|
||||
WHERE (ms.kuerzel LIKE \'%U%\' OR ms.kuerzel LIKE \'%S%\')
|
||||
AND ms.adresse != :address_id
|
||||
AND year(ms.datum) = :year
|
||||
AND ms.datum > CURDATE()
|
||||
UNION
|
||||
SELECT
|
||||
ms.datum AS `date`,
|
||||
ms.adresse AS `address_id`,
|
||||
a.name,
|
||||
(CASE
|
||||
WHEN ms.kuerzel LIKE \'%U%\' THEN \'vacation\'
|
||||
WHEN ms.kuerzel LIKE \'%R%\' THEN \'request-vacation\'
|
||||
WHEN ms.kuerzel LIKE \'%L%\' THEN \'remove-vacation\'
|
||||
WHEN ms.kuerzel LIKE \'%K%\' THEN \'sick\'
|
||||
WHEN ms.kuerzel LIKE \'%S%\' THEN \'request-sick\'
|
||||
WHEN ms.kuerzel LIKE \'%V%\' THEN \'remove-sick\'
|
||||
WHEN ms.kuerzel LIKE \'%X%\' THEN \'absent\'
|
||||
WHEN ms.kuerzel LIKE \'%N%\' THEN \'unpaid\'
|
||||
END) AS `type`,
|
||||
ms.urlaubminuten
|
||||
FROM `mitarbeiterzeiterfassung_sollstunden` AS `ms`
|
||||
INNER JOIN `adresse` AS `a` ON ms.adresse = a.id
|
||||
WHERE ms.kuerzel != \'\' AND ms.kuerzel NOT LIKE \'%C%\' AND ms.kuerzel NOT LIKE \'%J%\'
|
||||
AND ms.adresse = :address_id
|
||||
AND year(ms.datum) = :year
|
||||
) AS `days`
|
||||
WHERE days.address_id = :address_id
|
||||
ORDER BY days.address_id, days.date';
|
||||
|
||||
$results = $this->db->fetchAll($sql, ['year' => $year, 'address_id' => $addressId]);
|
||||
|
||||
$calendarDatas = [];
|
||||
if (!empty($results)) {
|
||||
foreach ($results as $result) {
|
||||
$calendarDatas[] = CalendarData::fromDbState($result);
|
||||
}
|
||||
}
|
||||
|
||||
return $calendarDatas;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $year
|
||||
*
|
||||
* @throws InvalidDateFormatException
|
||||
*
|
||||
* @return array|CalendarData[]
|
||||
*/
|
||||
public function findAllVacationCalendarDataByYear(int $year): array
|
||||
{
|
||||
$sql =
|
||||
'SELECT
|
||||
MONTH(days.date) AS `month`,
|
||||
days.date,
|
||||
days.address_id,
|
||||
days.name,
|
||||
days.type,
|
||||
IF(days.urlaubminuten > 0,true,false) AS `is_half`
|
||||
FROM
|
||||
(
|
||||
SELECT
|
||||
ms.datum AS `date`,
|
||||
ms.adresse AS `address_id`,
|
||||
a.name,
|
||||
(CASE
|
||||
WHEN ms.kuerzel LIKE \'%U%\' THEN \'vacation\'
|
||||
WHEN ms.kuerzel LIKE \'%K%\' THEN \'sick\'
|
||||
WHEN ms.kuerzel LIKE \'%X%\' THEN \'absent\'
|
||||
WHEN ms.kuerzel LIKE \'%N%\' THEN \'unpaid\'
|
||||
END) AS `type`,
|
||||
ms.urlaubminuten
|
||||
FROM `mitarbeiterzeiterfassung_sollstunden` AS `ms`
|
||||
INNER JOIN `adresse` AS `a` ON ms.adresse = a.id
|
||||
WHERE (
|
||||
ms.kuerzel LIKE \'%U%\'
|
||||
OR ms.kuerzel LIKE \'%N%\'
|
||||
OR ms.kuerzel LIKE \'%K%\'
|
||||
OR ms.kuerzel LIKE \'%X%\'
|
||||
)
|
||||
AND year(ms.datum) = :year
|
||||
) AS `days`
|
||||
INNER JOIN(
|
||||
SELECT DISTINCT
|
||||
ar_groups.adresse
|
||||
FROM `adresse_rolle` AS `ar_groups`
|
||||
WHERE ar_groups.subjekt = :subject
|
||||
AND (ar_groups.bis = \'0000-00-00\' OR ar_groups.bis > CURDATE())
|
||||
) AS `ar` ON ar.adresse = days.address_id
|
||||
ORDER BY days.date, days.address_id';
|
||||
|
||||
$results = $this->db->fetchAll($sql, ['year' => $year, 'subject' => 'Mitarbeiter']);
|
||||
|
||||
$calendarDatas = [];
|
||||
if (!empty($results)) {
|
||||
foreach ($results as $result) {
|
||||
$calendarDatas[] = CalendarData::fromDbState($result);
|
||||
}
|
||||
}
|
||||
|
||||
return $calendarDatas;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $addressId
|
||||
* @param DateTimeInterface $date
|
||||
*
|
||||
* @return DayInfoData
|
||||
*/
|
||||
public function findDayInfo(int $addressId, DateTimeInterface $date): DayInfoData
|
||||
{
|
||||
$sql =
|
||||
'SELECT
|
||||
ms.kuerzel AS `type`,
|
||||
ms.internal_comment AS `internal_comment`,
|
||||
(CASE WEEKDAY(:date)
|
||||
WHEN 0 THEN IFNULL(minutes.vorlagemo,0)
|
||||
WHEN 1 THEN IFNULL(minutes.vorlagedi,0)
|
||||
WHEN 2 THEN IFNULL(minutes.vorlagemi,0)
|
||||
WHEN 3 THEN IFNULL(minutes.vorlagedo,0)
|
||||
WHEN 4 THEN IFNULL(minutes.vorlagefr,0)
|
||||
WHEN 5 THEN IFNULL(minutes.vorlagesa,0)
|
||||
WHEN 6 THEN IFNULL(minutes.vorlageso,0)
|
||||
END) AS `workminutes`,
|
||||
ms.urlaubminuten AS `vacationminutes`
|
||||
FROM (
|
||||
SELECT
|
||||
me.adresse,
|
||||
me.vorlagemo,
|
||||
me.vorlagedi,
|
||||
me.vorlagemi,
|
||||
me.vorlagedo,
|
||||
me.vorlagefr,
|
||||
me.vorlagesa,
|
||||
me.vorlageso
|
||||
FROM `mitarbeiterzeiterfassung_einstellungen` AS `me`
|
||||
WHERE me.adresse = :address_id
|
||||
ORDER BY id DESC
|
||||
LIMIT 1
|
||||
) AS `minutes`
|
||||
LEFT JOIN `mitarbeiterzeiterfassung_sollstunden` AS `ms` ON minutes.adresse = ms.adresse AND ms.datum = :date
|
||||
LIMIT 1';
|
||||
|
||||
$result = $this->db->fetchRow($sql, ['date' => $date->format('Y-m-d'), 'address_id' => $addressId]);
|
||||
|
||||
return DayInfoData::fromDbState($result);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $requestToken
|
||||
*
|
||||
* @throws InvalidRequestTokenException
|
||||
* @throws InvalidDateFormatException
|
||||
*
|
||||
* @return RequestInfoData
|
||||
*/
|
||||
public function getRequestInfoByToken(string $requestToken): RequestInfoData
|
||||
{
|
||||
$sql =
|
||||
'SELECT
|
||||
a.id AS `employee_id`,
|
||||
a.mitarbeiternummer AS `employee_number`,
|
||||
a.name AS `employee_name`,
|
||||
DATE_FORMAT(MIN(ms.datum), \'%d.%m.%Y\') AS `min_date`,
|
||||
DATE_FORMAT(MAX(ms.datum), \'%d.%m.%Y\') AS `max_date`,
|
||||
COUNT(ms.id) AS `amount`,
|
||||
ms.kommentar AS `comment`,
|
||||
ms.kuerzel AS `type`,
|
||||
ms.internal_comment
|
||||
FROM `mitarbeiterzeiterfassung_sollstunden` AS `ms`
|
||||
INNER JOIN `adresse` AS `a` ON a.id = ms.adresse
|
||||
WHERE ms.vacation_request_token = :request_token
|
||||
AND (
|
||||
ms.kuerzel LIKE \'%R%\'
|
||||
OR ms.kuerzel LIKE \'%L%\'
|
||||
OR ms.kuerzel LIKE \'%S%\'
|
||||
OR ms.kuerzel LIKE \'%V%\'
|
||||
)
|
||||
GROUP BY ms.vacation_request_token
|
||||
ORDER BY ms.datum';
|
||||
|
||||
$result = $this->db->fetchRow($sql, ['request_token' => $requestToken]);
|
||||
|
||||
if (empty($result)) {
|
||||
throw new InvalidRequestTokenException($requestToken . 'not valid.');
|
||||
}
|
||||
|
||||
return RequestInfoData::fromDbState($result);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $requestToken
|
||||
*
|
||||
* @throws InvalidDateFormatException
|
||||
*
|
||||
* @throws InvalidRequestTokenException
|
||||
* @return array
|
||||
*/
|
||||
public function getRequestedDaysByToken(string $requestToken): array
|
||||
{
|
||||
$sql =
|
||||
'SELECT
|
||||
ms.datum AS `date`,
|
||||
ms.kuerzel AS `type`
|
||||
FROM `mitarbeiterzeiterfassung_sollstunden` AS `ms`
|
||||
WHERE ms.vacation_request_token = :vacation_request_token
|
||||
ORDER BY ms.datum';
|
||||
|
||||
$results = $this->db->fetchAll($sql, ['vacation_request_token' => $requestToken]);
|
||||
|
||||
if (empty($results)) {
|
||||
throw new InvalidRequestTokenException($requestToken . 'not valid.');
|
||||
}
|
||||
|
||||
$formatted = [];
|
||||
foreach ($results as $result) {
|
||||
try {
|
||||
$formatted[] = ['date' => new DateTimeImmutable($result['date']), 'type' => $result['type']];
|
||||
} catch (Exception $e) {
|
||||
throw new InvalidDateFormatException('Could not convert date: ' . $result['date']);
|
||||
}
|
||||
}
|
||||
|
||||
return $formatted;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $daysTillDeletion
|
||||
* @param int $addressId
|
||||
*
|
||||
* @throws InvalidDateFormatException
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function findRejectedDays(int $daysTillDeletion, int $addressId): array
|
||||
{
|
||||
$sql =
|
||||
'SELECT
|
||||
ms.datum AS `date`
|
||||
FROM `mitarbeiterzeiterfassung_sollstunden` AS `ms`
|
||||
WHERE (ms.kuerzel LIKE \'%J%\' OR ms.kuerzel LIKE \'%C%\')
|
||||
AND ms.adresse = :address_id
|
||||
AND DATE_ADD(FROM_UNIXTIME(ms.vacation_request_token), INTERVAL :days_till_deletion DAY) < CURDATE()';
|
||||
|
||||
$results = $this->db->fetchAll(
|
||||
$sql,
|
||||
[
|
||||
'days_till_deletion' => $daysTillDeletion,
|
||||
'address_id' => $addressId,
|
||||
]
|
||||
);
|
||||
|
||||
$formatted = [];
|
||||
if (!empty($results)) {
|
||||
foreach ($results as $result) {
|
||||
try {
|
||||
$formatted[] = ['date' => new DateTimeImmutable($result['date'])];
|
||||
} catch (Exception $e) {
|
||||
throw new InvalidDateFormatException('Could not convert date: ' . $result['date']);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $formatted;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $addressId
|
||||
*
|
||||
* @return float
|
||||
*/
|
||||
public function findAmountRequestedVacation(int $addressId): float
|
||||
{
|
||||
$sql =
|
||||
'SELECT SUM(info.amount) AS `amount`
|
||||
FROM(
|
||||
SELECT
|
||||
count(ms.id) AS `amount`
|
||||
FROM `mitarbeiterzeiterfassung_sollstunden` AS `ms`
|
||||
WHERE ms.adresse = :address_id
|
||||
AND ms.urlaubminuten = 0
|
||||
AND ms.kuerzel LIKE \'%R%\'
|
||||
UNION
|
||||
SELECT
|
||||
count(ms.id) / 2 AS `amount`
|
||||
FROM `mitarbeiterzeiterfassung_sollstunden` AS `ms`
|
||||
WHERE ms.adresse = :address_id
|
||||
AND ms.urlaubminuten > 0
|
||||
AND ms.kuerzel LIKE \'%R%\'
|
||||
) AS `info`';
|
||||
|
||||
$result = $this->db->fetchRow($sql, ['address_id' => $addressId]);
|
||||
|
||||
if (!empty($result)) {
|
||||
return (float)$result['amount'];
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,117 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Xentral\Modules\TimeManagement\Service;
|
||||
|
||||
use DateTimeInterface;
|
||||
use Xentral\Components\Database\Database;
|
||||
use Xentral\Modules\TimeManagement\Exception\InvalidQueryException;
|
||||
|
||||
final class TimeManagementTargetHourService
|
||||
{
|
||||
|
||||
/** @var Database $db */
|
||||
private $db;
|
||||
|
||||
/**
|
||||
* @param Database $db
|
||||
*/
|
||||
public function __construct(Database $db)
|
||||
{
|
||||
$this->db = $db;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $vacationRequestToken
|
||||
* @param string $internalComment
|
||||
*
|
||||
*/
|
||||
public function saveInternalComment(string $vacationRequestToken, string $internalComment): void
|
||||
{
|
||||
$sql =
|
||||
'UPDATE `mitarbeiterzeiterfassung_sollstunden` SET
|
||||
`internal_comment` = :internal_comment
|
||||
WHERE `vacation_request_token` = :vacation_request_token';
|
||||
|
||||
$this->db->perform(
|
||||
$sql,
|
||||
[
|
||||
'vacation_request_token' => $vacationRequestToken,
|
||||
'internal_comment' => $internalComment,
|
||||
]
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $addressId
|
||||
* @param DateTimeInterface $date
|
||||
* @param string $oldType
|
||||
* @param string $newType
|
||||
*
|
||||
*/
|
||||
public function updateTargetHourType(
|
||||
int $addressId,
|
||||
DateTimeInterface $date,
|
||||
string $oldType,
|
||||
string $newType
|
||||
): void {
|
||||
$sql =
|
||||
'UPDATE `mitarbeiterzeiterfassung_sollstunden` SET
|
||||
`kuerzel` = REPLACE(`kuerzel`,:old_type, :new_type)
|
||||
WHERE `adresse` = :address_id
|
||||
AND `datum` = :date';
|
||||
|
||||
$numAffected = (int)$this->db->fetchAffected(
|
||||
$sql,
|
||||
[
|
||||
'old_type' => $oldType,
|
||||
'new_type' => $newType,
|
||||
'address_id' => $addressId,
|
||||
'date' => $date->format('Y-m-d'),
|
||||
]
|
||||
);
|
||||
|
||||
if ($numAffected == 0) {
|
||||
throw new InvalidQueryException(
|
||||
'Target hour could not be updated. Maybe wrong arguments. addressId: ' . $addressId .
|
||||
', dateString: ' . $date->format('Y-m-d') .
|
||||
', oldType: ' . $oldType .
|
||||
', newType: ' . $newType
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $addressId
|
||||
* @param DateTimeInterface $date
|
||||
* @param string $requestToken
|
||||
*
|
||||
* @throws InvalidQueryException
|
||||
*/
|
||||
public function updateVacationRequestToken(int $addressId, DateTimeInterface $date, string $requestToken): void
|
||||
{
|
||||
$sql =
|
||||
'UPDATE `mitarbeiterzeiterfassung_sollstunden` SET
|
||||
`vacation_request_token` = :vacation_request_token
|
||||
WHERE `adresse` = :address_id
|
||||
AND `datum` = :date';
|
||||
|
||||
$numAffected = (int)$this->db->fetchAffected(
|
||||
$sql,
|
||||
[
|
||||
'vacation_request_token' => $requestToken,
|
||||
'address_id' => $addressId,
|
||||
'date' => $date->format('Y-m-d'),
|
||||
]
|
||||
);
|
||||
|
||||
if ($numAffected == 0) {
|
||||
throw new InvalidQueryException(
|
||||
'Target hour could not be updated. Maybe wrong arguments. addressId: ' . $addressId .
|
||||
', dateString: ' . $date->format('Y-m-d') .
|
||||
', requestToken: ' . $requestToken
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,663 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Xentral\Modules\TimeManagement;
|
||||
|
||||
use DateTimeImmutable;
|
||||
use DateTimeInterface;
|
||||
use Xentral\Modules\TimeManagement\Data\CalendarData;
|
||||
use Xentral\Modules\TimeManagement\Data\DayInfoData;
|
||||
use Xentral\Modules\TimeManagement\Data\HolidayData;
|
||||
use Xentral\Modules\TimeManagement\Data\RequestInfoData;
|
||||
use Xentral\Modules\TimeManagement\Data\WorkDayData;
|
||||
use Xentral\Modules\TimeManagement\Exception\InvalidDateFormatException;
|
||||
use Xentral\Modules\TimeManagement\Exception\InvalidQueryException;
|
||||
use Xentral\Modules\TimeManagement\Exception\InvalidRequestTokenException;
|
||||
use Xentral\Modules\TimeManagement\Exception\SupervisorNotFoundException;
|
||||
use Xentral\Modules\TimeManagement\Service\GroupGateway;
|
||||
use Xentral\Modules\TimeManagement\Service\HolidayGateway;
|
||||
use Xentral\Modules\TimeManagement\Service\TimeManagementHistoryService;
|
||||
use Xentral\Modules\TimeManagement\Service\TimeManagementSettingGateway;
|
||||
use Xentral\Modules\TimeManagement\Service\TimeManagementTargetHourGateway;
|
||||
use Xentral\Modules\TimeManagement\Service\TimeManagementTargetHourService;
|
||||
use Xentral\Modules\TimeManagement\Wrapper\TimeManagementTargetHourWrapper;
|
||||
|
||||
|
||||
class TimeManagementModule
|
||||
{
|
||||
/** @var TimeManagementTargetHourGateway $targetHourGateway */
|
||||
private $targetHourGateway;
|
||||
|
||||
/** @var TimeManagementTargetHourService $targetHourService */
|
||||
private $targetHourService;
|
||||
|
||||
/** @var HolidayGateway $holidayGateway */
|
||||
private $holidayGateway;
|
||||
|
||||
/** @var GroupGateway $groupGateway */
|
||||
private $groupGateway;
|
||||
|
||||
/** @var TimeManagementSettingGateway $settingGateway */
|
||||
private $settingGateway;
|
||||
|
||||
/** @var TimeManagementTargetHourWrapper $targetHourWrapper */
|
||||
private $targetHourWrapper;
|
||||
|
||||
/** @var TimeManagementHistoryService $historyService */
|
||||
private $historyService;
|
||||
|
||||
/** @var string UNPAID */
|
||||
public const UNPAID = 'N';
|
||||
|
||||
/** @var string ABSENT_DAY */
|
||||
public const ABSENT_DAY = 'X';
|
||||
|
||||
/** @var string NONE */
|
||||
public const NONE = '';
|
||||
|
||||
/** @var string SICK */
|
||||
public const SICK = 'K';
|
||||
|
||||
/** @var string SICK */
|
||||
public const SICKREQUEST = 'S';
|
||||
|
||||
/** @var string SICKREMOVE */
|
||||
public const SICKREMOVE = 'V';
|
||||
|
||||
/** @var string SICKREJECT */
|
||||
public const SICKREJECT = 'C';
|
||||
|
||||
/** @var string VACATION */
|
||||
public const VACATION = 'U';
|
||||
|
||||
/** @var string VACATIONREQUEST */
|
||||
public const VACATIONREQUEST = 'R';
|
||||
|
||||
/** @var string VACATIONREMOVE */
|
||||
public const VACATIONREMOVE = 'L';
|
||||
|
||||
/** @var string VACATIONREJECT */
|
||||
public const VACATIONREJECT = 'J';
|
||||
|
||||
/**
|
||||
* @param TimeManagementTargetHourGateway $targetHourGateway
|
||||
* @param TimeManagementTargetHourService $targetHourService
|
||||
* @param TimeManagementSettingGateway $settingGateway
|
||||
* @param HolidayGateway $holidayGateway
|
||||
* @param GroupGateway $groupGateway
|
||||
* @param TimeManagementTargetHourWrapper $targetHourWrapper
|
||||
* @param TimeManagementHistoryService $historyService
|
||||
*/
|
||||
public function __construct(
|
||||
TimeManagementTargetHourGateway $targetHourGateway,
|
||||
TimeManagementTargetHourService $targetHourService,
|
||||
TimeManagementSettingGateway $settingGateway,
|
||||
HolidayGateway $holidayGateway,
|
||||
GroupGateway $groupGateway,
|
||||
TimeManagementTargetHourWrapper $targetHourWrapper,
|
||||
TimeManagementHistoryService $historyService
|
||||
) {
|
||||
$this->targetHourGateway = $targetHourGateway;
|
||||
$this->targetHourService = $targetHourService;
|
||||
$this->holidayGateway = $holidayGateway;
|
||||
$this->groupGateway = $groupGateway;
|
||||
$this->settingGateway = $settingGateway;
|
||||
$this->targetHourWrapper = $targetHourWrapper;
|
||||
$this->historyService = $historyService;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $addressId
|
||||
* @param DateTimeImmutable $fromDate
|
||||
* @param DateTimeImmutable $tillDate
|
||||
* @param string $statusOldType
|
||||
* @param string $statusWishType
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
private function findPossibleDays(
|
||||
int $addressId,
|
||||
DateTimeImmutable $fromDate,
|
||||
DateTimeImmutable $tillDate,
|
||||
string $statusOldType,
|
||||
string $statusWishType
|
||||
): array {
|
||||
$evaluatedDays = [];
|
||||
|
||||
while ($fromDate <= $tillDate) {
|
||||
$dayInfo = $this->targetHourGateway->findDayInfo($addressId, $fromDate);
|
||||
$dayType = $dayInfo->getType();
|
||||
|
||||
$workminutes = (int)$dayInfo->getWorkMinutes();
|
||||
if ($workminutes < 0) {
|
||||
$workminutes = 0;
|
||||
}
|
||||
|
||||
$isWorkDay = $workminutes != 0;
|
||||
|
||||
//allowed are:
|
||||
//- days with no type
|
||||
//- days of the same type like the old
|
||||
//- rejected days which can be reclaimed
|
||||
if (
|
||||
empty($dayType) ||
|
||||
$dayType === $statusOldType ||
|
||||
$dayType === self::SICKREJECT ||
|
||||
$dayType === self::VACATIONREJECT
|
||||
) {
|
||||
if ($this->isAddableDay($fromDate, $isWorkDay)) {
|
||||
$evaluatedDays[] = [
|
||||
'date' => $fromDate,
|
||||
'type' => $this->getPossibleDayType($statusOldType, $statusWishType),
|
||||
'workminutes' => $workminutes,
|
||||
'vacationminutes' => $dayInfo->getVacationMinutes(),
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
$fromDate = $fromDate->modify('1 day');
|
||||
}
|
||||
|
||||
return $evaluatedDays;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param DateTimeInterface $date
|
||||
* @param bool $isWorkDay
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
private function isAddableDay(DateTimeInterface $date, bool $isWorkDay): bool
|
||||
{
|
||||
$year = (int)$date->format('Y');
|
||||
$holidays = $this->holidayGateway->findHolidayDataByYear($year);
|
||||
$isHoliday = $this->isHoliday($date, $holidays);
|
||||
|
||||
if (!$isHoliday && $isWorkDay) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $statusOldType
|
||||
* @param string $statusWishType
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
private function getPossibleDayType(string $statusOldType, string $statusWishType): string
|
||||
{
|
||||
$isStatusAcceptedRemove = false;
|
||||
$isStatusRequestedRemove = false;
|
||||
|
||||
if (
|
||||
strstr($statusOldType, TimeManagementModule::VACATIONREQUEST) !== false ||
|
||||
strstr($statusOldType, TimeManagementModule::SICKREQUEST) !== false
|
||||
) {
|
||||
$isStatusRequestedRemove = true;
|
||||
}
|
||||
|
||||
if (
|
||||
strstr($statusOldType, TimeManagementModule::VACATION) !== false ||
|
||||
strstr($statusOldType, TimeManagementModule::SICK) !== false ||
|
||||
strstr($statusOldType, TimeManagementModule::ABSENT_DAY) !== false ||
|
||||
strstr($statusOldType, TimeManagementModule::UNPAID) !== false
|
||||
) {
|
||||
$isStatusAcceptedRemove = true;
|
||||
}
|
||||
|
||||
$type = self::VACATIONREQUEST;
|
||||
if ($statusWishType === self::SICK) {
|
||||
$type = self::SICKREQUEST;
|
||||
}
|
||||
|
||||
if ($isStatusRequestedRemove) {
|
||||
$type = self::NONE;
|
||||
} elseif ($isStatusAcceptedRemove) {
|
||||
$type = self::VACATIONREMOVE;
|
||||
if ($statusOldType === self::SICK) {
|
||||
$type = self::SICKREMOVE;
|
||||
}
|
||||
}
|
||||
|
||||
return $type;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param DateTimeInterface $date
|
||||
* @param array $holidays
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
private function isHoliday(DateTimeInterface $date, array $holidays): bool
|
||||
{
|
||||
/** @var HolidayData $holiday */
|
||||
foreach ($holidays as $holiday) {
|
||||
if ($holiday->getDate()->getTimestamp() === $date->getTimestamp()) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $addressId
|
||||
* @param bool $hasSuperPrivileges
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function findGroupsByAddressId(int $addressId, bool $hasSuperPrivileges): array
|
||||
{
|
||||
if ($hasSuperPrivileges) {
|
||||
return $this->groupGateway->findAllActiveGroupsWithMembers();
|
||||
}
|
||||
|
||||
return $this->groupGateway->findGroupsByAddressId($addressId);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $requestToken
|
||||
*
|
||||
* @throws InvalidRequestTokenException
|
||||
* @throws InvalidDateFormatException
|
||||
*
|
||||
* @return RequestInfoData
|
||||
*/
|
||||
public function getRequestInfoByToken(string $requestToken): RequestInfoData
|
||||
{
|
||||
return $this->targetHourGateway->getRequestInfoByToken($requestToken);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $year
|
||||
*
|
||||
* @return array|HolidayData[]
|
||||
*/
|
||||
public function findHolidayDataByYear($year): array
|
||||
{
|
||||
return $this->holidayGateway->findHolidayDataByYear($year);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $addressId
|
||||
* @param int $year
|
||||
* @param bool $isAnonymised
|
||||
* @param int $groupId
|
||||
*
|
||||
* @throws InvalidDateFormatException
|
||||
*
|
||||
* @return array|CalendarData[]
|
||||
*/
|
||||
public function getCalendarData(
|
||||
int $addressId,
|
||||
int $year,
|
||||
bool $isAnonymised,
|
||||
int $groupId = 0
|
||||
): array {
|
||||
if ($isAnonymised) {
|
||||
if (empty($groupId)) {
|
||||
$calendarData = $this->targetHourGateway->findAnonymisedVacationCalendarDataByYearAndAddressId(
|
||||
$year,
|
||||
$addressId
|
||||
);
|
||||
} else {
|
||||
$calendarData = $this->targetHourGateway->findAnonymisedVacationCalendarDataByYearAndAddressIdAndGroupId(
|
||||
$year,
|
||||
$addressId,
|
||||
$groupId
|
||||
);
|
||||
}
|
||||
} else {
|
||||
$calendarData = $this->targetHourGateway->findAllVacationCalendarDataByYear($year);
|
||||
}
|
||||
|
||||
return $calendarData;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $addressId
|
||||
*
|
||||
* @throws InvalidQueryException
|
||||
*
|
||||
* @return WorkDayData
|
||||
*/
|
||||
public function getWorkingDaysForAddress(int $addressId): WorkDayData
|
||||
{
|
||||
return $this->settingGateway->getWorkingDaysForAddress($addressId);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $addressId
|
||||
* @param DateTimeInterface $date
|
||||
*
|
||||
* @return DayInfoData
|
||||
*/
|
||||
public function getDayInfo(int $addressId, DateTimeInterface $date): DayInfoData
|
||||
{
|
||||
return $this->targetHourGateway->findDayInfo($addressId, $date);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $addressId
|
||||
*
|
||||
* @return float
|
||||
*/
|
||||
public function getAmountRequestedVacation(int $addressId): float
|
||||
{
|
||||
return $this->targetHourGateway->findAmountRequestedVacation($addressId);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $dayType
|
||||
* @param bool $isReject
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
private function evaluateNextDayType(string $dayType, bool $isReject): string
|
||||
{
|
||||
$isVacation =
|
||||
strstr($dayType, self::VACATIONREMOVE) !== false ||
|
||||
strstr($dayType, self::VACATIONREQUEST) !== false;
|
||||
|
||||
$isRemove =
|
||||
strstr($dayType, self::VACATIONREMOVE) !== false ||
|
||||
strstr($dayType, self::SICKREMOVE) !== false;
|
||||
|
||||
if ($isRemove) {
|
||||
if ($isReject) {
|
||||
if ($isVacation) {
|
||||
$type = self::VACATION;
|
||||
} else {
|
||||
$type = self::SICK;
|
||||
}
|
||||
} else {
|
||||
$type = self::NONE;
|
||||
}
|
||||
} else {
|
||||
if ($isReject) {
|
||||
if ($isVacation) {
|
||||
$type = self::VACATIONREJECT;
|
||||
} else {
|
||||
$type = self::SICKREJECT;
|
||||
}
|
||||
} else {
|
||||
if ($isVacation) {
|
||||
$type = self::VACATION;
|
||||
} else {
|
||||
$type = self::SICK;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $type;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $addressId
|
||||
* @param DateTimeImmutable $from
|
||||
* @param DateTimeImmutable $till
|
||||
* @param bool $halfDay
|
||||
* @param string $comment
|
||||
* @param string $statusOldType
|
||||
* @param string $statusWishType
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function changeDays(
|
||||
int $addressId,
|
||||
DateTimeImmutable $from,
|
||||
DateTimeImmutable $till,
|
||||
bool $halfDay,
|
||||
string $comment,
|
||||
string $statusOldType,
|
||||
string $statusWishType
|
||||
): string {
|
||||
if ($from > $till) {
|
||||
$till = $from;
|
||||
}
|
||||
|
||||
$possibleDays =
|
||||
$this->findPossibleDays(
|
||||
$addressId,
|
||||
$from,
|
||||
$till,
|
||||
$statusOldType,
|
||||
$statusWishType
|
||||
);
|
||||
|
||||
if (empty($possibleDays)) {
|
||||
return '';
|
||||
}
|
||||
$date = new DateTimeImmutable();
|
||||
$requestToken = (string)$date->getTimestamp();
|
||||
|
||||
$this->historyService->saveActivity(
|
||||
$addressId,
|
||||
0,
|
||||
$statusOldType,
|
||||
$possibleDays[0]['type'],
|
||||
$requestToken,
|
||||
$from,
|
||||
$till,
|
||||
$comment
|
||||
);
|
||||
|
||||
foreach ($possibleDays as $day) {
|
||||
$time = $day['vacationminutes'] / 60;
|
||||
|
||||
if ($halfDay) {
|
||||
$workminutes = $day['workminutes'];
|
||||
if ($workminutes > 0) {
|
||||
$time = $workminutes / (2 * 60);
|
||||
}
|
||||
}
|
||||
|
||||
$this->changeDayType(
|
||||
$addressId,
|
||||
$day['date'],
|
||||
$day['type'],
|
||||
$comment,
|
||||
(string)$time,
|
||||
$requestToken
|
||||
);
|
||||
}
|
||||
if($day['type'] === self::NONE){
|
||||
return '';
|
||||
}
|
||||
else{
|
||||
return $requestToken;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $addressId
|
||||
* @param DateTimeInterface $date
|
||||
* @param string $type
|
||||
* @param string $comment
|
||||
* @param string $time
|
||||
* @param string $requestToken
|
||||
*/
|
||||
public function changeDayType(
|
||||
int $addressId,
|
||||
DateTimeInterface $date,
|
||||
string $type,
|
||||
string $comment,
|
||||
string $time,
|
||||
string $requestToken = ''
|
||||
): void {
|
||||
$this->clearDayType($addressId, $date, $type);
|
||||
|
||||
if ($type !== self::NONE) {
|
||||
$this->targetHourWrapper->handleType($addressId, $date, $type, true, $time, $requestToken);
|
||||
} else {
|
||||
if (!empty($requestToken)) {
|
||||
$this->targetHourService->updateVacationRequestToken($addressId, $date, $requestToken);
|
||||
}
|
||||
}
|
||||
|
||||
if (!empty($comment)) {
|
||||
$this->targetHourWrapper->saveComment($addressId, $date, $comment);
|
||||
}
|
||||
|
||||
$this->targetHourWrapper->recalculate($addressId, $date);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $addressId
|
||||
* @param DateTimeInterface $date
|
||||
* @param string $type
|
||||
*/
|
||||
private function clearDayType(int $addressId, DateTimeInterface $date, string $type): void
|
||||
{
|
||||
$types = [
|
||||
TimeManagementModule::UNPAID,
|
||||
TimeManagementModule::ABSENT_DAY,
|
||||
|
||||
TimeManagementModule::VACATION,
|
||||
TimeManagementModule::VACATIONREQUEST,
|
||||
TimeManagementModule::VACATIONREJECT,
|
||||
TimeManagementModule::VACATIONREMOVE,
|
||||
|
||||
TimeManagementModule::SICK,
|
||||
TimeManagementModule::SICKREQUEST,
|
||||
TimeManagementModule::SICKREMOVE,
|
||||
TimeManagementModule::SICKREJECT,
|
||||
];
|
||||
|
||||
if ($type != TimeManagementModule::NONE) {
|
||||
unset($types[$type]);
|
||||
}
|
||||
|
||||
$this->targetHourWrapper->handleType($addressId, $date, implode('', $types), false);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $employeeAddressId
|
||||
* @param int $supervisorAddressId
|
||||
* @param bool $isReject
|
||||
* @param string $internalComment
|
||||
* @param string $requestToken
|
||||
*
|
||||
* @throws InvalidDateFormatException
|
||||
* @throws InvalidRequestTokenException
|
||||
*/
|
||||
public function handleRequestedDays(
|
||||
int $employeeAddressId,
|
||||
int $supervisorAddressId,
|
||||
bool $isReject,
|
||||
string $internalComment,
|
||||
string $requestToken
|
||||
): void {
|
||||
$requestedDays = $this->targetHourGateway->getRequestedDaysByToken($requestToken);
|
||||
|
||||
if (!empty($requestedDays)) {
|
||||
$from = $requestedDays[0]['date'];
|
||||
$till = $requestedDays[count($requestedDays) - 1]['date'];
|
||||
|
||||
$oldType = $requestedDays[0]['type'];
|
||||
$newType = $this->evaluateNextDayType($oldType, $isReject);
|
||||
|
||||
$this->historyService->saveActivity(
|
||||
0,
|
||||
$supervisorAddressId,
|
||||
$oldType,
|
||||
$newType,
|
||||
$requestToken,
|
||||
$from,
|
||||
$till,
|
||||
$internalComment
|
||||
);
|
||||
|
||||
$date = new DateTimeImmutable();
|
||||
$requestToken = (string)$date->getTimestamp();
|
||||
|
||||
foreach ($requestedDays as $requestedDay) {
|
||||
$this->targetHourService->updateTargetHourType(
|
||||
$employeeAddressId,
|
||||
$requestedDay['date'],
|
||||
$requestedDay['type'],
|
||||
$newType
|
||||
);
|
||||
$this->targetHourService->updateVacationRequestToken(
|
||||
$employeeAddressId,
|
||||
$requestedDay['date'],
|
||||
$requestToken
|
||||
);
|
||||
$this->targetHourWrapper->recalculate($employeeAddressId,$requestedDay['date']);
|
||||
}
|
||||
}
|
||||
|
||||
if (!empty($internalComment)) {
|
||||
$this->targetHourService->saveInternalComment($requestToken, $internalComment);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $daysTillDeletion
|
||||
* @param int $addressId
|
||||
*
|
||||
* @throws InvalidDateFormatException
|
||||
*/
|
||||
public function removeRejectedAfterXDays(int $daysTillDeletion, int $addressId): void
|
||||
{
|
||||
$rejectedDays = $this->targetHourGateway->findRejectedDays($daysTillDeletion, $addressId);
|
||||
|
||||
if (!empty($rejectedDays)) {
|
||||
foreach ($rejectedDays as $day) {
|
||||
$this->clearDayType($addressId, $day['date'], TimeManagementModule::NONE);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $addressId
|
||||
* @param int $groupId
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function checkAddressHasGroup(int $addressId, int $groupId): bool
|
||||
{
|
||||
return $this->groupGateway->isAddressInGroup($addressId, $groupId);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $type
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function mapTypeToLanguage(string $type): string
|
||||
{
|
||||
$mapping =
|
||||
[
|
||||
self::NONE => 'Kein Status',
|
||||
self::VACATION => 'Urlaub',
|
||||
self::VACATIONREQUEST => 'Urlaubsantrag',
|
||||
self::VACATIONREJECT => 'Urlaub ablehnen',
|
||||
self::VACATIONREMOVE => 'Urlaub entfernen',
|
||||
self::SICK => 'Krank',
|
||||
self::SICKREQUEST => 'Krankheitsantrag',
|
||||
self::SICKREMOVE => 'Krankheit entfernen',
|
||||
self::SICKREJECT => 'Krankheit ablehnen',
|
||||
self::UNPAID => 'Unbezahlter Urlaub',
|
||||
self::ABSENT_DAY => 'Fehltag',
|
||||
];
|
||||
|
||||
return $mapping[$type];
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $employeeAddressId
|
||||
* @param int $groupId
|
||||
*
|
||||
* @throws SupervisorNotFoundException
|
||||
*
|
||||
* @return int[]
|
||||
*/
|
||||
public function getSupervisorAddressIds(int $employeeAddressId, int $groupId): array
|
||||
{
|
||||
return $this->groupGateway->getSupervisorAddressIds($employeeAddressId, $groupId);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,52 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Xentral\Modules\TimeManagement\Wrapper;
|
||||
|
||||
use erpAPI;
|
||||
use Xentral\Modules\TimeManagement\Exception\EmailNotSentException;
|
||||
use Xentral\Modules\TimeManagement\Exception\EmailAccountNotFoundException;
|
||||
|
||||
final class TimeManagementMailerWrapper
|
||||
{
|
||||
|
||||
/** @var erpAPI erp */
|
||||
private $erp;
|
||||
|
||||
/**
|
||||
* @param erpAPI $erp
|
||||
*/
|
||||
public function __construct(erpAPI $erp)
|
||||
{
|
||||
$this->erp = $erp;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $senderEmail
|
||||
* @param string[] $recipientEmails
|
||||
* @param string $mailSubject
|
||||
* @param string $mailContent
|
||||
*
|
||||
* @throws EmailAccountNotFoundException
|
||||
* @throws EmailNotSentException
|
||||
*/
|
||||
public function send(string $senderEmail, array $recipientEmails, string $mailSubject, string $mailContent): void
|
||||
{
|
||||
foreach ($recipientEmails as $email) {
|
||||
$isSent = $this->erp->MailSend(
|
||||
$this->erp->GetFirmaMail(),
|
||||
$senderEmail,
|
||||
$email,
|
||||
'',
|
||||
$mailSubject,
|
||||
$mailContent,
|
||||
"",
|
||||
""
|
||||
);
|
||||
if (!$isSent) {
|
||||
throw new EmailNotSentException('Mail could not be sent. More info in the logger');
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,69 @@
|
||||
<?php
|
||||
|
||||
namespace Xentral\Modules\TimeManagement\Wrapper;
|
||||
|
||||
use DateTimeInterface;
|
||||
use Mitarbeiterzeiterfassung;
|
||||
|
||||
final class TimeManagementTargetHourWrapper
|
||||
{
|
||||
|
||||
/** @var Mitarbeiterzeiterfassung $timeRecordingModule */
|
||||
private $timeRecordingModule;
|
||||
|
||||
public function __construct(Mitarbeiterzeiterfassung $timeRecordingModule)
|
||||
{
|
||||
$this->timeRecordingModule = $timeRecordingModule;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $address_id
|
||||
* @param DateTimeInterface $date
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function recalculate(int $address_id, DateTimeInterface $date): bool
|
||||
{
|
||||
return $this->timeRecordingModule->MitarbeitererfassungIstNeuberechnen($address_id, $date->format('Y-m-d'));
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $addressId
|
||||
* @param DateTimeInterface $date
|
||||
* @param string $type
|
||||
* @param bool $add
|
||||
* @param string $time
|
||||
* @param string $requestToken
|
||||
*/
|
||||
public function handleType(
|
||||
int $addressId,
|
||||
DateTimeInterface $date,
|
||||
string $type,
|
||||
bool $add = true,
|
||||
string $time = '0',
|
||||
string $requestToken = ''
|
||||
): void {
|
||||
$this->timeRecordingModule->MitarbeiterzeiterfassungInsertUpdateKuerzel(
|
||||
$addressId,
|
||||
$date->format('Y-m-d'),
|
||||
$type,
|
||||
$add,
|
||||
$time,
|
||||
$requestToken
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $addressId
|
||||
* @param DateTimeInterface $date
|
||||
* @param string $comment
|
||||
*/
|
||||
public function saveComment(int $addressId, DateTimeInterface $date, string $comment): void
|
||||
{
|
||||
$this->timeRecordingModule->MitarbeiterzeiterfassungInsertUpdateKommentar(
|
||||
$addressId,
|
||||
$date->format('Y-m-d'),
|
||||
$comment
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,205 @@
|
||||
:root{
|
||||
--calendar-vacation-standard: var(--xentral-signature-green); /* green */
|
||||
--calendar-vacation-away: rgba(44, 229, 162, 0.63);
|
||||
--calendar-vacation-request: rgba(44, 229, 162, 0.25);
|
||||
|
||||
--calendar-vacation-reject: var(--xentral-signature-petrol); /* petrol */
|
||||
--calendar-vacation-remove: rgba(59, 184, 195, 0.5);
|
||||
|
||||
--calendar-sick-standard:var(--xentral-signature-pink); /* pink */
|
||||
--calendar-sick-request: rgba(229, 110, 202, 0.25);
|
||||
|
||||
--calendar-sick-reject: var(--xentral-signature-orange); /* orange */
|
||||
--calendar-sick-remove: rgba(238, 134, 103, 0.5);
|
||||
|
||||
--calendar-unpaid-standard: var(--xentral-signature-violet); /* violett */
|
||||
--calendar-absent-standard: var(--xentral-signature-blue); /* blue */
|
||||
}
|
||||
|
||||
#easycalendar {
|
||||
display: grid;
|
||||
grid-template-columns: 7% repeat(31, 3%);
|
||||
box-sizing: border-box;
|
||||
color: #6d6d6f;
|
||||
}
|
||||
|
||||
#easycalendar-legend {
|
||||
border-top:1px solid var(--current-grey);
|
||||
padding: 15px 0 15px 0;
|
||||
}
|
||||
|
||||
#easycalendar-legend span{
|
||||
line-height:1.5em;
|
||||
}
|
||||
|
||||
#easycalendar-legend .txt{
|
||||
padding: 0 5px 0 3px;
|
||||
}
|
||||
|
||||
#easycalendar-legend .box{
|
||||
margin: 0 0 0 5px;
|
||||
color: transparent;
|
||||
}
|
||||
|
||||
#easycalendar .standard,
|
||||
#easycalendar .saturday,
|
||||
#easycalendar .sunday,
|
||||
#easycalendar .holiday,
|
||||
#easycalendar .vacation,
|
||||
#easycalendar .unpaid,
|
||||
#easycalendar .sick,
|
||||
#easycalendar .requestsick,
|
||||
#easycalendar .absent,
|
||||
#easycalendar .away,
|
||||
#easycalendar .requested,
|
||||
#easycalendar .noday,
|
||||
#easycalendar .rejected,
|
||||
#easycalendar .remove{
|
||||
box-sizing: border-box;
|
||||
border-top:1px solid var(--current-grey);
|
||||
border-left:1px solid var(--current-grey);
|
||||
color:#fff;
|
||||
text-align:center;
|
||||
}
|
||||
|
||||
#easycalendar .month,
|
||||
#easycalendar .top {
|
||||
box-sizing: border-box;
|
||||
font-weight:bold;
|
||||
padding: 3px 0 4px 4px;
|
||||
}
|
||||
|
||||
#easycalendar .month {
|
||||
border-top:1px solid var(--current-grey);
|
||||
}
|
||||
|
||||
#easycalendar .employee-name {
|
||||
box-sizing: border-box;
|
||||
font-style:italic;
|
||||
padding: 3px 0 4px 10px;
|
||||
}
|
||||
|
||||
#easycalendar .top {
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
#easycalendar.monclick .monday,
|
||||
#easycalendar.tueclick .tuesday,
|
||||
#easycalendar.wedclick .wednesday,
|
||||
#easycalendar.thuclick .thursday,
|
||||
#easycalendar.friclick .friday,
|
||||
#easycalendar.satclick .saturday,
|
||||
#easycalendar.sunclick .sunday{
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
#easycalendar.monclick .monday:hover,
|
||||
#easycalendar.tueclick .tuesday:hover,
|
||||
#easycalendar.wedclick .wednesday:hover,
|
||||
#easycalendar.thuclick .thursday:hover,
|
||||
#easycalendar.friclick .friday:hover,
|
||||
#easycalendar.satclick .saturday:hover,
|
||||
#easycalendar.sunclick .sunday:hover{
|
||||
background-color:var(--xentral-signature-violet-transparent);
|
||||
}
|
||||
|
||||
#easycalendar .saturday,
|
||||
#easycalendar .sunday,
|
||||
#easycalendar .holiday {
|
||||
background-color:var(--current-grey);
|
||||
}
|
||||
|
||||
#easycalendar .noday {
|
||||
background-color:#fff;
|
||||
}
|
||||
#easycalendar-legend .unpaid,
|
||||
#easycalendar .unpaid {
|
||||
background-color: var(--calendar-unpaid-standard);
|
||||
}
|
||||
|
||||
#easycalendar-legend .absent,
|
||||
#easycalendar .absent {
|
||||
background-color: var(--calendar-absent-standard);
|
||||
}
|
||||
|
||||
#easycalendar-legend .away,
|
||||
#easycalendar .away {
|
||||
background-color: var(--calendar-vacation-away);
|
||||
}
|
||||
|
||||
#easycalendar-legend .vacation,
|
||||
#easycalendar .vacation {
|
||||
background-color: var(--calendar-vacation-standard);
|
||||
}
|
||||
|
||||
#easycalendar-legend .request-vacation,
|
||||
#easycalendar .request-vacation {
|
||||
background-color: var(--calendar-vacation-request);
|
||||
}
|
||||
|
||||
#easycalendar-legend .reject-vacation,
|
||||
#easycalendar .reject-vacation {
|
||||
background-color: var(--calendar-vacation-reject);
|
||||
}
|
||||
|
||||
#easycalendar-legend .remove-vacation,
|
||||
#easycalendar .remove-vacation {
|
||||
background-color: var(--calendar-vacation-remove);
|
||||
}
|
||||
|
||||
#easycalendar-legend .sick,
|
||||
#easycalendar .sick {
|
||||
background-color: var(--calendar-sick-standard);
|
||||
}
|
||||
|
||||
#easycalendar-legend .request-sick,
|
||||
#easycalendar .request-sick {
|
||||
background-color: var(--calendar-sick-request);
|
||||
}
|
||||
|
||||
#easycalendar-legend .reject-sick,
|
||||
#easycalendar .reject-sick {
|
||||
background-color: var(--calendar-sick-reject);
|
||||
}
|
||||
|
||||
#easycalendar-legend .remove-sick,
|
||||
#easycalendar .remove-sick {
|
||||
background-color: var(--calendar-sick-remove);
|
||||
}
|
||||
|
||||
#easycalendar .unpaid.half,
|
||||
#easycalendar .absent.half,
|
||||
#easycalendar .away.half,
|
||||
#easycalendar .vacation.half,
|
||||
#easycalendar .request-vacation.half,
|
||||
#easycalendar .reject-vacation.half,
|
||||
#easycalendar .remove-vacation.half,
|
||||
#easycalendar .sick.half,
|
||||
#easycalendar .request-sick.half,
|
||||
#easycalendar .reject-sick.half,
|
||||
#easycalendar .remove-sick.half {
|
||||
color: transparent;
|
||||
shape-outside: polygon(
|
||||
0 0,
|
||||
0 100%,
|
||||
100% 0
|
||||
);
|
||||
|
||||
clip-path: polygon(
|
||||
0 0,
|
||||
0 100%,
|
||||
100% 0
|
||||
);
|
||||
}
|
||||
|
||||
#easycalendar .inline {
|
||||
display: inline-block;
|
||||
height:100%;
|
||||
border: 0 none;
|
||||
text-align: center;
|
||||
padding: 3px 0 0 0;
|
||||
}
|
||||
|
||||
#easycalendar .today {
|
||||
color:var(--calendar-vacation-standard);
|
||||
}
|
||||
@@ -0,0 +1,421 @@
|
||||
var TimeManagementEasyCalendar = (function ($) {
|
||||
'use strict';
|
||||
|
||||
var me = {
|
||||
isInitialized: false,
|
||||
|
||||
selector: {
|
||||
easyCalendar: '#easycalendar',
|
||||
easyCalendarLegend: '#easycalendar-legend',
|
||||
calendarattributes: '#calendarattributes'
|
||||
},
|
||||
|
||||
storage: {
|
||||
days: [],
|
||||
dataEndpoint: '',
|
||||
monthNames: [
|
||||
'Januar', 'Februar', 'März', 'April', 'Mai',
|
||||
'Juni', 'Juli', 'August', 'September', 'Oktober', 'November', 'Dezember'],
|
||||
statusMapping: {
|
||||
'unpaid': 'Unbezahlt',
|
||||
'absent': 'Fehltag',
|
||||
'away': 'Abwesend',
|
||||
'vacation': 'Urlaub',
|
||||
'request-vacation': 'Urlaubsantrag',
|
||||
'remove-vacation': 'Stornoantrag Urlaub',
|
||||
'sick': 'Krank',
|
||||
'request-sick': 'Krankheitsantrag',
|
||||
'remove-sick': 'Stornoantrag Krankheit'
|
||||
}
|
||||
},
|
||||
|
||||
init: function () {
|
||||
if (me.isInitialized === true) {
|
||||
return;
|
||||
}
|
||||
me.registerMonthNames();
|
||||
me.drawCalendar();
|
||||
me.drawLegend();
|
||||
},
|
||||
|
||||
drawLegend: function () {
|
||||
|
||||
for (let statusClass in me.storage.statusMapping) {
|
||||
let statusTxt = me.storage.statusMapping[statusClass];
|
||||
|
||||
let html = '<span class="' + statusClass + ' box">m</span><span class="txt">' + statusTxt + '</span>';
|
||||
|
||||
$(me.selector.easyCalendarLegend).append(html);
|
||||
}
|
||||
},
|
||||
|
||||
registerMonthNames: function () {
|
||||
|
||||
if ($(me.selector.calendarattributes).length !== 0) {
|
||||
try {
|
||||
let calendarattributes = JSON.parse($(me.selector.calendarattributes).html());
|
||||
me.storage.monthNames = calendarattributes.monthNames;
|
||||
}
|
||||
catch (e) {
|
||||
//do nothing, fallback from storage
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
drawCalendar: function () {
|
||||
|
||||
me.storage.dataEndpoint = $(me.selector.easyCalendar).data('endpoint');
|
||||
|
||||
$.ajax({
|
||||
url: me.storage.dataEndpoint,
|
||||
type: 'POST',
|
||||
dataType: 'json',
|
||||
success: function (data) {
|
||||
|
||||
if (data.error) {
|
||||
me.storage.$dialog.find(me.selector.msg).text(data.error);
|
||||
} else {
|
||||
let formattedData = [];
|
||||
if (data.is_expanded === true) {
|
||||
formattedData = me.buildCalendarDataExpanded(data.holidays, data.calendar_data,
|
||||
data.calendar_year);
|
||||
} else {
|
||||
formattedData = me.buildCalendarDataSummed(data.holidays, data.calendar_data,
|
||||
data.calendar_year);
|
||||
}
|
||||
|
||||
let html = '';
|
||||
for (let i = 0; i < formattedData.length; i++) {
|
||||
html +=
|
||||
'<div ' +
|
||||
'class="' + formattedData[i].class + '" ' +
|
||||
'title="' + formattedData[i].title + '" ' +
|
||||
'data-day="' + formattedData[i].day + '" ' +
|
||||
'data-month="' + formattedData[i].month + '" ' +
|
||||
'data-year="' + formattedData[i].year + '" ' +
|
||||
'>' +
|
||||
formattedData[i].txt +
|
||||
'</div>';
|
||||
}
|
||||
|
||||
$(me.selector.easyCalendar).append(html);
|
||||
}
|
||||
},
|
||||
beforeSend: function () {}
|
||||
});
|
||||
},
|
||||
|
||||
buildCalendarDataExpanded: function (holidays, vacations, year) {
|
||||
|
||||
let dayAmount = 31;
|
||||
let monthAmount = 12;
|
||||
|
||||
let currentMonth = new Date().getMonth() + 1;
|
||||
|
||||
let allDays = me.buildCalendarFirstLine(year, dayAmount);
|
||||
|
||||
for (let month = 1; month <= monthAmount; month++) {
|
||||
|
||||
let daysInMonth = me.daysInMonth(year, month);
|
||||
let monthName = me.storage.monthNames[month - 1];
|
||||
|
||||
allDays.push({
|
||||
txt: monthName,
|
||||
class: (currentMonth === month ? 'month today' : 'month'),
|
||||
title: '',
|
||||
year: year,
|
||||
month: month,
|
||||
day: 0
|
||||
});
|
||||
|
||||
// first line with month
|
||||
for (let day = 1; day <= dayAmount; day++) {
|
||||
|
||||
let classAndTitle = me.findClassAndTitle(daysInMonth, holidays, year, month, day);
|
||||
let htmlClass = classAndTitle.htmlClass;
|
||||
let title = classAndTitle.title;
|
||||
|
||||
allDays.push({
|
||||
txt: '',
|
||||
class: htmlClass,
|
||||
title: title,
|
||||
year: year,
|
||||
month: month,
|
||||
day: day
|
||||
});
|
||||
}
|
||||
|
||||
// month info by employee
|
||||
if (vacations) {
|
||||
for (let employeeName in vacations) {
|
||||
|
||||
if (vacations.hasOwnProperty(employeeName)) {
|
||||
let employeeVacation = vacations[employeeName];
|
||||
|
||||
allDays.push({
|
||||
txt: employeeName,
|
||||
class: 'employee-name',
|
||||
title: '',
|
||||
year: year,
|
||||
month: month,
|
||||
day: 0
|
||||
});
|
||||
|
||||
for (let day = 1; day <= dayAmount; day++) {
|
||||
|
||||
let classAndTitle = me.findClassAndTitle(daysInMonth, holidays, year, month, day);
|
||||
let htmlClass = classAndTitle.htmlClass;
|
||||
let title = classAndTitle.title;
|
||||
|
||||
let date = me.buildDateString(year, month, day);
|
||||
if (date in employeeVacation) {
|
||||
|
||||
let type = employeeVacation[date];
|
||||
htmlClass += ' ' + type;
|
||||
title = me.mapTypeToName(type) + ': ' + employeeName;
|
||||
}
|
||||
|
||||
allDays.push({
|
||||
txt: '',
|
||||
class: htmlClass,
|
||||
title: title,
|
||||
year: year,
|
||||
month: month,
|
||||
day: day
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return allDays;
|
||||
},
|
||||
|
||||
mapTypeToName: function (type) {
|
||||
|
||||
if (type.search('half')) {
|
||||
type = type.replace('half', '').trim();
|
||||
}
|
||||
|
||||
|
||||
if (type in me.storage.statusMapping) {
|
||||
return me.storage.statusMapping[type];
|
||||
}
|
||||
return '';
|
||||
},
|
||||
|
||||
buildCalendarFirstLine: function (year, dayAmount) {
|
||||
|
||||
let allDays = [];
|
||||
|
||||
let currentDay = new Date().getDate();
|
||||
|
||||
//first line with day-numbers
|
||||
for (let day = 0; day <= dayAmount; day++) {
|
||||
|
||||
if (day === 0) {
|
||||
allDays.push({
|
||||
txt: '',
|
||||
class: 'top',
|
||||
title: '',
|
||||
year: year,
|
||||
month: 0,
|
||||
day: 0
|
||||
});
|
||||
} else {
|
||||
allDays.push({
|
||||
txt: day,
|
||||
class: (day === currentDay ? 'top today' : 'top'),
|
||||
title: '',
|
||||
year: year,
|
||||
month: 0,
|
||||
day: 0
|
||||
});
|
||||
}
|
||||
}
|
||||
return allDays;
|
||||
},
|
||||
|
||||
buildCalendarDataSummed: function (holidays, vacations, year) {
|
||||
|
||||
let dayAmount = 31;
|
||||
let monthAmount = 12;
|
||||
|
||||
let summedVacations = me.sumVacations(vacations);
|
||||
let allDays = me.buildCalendarFirstLine(year, dayAmount);
|
||||
|
||||
let currentMonth = new Date().getMonth() + 1;
|
||||
|
||||
for (let month = 1; month <= monthAmount; month++) {
|
||||
|
||||
let daysInMonth = me.daysInMonth(year, month);
|
||||
let monthName = me.storage.monthNames[month - 1];
|
||||
|
||||
allDays.push({
|
||||
txt: monthName,
|
||||
class: (currentMonth === month ? 'month today' : 'month'),
|
||||
title: '',
|
||||
year: year,
|
||||
month: month,
|
||||
day: 0
|
||||
});
|
||||
|
||||
for (let day = 1; day <= dayAmount; day++) {
|
||||
|
||||
let classAndTitle = me.findClassAndTitle(daysInMonth, holidays, year, month, day);
|
||||
let htmlClass = classAndTitle.htmlClass;
|
||||
let title = classAndTitle.title;
|
||||
|
||||
let date = me.buildDateString(year, month, day);
|
||||
|
||||
if (summedVacations.hasOwnProperty(date)) {
|
||||
|
||||
let txt = '';
|
||||
let typeAddress = summedVacations[date];
|
||||
|
||||
let countTypes = 0;
|
||||
for (let type in typeAddress) {
|
||||
countTypes++;
|
||||
}
|
||||
|
||||
for (let type in typeAddress) {
|
||||
if (typeAddress.hasOwnProperty(type)) {
|
||||
let addresses = typeAddress[type];
|
||||
txt +=
|
||||
'<div class="' + type + ' inline" ' +
|
||||
'title="' + me.mapTypeToName(type) + ': ' + addresses.join(', ') + '" ' +
|
||||
'style="width:' + Math.floor(100 / countTypes) + '%">' +
|
||||
(addresses.length === 1 ? '' : addresses.length) +
|
||||
'</div>';
|
||||
}
|
||||
}
|
||||
|
||||
allDays.push({
|
||||
txt: txt,
|
||||
class: htmlClass,
|
||||
title: title,
|
||||
year: year,
|
||||
month: month,
|
||||
day: day
|
||||
});
|
||||
} else {
|
||||
allDays.push({
|
||||
txt: '',
|
||||
class: htmlClass,
|
||||
title: title,
|
||||
year: year,
|
||||
month: month,
|
||||
day: day
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
return allDays;
|
||||
},
|
||||
|
||||
sumVacations: function (vacations) {
|
||||
|
||||
let summedVacation = {};
|
||||
|
||||
for (let employeeName in vacations) {
|
||||
if (vacations.hasOwnProperty(employeeName)) {
|
||||
|
||||
let employeeVacation = vacations[employeeName];
|
||||
|
||||
for (let date in employeeVacation) {
|
||||
if (employeeVacation.hasOwnProperty(date)) {
|
||||
|
||||
let type = employeeVacation[date];
|
||||
|
||||
if (summedVacation.hasOwnProperty(date)) {
|
||||
|
||||
let typeAddress = summedVacation[date];
|
||||
if (typeAddress.hasOwnProperty(type)) {
|
||||
|
||||
let addresses = typeAddress[type];
|
||||
addresses.push(employeeName);
|
||||
typeAddress[type] = addresses;
|
||||
summedVacation[date] = typeAddress;
|
||||
} else {
|
||||
|
||||
let typeAddress = summedVacation[date];
|
||||
typeAddress[type] = [employeeName];
|
||||
summedVacation[date] = typeAddress;
|
||||
}
|
||||
} else {
|
||||
|
||||
let typeAddress = {};
|
||||
typeAddress[type] = [employeeName];
|
||||
summedVacation[date] = typeAddress;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return summedVacation;
|
||||
},
|
||||
|
||||
buildDateString: function (year, month, day) {
|
||||
return year + '-' + (month < 10 ? '0' + month : month) + '-' + (day < 10 ? '0' + day : day);
|
||||
},
|
||||
|
||||
findClassAndTitle: function (daysInMonth, holidays, year, month, day) {
|
||||
|
||||
let date = me.buildDateString(year, month, day);
|
||||
|
||||
let htmlClass = 'standard';
|
||||
let title = '';
|
||||
|
||||
//always counting to 31, therefore some days dont exist
|
||||
if (day > daysInMonth) {
|
||||
htmlClass = 'noday';
|
||||
}
|
||||
|
||||
if (me.isSaturday(date) || me.isSunday(date)) {
|
||||
htmlClass = me.getWeekDayName(date);
|
||||
} else {
|
||||
htmlClass += ' ' + me.getWeekDayName(date);
|
||||
}
|
||||
|
||||
// is a holiday
|
||||
if (date in holidays) {
|
||||
htmlClass = 'holiday';
|
||||
title = holidays[date];
|
||||
}
|
||||
|
||||
return {
|
||||
htmlClass: htmlClass,
|
||||
title: title
|
||||
};
|
||||
},
|
||||
|
||||
daysInMonth: function (year, month) {
|
||||
return new Date(year, month, 0).getDate();
|
||||
},
|
||||
|
||||
isSaturday: function (dateString) {
|
||||
let day = new Date(dateString).getDay();
|
||||
return (day === 6);
|
||||
},
|
||||
|
||||
isSunday: function (dateString) {
|
||||
let day = new Date(dateString).getDay();
|
||||
return (day === 0);
|
||||
},
|
||||
|
||||
getWeekDayName: function (dateString) {
|
||||
let weekdays = ['sunday', 'monday', 'tuesday', 'wednesday', 'thursday', 'friday', 'saturday'];
|
||||
let day = new Date(dateString).getDay();
|
||||
return weekdays[day];
|
||||
}
|
||||
};
|
||||
|
||||
return {
|
||||
init: me.init
|
||||
};
|
||||
|
||||
})(jQuery);
|
||||
|
||||
$(document).ready(function () {
|
||||
TimeManagementEasyCalendar.init();
|
||||
});
|
||||
@@ -0,0 +1,162 @@
|
||||
var TimeManagementHandle = (function ($) {
|
||||
'use strict';
|
||||
|
||||
var me = {
|
||||
isInitialized: false,
|
||||
|
||||
selector: {
|
||||
handleDialog: '#timemanagement-handle-dialog',
|
||||
form: '#timemanagement-handle-form',
|
||||
msg: '#timemanagement-handle-msg',
|
||||
overviewTable: '#requesteddaystatus',
|
||||
clickClass: '.handle-day-status',
|
||||
commentSpan: '#comment',
|
||||
fromSpan: '#from',
|
||||
tillSpan: '#till',
|
||||
amountSpan: '#amount',
|
||||
employeeNameSpan: '#employee-name',
|
||||
employeeNumberSpan: '#employee-number',
|
||||
requestTokenHidden: '#request-token',
|
||||
requestAddressIdHidden: '#request-address-id',
|
||||
requestRejectHidden: '#request-reject',
|
||||
deleteTitle: '#delete-title',
|
||||
requestTitle: '#request-title',
|
||||
defaultNoteVacation: '#default-note-vacation',
|
||||
defaultNoteSick: '#default-note-sick',
|
||||
internalComment: '#internal-comment'
|
||||
|
||||
},
|
||||
|
||||
storage: {
|
||||
$dialog: null
|
||||
},
|
||||
|
||||
init: function () {
|
||||
if (me.isInitialized === true) {
|
||||
return;
|
||||
}
|
||||
|
||||
me.storage.$dialog = $(me.selector.handleDialog);
|
||||
me.dialogInit();
|
||||
me.registerEvents();
|
||||
me.isInitialized = true;
|
||||
},
|
||||
|
||||
registerEvents: function () {
|
||||
|
||||
$(me.selector.overviewTable).on('click', me.selector.clickClass, function (event) {
|
||||
event.preventDefault();
|
||||
me.dialogOpen(this.id.replace('vac-', ''));
|
||||
});
|
||||
},
|
||||
|
||||
dialogInit: function () {
|
||||
me.storage.$dialog.dialog({
|
||||
modal: true,
|
||||
bgiframe: true,
|
||||
closeOnEscape: false,
|
||||
minWidth: 650,
|
||||
minHeight: 200,
|
||||
autoOpen: false,
|
||||
open: function () {
|
||||
$(me.selector.inputKey).trigger('focus');
|
||||
},
|
||||
close: function () {
|
||||
me.dialogReset();
|
||||
},
|
||||
buttons: {
|
||||
|
||||
ZUSTIMMEN: function () {
|
||||
$(me.selector.form).submit();
|
||||
},
|
||||
|
||||
ABLEHNEN: function () {
|
||||
$(me.selector.requestRejectHidden).val(1);
|
||||
$(me.selector.form).submit();
|
||||
}
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
dialogOpen: function (requestToken) {
|
||||
|
||||
$.ajax({
|
||||
url: 'index.php?module=mitarbeiterzeiterfassung&action=timemanagementhandle&cmd=timemanagementhandleinfo',
|
||||
type: 'POST',
|
||||
dataType: 'json',
|
||||
data: {
|
||||
requestToken: requestToken
|
||||
},
|
||||
success: function (data) {
|
||||
|
||||
if (data.error) {
|
||||
me.storage.$dialog.find(me.selector.msg).text(data.error);
|
||||
} else {
|
||||
|
||||
me.dialogReset();
|
||||
|
||||
let title = '';
|
||||
if (data.type === 'L' || data.type === 'V') {
|
||||
title = $(me.selector.deleteTitle).text();
|
||||
} else {
|
||||
title = $(me.selector.requestTitle).text();
|
||||
}
|
||||
|
||||
let defaultNote = '';
|
||||
if(data.type === 'S'){
|
||||
defaultNote = $(me.selector.defaultNoteSick).text();
|
||||
}
|
||||
|
||||
if(data.type === 'R'){
|
||||
defaultNote = $(me.selector.defaultNoteVacation).text();
|
||||
}
|
||||
|
||||
me.storage.$dialog.find(me.selector.commentSpan).text(data.comment);
|
||||
me.storage.$dialog.find(me.selector.fromSpan).text(data.min_date);
|
||||
me.storage.$dialog.find(me.selector.tillSpan).text(data.max_date);
|
||||
me.storage.$dialog.find(me.selector.amountSpan).text(data.amount);
|
||||
me.storage.$dialog.find(me.selector.employeeNameSpan).text(data.employee_name);
|
||||
me.storage.$dialog.find(me.selector.employeeNumberSpan).text(data.employee_number);
|
||||
me.storage.$dialog.find(me.selector.internalComment).val(defaultNote);
|
||||
|
||||
me.storage.$dialog.find(me.selector.requestTokenHidden).val(requestToken);
|
||||
me.storage.$dialog.find(me.selector.requestAddressIdHidden).val(data.employee_id);
|
||||
|
||||
me.storage.$dialog.dialog('option', 'title', title);
|
||||
me.storage.$dialog.dialog('open');
|
||||
}
|
||||
},
|
||||
beforeSend: function () {}
|
||||
});
|
||||
|
||||
},
|
||||
|
||||
dialogClose: function () {
|
||||
me.storage.$dialog.dialog('close');
|
||||
},
|
||||
|
||||
dialogReset: function () {
|
||||
|
||||
me.storage.$dialog.find(me.selector.commentSpan).text('');
|
||||
me.storage.$dialog.find(me.selector.fromSpan).text('');
|
||||
me.storage.$dialog.find(me.selector.tillSpan).text('');
|
||||
me.storage.$dialog.find(me.selector.amountSpan).text('');
|
||||
me.storage.$dialog.find(me.selector.employeeNameSpan).text('');
|
||||
me.storage.$dialog.find(me.selector.employeeNumberSpan).text('');
|
||||
me.storage.$dialog.find(me.selector.internalComment).val('');
|
||||
|
||||
me.storage.$dialog.find(me.selector.requestRejectHidden).val(0);
|
||||
me.storage.$dialog.find(me.selector.requestTokenHidden).val(null);
|
||||
me.storage.$dialog.find(me.selector.requestAddressIdHidden).val(null);
|
||||
}
|
||||
};
|
||||
|
||||
return {
|
||||
init: me.init
|
||||
};
|
||||
|
||||
})(jQuery);
|
||||
|
||||
$(document).ready(function () {
|
||||
TimeManagementHandle.init();
|
||||
});
|
||||
@@ -0,0 +1,261 @@
|
||||
var TimeManagementRequest = (function ($) {
|
||||
'use strict';
|
||||
|
||||
var me = {
|
||||
isInitialized: false,
|
||||
|
||||
selector: {
|
||||
msg: '#timemanagement-msg',
|
||||
easyCalendar: '#easycalendar',
|
||||
form: '#timemanagement-form',
|
||||
newEdit: '#timemanagement-new-edit',
|
||||
fromInput: '#from',
|
||||
tillInput: '#till',
|
||||
remainingVacationSpan: '#remaining-vacation',
|
||||
totalVacationSpan: '#total-vacation',
|
||||
acceptedVacationSpan: '#accepted-vacation',
|
||||
commentTextarea: '#comment',
|
||||
newDialog: '#timemanagement-new-dialog',
|
||||
requestTitle: '#request-title',
|
||||
deleteTitle: '#delete-title',
|
||||
calendarattributes: '#calendarattributes',
|
||||
buttonOk: '#button-ok',
|
||||
plannedVacationSpan: '#planned-vacation',
|
||||
statusOldTypeHidden: '#status-old-type',
|
||||
statusWishTypeDiv: '#status-wish-type-box',
|
||||
//internalComment: '#internal-comment',
|
||||
halfday: '#halfday'
|
||||
},
|
||||
|
||||
storage: {
|
||||
$dialog: null,
|
||||
monthNames: [
|
||||
'Januar', 'Februar', 'März', 'April', 'Mai',
|
||||
'Juni', 'Juli', 'August', 'September', 'Oktober', 'November', 'Dezember'],
|
||||
dayNames: ['SO', 'MO', 'DI', 'MI', 'DO', 'FR', 'SA']
|
||||
},
|
||||
|
||||
init: function () {
|
||||
if (me.isInitialized === true) {
|
||||
return;
|
||||
}
|
||||
|
||||
me.storage.$dialog = $(me.selector.newEdit);
|
||||
me.dialogInit();
|
||||
me.registerEvents();
|
||||
me.registerDatepicker(me.selector.fromInput);
|
||||
me.registerDatepicker(me.selector.tillInput);
|
||||
|
||||
me.isInitialized = true;
|
||||
},
|
||||
|
||||
registerDatepicker: function (field) {
|
||||
|
||||
if ($(me.selector.calendarattributes).length !== 0) {
|
||||
try {
|
||||
var calendarattributes = JSON.parse($(me.selector.calendarattributes).html());
|
||||
|
||||
me.storage.monthNames = calendarattributes.monthNames;
|
||||
|
||||
let dayNames = calendarattributes.dayNames;
|
||||
|
||||
let shortNames = [];
|
||||
me.storage.dayNames = [];
|
||||
for (let i = 0; i <= dayNames.length; i++) {
|
||||
let shortname = dayNames[i].toUpperCase().substring(0, 2);
|
||||
me.storage.dayNames.push(shortname);
|
||||
}
|
||||
}
|
||||
catch (e) {
|
||||
//do nothing, fallback from storage
|
||||
}
|
||||
}
|
||||
|
||||
$(field).datepicker({
|
||||
dateFormat: 'dd.mm.yy',
|
||||
dayNamesMin: me.storage.dayNames,
|
||||
firstDay: 1,
|
||||
showWeek: false,
|
||||
monthNames: me.storage.monthNames
|
||||
});
|
||||
},
|
||||
|
||||
registerEvents: function () {
|
||||
|
||||
let clickables = [
|
||||
'monclick',
|
||||
'tueclick',
|
||||
'wedclick',
|
||||
'thuclick',
|
||||
'friclick',
|
||||
'satclick',
|
||||
'sunclick'
|
||||
];
|
||||
|
||||
let clickClasses = [
|
||||
'.monday',
|
||||
'.tuesday',
|
||||
'.wednesday',
|
||||
'.thursday',
|
||||
'.friday',
|
||||
'.saturday',
|
||||
'.sunday'
|
||||
];
|
||||
|
||||
for (let i = 0; i <= clickables.length; i++) {
|
||||
if ($(me.selector.easyCalendar).hasClass(clickables[i])) {
|
||||
$(me.selector.easyCalendar).on('click', clickClasses[i], function (event) {
|
||||
let day = $(this).data('day');
|
||||
let month = $(this).data('month');
|
||||
let year = $(this).data('year');
|
||||
me.dialogOpen(day, month, year);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
$(me.selector.newDialog).on('click', function (event) {
|
||||
event.preventDefault();
|
||||
me.dialogOpen();
|
||||
});
|
||||
},
|
||||
|
||||
dialogInit: function () {
|
||||
me.storage.$dialog.dialog({
|
||||
modal: true,
|
||||
bgiframe: true,
|
||||
closeOnEscape: false,
|
||||
minWidth: 650,
|
||||
minHeight: 350,
|
||||
maxHeight: 500,
|
||||
autoOpen: false,
|
||||
open: function () {
|
||||
if ($(me.selector.fromInput).val() === '') {
|
||||
$(me.selector.fromInput).trigger('focus');
|
||||
} else {
|
||||
$(me.selector.tillInput).trigger('focus');
|
||||
}
|
||||
},
|
||||
|
||||
close: function () {
|
||||
me.dialogReset();
|
||||
},
|
||||
buttons: [
|
||||
{
|
||||
id: 'button-ok',
|
||||
text: 'SPEICHERN',
|
||||
click: function () {
|
||||
$(me.selector.form).submit();
|
||||
}
|
||||
}
|
||||
]
|
||||
});
|
||||
},
|
||||
|
||||
dialogOpen: function (day, month, year) {
|
||||
|
||||
$.ajax({
|
||||
url: 'index.php?module=mitarbeiterzeiterfassung&action=timemanagementrequest&cmd=timemanagementinfo',
|
||||
type: 'POST',
|
||||
dataType: 'json',
|
||||
data: {
|
||||
year: year,
|
||||
month: month,
|
||||
day: day
|
||||
},
|
||||
success: function (data) {
|
||||
|
||||
if (data.error) {
|
||||
me.storage.$dialog.find(me.selector.msg).text(data.error);
|
||||
$(me.selector.msg).addClass('error');
|
||||
} else {
|
||||
|
||||
me.dialogReset();
|
||||
var date = '';
|
||||
|
||||
if (day && month && year) {
|
||||
date = day + '.' + month + '.' + year;
|
||||
}
|
||||
|
||||
let title = '';
|
||||
if (
|
||||
data.day_type !== '' &&
|
||||
data.day_type !== 'C' &&
|
||||
data.day_type !== 'J'
|
||||
) {
|
||||
title = $(me.selector.deleteTitle).text();
|
||||
me.storage.$dialog.find(me.selector.statusOldTypeHidden).val(data.day_type);
|
||||
$(me.selector.statusWishTypeDiv).css('display', 'none');
|
||||
} else {
|
||||
title = $(me.selector.requestTitle).text();
|
||||
}
|
||||
|
||||
if (me.isInPast(day, month, year)) {
|
||||
$(me.selector.msg).text('Der Tag liegt in der Vergangenheit.');
|
||||
if (data.is_accepted_type) {
|
||||
$(me.selector.msg).addClass('error');
|
||||
} else {
|
||||
$(me.selector.msg).addClass('warning');
|
||||
}
|
||||
}
|
||||
|
||||
me.storage.$dialog.find(me.selector.totalVacationSpan).text(data.vacation_total);
|
||||
me.storage.$dialog.find(me.selector.acceptedVacationSpan).text(data.vacation_accepted);
|
||||
me.storage.$dialog.find(me.selector.plannedVacationSpan).text(data.planned);
|
||||
me.storage.$dialog.find(me.selector.remainingVacationSpan).text(
|
||||
data.vacation_total - data.vacation_accepted - data.planned
|
||||
);
|
||||
//me.storage.$dialog.find(me.selector.internalComment).text(data.internal_comment);
|
||||
|
||||
me.storage.$dialog.find(me.selector.fromInput).val(date);
|
||||
me.storage.$dialog.find(me.selector.tillInput).val(date);
|
||||
|
||||
if (me.isInPast(day, month, year) && data.is_accepted_type) {
|
||||
$(me.selector.buttonOk).button('disable');
|
||||
}
|
||||
|
||||
me.storage.$dialog.dialog('option', 'title', title);
|
||||
me.storage.$dialog.dialog('open');
|
||||
}
|
||||
},
|
||||
beforeSend: function () {}
|
||||
});
|
||||
},
|
||||
|
||||
isInPast: function (day, month, year) {
|
||||
let dateString = year + '-' + month + '-' + day;
|
||||
let date = new Date(dateString).setHours(0, 0, 0, 0);
|
||||
let now = new Date().setHours(0, 0, 0, 0);
|
||||
return date < now;
|
||||
},
|
||||
|
||||
dialogClose: function () {
|
||||
me.storage.$dialog.dialog('close');
|
||||
},
|
||||
|
||||
dialogReset: function () {
|
||||
me.storage.$dialog.find(me.selector.fromInput).val(null);
|
||||
me.storage.$dialog.find(me.selector.tillInput).val(null);
|
||||
me.storage.$dialog.find(me.selector.commentTextarea).val(null);
|
||||
me.storage.$dialog.find(me.selector.statusOldTypeHidden).val('');
|
||||
$(me.selector.statusWishTypeDiv).css('display', 'inline');
|
||||
me.storage.$dialog.find(me.selector.halfday).prop('checked', false);
|
||||
|
||||
$(me.selector.msg).removeClass('error');
|
||||
$(me.selector.msg).removeClass('warning');
|
||||
me.storage.$dialog.find(me.selector.msg).text('');
|
||||
$(me.selector.buttonOk).button('enable');
|
||||
|
||||
let title = $(me.selector.requestTitle).text();
|
||||
me.storage.$dialog.dialog('option', 'title', title);
|
||||
}
|
||||
};
|
||||
|
||||
return {
|
||||
init: me.init
|
||||
};
|
||||
|
||||
})(jQuery);
|
||||
|
||||
$(document).ready(function () {
|
||||
TimeManagementRequest.init();
|
||||
});
|
||||
Reference in New Issue
Block a user