Compare commits
3
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
532c0d60e8 | ||
|
|
cf6eff6ab0 | ||
|
|
a964663f51 |
@@ -4,7 +4,7 @@
|
||||
"title": "Zeiterfassung App",
|
||||
"contact": {
|
||||
"name": "Torsten Lücke",
|
||||
"url": "http://torsten-hettstedt.de",
|
||||
"url": "https://torsten-hettstedt.de",
|
||||
"email": "arbeit@torsten-hettstedt.de"
|
||||
},
|
||||
"license": {
|
||||
@@ -188,6 +188,10 @@
|
||||
"type": "string",
|
||||
"pattern": "[0-5]\\d:[0-5]\\d:[0-5]\\d",
|
||||
"example": "08:01:00"
|
||||
},
|
||||
"isHomeOffice": {
|
||||
"description": "Wurde an diesem Tag zuhause gearbeitet?",
|
||||
"type": "boolean"
|
||||
}
|
||||
}
|
||||
},
|
||||
@@ -217,6 +221,10 @@
|
||||
"description": "Arbeitstage im Zeitraum",
|
||||
"type": "integer"
|
||||
},
|
||||
"homeOfficeDays": {
|
||||
"description": "Anzahl der Tage, an denen zuhause gearbeitet wurde.",
|
||||
"type": "number"
|
||||
},
|
||||
"overtime": {
|
||||
"description": "Überstunden im Zeitraum",
|
||||
"type": "string",
|
||||
|
||||
@@ -34,7 +34,7 @@ class WorkingHoursController extends AbstractController
|
||||
{
|
||||
$body = $request->getParsedBody();
|
||||
$repository = new WorkingHoursRepository($this->databases);
|
||||
$model = $this->buildModel($request, $args['id'], $body['workingTime']);
|
||||
$model = $this->buildModel($request, $args['id'], $body['workingTime'], $body['isHomeOfficeDay'] ?? false);
|
||||
try {
|
||||
$repository->update($model);
|
||||
} catch (RepositoryRecordNotFoundException $exception) {
|
||||
@@ -120,7 +120,12 @@ class WorkingHoursController extends AbstractController
|
||||
{
|
||||
$body = $request->getParsedBody();
|
||||
$repository = new WorkingHoursRepository($this->databases);
|
||||
$model = $this->buildModel($request, $body['workingDay'], $body['workingTime']);
|
||||
$model = $this->buildModel(
|
||||
$request,
|
||||
$body['workingDay'],
|
||||
$body['workingTime'],
|
||||
$body['isHomeOfficeDay'] ?? false
|
||||
);
|
||||
try {
|
||||
$repository->insert($model);
|
||||
} catch (RepositoryRecordAlreadyExistException $exception) {
|
||||
@@ -143,7 +148,7 @@ class WorkingHoursController extends AbstractController
|
||||
* @return WorkingHours
|
||||
* @throws HttpBadRequestException
|
||||
*/
|
||||
protected function buildModel(Request $request, string $date, string $time): WorkingHours
|
||||
protected function buildModel(Request $request, string $date, string $time, bool $isHomeOffice): WorkingHours
|
||||
{
|
||||
try {
|
||||
$workingDay = new DateTime($date);
|
||||
@@ -155,7 +160,10 @@ class WorkingHoursController extends AbstractController
|
||||
} catch (Exception $exception) {
|
||||
throw new HttpBadRequestException($request, 'Der Wert für die Zeit ist falsch', $exception);
|
||||
}
|
||||
return (new WorkingHours())->setWorkingDay($workingDay)->setWorkingTime($workingTime);
|
||||
return (new WorkingHours())
|
||||
->setWorkingDay($workingDay)
|
||||
->setWorkingTime($workingTime)
|
||||
->setIsHomeOffice($isHomeOffice);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -10,8 +10,9 @@ use JetBrains\PhpStorm\ArrayShape;
|
||||
|
||||
class WorkingHours implements ModelInterface
|
||||
{
|
||||
protected ?DateTime $workingDay = null;
|
||||
protected ?DateTime $workingDay = null;
|
||||
protected ?DateInterval $workingTime = null;
|
||||
protected bool $isHomeOffice = false;
|
||||
|
||||
public function getWorkingDay(): ?DateTime
|
||||
{
|
||||
@@ -35,15 +36,27 @@ class WorkingHours implements ModelInterface
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function isHomeOffice(): bool
|
||||
{
|
||||
return $this->isHomeOffice;
|
||||
}
|
||||
|
||||
public function setIsHomeOffice(bool $isHomeOffice): WorkingHours
|
||||
{
|
||||
$this->isHomeOffice = $isHomeOffice;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array<string, string>
|
||||
*/
|
||||
#[ArrayShape(['workingDay' => "string", 'workingTime' => "string"])]
|
||||
#[ArrayShape(['workingDay' => "string", 'workingTime' => "string", 'isHomeOffice' => "boolean"])]
|
||||
public function jsonSerialize(): array
|
||||
{
|
||||
return [
|
||||
'workingDay' => $this->getWorkingDay()->format('Y-m-d'),
|
||||
'workingTime' => $this->getWorkingTime()->format('%H:%I:%S')
|
||||
'workingDay' => $this->getWorkingDay()->format('Y-m-d'),
|
||||
'workingTime' => $this->getWorkingTime()->format('%H:%I:%S'),
|
||||
'isHomeOffice' => $this->isHomeOffice(),
|
||||
];
|
||||
}
|
||||
}
|
||||
@@ -16,6 +16,7 @@ class WorkingHoursView implements ModelInterface
|
||||
protected PeriodDesignationEnum $periodDesignation,
|
||||
protected int $workingDays,
|
||||
protected DateInterval $totalHours,
|
||||
private int $homeOfficeDays,
|
||||
protected DateInterval $overtime
|
||||
) {
|
||||
}
|
||||
@@ -35,6 +36,11 @@ class WorkingHoursView implements ModelInterface
|
||||
return $this->workingDays;
|
||||
}
|
||||
|
||||
public function getHomeOfficeDays(): int
|
||||
{
|
||||
return $this->homeOfficeDays;
|
||||
}
|
||||
|
||||
public function getTotalHours(): DateInterval
|
||||
{
|
||||
return $this->totalHours;
|
||||
@@ -45,19 +51,13 @@ class WorkingHoursView implements ModelInterface
|
||||
return $this->overtime;
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*
|
||||
* @return array<string, mixed>
|
||||
*/
|
||||
#[ArrayShape([
|
||||
'period' => "string",
|
||||
'periodDesignation' => "string",
|
||||
'totalHours' => "string",
|
||||
'workingDays' => "int",
|
||||
'overtime' => "string"
|
||||
])]
|
||||
public function jsonSerialize(): array
|
||||
#[ArrayShape(['period' => "string",
|
||||
'periodDesignation' => "string",
|
||||
'totalHours' => "string",
|
||||
'workingDays' => "int",
|
||||
'homeOfficeDays' => "int",
|
||||
'overtime' => "string"
|
||||
])] public function jsonSerialize(): array
|
||||
{
|
||||
$formatOvertime = (($this->getOvertime()->invert === 1) ? '-' : '') . '%H:%I:%S';
|
||||
return [
|
||||
@@ -65,6 +65,7 @@ class WorkingHoursView implements ModelInterface
|
||||
'periodDesignation' => strtolower($this->getPeriodDesignation()->name),
|
||||
'workingDays' => $this->getWorkingDays(),
|
||||
'totalHours' => $this->getTotalHours()->format('%H:%I:%S'),
|
||||
'homeOfficeDays' => $this->getHomeOfficeDays(),
|
||||
'overtime' => $this->getOvertime()->format($formatOvertime)
|
||||
];
|
||||
}
|
||||
|
||||
@@ -49,8 +49,9 @@ abstract class AbstractWorkingHoursViewRepository implements RepositoryReaderInt
|
||||
$model = new WorkingHoursView(
|
||||
$this->buildDateFromPeriod($row['period']),
|
||||
$this->periodDesignation,
|
||||
(int)$row['workingDays'],
|
||||
(int) $row['workingDays'],
|
||||
$this->buildDateInterval($row['totalHours']),
|
||||
(int) $row['homeOfficeDays'],
|
||||
$this->buildDateInterval($row['overtime'])
|
||||
);
|
||||
$models[] = $model;
|
||||
@@ -82,6 +83,7 @@ abstract class AbstractWorkingHoursViewRepository implements RepositoryReaderInt
|
||||
$this->periodDesignation,
|
||||
(int)$row['workingDays'],
|
||||
$this->buildDateInterval($row['totalHours']),
|
||||
(int)$row['homeOfficeDays'],
|
||||
$this->buildDateInterval($row['overtime'])
|
||||
);
|
||||
}
|
||||
|
||||
@@ -12,11 +12,12 @@ use TorstenHettstedt\TimekeepingApi\Models\PeriodDesignationEnum;
|
||||
class WorkingHoursMonthlyViewRepository extends AbstractWorkingHoursViewRepository
|
||||
{
|
||||
|
||||
protected const string SQL_SELECT = <<<SQL
|
||||
protected const SQL_SELECT = <<<SQL
|
||||
select
|
||||
"Monat" as "period",
|
||||
"Gesamtarbeitszeit" as "totalHours",
|
||||
"Arbeitstage" as "workingDays",
|
||||
"Home-Office-Tage" as "homeOfficeDays",
|
||||
"Überstunden" as "overtime"
|
||||
from "Arbeitszeiten - Monat"
|
||||
SQL;
|
||||
|
||||
@@ -23,7 +23,8 @@ class WorkingHoursRepository implements RepositoryReaderInterface, RepositoryWri
|
||||
protected const string SQL_SELECT = <<<'SQL'
|
||||
select
|
||||
"Datum" as "workingDay",
|
||||
"Arbeitszeit" as "workingTime"
|
||||
"Arbeitszeit" as "workingTime",
|
||||
"HomeOffice" as "isHomeOfficeDay"
|
||||
from public."Arbeitszeiten"
|
||||
SQL;
|
||||
|
||||
@@ -73,7 +74,8 @@ SQL;
|
||||
$model = new WorkingHours();
|
||||
$model
|
||||
->setWorkingDay(new DateTime($row['workingDay']))
|
||||
->setWorkingTime(new DateInterval('P0000-00-00T' . $row['workingTime']));
|
||||
->setWorkingTime(new DateInterval('P0000-00-00T' . $row['workingTime']))
|
||||
->setIsHomeOffice($row['isHomeOfficeDay']);
|
||||
$models[] = $model;
|
||||
}
|
||||
return $models;
|
||||
@@ -130,7 +132,8 @@ SQL;
|
||||
$model = new WorkingHours();
|
||||
$model
|
||||
->setWorkingDay(new DateTime($row['workingDay']))
|
||||
->setWorkingTime(new DateInterval('P0000-00-00T' . $row['workingTime']));
|
||||
->setWorkingTime(new DateInterval('P0000-00-00T' . $row['workingTime']))
|
||||
->setIsHomeOffice($row['isHomeOfficeDay']);
|
||||
return $model;
|
||||
}
|
||||
|
||||
@@ -145,6 +148,7 @@ SQL;
|
||||
if ($model instanceof WorkingHours) {
|
||||
$workingDay = $model->getWorkingDay()->format('Y-m-d');
|
||||
$workingTime = $model->getWorkingTime()->format('%H:%I:%S');
|
||||
$isHomeOffice = $model->isHomeOffice();
|
||||
} else {
|
||||
throw new InvalidArgumentException('Es wird ein Modell der Klasse "' . WorkingHours::class . '" verlangt.');
|
||||
}
|
||||
@@ -154,11 +158,15 @@ SQL;
|
||||
throw new RepositoryRecordAlreadyExistException();
|
||||
} /** @noinspection PhpUnusedLocalVariableInspection */
|
||||
catch (RepositoryRecordNotFoundException $exception) {
|
||||
$stmt = $this->database->prepare(
|
||||
'insert into public."Arbeitszeiten" ("Datum", "Arbeitszeit") values (?, ?) on conflict do nothing'
|
||||
);
|
||||
$stmt = $this->database->prepare(<<<'SQL'
|
||||
insert into public."Arbeitszeiten" ("Datum", "Arbeitszeit", "HomeOffice")
|
||||
values (?, ?, ?)
|
||||
on conflict do nothing
|
||||
SQL
|
||||
);
|
||||
$stmt->bindParam(1, $workingDay);
|
||||
$stmt->bindParam(2, $workingTime);
|
||||
$stmt->bindParam(3, $isHomeOffice, PDO::PARAM_BOOL);
|
||||
$stmt->execute();
|
||||
}
|
||||
}
|
||||
@@ -173,12 +181,19 @@ SQL;
|
||||
if ($model instanceof WorkingHours) {
|
||||
$workingDay = $model->getWorkingDay()->format('Y-m-d');
|
||||
$workingTime = $model->getWorkingTime()->format('%H:%I:%S');
|
||||
$isHomeOffice = $model->isHomeOffice();
|
||||
} else {
|
||||
throw new InvalidArgumentException('Es wird ein Modell der Klasse "' . WorkingHours::class . '" verlangt.');
|
||||
}
|
||||
$stmt = $this->database->prepare('update public."Arbeitszeiten" set "Arbeitszeit" = ? where "Datum" = ?');
|
||||
$stmt = $this->database->prepare(<<<'SQL'
|
||||
update public."Arbeitszeiten"
|
||||
set "Arbeitszeit" = ?, "HomeOffice" = ?
|
||||
where "Datum" = ?
|
||||
SQL
|
||||
);
|
||||
$stmt->bindParam(1, $workingTime);
|
||||
$stmt->bindParam(2, $workingDay);
|
||||
$stmt->bindParam(2, $isHomeOffice, PDO::PARAM_BOOL);
|
||||
$stmt->bindParam(3, $workingDay);
|
||||
$stmt->execute();
|
||||
if ($stmt->rowCount() < 1) {
|
||||
throw new RepositoryRecordNotFoundException();
|
||||
|
||||
@@ -16,6 +16,7 @@ class WorkingHoursWeeklyViewRepository extends AbstractWorkingHoursViewRepositor
|
||||
"Woche" as "period",
|
||||
"Gesamtarbeitszeit" as "totalHours",
|
||||
"Arbeitstage" as "workingDays",
|
||||
"Home-Office-Tage" as "homeOfficeDays",
|
||||
"Überstunden" as "overtime"
|
||||
from "Arbeitszeiten - Woche"
|
||||
SQL;
|
||||
|
||||
@@ -16,6 +16,7 @@ class WorkingHoursYearlyViewRepository extends AbstractWorkingHoursViewRepositor
|
||||
"Jahr" as "period",
|
||||
"Gesamtarbeitszeit" as "totalHours",
|
||||
"Arbeitstage" as "workingDays",
|
||||
"Home-Office-Tage" as "homeOfficeDays",
|
||||
"Überstunden" as "overtime"
|
||||
from "Arbeitszeiten - Jahr"
|
||||
SQL;
|
||||
|
||||
+107
-90
@@ -22,127 +22,144 @@ DROP TABLE IF EXISTS public."Arbeitszeiten";
|
||||
-- Name: Arbeitszeiten; Type: TABLE; Schema: public; Owner: torsten
|
||||
--
|
||||
|
||||
CREATE TABLE public."Arbeitszeiten" (
|
||||
"Datum" date not null,
|
||||
"Arbeitszeit" interval(6) null,
|
||||
CREATE TABLE public."Arbeitszeiten"
|
||||
(
|
||||
"Datum" date not null,
|
||||
"Arbeitszeit" interval(6) null,
|
||||
"HomeOffice" boolean default FALSE not null,
|
||||
constraint "Arbeitszeiten_pkey" primary key ("Datum")
|
||||
);
|
||||
|
||||
|
||||
ALTER TABLE public."Arbeitszeiten" OWNER TO bruce;
|
||||
ALTER TABLE public."Arbeitszeiten"
|
||||
OWNER TO bruce;
|
||||
|
||||
--
|
||||
-- Name: Arbeitszeiten - Jahr; Type: VIEW; Schema: public; Owner: torsten
|
||||
--
|
||||
|
||||
CREATE OR REPLACE VIEW public."Arbeitszeiten - Jahr" AS
|
||||
SELECT (date_part('year'::text, "Arbeitszeiten"."Datum"))::text AS "Jahr",
|
||||
sum("Arbeitszeiten"."Arbeitszeit") AS "Gesamtarbeitszeit",
|
||||
count("Arbeitszeiten"."Datum") AS "Arbeitstage",
|
||||
(sum("Arbeitszeiten"."Arbeitszeit") - ((count("Arbeitszeiten"."Datum"))::double precision * '08:00:00'::interval)) AS "Überstunden"
|
||||
FROM public."Arbeitszeiten"
|
||||
GROUP BY (date_part('year'::text, "Arbeitszeiten"."Datum"))
|
||||
ORDER BY (date_part('year'::text, "Arbeitszeiten"."Datum"));
|
||||
SELECT (date_part('year'::text, "Arbeitszeiten"."Datum"))::text AS "Jahr",
|
||||
sum("Arbeitszeiten"."Arbeitszeit")::interval AS "Gesamtarbeitszeit",
|
||||
count("Arbeitszeiten"."Datum")::bigint AS "Arbeitstage",
|
||||
(sum("Arbeitszeiten"."Arbeitszeit") -
|
||||
((count("Arbeitszeiten"."Datum"))::double precision * '08:00:00'::interval)) AS "Überstunden",
|
||||
(count(*) filter (where "Arbeitszeiten"."HomeOffice"))::int as "Home-Office-Tage"
|
||||
FROM public."Arbeitszeiten"
|
||||
GROUP BY (date_part('year'::text, "Arbeitszeiten"."Datum"))
|
||||
ORDER BY (date_part('year'::text, "Arbeitszeiten"."Datum"));
|
||||
|
||||
|
||||
ALTER TABLE public."Arbeitszeiten - Jahr" OWNER TO bruce;
|
||||
ALTER TABLE public."Arbeitszeiten - Jahr"
|
||||
OWNER TO bruce;
|
||||
|
||||
--
|
||||
-- Name: Arbeitszeiten - Monat; Type: VIEW; Schema: public; Owner: torsten
|
||||
--
|
||||
|
||||
CREATE OR REPLACE VIEW public."Arbeitszeiten - Monat" AS
|
||||
SELECT to_char(date_trunc('month'::text, ("Arbeitszeiten"."Datum")::timestamp with time zone), 'TMYYYY TMMonth'::text) AS "Monat",
|
||||
sum("Arbeitszeiten"."Arbeitszeit") AS "Gesamtarbeitszeit",
|
||||
count("Arbeitszeiten"."Datum") AS "Arbeitstage",
|
||||
(sum("Arbeitszeiten"."Arbeitszeit") - ((count("Arbeitszeiten"."Datum"))::double precision * '08:00:00'::interval)) AS "Überstunden"
|
||||
FROM public."Arbeitszeiten"
|
||||
GROUP BY (date_trunc('month'::text, ("Arbeitszeiten"."Datum")::timestamp with time zone))
|
||||
ORDER BY (date_trunc('month'::text, ("Arbeitszeiten"."Datum")::timestamp with time zone));
|
||||
SELECT to_char(date_trunc('month'::text, ("Arbeitszeiten"."Datum")::timestamp with time zone),
|
||||
'TMYYYY TMMonth'::text) AS "Monat",
|
||||
sum("Arbeitszeiten"."Arbeitszeit")::interval AS "Gesamtarbeitszeit",
|
||||
count("Arbeitszeiten"."Datum")::bigint AS "Arbeitstage",
|
||||
(sum("Arbeitszeiten"."Arbeitszeit") -
|
||||
((count("Arbeitszeiten"."Datum"))::double precision * '08:00:00'::interval)) AS "Überstunden",
|
||||
(count(*) filter (where "Arbeitszeiten"."HomeOffice"))::int as "Home-Office-Tage"
|
||||
FROM public."Arbeitszeiten"
|
||||
GROUP BY (date_trunc('month'::text, ("Arbeitszeiten"."Datum")::timestamp with time zone))
|
||||
ORDER BY (date_trunc('month'::text, ("Arbeitszeiten"."Datum")::timestamp with time zone));
|
||||
|
||||
|
||||
ALTER TABLE public."Arbeitszeiten - Monat" OWNER TO bruce;
|
||||
ALTER TABLE public."Arbeitszeiten - Monat"
|
||||
OWNER TO bruce;
|
||||
|
||||
--
|
||||
-- Name: Arbeitszeiten - Woche; Type: VIEW; Schema: public; Owner: torsten
|
||||
--
|
||||
|
||||
CREATE OR REPLACE VIEW public."Arbeitszeiten - Woche" AS
|
||||
SELECT to_char(date_trunc('week'::text, ("Arbeitszeiten"."Datum")::timestamp with time zone), 'TMYYYY#WW'::text) AS "Woche",
|
||||
sum("Arbeitszeiten"."Arbeitszeit") AS "Gesamtarbeitszeit",
|
||||
count("Arbeitszeiten"."Datum") AS "Arbeitstage",
|
||||
(sum("Arbeitszeiten"."Arbeitszeit") - ((count("Arbeitszeiten"."Datum"))::double precision * '08:00:00'::interval)) AS "Überstunden"
|
||||
FROM public."Arbeitszeiten"
|
||||
GROUP BY (date_trunc('week'::text, ("Arbeitszeiten"."Datum")::timestamp with time zone))
|
||||
ORDER BY (date_trunc('week'::text, ("Arbeitszeiten"."Datum")::timestamp with time zone));
|
||||
SELECT to_char(date_trunc('week'::text, ("Arbeitszeiten"."Datum")::timestamp with time zone),
|
||||
'TMYYYY#WW'::text) AS "Woche",
|
||||
sum("Arbeitszeiten"."Arbeitszeit")::interval AS "Gesamtarbeitszeit",
|
||||
count("Arbeitszeiten"."Datum")::bigint AS "Arbeitstage",
|
||||
(sum("Arbeitszeiten"."Arbeitszeit") -
|
||||
((count("Arbeitszeiten"."Datum"))::double precision * '08:00:00'::interval)) AS "Überstunden",
|
||||
(count(*) filter (where "Arbeitszeiten"."HomeOffice"))::int as "Home-Office-Tage"
|
||||
FROM public."Arbeitszeiten"
|
||||
GROUP BY (date_trunc('week'::text, ("Arbeitszeiten"."Datum")::timestamp with time zone))
|
||||
ORDER BY (date_trunc('week'::text, ("Arbeitszeiten"."Datum")::timestamp with time zone));
|
||||
|
||||
|
||||
ALTER TABLE public."Arbeitszeiten - Woche" OWNER TO bruce;
|
||||
ALTER TABLE public."Arbeitszeiten - Woche"
|
||||
OWNER TO bruce;
|
||||
|
||||
--
|
||||
-- Data for Name: Arbeitszeiten; Type: TABLE DATA; Schema: public; Owner: torsten
|
||||
--
|
||||
|
||||
INSERT INTO public."Arbeitszeiten" ("Datum", "Arbeitszeit") VALUES
|
||||
('2020-01-07','08:06:00'),
|
||||
('2020-01-08','08:16:00'),
|
||||
('2020-01-09','07:49:00'),
|
||||
('2020-01-10','07:30:00'),
|
||||
('2020-01-13','08:06:00'),
|
||||
('2020-01-14','08:04:00'),
|
||||
('2020-01-15','08:20:00'),
|
||||
('2020-01-16','07:13:00'),
|
||||
('2020-01-17','07:57:00'),
|
||||
('2020-01-20','07:53:00'),
|
||||
('2020-01-21','07:49:00'),
|
||||
('2020-01-22','07:56:00'),
|
||||
('2020-01-23','07:55:00'),
|
||||
('2020-01-24','07:08:00'),
|
||||
('2020-01-27','08:23:00'),
|
||||
('2020-01-28','07:20:00'),
|
||||
('2020-01-29','08:13:00'),
|
||||
('2020-01-30','08:43:00'),
|
||||
('2020-01-31','07:21:00'),
|
||||
('2020-02-03','07:56:00'),
|
||||
('2020-02-04','08:05:00'),
|
||||
('2020-02-05','07:58:00'),
|
||||
('2020-02-06','08:01:00'),
|
||||
('2020-02-07','07:59:00'),
|
||||
('2020-02-10','07:50:00'),
|
||||
('2020-02-11','08:01:00'),
|
||||
('2020-02-12','08:14:00'),
|
||||
('2020-02-13','08:12:00'),
|
||||
('2020-02-14','07:51:00'),
|
||||
('2020-02-17','07:59:00'),
|
||||
('2020-02-18','08:05:00'),
|
||||
('2020-02-19','07:34:00'),
|
||||
('2020-02-20','07:33:00'),
|
||||
('2020-02-21','07:56:00'),
|
||||
('2020-02-24','08:02:00'),
|
||||
('2020-02-25','08:13:00'),
|
||||
('2020-02-26','08:42:00'),
|
||||
('2020-02-27','07:49:00'),
|
||||
('2020-02-28','08:16:00'),
|
||||
('2020-03-02','08:22:00'),
|
||||
('2020-03-03','08:20:00'),
|
||||
('2020-03-04','08:12:00'),
|
||||
('2020-03-05','08:32:00'),
|
||||
('2020-03-06','04:41:00'),
|
||||
('2020-03-09','07:05:00'),
|
||||
('2020-03-10','07:34:00'),
|
||||
('2020-03-11','07:39:00'),
|
||||
('2020-03-12','07:50:00'),
|
||||
('2020-03-13','08:26:00'),
|
||||
('2020-03-16','07:51:00'),
|
||||
('2020-03-17','07:50:00'),
|
||||
('2020-03-18','07:19:00'),
|
||||
('2020-03-19','07:55:00'),
|
||||
('2020-03-20','05:43:00'),
|
||||
('2020-03-23','08:05:00'),
|
||||
('2020-03-24','08:21:00'),
|
||||
('2020-03-25','08:10:00'),
|
||||
('2020-03-26','10:31:00'),
|
||||
('2020-03-27','04:55:00'),
|
||||
('2020-03-30','08:21:00'),
|
||||
('2020-03-31','08:01:00')
|
||||
INSERT INTO public."Arbeitszeiten" ("Datum", "Arbeitszeit")
|
||||
VALUES ('2020-01-07', '08:06:00'),
|
||||
('2020-01-08', '08:16:00'),
|
||||
('2020-01-09', '07:49:00'),
|
||||
('2020-01-10', '07:30:00'),
|
||||
('2020-01-13', '08:06:00'),
|
||||
('2020-01-14', '08:04:00'),
|
||||
('2020-01-15', '08:20:00'),
|
||||
('2020-01-16', '07:13:00'),
|
||||
('2020-01-17', '07:57:00'),
|
||||
('2020-01-20', '07:53:00'),
|
||||
('2020-01-21', '07:49:00'),
|
||||
('2020-01-22', '07:56:00'),
|
||||
('2020-01-23', '07:55:00'),
|
||||
('2020-01-24', '07:08:00'),
|
||||
('2020-01-27', '08:23:00'),
|
||||
('2020-01-28', '07:20:00'),
|
||||
('2020-01-29', '08:13:00'),
|
||||
('2020-01-30', '08:43:00'),
|
||||
('2020-01-31', '07:21:00'),
|
||||
('2020-02-03', '07:56:00'),
|
||||
('2020-02-04', '08:05:00'),
|
||||
('2020-02-05', '07:58:00'),
|
||||
('2020-02-06', '08:01:00')
|
||||
;
|
||||
|
||||
INSERT INTO public."Arbeitszeiten" ("Datum", "Arbeitszeit", "HomeOffice")
|
||||
VALUES ('2020-02-07', '07:59:00', FALSE),
|
||||
('2020-02-10', '07:50:00', FALSE),
|
||||
('2020-02-11', '08:01:00', FALSE),
|
||||
('2020-02-12', '08:14:00', FALSE),
|
||||
('2020-02-13', '08:12:00', FALSE),
|
||||
('2020-02-14', '07:51:00', FALSE),
|
||||
('2020-02-17', '07:59:00', FALSE),
|
||||
('2020-02-18', '08:05:00', FALSE),
|
||||
('2020-02-19', '07:34:00', FALSE),
|
||||
('2020-02-20', '07:33:00', FALSE),
|
||||
('2020-02-21', '07:56:00', FALSE),
|
||||
('2020-02-24', '08:02:00', FALSE),
|
||||
('2020-02-25', '08:13:00', FALSE),
|
||||
('2020-02-26', '08:42:00', FALSE),
|
||||
('2020-02-27', '07:49:00', TRUE),
|
||||
('2020-02-28', '08:16:00', FALSE),
|
||||
('2020-03-02', '08:22:00', FALSE),
|
||||
('2020-03-03', '08:20:00', FALSE),
|
||||
('2020-03-04', '08:12:00', FALSE),
|
||||
('2020-03-05', '08:32:00', FALSE),
|
||||
('2020-03-06', '04:41:00', FALSE),
|
||||
('2020-03-09', '07:05:00', FALSE),
|
||||
('2020-03-10', '07:34:00', FALSE),
|
||||
('2020-03-11', '07:39:00', TRUE),
|
||||
('2020-03-12', '07:50:00', FALSE),
|
||||
('2020-03-13', '08:26:00', FALSE),
|
||||
('2020-03-16', '07:51:00', FALSE),
|
||||
('2020-03-17', '07:50:00', FALSE),
|
||||
('2020-03-18', '07:19:00', FALSE),
|
||||
('2020-03-19', '07:55:00', FALSE),
|
||||
('2020-03-20', '05:43:00', TRUE),
|
||||
('2020-03-23', '08:05:00', FALSE),
|
||||
('2020-03-24', '08:21:00', FALSE),
|
||||
('2020-03-25', '08:10:00', FALSE),
|
||||
('2020-03-26', '10:31:00', FALSE),
|
||||
('2020-03-27', '04:55:00', FALSE),
|
||||
('2020-03-30', '08:21:00', FALSE),
|
||||
('2020-03-31', '08:01:00', FALSE)
|
||||
;
|
||||
@@ -1,4 +1,5 @@
|
||||
<?php
|
||||
|
||||
namespace Helper;
|
||||
|
||||
// here you can define custom actions
|
||||
@@ -13,8 +14,9 @@ class Api extends Module
|
||||
const FORMAT_DATE = 'string:regex(/\d{4}-\d{2}-\d{2}/)';
|
||||
|
||||
const WORKING_HOURS_JSON_FORMAT = [
|
||||
'workingDay' => self::FORMAT_DATE,
|
||||
'workingTime' => self::FORMAT_TIME,
|
||||
'workingDay' => self::FORMAT_DATE,
|
||||
'workingTime' => self::FORMAT_TIME,
|
||||
'isHomeOffice' => 'boolean',
|
||||
];
|
||||
|
||||
const WORKING_HOURS_VIEW_JSON_FORMAT = [
|
||||
@@ -22,6 +24,7 @@ class Api extends Module
|
||||
"periodDesignation" => "string",
|
||||
"totalHours" => self::FORMAT_TIME,
|
||||
"workingDays" => 'integer:>0',
|
||||
'homeOfficeDays' => 'number:>=0',
|
||||
"overtime" => self::FORMAT_TIME,
|
||||
];
|
||||
|
||||
|
||||
@@ -28,6 +28,7 @@ class CreateWorkingHoursCest
|
||||
$I->sendPost('/working-hours', [
|
||||
'workingDay' => '2020-04-01',
|
||||
'workingTime' => '08:00:00',
|
||||
'isHomeOffice' => false,
|
||||
]);
|
||||
$I->seeResponseCodeIs(HttpCode::CREATED);
|
||||
$I->canSeeHttpHeader('Access-Control-Allow-Origin', Api::TEST_ORIGIN);
|
||||
@@ -44,6 +45,7 @@ class CreateWorkingHoursCest
|
||||
$I->sendPost('/working-hours', [
|
||||
'workingDay' => '2020-04-01',
|
||||
'workingTime' => 8.0,
|
||||
'isHomeOffice' => false,
|
||||
]);
|
||||
$I->seeResponseCodeIs(HttpCode::BAD_REQUEST);
|
||||
$I->canSeeHttpHeader('Access-Control-Allow-Origin', Api::TEST_ORIGIN);
|
||||
@@ -60,6 +62,7 @@ class CreateWorkingHoursCest
|
||||
$I->sendPost('/working-hours', [
|
||||
'workingDay' => '2020-01-15',
|
||||
'workingTime' => '08:00:00',
|
||||
'isHomeOffice' => false,
|
||||
]);
|
||||
$I->seeResponseCodeIs(HttpCode::CONFLICT);
|
||||
$I->canSeeHttpHeader('Access-Control-Allow-Origin', Api::TEST_ORIGIN);
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
<?php /** @noinspection PhpUnused */
|
||||
<?php
|
||||
/** @noinspection PhpUnused */
|
||||
|
||||
namespace TorstenHettstedt\TimekeepingApi\Tests\Api\WorkingHours;
|
||||
|
||||
@@ -26,8 +27,9 @@ class UpdateWorkingHoursCest
|
||||
$I->haveHttpHeader('content-type', 'application/json');
|
||||
$I->haveHttpHeader('Origin', Api::TEST_ORIGIN);
|
||||
$I->sendPut('/working-hours/2020-01-15', [
|
||||
'workingDay' => '2020-01-15',
|
||||
'workingTime' => '10:00:00',
|
||||
'workingDay' => '2020-01-15',
|
||||
'workingTime' => '10:00:00',
|
||||
'isHomeOffice' => false,
|
||||
]);
|
||||
$I->seeResponseCodeIs(HttpCode::OK);
|
||||
$I->canSeeHttpHeader('Access-Control-Allow-Origin', Api::TEST_ORIGIN);
|
||||
@@ -43,6 +45,7 @@ class UpdateWorkingHoursCest
|
||||
$I->sendPut('/working-hours/2020-04-15', [
|
||||
'workingDay' => '2020-04-15',
|
||||
'workingTime' => '10:00:00',
|
||||
'isHomeOffice' => false,
|
||||
]);
|
||||
$I->seeResponseCodeIs(HttpCode::NOT_FOUND);
|
||||
$I->canSeeHttpHeader('Access-Control-Allow-Origin', Api::TEST_ORIGIN);
|
||||
@@ -58,6 +61,7 @@ class UpdateWorkingHoursCest
|
||||
$I->sendPut('/working-hours/2020-01-15', [
|
||||
'workingDay' => '2020-01-15',
|
||||
'workingTime' => 8.0,
|
||||
'isHomeOffice' => false,
|
||||
]);
|
||||
$I->seeResponseCodeIs(HttpCode::BAD_REQUEST);
|
||||
$I->canSeeHttpHeader('Access-Control-Allow-Origin', Api::TEST_ORIGIN);
|
||||
|
||||
@@ -32,8 +32,9 @@ class WorkingHoursControllerTest extends AbstractControllerTest
|
||||
parent::_before();
|
||||
$this->request = $this->makeEmpty(Request::class, [
|
||||
'getParsedBody' => [
|
||||
'workingDay' => self::EXISTING_DATE,
|
||||
'workingTime' => self::EXISTING_INTERVAL,
|
||||
'workingDay' => self::EXISTING_DATE,
|
||||
'workingTime' => self::EXISTING_INTERVAL,
|
||||
'isHomeOfficeDay' => true,
|
||||
],
|
||||
]);
|
||||
}
|
||||
@@ -260,6 +261,28 @@ class WorkingHoursControllerTest extends AbstractControllerTest
|
||||
$this->assertNotEmpty($response->getBody()->getContents());
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws ContainerExceptionInterface
|
||||
* @throws NotDatabasesException
|
||||
* @throws NotFoundExceptionInterface
|
||||
* @throws Exception
|
||||
*/
|
||||
public function testUpdateExistRecordWithoutHomeOffice(): void
|
||||
{
|
||||
$this->request = $this->makeEmpty(Request::class, [
|
||||
'getParsedBody' => [
|
||||
'workingDay' => self::EXISTING_DATE,
|
||||
'workingTime' => self::EXISTING_INTERVAL,
|
||||
],
|
||||
]);
|
||||
$controller = new WorkingHoursController($this->container);
|
||||
$response = $controller->update($this->request, $this->response, [
|
||||
'id' => self::EXISTING_DATE,
|
||||
]);
|
||||
$this->assertEquals(self::FICTIONAL_STATUS_CODE, $response->getStatusCode());
|
||||
$this->assertNotEmpty($response->getBody()->getContents());
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws ContainerExceptionInterface
|
||||
* @throws NotDatabasesException
|
||||
@@ -302,12 +325,13 @@ class WorkingHoursControllerTest extends AbstractControllerTest
|
||||
* @throws Exception
|
||||
*/
|
||||
#[DataProvider('invalidCreatDataProvider')]
|
||||
public function testCreatInvalidData(string $date, string $time): void
|
||||
public function testCreatInvalidData(string $date, string $time, bool $isHomeOffice = false): void
|
||||
{
|
||||
$this->request = $this->makeEmpty(Request::class, [
|
||||
'getParsedBody' => [
|
||||
'workingDay' => $date,
|
||||
'workingTime' => $time,
|
||||
'workingDay' => $date,
|
||||
'workingTime' => $time,
|
||||
'isHomeOfficeDay' => $isHomeOffice,
|
||||
],
|
||||
]);
|
||||
$controller = new WorkingHoursController($this->container);
|
||||
@@ -325,8 +349,29 @@ class WorkingHoursControllerTest extends AbstractControllerTest
|
||||
{
|
||||
$this->request = $this->makeEmpty(Request::class, [
|
||||
'getParsedBody' => [
|
||||
'workingDay' => self::NEW_DATE,
|
||||
'workingTime' => self::NEW_INTERVAL,
|
||||
'workingDay' => self::NEW_DATE,
|
||||
'workingTime' => self::NEW_INTERVAL,
|
||||
'isHomeOfficeDay' => true,
|
||||
],
|
||||
]);
|
||||
$controller = new WorkingHoursController($this->container);
|
||||
$response = $controller->creat($this->request, $this->response, []);
|
||||
$this->assertEquals(self::FICTIONAL_STATUS_CODE, $response->getStatusCode());
|
||||
$this->assertNotEmpty($response->getBody()->getContents());
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws ContainerExceptionInterface
|
||||
* @throws NotDatabasesException
|
||||
* @throws NotFoundExceptionInterface
|
||||
* @throws Exception
|
||||
*/
|
||||
public function testCreatNewRecordWithoutHomeOffice(): void
|
||||
{
|
||||
$this->request = $this->makeEmpty(Request::class, [
|
||||
'getParsedBody' => [
|
||||
'workingDay' => self::NEW_DATE,
|
||||
'workingTime' => self::NEW_INTERVAL,
|
||||
],
|
||||
]);
|
||||
$controller = new WorkingHoursController($this->container);
|
||||
@@ -345,8 +390,9 @@ class WorkingHoursControllerTest extends AbstractControllerTest
|
||||
{
|
||||
$this->request = $this->makeEmpty(Request::class, [
|
||||
'getParsedBody' => [
|
||||
'workingDay' => self::EXISTING_DATE,
|
||||
'workingTime' => self::EXISTING_INTERVAL,
|
||||
'workingDay' => self::EXISTING_DATE,
|
||||
'workingTime' => self::EXISTING_INTERVAL,
|
||||
'isHomeOfficeDay' => true,
|
||||
],
|
||||
]);
|
||||
$controller = new WorkingHoursController($this->container);
|
||||
|
||||
@@ -17,6 +17,7 @@ class WorkingHoursTest extends Unit
|
||||
$obj = new WorkingHours();
|
||||
$this->assertNull($obj->getWorkingDay());
|
||||
$this->assertNull($obj->getWorkingTime());
|
||||
$this->assertFalse($obj->isHomeOffice());
|
||||
|
||||
$this->expectException(Error::class);
|
||||
$obj->jsonSerialize();
|
||||
@@ -32,17 +33,21 @@ class WorkingHoursTest extends Unit
|
||||
new DateTime('2020-11-30'),
|
||||
new DateInterval("PT8H"),
|
||||
[
|
||||
'workingDay' => '2020-11-30',
|
||||
'workingTime' => '08:00:00',
|
||||
'workingDay' => '2020-11-30',
|
||||
'workingTime' => '08:00:00',
|
||||
'isHomeOffice' => true,
|
||||
],
|
||||
true,
|
||||
],
|
||||
[
|
||||
new DateTime('2021-05-03'),
|
||||
new DateInterval("PT7H45M"),
|
||||
[
|
||||
'workingDay' => '2021-05-03',
|
||||
'workingTime' => '07:45:00',
|
||||
'workingDay' => '2021-05-03',
|
||||
'workingTime' => '07:45:00',
|
||||
'isHomeOffice' => false,
|
||||
],
|
||||
false,
|
||||
],
|
||||
];
|
||||
}
|
||||
@@ -51,10 +56,38 @@ class WorkingHoursTest extends Unit
|
||||
* @param DateTime $date
|
||||
* @param DateInterval $interval
|
||||
* @param array<string, string> $shouldJson
|
||||
* @param bool $isHomeOffice
|
||||
*/
|
||||
#[DataProvider('workingHoursProvider')]
|
||||
public function testWorkingHoursWithContent(DateTime $date, DateInterval $interval, array $shouldJson): void
|
||||
public function testWorkingHoursWithContent(DateTime $date, DateInterval $interval, array $shouldJson, bool $isHomeOffice): void
|
||||
{
|
||||
$obj = new WorkingHours();
|
||||
$obj->setWorkingDay($date)->setWorkingTime($interval)->setIsHomeOffice($isHomeOffice);
|
||||
|
||||
$this->assertNotNull($obj->getWorkingDay());
|
||||
$this->assertInstanceOf(DateTime::class, $obj->getWorkingDay());
|
||||
$this->assertEquals($date, $obj->getWorkingDay());
|
||||
|
||||
$this->assertNotNull($obj->getWorkingTime());
|
||||
$this->assertInstanceOf(DateInterval::class, $obj->getWorkingTime());
|
||||
$this->assertEquals($interval, $obj->getWorkingTime());
|
||||
|
||||
$this->assertIsBool($obj->isHomeOffice());
|
||||
$this->assertEquals($isHomeOffice, $obj->isHomeOffice());
|
||||
|
||||
$json = $obj->jsonSerialize();
|
||||
$this->assertEquals($shouldJson, $json);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param DateTime $date
|
||||
* @param DateInterval $interval
|
||||
* @param array<string, string> $shouldJson
|
||||
*/
|
||||
#[DataProvider('workingHoursProvider')]
|
||||
public function testWorkingHoursWithContentWithoutHomeOfficeInformation(DateTime $date, DateInterval $interval, array $shouldJson): void
|
||||
{
|
||||
$shouldJson['isHomeOffice'] = false;
|
||||
$obj = new WorkingHours();
|
||||
$obj->setWorkingDay($date)->setWorkingTime($interval);
|
||||
|
||||
@@ -66,6 +99,9 @@ class WorkingHoursTest extends Unit
|
||||
$this->assertInstanceOf(DateInterval::class, $obj->getWorkingTime());
|
||||
$this->assertEquals($interval, $obj->getWorkingTime());
|
||||
|
||||
$this->assertIsBool($obj->isHomeOffice());
|
||||
$this->assertFalse($obj->isHomeOffice());
|
||||
|
||||
$json = $obj->jsonSerialize();
|
||||
$this->assertEquals($shouldJson, $json);
|
||||
}
|
||||
|
||||
@@ -20,6 +20,7 @@ class WorkingHoursViewTest extends Unit
|
||||
{
|
||||
$date = new DateTime('2020-11-30');
|
||||
$work_days = 15;
|
||||
$home_work_days = 12;
|
||||
$total_hours = new DateInterval("PT32H22M");
|
||||
$overtime = new DateInterval("PT22M");
|
||||
$absence_time = clone $overtime;
|
||||
@@ -30,12 +31,14 @@ class WorkingHoursViewTest extends Unit
|
||||
PeriodDesignationEnum::WEEKLY,
|
||||
$work_days,
|
||||
$total_hours,
|
||||
$home_work_days,
|
||||
$overtime,
|
||||
[
|
||||
'period' => '2020#49',
|
||||
'periodDesignation' => 'weekly',
|
||||
'workingDays' => 15,
|
||||
'totalHours' => '32:22:00',
|
||||
'homeOfficeDays' => $home_work_days,
|
||||
'overtime' => '00:22:00'
|
||||
],
|
||||
],
|
||||
@@ -44,12 +47,14 @@ class WorkingHoursViewTest extends Unit
|
||||
PeriodDesignationEnum::WEEKLY,
|
||||
$work_days,
|
||||
$total_hours,
|
||||
$home_work_days,
|
||||
$absence_time,
|
||||
[
|
||||
'period' => '2020#49',
|
||||
'periodDesignation' => 'weekly',
|
||||
'workingDays' => 15,
|
||||
'totalHours' => '32:22:00',
|
||||
'homeOfficeDays' => $home_work_days,
|
||||
'overtime' => '-00:22:00'
|
||||
],
|
||||
],
|
||||
@@ -58,12 +63,14 @@ class WorkingHoursViewTest extends Unit
|
||||
PeriodDesignationEnum::MONTHLY,
|
||||
$work_days,
|
||||
$total_hours,
|
||||
$home_work_days,
|
||||
$overtime,
|
||||
[
|
||||
'period' => '2020-11',
|
||||
'periodDesignation' => 'monthly',
|
||||
'workingDays' => 15,
|
||||
'totalHours' => '32:22:00',
|
||||
'homeOfficeDays' => $home_work_days,
|
||||
'overtime' => '00:22:00'
|
||||
],
|
||||
],
|
||||
@@ -72,12 +79,14 @@ class WorkingHoursViewTest extends Unit
|
||||
PeriodDesignationEnum::MONTHLY,
|
||||
$work_days,
|
||||
$total_hours,
|
||||
$home_work_days,
|
||||
$absence_time,
|
||||
[
|
||||
'period' => '2020-11',
|
||||
'periodDesignation' => 'monthly',
|
||||
'workingDays' => 15,
|
||||
'totalHours' => '32:22:00',
|
||||
'homeOfficeDays' => $home_work_days,
|
||||
'overtime' => '-00:22:00'
|
||||
],
|
||||
],
|
||||
@@ -86,12 +95,14 @@ class WorkingHoursViewTest extends Unit
|
||||
PeriodDesignationEnum::YEARLY,
|
||||
$work_days,
|
||||
$total_hours,
|
||||
$home_work_days,
|
||||
$overtime,
|
||||
[
|
||||
'period' => '2020',
|
||||
'periodDesignation' => 'yearly',
|
||||
'workingDays' => 15,
|
||||
'totalHours' => '32:22:00',
|
||||
'homeOfficeDays' => $home_work_days,
|
||||
'overtime' => '00:22:00'
|
||||
],
|
||||
],
|
||||
@@ -100,12 +111,14 @@ class WorkingHoursViewTest extends Unit
|
||||
PeriodDesignationEnum::YEARLY,
|
||||
$work_days,
|
||||
$total_hours,
|
||||
$home_work_days,
|
||||
$absence_time,
|
||||
[
|
||||
'period' => '2020',
|
||||
'periodDesignation' => 'yearly',
|
||||
'workingDays' => 15,
|
||||
'totalHours' => '32:22:00',
|
||||
'homeOfficeDays' => $home_work_days,
|
||||
'overtime' => '-00:22:00'
|
||||
],
|
||||
],
|
||||
@@ -117,6 +130,7 @@ class WorkingHoursViewTest extends Unit
|
||||
* @param PeriodDesignationEnum $periodDesignation
|
||||
* @param int $workingDays
|
||||
* @param DateInterval $totalHours
|
||||
* @param int $homeWorkDays ,
|
||||
* @param DateInterval $overtime
|
||||
* @param array<string, string> $shouldJson
|
||||
*/
|
||||
@@ -126,10 +140,11 @@ class WorkingHoursViewTest extends Unit
|
||||
PeriodDesignationEnum $periodDesignation,
|
||||
int $workingDays,
|
||||
DateInterval $totalHours,
|
||||
int $homeWorkDays,
|
||||
DateInterval $overtime,
|
||||
array $shouldJson
|
||||
): void {
|
||||
$obj = new WorkingHoursView($period, $periodDesignation, $workingDays, $totalHours, $overtime);
|
||||
$obj = new WorkingHoursView($period, $periodDesignation, $workingDays, $totalHours, $homeWorkDays, $overtime);
|
||||
|
||||
$this->assertInstanceOf(DateTimeInterface::class, $obj->getPeriod());
|
||||
$this->assertEquals($period, $obj->getPeriod());
|
||||
@@ -142,6 +157,9 @@ class WorkingHoursViewTest extends Unit
|
||||
$this->assertInstanceOf(DateInterval::class, $obj->getTotalHours());
|
||||
$this->assertEquals($totalHours, $obj->getTotalHours());
|
||||
|
||||
$this->assertIsInt($obj->getHomeOfficeDays());
|
||||
$this->assertEquals($homeWorkDays, $obj->getHomeOfficeDays());
|
||||
|
||||
$this->assertInstanceOf(DateInterval::class, $obj->getOvertime());
|
||||
$this->assertEquals($overtime, $obj->getOvertime());
|
||||
|
||||
|
||||
@@ -157,8 +157,9 @@ class WorkingHoursRepositoryTest extends Unit
|
||||
{
|
||||
$repository = new WorkingHoursRepository($this->pdoObject);
|
||||
$model = $this->make(WorkingHours::class, [
|
||||
'workingDay' => new DateTime(self::NEW_DATE),
|
||||
'workingTime' => new DateInterval(self::NEW_INTERVAL),
|
||||
'workingDay' => new DateTime(self::NEW_DATE),
|
||||
'workingTime' => new DateInterval(self::NEW_INTERVAL),
|
||||
'isHomeOffice' => false,
|
||||
]);
|
||||
$repository->insert($model);
|
||||
$model = $repository->findByKey(self::NEW_DATE);
|
||||
@@ -174,8 +175,9 @@ class WorkingHoursRepositoryTest extends Unit
|
||||
{
|
||||
$repository = new WorkingHoursRepository($this->pdoObject);
|
||||
$model = $this->make(WorkingHours::class, [
|
||||
'workingDay' => new DateTime(self::EXISTING_DATE),
|
||||
'workingTime' => new DateInterval(self::NEW_INTERVAL),
|
||||
'workingDay' => new DateTime(self::EXISTING_DATE),
|
||||
'workingTime' => new DateInterval(self::NEW_INTERVAL),
|
||||
'isHomeOffice' => false,
|
||||
]);
|
||||
$this->expectException(RepositoryRecordAlreadyExistException::class);
|
||||
$repository->insert($model);
|
||||
@@ -201,8 +203,9 @@ class WorkingHoursRepositoryTest extends Unit
|
||||
{
|
||||
$repository = new WorkingHoursRepository($this->pdoObject);
|
||||
$model = $this->make(WorkingHours::class, [
|
||||
'workingDay' => new DateTime(self::EXISTING_DATE),
|
||||
'workingTime' => new DateInterval(self::EXISTING_INTERVAL),
|
||||
'workingDay' => new DateTime(self::EXISTING_DATE),
|
||||
'workingTime' => new DateInterval(self::EXISTING_INTERVAL),
|
||||
'isHomeOffice' => false,
|
||||
]);
|
||||
$repository->delete($model);
|
||||
$this->expectException(RepositoryRecordNotFoundException::class);
|
||||
@@ -217,8 +220,9 @@ class WorkingHoursRepositoryTest extends Unit
|
||||
{
|
||||
$repository = new WorkingHoursRepository($this->pdoObject);
|
||||
$model = $this->make(WorkingHours::class, [
|
||||
'workingDay' => new DateTime(self::NEW_DATE),
|
||||
'workingTime' => new DateInterval(self::NEW_INTERVAL),
|
||||
'workingDay' => new DateTime(self::NEW_DATE),
|
||||
'workingTime' => new DateInterval(self::NEW_INTERVAL),
|
||||
'isHomeOffice' => false,
|
||||
]);
|
||||
$this->expectException(RepositoryRecordNotFoundException::class);
|
||||
$repository->delete($model);
|
||||
@@ -244,8 +248,9 @@ class WorkingHoursRepositoryTest extends Unit
|
||||
{
|
||||
$repository = new WorkingHoursRepository($this->pdoObject);
|
||||
$model = $this->make(WorkingHours::class, [
|
||||
'workingDay' => new DateTime(self::EXISTING_DATE),
|
||||
'workingTime' => new DateInterval(self::NEW_INTERVAL),
|
||||
'workingDay' => new DateTime(self::EXISTING_DATE),
|
||||
'workingTime' => new DateInterval(self::NEW_INTERVAL),
|
||||
'isHomeOffice' => false,
|
||||
]);
|
||||
$repository->update($model);
|
||||
$model_db = $repository->findByKey(self::EXISTING_DATE);
|
||||
@@ -259,8 +264,9 @@ class WorkingHoursRepositoryTest extends Unit
|
||||
{
|
||||
$repository = new WorkingHoursRepository($this->pdoObject);
|
||||
$model = $this->make(WorkingHours::class, [
|
||||
'workingDay' => new DateTime(self::NEW_DATE),
|
||||
'workingTime' => new DateInterval(self::NEW_INTERVAL),
|
||||
'workingDay' => new DateTime(self::NEW_DATE),
|
||||
'workingTime' => new DateInterval(self::NEW_INTERVAL),
|
||||
'isHomeOffice' => false,
|
||||
]);
|
||||
$this->expectException(RepositoryRecordNotFoundException::class);
|
||||
$repository->update($model);
|
||||
|
||||
@@ -6,7 +6,8 @@ use Codeception\Attribute\DataProvider;
|
||||
use Codeception\Test\Unit;
|
||||
use DateTime;
|
||||
use DateTimeZone;
|
||||
use PDO;use TorstenHettstedt\TimekeepingApi\Models\WorkingHoursView;
|
||||
use PDO;
|
||||
use TorstenHettstedt\TimekeepingApi\Models\WorkingHoursView;
|
||||
use TorstenHettstedt\TimekeepingApi\Repositories\RepositoryRecordNotFoundException;
|
||||
use TorstenHettstedt\TimekeepingApi\Repositories\WorkingHoursWeeklyViewRepository;
|
||||
use TorstenHettstedt\TimekeepingApi\Repositories\WorkingHoursMonthlyViewRepository;
|
||||
@@ -14,12 +15,14 @@ use TorstenHettstedt\TimekeepingApi\Repositories\WorkingHoursYearlyViewRepositor
|
||||
|
||||
class WorkingHoursViewRepositoryTest extends Unit
|
||||
{
|
||||
protected PDO $pdoObject;
|
||||
protected PDO $pdoObject;
|
||||
|
||||
protected function _before(): void
|
||||
{
|
||||
/** @noinspection SpellCheckingInspection */
|
||||
$this->pdoObject = new PDO('pgsql:host=psql.torsten-hettstedt.net;port=5432;dbname=testdb;user=bruce;password=mypass');
|
||||
$this->pdoObject = new PDO(
|
||||
'pgsql:host=psql.torsten-hettstedt.net;port=5432;dbname=testdb;user=bruce;password=mypass'
|
||||
);
|
||||
parent::_before();
|
||||
}
|
||||
|
||||
@@ -29,7 +32,7 @@ class WorkingHoursViewRepositoryTest extends Unit
|
||||
public function listObjectProvider(): array
|
||||
{
|
||||
return [
|
||||
[WorkingHoursYearlyViewRepository::class, 1],
|
||||
[WorkingHoursYearlyViewRepository::class, 1],
|
||||
[WorkingHoursMonthlyViewRepository::class, 3],
|
||||
[WorkingHoursWeeklyViewRepository::class, 13],
|
||||
];
|
||||
@@ -41,9 +44,27 @@ class WorkingHoursViewRepositoryTest extends Unit
|
||||
public function existingObjectProvider(): array
|
||||
{
|
||||
return [
|
||||
[WorkingHoursYearlyViewRepository::class, '2020', 61, date_create('2020-01-01', new DateTimeZone('UCT'))],
|
||||
[WorkingHoursMonthlyViewRepository::class, '2020 February', 20, date_create('2020-02-01', new DateTimeZone('UCT'))],
|
||||
[WorkingHoursWeeklyViewRepository::class, '2020#03', 5, date_create('2020-01-13', new DateTimeZone('UCT'))],
|
||||
[
|
||||
WorkingHoursYearlyViewRepository::class,
|
||||
'2020',
|
||||
61,
|
||||
date_create('2020-01-01', new DateTimeZone('UCT')),
|
||||
3,
|
||||
],
|
||||
[
|
||||
WorkingHoursMonthlyViewRepository::class,
|
||||
'2020 February',
|
||||
20,
|
||||
date_create('2020-02-01', new DateTimeZone('UCT')),
|
||||
1,
|
||||
],
|
||||
[
|
||||
WorkingHoursWeeklyViewRepository::class,
|
||||
'2020#03',
|
||||
5,
|
||||
date_create('2020-01-13', new DateTimeZone('UCT')),
|
||||
0,
|
||||
],
|
||||
];
|
||||
}
|
||||
|
||||
@@ -53,9 +74,9 @@ class WorkingHoursViewRepositoryTest extends Unit
|
||||
public function notExistingObjectProvider(): array
|
||||
{
|
||||
return [
|
||||
[WorkingHoursYearlyViewRepository::class, '2022',],
|
||||
[WorkingHoursYearlyViewRepository::class, '2022',],
|
||||
[WorkingHoursMonthlyViewRepository::class, '2020 May',],
|
||||
[WorkingHoursWeeklyViewRepository::class, '2020#30',],
|
||||
[WorkingHoursWeeklyViewRepository::class, '2020#30',],
|
||||
];
|
||||
}
|
||||
|
||||
@@ -70,13 +91,19 @@ class WorkingHoursViewRepositoryTest extends Unit
|
||||
}
|
||||
|
||||
#[DataProvider(('existingObjectProvider'))]
|
||||
public function testExistingFindByKey(string $periodClass, string $search, int $workingDays, DateTime $period): void
|
||||
{
|
||||
public function testExistingFindByKey(
|
||||
string $periodClass,
|
||||
string $search,
|
||||
int $workingDays,
|
||||
DateTime $period,
|
||||
int $homeOfficeDays
|
||||
): void {
|
||||
$repository = new $periodClass($this->pdoObject);
|
||||
$model = $repository->findByKey($search);
|
||||
$this->assertInstanceOf(WorkingHoursView::class, $model);
|
||||
$this->assertEquals($workingDays, $model->getWorkingDays());
|
||||
$this->assertEquals($period->format('Ymd'), $model->getPeriod()->format('Ymd'));
|
||||
$this->assertEquals($homeOfficeDays, $model->getHomeOfficeDays());
|
||||
}
|
||||
|
||||
#[DataProvider(('notExistingObjectProvider'))]
|
||||
|
||||
@@ -2,44 +2,48 @@
|
||||
-- DROP TABLE public."Arbeitszeiten";
|
||||
create table public."Arbeitszeiten"
|
||||
(
|
||||
"Datum" date not null,
|
||||
"Arbeitszeit" interval(6) null,
|
||||
"Datum" date not null,
|
||||
"Arbeitszeit" interval(6) null,
|
||||
"HomeOffice" boolean default FALSE not null,
|
||||
constraint "Arbeitszeiten_pkey" primary key ("Datum")
|
||||
);
|
||||
|
||||
|
||||
-- # Definition der Ansichten
|
||||
-- ## Wöchentlich
|
||||
create view "Arbeitszeiten - Woche" ("Woche", "Gesamtarbeitszeit", "Arbeitstage", "Überstunden") as
|
||||
select
|
||||
to_char(date_trunc('week'::text, "Arbeitszeiten"."Datum"::timestamp with time zone),
|
||||
'TMYYYY#WW'::text) as "Woche",
|
||||
sum("Arbeitszeiten"."Arbeitszeit") as "Gesamtarbeitszeit",
|
||||
count("Arbeitszeiten"."Datum") as "Arbeitstage",
|
||||
sum("Arbeitszeiten"."Arbeitszeit") - count("Arbeitszeiten"."Datum") ::double precision * '08:00:00'::interval as "Überstunden"
|
||||
from "Arbeitszeiten"
|
||||
group by (date_trunc('week'::text, "Arbeitszeiten"."Datum"::timestamp with time zone))
|
||||
order by (date_trunc('week'::text, "Arbeitszeiten"."Datum"::timestamp with time zone));
|
||||
create view "Arbeitszeiten - Woche" ("Woche", "Gesamtarbeitszeit", "Arbeitstage", "Überstunden", "Home-Office-Tage") as
|
||||
select to_char(date_trunc('week'::text, "Arbeitszeiten"."Datum"::timestamp with time zone),
|
||||
'TMYYYY#WW'::text) as "Woche",
|
||||
sum("Arbeitszeiten"."Arbeitszeit")::interval AS "Gesamtarbeitszeit",
|
||||
count("Arbeitszeiten"."Datum")::bigint AS "Arbeitstage",
|
||||
(sum("Arbeitszeiten"."Arbeitszeit") -
|
||||
((count("Arbeitszeiten"."Datum"))::double precision * '08:00:00'::interval)) AS "Überstunden",
|
||||
(count(*) filter (where "Arbeitszeiten"."HomeOffice"))::int as "Home-Office-Tage"
|
||||
from "Arbeitszeiten"
|
||||
group by (date_trunc('week'::text, "Arbeitszeiten"."Datum"::timestamp with time zone))
|
||||
order by (date_trunc('week'::text, "Arbeitszeiten"."Datum"::timestamp with time zone));
|
||||
|
||||
-- ## Monatlich
|
||||
create view "Arbeitszeiten - Monat" ("Monat", "Gesamtarbeitszeit", "Arbeitstage", "Überstunden") as
|
||||
select
|
||||
to_char(date_trunc('month'::text, "Arbeitszeiten"."Datum"::timestamp with time zone),
|
||||
'TMYYYY TMMonth'::text) as "Monat",
|
||||
sum("Arbeitszeiten"."Arbeitszeit") as "Gesamtarbeitszeit",
|
||||
count("Arbeitszeiten"."Datum") as "Arbeitstage",
|
||||
sum("Arbeitszeiten"."Arbeitszeit") - count("Arbeitszeiten"."Datum") ::double precision * '08:00:00'::interval as "Überstunden"
|
||||
from "Arbeitszeiten"
|
||||
group by (date_trunc('month'::text, "Arbeitszeiten"."Datum"::timestamp with time zone))
|
||||
order by (date_trunc('month'::text, "Arbeitszeiten"."Datum"::timestamp with time zone));
|
||||
create view "Arbeitszeiten - Monat" ("Monat", "Gesamtarbeitszeit", "Arbeitstage", "Überstunden", "Home-Office-Tage") as
|
||||
select to_char(date_trunc('month'::text, "Arbeitszeiten"."Datum"::timestamp with time zone),
|
||||
'TMYYYY TMMonth'::text) as "Monat",
|
||||
sum("Arbeitszeiten"."Arbeitszeit")::interval AS "Gesamtarbeitszeit",
|
||||
count("Arbeitszeiten"."Datum")::bigint AS "Arbeitstage",
|
||||
(sum("Arbeitszeiten"."Arbeitszeit") -
|
||||
((count("Arbeitszeiten"."Datum"))::double precision * '08:00:00'::interval)) AS "Überstunden",
|
||||
(count(*) filter (where "Arbeitszeiten"."HomeOffice"))::int as "Home-Office-Tage"
|
||||
from "Arbeitszeiten"
|
||||
group by (date_trunc('month'::text, "Arbeitszeiten"."Datum"::timestamp with time zone))
|
||||
order by (date_trunc('month'::text, "Arbeitszeiten"."Datum"::timestamp with time zone));
|
||||
|
||||
-- ## Jährlich
|
||||
create view "Arbeitszeiten - Jahr"("Jahr", "Gesamtarbeitszeit", "Arbeitstage", "Überstunden") as
|
||||
select
|
||||
date_part('year'::text, "Arbeitszeiten"."Datum")::text as "Jahr",
|
||||
sum("Arbeitszeiten"."Arbeitszeit") as "Gesamtarbeitszeit",
|
||||
count("Arbeitszeiten"."Datum") as "Arbeitstage",
|
||||
sum("Arbeitszeiten"."Arbeitszeit") - count("Arbeitszeiten"."Datum") ::double precision * '08:00:00'::interval as "Überstunden"
|
||||
from "Arbeitszeiten"
|
||||
group by (date_part('year'::text, "Arbeitszeiten"."Datum"))
|
||||
order by (date_part('year'::text, "Arbeitszeiten"."Datum"));
|
||||
create view "Arbeitszeiten - Jahr"("Jahr", "Gesamtarbeitszeit", "Arbeitstage", "Überstunden", "Home-Office-Tage") as
|
||||
select date_part('year'::text, "Arbeitszeiten"."Datum")::text as "Jahr",
|
||||
sum("Arbeitszeiten"."Arbeitszeit")::interval AS "Gesamtarbeitszeit",
|
||||
count("Arbeitszeiten"."Datum")::bigint AS "Arbeitstage",
|
||||
(sum("Arbeitszeiten"."Arbeitszeit") -
|
||||
((count("Arbeitszeiten"."Datum"))::double precision * '08:00:00'::interval)) AS "Überstunden",
|
||||
(count(*) filter (where "Arbeitszeiten"."HomeOffice"))::int as "Home-Office-Tage"
|
||||
from "Arbeitszeiten"
|
||||
group by (date_part('year'::text, "Arbeitszeiten"."Datum"))
|
||||
order by (date_part('year'::text, "Arbeitszeiten"."Datum"));
|
||||
Reference in New Issue
Block a user