Skip to content

Commit e594b1c

Browse files
authored
Merge pull request #23 from lnNgyn1/release-1.8
Release 1.8
2 parents 9a5b33d + 2368c71 commit e594b1c

10 files changed

Lines changed: 222 additions & 102 deletions

File tree

CHANGELOG.md

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,13 @@
1+
# Version 1.8.0
2+
3+
Compatible with Kimai version 2.38.0 or higher.
4+
5+
- Added break field and validator
6+
- Updated validator
7+
- Duration cannot be longer than 24 hours
8+
- Fixed budget validator
9+
10+
111
# Version 1.7.0
212

313
Compatible with Kimai version 2.36.0 or higher.

Controller/PeriodInsertController.php

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -30,9 +30,9 @@
3030
final class PeriodInsertController extends AbstractController
3131
{
3232
public function __construct(
33-
protected PeriodInsertRepository $repository,
34-
protected TimesheetService $timesheetService,
35-
protected SystemConfiguration $configuration
33+
protected readonly PeriodInsertRepository $repository,
34+
protected readonly TimesheetService $timesheetService,
35+
protected readonly SystemConfiguration $configuration
3636
)
3737
{
3838
}

Entity/PeriodInsert.php

Lines changed: 39 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -25,12 +25,11 @@
2525
#[Constraints\PeriodInsert]
2626
class PeriodInsert
2727
{
28-
private const SECONDS_IN_A_DAY = 24 * 60 * 60;
29-
3028
private ?User $user = null;
3129
private ?DateRange $dateRange = null;
3230
private ?DateTime $beginTime = null;
3331
private ?int $duration = null;
32+
private ?int $break = null;
3433
private ?Project $project = null;
3534
private ?Activity $activity = null;
3635
private ?string $description = null;
@@ -57,7 +56,7 @@ class PeriodInsert
5756
/**
5857
* @var DateTimeImmutable[]
5958
*/
60-
private array $validDays = [];
59+
private array $validDates = [];
6160

6261
public function __construct()
6362
{
@@ -152,10 +151,41 @@ public function getDuration(): ?int
152151
*/
153152
public function setDuration(?int $duration): PeriodInsert
154153
{
155-
$this->duration = $duration !== null ? $duration % PeriodInsert::SECONDS_IN_A_DAY : $duration;
154+
$this->duration = $duration;
156155

157156
return $this;
158157
}
158+
159+
/**
160+
* @return int
161+
*/
162+
public function getBreak(): int
163+
{
164+
return $this->break ?? 0;
165+
}
166+
167+
/**
168+
* @param int|null $break
169+
* @return PeriodInsert
170+
*/
171+
public function setBreak(?int $break): PeriodInsert
172+
{
173+
$this->break = $break;
174+
175+
return $this;
176+
}
177+
178+
/**
179+
* @return int|null
180+
*/
181+
public function getCalculatedDuration(): ?int
182+
{
183+
if (null !== $this->getDuration()) {
184+
return $this->getDuration() - $this->getBreak();
185+
}
186+
187+
return null;
188+
}
159189

160190
/**
161191
* @return Project|null
@@ -508,21 +538,21 @@ public function setExported(bool $exported): PeriodInsert
508538
/**
509539
* @return DateTimeImmutable[]
510540
*/
511-
public function getValidDays(): array
541+
public function getValidDates(): array
512542
{
513-
return $this->validDays;
543+
return $this->validDates;
514544
}
515545

516546
/**
517547
* @param DateTime
518548
* @return PeriodInsert
519549
*/
520-
public function addValidDay(DateTime $day): PeriodInsert
550+
public function addValidDate(DateTime $date): PeriodInsert
521551
{
522-
if (in_array($day, $this->validDays)) {
552+
if (in_array($date, $this->validDates)) {
523553
return $this;
524554
}
525-
$this->validDays[] = DateTimeImmutable::createFromMutable($day);
555+
$this->validDates[] = DateTimeImmutable::createFromMutable($date);
526556

527557
return $this;
528558
}

Form/PeriodInsertForm.php

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -116,10 +116,10 @@ public function buildForm(FormBuilderInterface $builder, array $options): void
116116
$this->addBillable($builder, $options);
117117
$this->addExported($builder, $options);
118118

119-
// find days that will be inserted by the period insert (by default, selected + no absences + working day)
119+
// find dates that will be inserted by the period insert (by default, selected + no absences + working day)
120120
$builder->addEventListener(
121121
FormEvents::SUBMIT,
122-
function (FormEvent $event) {
122+
function (FormEvent $event): void {
123123
/** @var PeriodInsert $periodInsert */
124124
$periodInsert = $event->getData();
125125

@@ -145,7 +145,7 @@ function (FormEvent $event) {
145145
}
146146

147147
if ($periodInsert->isDaySelected($begin) && ($includeAbsences || !in_array($begin->format('Y-m-d'), $absences)) && ($includeNonWorkdays || $contractModeCalculator->isWorkDay($begin))) {
148-
$periodInsert->addValidDay($begin);
148+
$periodInsert->addValidDate($begin);
149149
}
150150
}
151151
}
@@ -166,7 +166,7 @@ protected function addDateRange(FormBuilderInterface $builder, array $options):
166166

167167
$builder->addEventListener(
168168
FormEvents::SUBMIT,
169-
function (FormEvent $event) {
169+
function (FormEvent $event): void {
170170
/** @var PeriodInsert $periodInsert */
171171
$periodInsert = $event->getData();
172172
$dateRange = $periodInsert->getDateRange();
@@ -231,6 +231,10 @@ protected function addDuration(FormBuilderInterface $builder, array $options, bo
231231
}
232232

233233
$builder->add('duration', DurationType::class, $durationOptions);
234+
235+
if ($this->systemConfiguration->isBreakTimeEnabled()) {
236+
$builder->add('break', DurationType::class, ['label' => 'break', 'required' => false, 'icon' => 'break']);
237+
}
234238
}
235239

236240
/**
@@ -245,7 +249,7 @@ protected function addBillable(FormBuilderInterface $builder, array $options): v
245249

246250
$builder->addEventListener(
247251
FormEvents::SUBMIT,
248-
function (FormEvent $event) {
252+
function (FormEvent $event): void {
249253
/** @var PeriodInsert $periodInsert */
250254
$periodInsert = $event->getData();
251255

README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ This plugin is compatible with the following Kimai releases:
88

99
| Bundle version | Minimum Kimai version |
1010
|----------------|-----------------------|
11+
| 1.8.0 | 2.38.0 |
1112
| 1.7.0 | 2.36.0 |
1213
| 1.3 - 1.6 | 2.26.0 |
1314
| 1.0 - 1.2 | 2.1.0 |

Repository/PeriodInsertRepository.php

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -29,8 +29,8 @@ public function savePeriodInsert(PeriodInsert $periodInsert): void
2929
{
3030
$validatedTimesheets = [];
3131

32-
foreach ($periodInsert->getValidDays() as $day) {
33-
$timesheet = $this->createTimesheet($periodInsert, $day);
32+
foreach ($periodInsert->getValidDates() as $date) {
33+
$timesheet = $this->createTimesheet($periodInsert, $date);
3434
$this->timesheetService->validateTimesheet($timesheet);
3535
$validatedTimesheets[] = $timesheet;
3636
}
@@ -54,6 +54,7 @@ public function createTimesheet(PeriodInsert $periodInsert, DateTimeImmutable $b
5454
$timesheet->setBegin($begin);
5555
$timesheet->setEnd((clone $begin)->modify('+' . $periodInsert->getDuration() . ' seconds'));
5656
$timesheet->setDuration($periodInsert->getDuration());
57+
$timesheet->setBreak($periodInsert->getBreak());
5758

5859
if (null !== $periodInsert->getProject()) {
5960
$timesheet->setProject($periodInsert->getProject());

Resources/views/form.html.twig

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,9 @@
1414
{% if form.duration is defined %}
1515
{{ form_row(form.duration, {'row_attr': {'class': 'mb-3 ' ~ form.vars.name ~ '_row_' ~ form.duration.vars.name}}) }}
1616
{% endif %}
17+
{% if form.break is defined %}
18+
{{ form_row(form.break, {'row_attr': {'class': 'mb-3 ' ~ form.vars.name ~ '_row_' ~ form.break.vars.name}}) }}
19+
{% endif %}
1720
{% if form.customer is defined %}
1821
{{ form_row(form.customer, {'row_attr': {'class': 'mb-3 ' ~ form.vars.name ~ '_row_' ~ form.customer.vars.name}}) }}
1922
{% endif %}

Validator/Constraints/PeriodInsert.php

Lines changed: 32 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -15,36 +15,48 @@
1515
final class PeriodInsert extends Constraint
1616
{
1717
public const MISSING_TIME_RANGE_ERROR = 'kimai-period-insert-bundle-01';
18-
public const MISSING_ACTIVITY_ERROR = 'kimai-period-insert-bundle-02';
19-
public const DISABLED_ACTIVITY_ERROR = 'kimai-period-insert-bundle-03';
20-
public const MISSING_PROJECT_ERROR = 'kimai-period-insert-bundle-04';
21-
public const DISABLED_PROJECT_ERROR = 'kimai-period-insert-bundle-05';
22-
public const ACTIVITY_PROJECT_MISMATCH_ERROR = 'kimai-period-insert-bundle-06';
23-
public const PROJECT_DISALLOWS_GLOBAL_ACTIVITY_ERROR = 'kimai-period-insert-bundle-07';
24-
public const DISABLED_CUSTOMER_ERROR = 'kimai-period-insert-bundle-08';
25-
public const ZERO_DURATION_ERROR = 'kimai-period-insert-bundle-09';
26-
public const NEGATIVE_DURATION_ERROR = 'kimai-period-insert-bundle-10';
27-
public const MISSING_DAY_ERROR = 'kimai-period-insert-bundle-11';
28-
public const PROJECT_NOT_STARTED_ERROR = 'kimai-period-insert-bundle-12';
29-
public const PROJECT_ALREADY_ENDED_ERROR = 'kimai-period-insert-bundle-13';
30-
public const TIME_RANGE_IN_FUTURE_ERROR = 'kimai-period-insert-bundle-14';
31-
public const BEGIN_IN_FUTURE_ERROR = 'kimai-period-insert-bundle-15';
32-
public const END_IN_FUTURE_ERROR = 'kimai-period-insert-bundle-16';
33-
public const RECORD_OVERLAPPING_ERROR = 'kimai-period-insert-bundle-17';
34-
public const BUDGET_USED_ERROR = 'kimai-period-insert-bundle-18';
18+
public const MISSING_BEGIN_TIME_ERROR = 'kimai-period-insert-bundle-02';
19+
public const MISSING_DURATION_ERROR = 'kimai-period-insert-bundle-03';
20+
public const NEGATIVE_DURATION_ERROR = 'kimai-period-insert-bundle-04';
21+
public const INVALID_DURATION_ERROR = 'kimai-period-insert-bundle-05';
22+
public const ZERO_DURATION_ERROR = 'kimai-period-insert-bundle-06';
23+
public const NEGATIVE_BREAK_ERROR = 'kimai-period-insert-bundle-07';
24+
public const INVALID_BREAK_ERROR = 'kimai-period-insert-bundle-08';
25+
public const DURATION_BREAK_ERROR = 'kimai-period-insert-bundle-09';
26+
public const MISSING_ACTIVITY_ERROR = 'kimai-period-insert-bundle-10';
27+
public const DISABLED_ACTIVITY_ERROR = 'kimai-period-insert-bundle-11';
28+
public const MISSING_PROJECT_ERROR = 'kimai-period-insert-bundle-12';
29+
public const DISABLED_PROJECT_ERROR = 'kimai-period-insert-bundle-13';
30+
public const ACTIVITY_PROJECT_MISMATCH_ERROR = 'kimai-period-insert-bundle-14';
31+
public const PROJECT_DISALLOWS_GLOBAL_ACTIVITY_ERROR = 'kimai-period-insert-bundle-15';
32+
public const DISABLED_CUSTOMER_ERROR = 'kimai-period-insert-bundle-16';
33+
public const MISSING_DATE_ERROR = 'kimai-period-insert-bundle-17';
34+
public const PROJECT_NOT_STARTED_ERROR = 'kimai-period-insert-bundle-18';
35+
public const PROJECT_ALREADY_ENDED_ERROR = 'kimai-period-insert-bundle-19';
36+
public const TIME_RANGE_IN_FUTURE_ERROR = 'kimai-period-insert-bundle-20';
37+
public const BEGIN_IN_FUTURE_ERROR = 'kimai-period-insert-bundle-21';
38+
public const END_IN_FUTURE_ERROR = 'kimai-period-insert-bundle-22';
39+
public const RECORD_OVERLAPPING_ERROR = 'kimai-period-insert-bundle-23';
40+
public const BUDGET_USED_ERROR = 'kimai-period-insert-bundle-24';
3541

3642
protected const ERROR_NAMES = [
3743
self::MISSING_TIME_RANGE_ERROR => 'You must submit a time range.',
44+
self::MISSING_BEGIN_TIME_ERROR => 'You must submit a begin time.',
45+
self::MISSING_DURATION_ERROR => 'You must submit a duration.',
46+
self::NEGATIVE_DURATION_ERROR => 'A negative duration is not allowed.',
47+
self::INVALID_DURATION_ERROR => 'Duration cannot be be longer than 24 hours.',
48+
self::ZERO_DURATION_ERROR => 'An empty duration is not allowed.',
49+
self::NEGATIVE_BREAK_ERROR => 'A negative break is not allowed.',
50+
self::INVALID_BREAK_ERROR => 'Break cannot be be longer than 24 hours.',
51+
self::DURATION_BREAK_ERROR => 'Break must be shorter than the duration.',
3852
self::MISSING_ACTIVITY_ERROR => 'An activity needs to be selected.',
3953
self::DISABLED_ACTIVITY_ERROR => 'Cannot start a disabled activity.',
4054
self::MISSING_PROJECT_ERROR => 'A project needs to be selected.',
4155
self::DISABLED_PROJECT_ERROR => 'Cannot start a disabled project.',
4256
self::ACTIVITY_PROJECT_MISMATCH_ERROR => 'Project mismatch, project specific activity and period insert project are different.',
4357
self::PROJECT_DISALLOWS_GLOBAL_ACTIVITY_ERROR => 'Global activities are forbidden for the selected project.',
4458
self::DISABLED_CUSTOMER_ERROR => 'Cannot start a disabled customer.',
45-
self::ZERO_DURATION_ERROR => 'Duration cannot be zero.',
46-
self::NEGATIVE_DURATION_ERROR => 'Duration cannot be negative.',
47-
self::MISSING_DAY_ERROR => 'Could not find a valid day in the selected time range. Check the time range for absences and working days.',
59+
self::MISSING_DATE_ERROR => 'Could not find a valid date in the selected time range. Check the time range for absences and working days.',
4860
self::PROJECT_NOT_STARTED_ERROR => 'The project has not started during the selected time range.',
4961
self::PROJECT_ALREADY_ENDED_ERROR => 'The project is finished during the selected time range.',
5062
self::TIME_RANGE_IN_FUTURE_ERROR => 'The time range cannot be in the future.',

0 commit comments

Comments
 (0)