mirror of
https://github.com/solidtime-io/solidtime.git
synced 2026-10-15 17:23:16 +01:00
Allow only one running time entry per user across organizations
The running time entry check in the store endpoint was scoped to the member, so a user could start a time entry in each of their organizations. The active time entry endpoint and the database consistency check expect only one running time entry per user.
This commit is contained in:
@@ -630,7 +630,8 @@ class TimeEntryController extends Controller
|
|||||||
*/
|
*/
|
||||||
private function storeTimeEntry(Organization $organization, Member $member, TimeEntryStoreRequest $request): JsonResource
|
private function storeTimeEntry(Organization $organization, Member $member, TimeEntryStoreRequest $request): JsonResource
|
||||||
{
|
{
|
||||||
if ($request->input('end') === null && TimeEntry::query()->whereBelongsTo($member, 'member')->where('end', null)->exists()) {
|
// A user can only have one running time entry, across all organizations
|
||||||
|
if ($request->input('end') === null && TimeEntry::query()->where('user_id', $member->user_id)->whereNull('end')->exists()) {
|
||||||
throw new TimeEntryStillRunningApiException;
|
throw new TimeEntryStillRunningApiException;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -2446,6 +2446,31 @@ class TimeEntryEndpointTest extends ApiEndpointTestAbstract
|
|||||||
$response->assertJsonPath('error', true);
|
$response->assertJsonPath('error', true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function test_store_endpoint_fails_if_user_already_has_active_time_entry_in_another_organization(): void
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
$data = $this->createUserWithPermission([
|
||||||
|
'time-entries:create:own',
|
||||||
|
]);
|
||||||
|
$otherOrganization = Organization::factory()->create();
|
||||||
|
$otherMember = Member::factory()->forOrganization($otherOrganization)->forUser($data->user)->create();
|
||||||
|
TimeEntry::factory()->forOrganization($otherOrganization)->forMember($otherMember)->active()->create();
|
||||||
|
Passport::actingAs($data->user);
|
||||||
|
|
||||||
|
// Act
|
||||||
|
$response = $this->postJson(route('api.v1.time-entries.store', [$data->organization->getKey()]), [
|
||||||
|
'billable' => true,
|
||||||
|
'start' => Carbon::now()->toIso8601ZuluString(),
|
||||||
|
'end' => null,
|
||||||
|
'member_id' => $data->member->getKey(),
|
||||||
|
]);
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
$response->assertStatus(400);
|
||||||
|
$response->assertJsonPath('key', 'time_entry_still_running');
|
||||||
|
$this->assertSame(0, TimeEntry::query()->whereBelongsTo($data->organization, 'organization')->count());
|
||||||
|
}
|
||||||
|
|
||||||
public function test_store_endpoint_releases_running_time_entry_lock_after_request(): void
|
public function test_store_endpoint_releases_running_time_entry_lock_after_request(): void
|
||||||
{
|
{
|
||||||
// Arrange
|
// Arrange
|
||||||
|
|||||||
Reference in New Issue
Block a user