@@ -15,8 +15,8 @@ use App\Model\Day as BaseDay;
|
||||
final class Day extends BaseDay
|
||||
{
|
||||
private ?WorkingTime $workingTime = null;
|
||||
/** @var array<string, int> */
|
||||
private array $descriptions = [];
|
||||
/** @var array<DayAddon> */
|
||||
private array $addons = [];
|
||||
|
||||
public function isLocked(): bool
|
||||
{
|
||||
@@ -38,18 +38,27 @@ final class Day extends BaseDay
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array<string, int>
|
||||
* @return array<DayAddon>
|
||||
*/
|
||||
public function getDescriptions(): array
|
||||
public function getAddons(): array
|
||||
{
|
||||
return $this->descriptions;
|
||||
return $this->addons;
|
||||
}
|
||||
|
||||
public function hasAddons(): bool
|
||||
{
|
||||
return \count($this->addons) > 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Descriptions show up in the approval PDF and maybe in other places as well.
|
||||
*/
|
||||
public function addDescription(string $description, int $duration): void
|
||||
public function addAddon(DayAddon $addon): void
|
||||
{
|
||||
$this->descriptions[$description] = $duration;
|
||||
$this->addons[] = $addon;
|
||||
|
||||
if (!$this->isLocked() && $this->workingTime !== null) {
|
||||
$this->workingTime->setActualTime($this->workingTime->getActualTime() + $addon->getDuration());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
43
src/WorkingTime/Model/DayAddon.php
Normal file
43
src/WorkingTime/Model/DayAddon.php
Normal file
@@ -0,0 +1,43 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Kimai time-tracking app.
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace App\WorkingTime\Model;
|
||||
|
||||
final class DayAddon
|
||||
{
|
||||
private string $title;
|
||||
private int $duration;
|
||||
private bool $billable = true;
|
||||
|
||||
public function __construct(string $title, int $duration)
|
||||
{
|
||||
$this->title = $title;
|
||||
$this->duration = $duration;
|
||||
}
|
||||
|
||||
public function getTitle(): string
|
||||
{
|
||||
return $this->title;
|
||||
}
|
||||
|
||||
public function getDuration(): int
|
||||
{
|
||||
return $this->duration;
|
||||
}
|
||||
|
||||
public function isBillable(): bool
|
||||
{
|
||||
return $this->billable;
|
||||
}
|
||||
|
||||
public function setBillable(bool $billable): void
|
||||
{
|
||||
$this->billable = $billable;
|
||||
}
|
||||
}
|
||||
@@ -18,6 +18,16 @@ use App\Model\Month as BaseMonth;
|
||||
*/
|
||||
final class Month extends BaseMonth
|
||||
{
|
||||
public function __construct(\DateTimeInterface $month, private User $user)
|
||||
{
|
||||
parent::__construct($month);
|
||||
}
|
||||
|
||||
public function getUser(): User
|
||||
{
|
||||
return $this->user;
|
||||
}
|
||||
|
||||
/**
|
||||
* A month is only locked IF every day is approved.
|
||||
* If there is even one day left open, the entire month is not locked.
|
||||
|
||||
@@ -30,7 +30,7 @@ final class Year extends BaseYear
|
||||
|
||||
protected function createMonth(\DateTimeInterface $month): Month
|
||||
{
|
||||
return new Month($month);
|
||||
return new Month($month, $this->user);
|
||||
}
|
||||
|
||||
public function getExpectedTime(\DateTimeInterface $until): int
|
||||
|
||||
@@ -46,7 +46,7 @@ final class WorkingTimeService
|
||||
return $this->workingTimeRepository->getLatestApproval($user);
|
||||
}
|
||||
|
||||
public function getYear(User $user, \DateTimeInterface $yearDate): Year
|
||||
public function getYear(User $user, \DateTimeInterface $yearDate, \DateTimeInterface $until): Year
|
||||
{
|
||||
$yearTimes = $this->workingTimeRepository->findForYear($user, $yearDate);
|
||||
$existing = [];
|
||||
@@ -57,6 +57,7 @@ final class WorkingTimeService
|
||||
$year = new Year(\DateTimeImmutable::createFromInterface($yearDate), $user);
|
||||
|
||||
$stats = null;
|
||||
$firstDay = $user->getWorkStartingDay();
|
||||
|
||||
foreach ($year->getMonths() as $month) {
|
||||
foreach ($month->getDays() as $day) {
|
||||
@@ -70,8 +71,12 @@ final class WorkingTimeService
|
||||
$stats = $this->getYearStatistics($yearDate, $user);
|
||||
}
|
||||
|
||||
$result = new WorkingTime($user, $day->getDay());
|
||||
$result->setExpectedTime($user->getWorkHoursForDay($day->getDay()));
|
||||
$dayDate = $day->getDay();
|
||||
$result = new WorkingTime($user, $dayDate);
|
||||
|
||||
if ($firstDay === null || $firstDay <= $dayDate) {
|
||||
$result->setExpectedTime($user->getWorkHoursForDay($dayDate));
|
||||
}
|
||||
|
||||
if (\array_key_exists($key, $stats)) {
|
||||
$result->setActualTime($stats[$key]);
|
||||
@@ -81,16 +86,16 @@ final class WorkingTimeService
|
||||
}
|
||||
}
|
||||
|
||||
$event = new WorkingTimeYearEvent($year);
|
||||
$event = new WorkingTimeYearEvent($year, $until);
|
||||
$this->eventDispatcher->dispatch($event);
|
||||
|
||||
return $year;
|
||||
}
|
||||
|
||||
public function getMonth(User $user, \DateTimeInterface $monthDate): Month
|
||||
public function getMonth(User $user, \DateTimeInterface $monthDate, \DateTimeInterface $until): Month
|
||||
{
|
||||
// uses the year, because that triggers the required events to collect all different working times
|
||||
$year = $this->getYear($user, $monthDate);
|
||||
$year = $this->getYear($user, $monthDate, $until);
|
||||
|
||||
return $year->getMonth($monthDate);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user