Skip to content

Commit b9492ec

Browse files
committed
add break time entries and simplified time tracker ui
1 parent 4fb18f3 commit b9492ec

128 files changed

Lines changed: 6253 additions & 438 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

app/Enums/TimeEntryAggregationType.php

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ enum TimeEntryAggregationType: string
2121
case Billable = 'billable';
2222
case Description = 'description';
2323
case Tag = 'tag';
24+
case Type = 'type';
2425

2526
public static function fromInterval(TimeEntryAggregationTypeInterval $timeEntryAggregationTypeInterval): TimeEntryAggregationType
2627
{

app/Enums/TimeEntryType.php

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace App\Enums;
6+
7+
use Datomatic\LaravelEnumHelper\LaravelEnumHelper;
8+
9+
enum TimeEntryType: string
10+
{
11+
use LaravelEnumHelper;
12+
13+
case Work = 'work';
14+
case Break = 'break';
15+
}

app/Http/Controllers/Api/V1/OrganizationController.php

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -78,6 +78,9 @@ public function update(Organization $organization, OrganizationUpdateRequest $re
7878
if ($request->getPreventOverlappingTimeEntries() !== null) {
7979
$organization->prevent_overlapping_time_entries = $request->getPreventOverlappingTimeEntries();
8080
}
81+
if ($request->getBreaksEnabled() !== null) {
82+
$organization->breaks_enabled = $request->getBreaksEnabled();
83+
}
8184
$hasBillableRate = $request->has('billable_rate');
8285
if ($hasBillableRate) {
8386
$oldBillableRate = $organization->billable_rate;

app/Http/Controllers/Api/V1/Public/ReportController.php

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,7 @@ public function show(Request $request, TimeEntryAggregationService $timeEntryAgg
5757
$filter->addEnd($properties->end);
5858
$filter->addActive($properties->active);
5959
$filter->addBillable($properties->billable);
60+
$filter->addType($properties->timeEntryType);
6061
$filter->addMemberIdsFilter($properties->memberIds?->toArray());
6162
$filter->addProjectIdsFilter($properties->projectIds?->toArray());
6263
$filter->addTagIdsFilter($properties->tagIds?->toArray(), $properties->tagMatchType);

app/Http/Controllers/Api/V1/ReportController.php

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -112,6 +112,7 @@ public function store(Organization $organization, ReportStoreRequest $request, T
112112
$properties->timezone = $timezone;
113113
$properties->roundingType = $request->getPropertyRoundingType();
114114
$properties->roundingMinutes = $request->getPropertyRoundingMinutes();
115+
$properties->timeEntryType = $request->getPropertyTimeEntryType();
115116
$report->properties = $properties;
116117
if ($isPublic) {
117118
$report->share_secret = $reportService->generateSecret();

app/Http/Controllers/Api/V1/TimeEntryController.php

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66

77
use App\Enums\ExportFormat;
88
use App\Enums\Role;
9+
use App\Enums\TimeEntryType;
910
use App\Exceptions\Api\FeatureIsNotAvailableInFreePlanApiException;
1011
use App\Exceptions\Api\OverlappingTimeEntryApiException;
1112
use App\Exceptions\Api\PdfRendererIsNotConfiguredException;
@@ -208,6 +209,7 @@ private function getTimeEntriesQuery(Organization $organization, TimeEntryIndexR
208209
$filter->addTaskIdsFilter($request->input('task_ids'));
209210
$filter->addClientIdsFilter($request->input('client_ids'));
210211
$filter->addBillableFilter($request->input('billable'));
212+
$filter->addTypeFilter($request->input('type'));
211213

212214
return $filter->get();
213215
}
@@ -564,6 +566,7 @@ private function getTimeEntriesAggregateQuery(Organization $organization, TimeEn
564566
$filter->addTaskIdsFilter($request->input('task_ids'));
565567
$filter->addClientIdsFilter($request->input('client_ids'));
566568
$filter->addBillableFilter($request->input('billable'));
569+
$filter->addTypeFilter($request->input('type'));
567570

568571
return $filter->get();
569572
}
@@ -746,6 +749,19 @@ public function updateMultiple(Organization $organization, TimeEntryUpdateMultip
746749
continue;
747750

748751
}
752+
// Changing time entries to Break entries is only allowed when breaks are enabled in the org settings
753+
$resultingType = isset($changes['type']) ? TimeEntryType::from($changes['type']) : $timeEntry->type;
754+
if ($resultingType === TimeEntryType::Break && $timeEntry->type !== TimeEntryType::Break && ! $organization->breaks_enabled) {
755+
$error->push($id);
756+
757+
continue;
758+
}
759+
// Break entries can not be billable, have tags or belong to a project/task (see TimeEntry::booted)
760+
if ($resultingType === TimeEntryType::Break && ($project !== null || $task !== null || $request->boolean('changes.billable') || count($changes['tags'] ?? []) > 0)) {
761+
$error->push($id);
762+
763+
continue;
764+
}
749765
$oldProject = $timeEntry->project;
750766
$oldTask = $timeEntry->task;
751767

app/Http/Requests/V1/Organization/OrganizationUpdateRequest.php

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,9 @@ public function rules(): array
5151
'prevent_overlapping_time_entries' => [
5252
'boolean',
5353
],
54+
'breaks_enabled' => [
55+
'boolean',
56+
],
5457
'number_format' => [
5558
Rule::enum(NumberFormat::class),
5659
],
@@ -125,4 +128,9 @@ public function getPreventOverlappingTimeEntries(): ?bool
125128
{
126129
return $this->has('prevent_overlapping_time_entries') ? $this->boolean('prevent_overlapping_time_entries') : null;
127130
}
131+
132+
public function getBreaksEnabled(): ?bool
133+
{
134+
return $this->has('breaks_enabled') ? $this->boolean('breaks_enabled') : null;
135+
}
128136
}

app/Http/Requests/V1/Report/ReportStoreRequest.php

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
use App\Enums\TimeEntryAggregationType;
99
use App\Enums\TimeEntryAggregationTypeInterval;
1010
use App\Enums\TimeEntryRoundingType;
11+
use App\Enums\TimeEntryType;
1112
use App\Enums\Weekday;
1213
use App\Http\Requests\V1\BaseFormRequest;
1314
use App\Models\Organization;
@@ -177,6 +178,12 @@ function (string $attribute, mixed $value, \Closure $fail): void {
177178
'numeric',
178179
'integer',
179180
],
181+
// Filter by time entry type
182+
'properties.time_entry_type' => [
183+
'nullable',
184+
'string',
185+
Rule::enum(TimeEntryType::class),
186+
],
180187
];
181188
}
182189

@@ -240,6 +247,15 @@ public function getPropertyBillable(): ?bool
240247
return null;
241248
}
242249

250+
public function getPropertyTimeEntryType(): ?TimeEntryType
251+
{
252+
if (! $this->has('properties.time_entry_type') || $this->input('properties.time_entry_type') === null) {
253+
return null;
254+
}
255+
256+
return TimeEntryType::from($this->input('properties.time_entry_type'));
257+
}
258+
243259
public function getPropertyGroup(): TimeEntryAggregationType
244260
{
245261
return TimeEntryAggregationType::from($this->input('properties.group'));

app/Http/Requests/V1/TimeEntry/TimeEntryAggregateExportRequest.php

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
use App\Enums\TimeEntryAggregationType;
1010
use App\Enums\TimeEntryAggregationTypeInterval;
1111
use App\Enums\TimeEntryRoundingType;
12+
use App\Enums\TimeEntryType;
1213
use App\Http\Requests\V1\BaseFormRequest;
1314
use App\Models\Client;
1415
use App\Models\Member;
@@ -183,6 +184,11 @@ function (string $attribute, mixed $value, \Closure $fail): void {
183184
'string',
184185
'in:true,false',
185186
],
187+
// Filter by time entry type
188+
'type' => [
189+
'string',
190+
Rule::enum(TimeEntryType::class),
191+
],
186192
'fill_gaps_in_time_groups' => [
187193
'string',
188194
'in:true,false',

app/Http/Requests/V1/TimeEntry/TimeEntryAggregateRequest.php

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
use App\Enums\TagMatchType;
88
use App\Enums\TimeEntryAggregationType;
99
use App\Enums\TimeEntryRoundingType;
10+
use App\Enums\TimeEntryType;
1011
use App\Http\Requests\V1\BaseFormRequest;
1112
use App\Models\Client;
1213
use App\Models\Member;
@@ -169,6 +170,11 @@ function (string $attribute, mixed $value, \Closure $fail): void {
169170
'string',
170171
'in:true,false',
171172
],
173+
// Filter by time entry type
174+
'type' => [
175+
'string',
176+
Rule::enum(TimeEntryType::class),
177+
],
172178
'fill_gaps_in_time_groups' => [
173179
'string',
174180
'in:true,false',

0 commit comments

Comments
 (0)