Skip to content

Commit e7fa414

Browse files
committed
Restrict rounding to premium users
1 parent 43073b5 commit e7fa414

2 files changed

Lines changed: 68 additions & 13 deletions

File tree

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

Lines changed: 19 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -86,7 +86,8 @@ public function index(Organization $organization, TimeEntryIndexRequest $request
8686
$this->checkPermission($organization, 'time-entries:view:all');
8787
}
8888

89-
$timeEntriesQuery = $this->getTimeEntriesQuery($organization, $request, $member);
89+
$canAccessPremiumFeatures = $this->canAccessPremiumFeatures($organization);
90+
$timeEntriesQuery = $this->getTimeEntriesQuery($organization, $request, $member, $canAccessPremiumFeatures);
9091

9192
$totalCount = $timeEntriesQuery->count();
9293

@@ -140,13 +141,15 @@ public function index(Organization $organization, TimeEntryIndexRequest $request
140141
/**
141142
* @return Builder<TimeEntry>
142143
*/
143-
private function getTimeEntriesQuery(Organization $organization, TimeEntryIndexRequest|TimeEntryIndexExportRequest $request, ?Member $member): Builder
144+
private function getTimeEntriesQuery(Organization $organization, TimeEntryIndexRequest|TimeEntryIndexExportRequest $request, ?Member $member, bool $canAccessPremiumFeatures): Builder
144145
{
145146
$select = TimeEntry::SELECT_COLUMNS;
146-
if ($request->getRoundingType() !== null && $request->getRoundingMinutes() !== null) {
147+
$roundingType = $canAccessPremiumFeatures ? $request->getRoundingType() : null;
148+
$roundingMinutes = $canAccessPremiumFeatures ? $request->getRoundingMinutes() : null;
149+
if ($roundingType !== null && $roundingMinutes !== null) {
147150
$select = array_diff($select, ['start', 'end']);
148-
$select[] = DB::raw(app(TimeEntryService::class)->getStartSelectRawForRounding($request->getRoundingType(), $request->getRoundingMinutes()).' as start');
149-
$select[] = DB::raw(app(TimeEntryService::class)->getEndSelectRawForRounding($request->getRoundingType(), $request->getRoundingMinutes()).' as end');
151+
$select[] = DB::raw(app(TimeEntryService::class)->getStartSelectRawForRounding($roundingType, $roundingMinutes).' as start');
152+
$select[] = DB::raw(app(TimeEntryService::class)->getEndSelectRawForRounding($roundingType, $roundingMinutes).' as end');
150153
}
151154
$timeEntriesQuery = TimeEntry::query()
152155
->whereBelongsTo($organization, 'organization')
@@ -184,18 +187,19 @@ public function indexExport(Organization $organization, TimeEntryIndexExportRequ
184187
} else {
185188
$this->checkPermission($organization, 'time-entries:view:all');
186189
}
190+
$canAccessPremiumFeatures = $this->canAccessPremiumFeatures($organization);
187191
$debug = $request->getDebug();
188192
$format = $request->getFormatValue();
189-
if ($format === ExportFormat::PDF && ! $this->canAccessPremiumFeatures($organization)) {
193+
if ($format === ExportFormat::PDF && ! $canAccessPremiumFeatures) {
190194
throw new FeatureIsNotAvailableInFreePlanApiException;
191195
}
192196
$user = $this->user();
193197
$timezone = $user->timezone;
194198
$showBillableRate = $this->member($organization)->role !== Role::Employee->value || $organization->employees_can_see_billable_rates;
195-
$roundingType = $request->getRoundingType();
196-
$roundingMinutes = $request->getRoundingMinutes();
199+
$roundingType = $canAccessPremiumFeatures ? $request->getRoundingType() : null;
200+
$roundingMinutes = $canAccessPremiumFeatures ? $request->getRoundingMinutes() : null;
197201

198-
$timeEntriesQuery = $this->getTimeEntriesQuery($organization, $request, $member);
202+
$timeEntriesQuery = $this->getTimeEntriesQuery($organization, $request, $member, $canAccessPremiumFeatures);
199203
$timeEntriesQuery->with([
200204
'task',
201205
'client',
@@ -332,14 +336,15 @@ public function aggregate(Organization $organization, TimeEntryAggregateRequest
332336
} else {
333337
$this->checkPermission($organization, 'time-entries:view:all');
334338
}
339+
$canAccessPremiumFeatures = $this->canAccessPremiumFeatures($organization);
335340
$user = $this->user();
336341
$showBillableRate = $this->member($organization)->role !== Role::Employee->value || $organization->employees_can_see_billable_rates;
337342

338343
$group1Type = $request->getGroup();
339344
$group2Type = $request->getSubGroup();
340345
$timeEntriesAggregateQuery = $this->getTimeEntriesAggregateQuery($organization, $request, $member);
341-
$roundingType = $request->getRoundingType();
342-
$roundingMinutes = $request->getRoundingMinutes();
346+
$roundingType = $canAccessPremiumFeatures ? $request->getRoundingType() : null;
347+
$roundingMinutes = $canAccessPremiumFeatures ? $request->getRoundingMinutes() : null;
343348

344349
$aggregatedData = $timeEntryAggregationService->getAggregatedTimeEntries(
345350
$timeEntriesAggregateQuery,
@@ -380,6 +385,7 @@ public function aggregateExport(Organization $organization, TimeEntryAggregateEx
380385
} else {
381386
$this->checkPermission($organization, 'time-entries:view:all');
382387
}
388+
$canAccessPremiumFeatures = $this->canAccessPremiumFeatures($organization);
383389
$format = $request->getFormatValue();
384390
if ($format === ExportFormat::PDF && ! $this->canAccessPremiumFeatures($organization)) {
385391
throw new FeatureIsNotAvailableInFreePlanApiException;
@@ -391,8 +397,8 @@ public function aggregateExport(Organization $organization, TimeEntryAggregateEx
391397
$group = $request->getGroup();
392398
$subGroup = $request->getSubGroup();
393399
$timeEntriesAggregateQuery = $this->getTimeEntriesAggregateQuery($organization, $request, $member);
394-
$roundingType = $request->getRoundingType();
395-
$roundingMinutes = $request->getRoundingMinutes();
400+
$roundingType = $canAccessPremiumFeatures ? $request->getRoundingType() : null;
401+
$roundingMinutes = $canAccessPremiumFeatures ? $request->getRoundingMinutes() : null;
396402

397403
$aggregatedData = $timeEntryAggregationService->getAggregatedTimeEntriesWithDescriptions(
398404
$timeEntriesAggregateQuery->clone(),

tests/Unit/Endpoint/Api/V1/TimeEntryEndpointTest.php

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -409,6 +409,7 @@ public function test_index_endpoint_can_round_up(): void
409409
'start' => Carbon::createFromFormat('Y-m-d H:i:s', '2020-01-01 00:00:07'),
410410
'end' => null,
411411
]);
412+
$this->actAsOrganizationWithSubscription();
412413
Passport::actingAs($data->user);
413414

414415
// Act
@@ -435,6 +436,52 @@ public function test_index_endpoint_can_round_up(): void
435436
);
436437
}
437438

439+
public function test_index_endpoint_ignores_rounding_if_organization_has_no_premium_features(): void
440+
{
441+
// Arrange
442+
$this->travelTo(Carbon::createFromFormat('Y-m-d H:i:s', '2020-01-01 00:15:04'));
443+
$data = $this->createUserWithPermission([
444+
'time-entries:view:own',
445+
]);
446+
$timeEntry1 = TimeEntry::factory()->forOrganization($data->organization)
447+
->forMember($data->member)
448+
->create([
449+
'start' => Carbon::createFromFormat('Y-m-d H:i:s', '2020-01-01 00:00:08'),
450+
'end' => Carbon::createFromFormat('Y-m-d H:i:s', '2020-01-01 00:00:01'),
451+
]);
452+
$timeEntry2 = TimeEntry::factory()->forOrganization($data->organization)
453+
->forMember($data->member)
454+
->create([
455+
'start' => Carbon::createFromFormat('Y-m-d H:i:s', '2020-01-01 00:00:07'),
456+
'end' => null,
457+
]);
458+
$this->actAsOrganizationWithoutSubscriptionAndWithoutTrial();
459+
Passport::actingAs($data->user);
460+
461+
// Act
462+
$response = $this->getJson(route('api.v1.time-entries.index', [
463+
$data->organization->getKey(),
464+
'member_id' => $data->member->getKey(),
465+
'rounding_type' => TimeEntryRoundingType::Up,
466+
'rounding_minutes' => 6,
467+
]));
468+
469+
// Assert
470+
$this->assertResponseCode($response, 200);
471+
$response->assertJson(fn (AssertableJson $json) => $json
472+
->has('data')
473+
->has('meta')
474+
->where('meta.total', 2)
475+
->count('data', 2)
476+
->where('data.0.id', $timeEntry1->getKey())
477+
->where('data.0.start', '2020-01-01T00:00:08Z')
478+
->where('data.0.end', '2020-01-01T00:00:01Z')
479+
->where('data.1.id', $timeEntry2->getKey())
480+
->where('data.1.start', '2020-01-01T00:00:07Z')
481+
->where('data.1.end', null)
482+
);
483+
}
484+
438485
public function test_index_endpoint_can_round_down(): void
439486
{
440487
// Arrange
@@ -454,6 +501,7 @@ public function test_index_endpoint_can_round_down(): void
454501
'start' => Carbon::createFromFormat('Y-m-d H:i:s', '2020-01-01 00:00:07'),
455502
'end' => null,
456503
]);
504+
$this->actAsOrganizationWithSubscription();
457505
Passport::actingAs($data->user);
458506

459507
// Act
@@ -499,6 +547,7 @@ public function test_index_endpoint_can_round_nearest(): void
499547
'start' => Carbon::createFromFormat('Y-m-d H:i:s', '2020-01-01 00:00:07'),
500548
'end' => null,
501549
]);
550+
$this->actAsOrganizationWithSubscription();
502551
Passport::actingAs($data->user);
503552

504553
// Act

0 commit comments

Comments
 (0)