diff --git a/src/Dto/ChangeTermConsultationDto.php b/src/Dto/ChangeTermConsultationDto.php index 724893d..ca6d577 100644 --- a/src/Dto/ChangeTermConsultationDto.php +++ b/src/Dto/ChangeTermConsultationDto.php @@ -6,7 +6,7 @@ class ChangeTermConsultationDto extends BaseDto { protected string $executedAt; protected string $term; - protected bool $forAllUsers = false; + protected ?int $userId = null; protected function setExecutedAt(string $executedAt): void { @@ -28,13 +28,13 @@ public function getTerm(): string return $this->term; } - protected function setForAllUsers(bool $forAllUsers): void + protected function setUserId(int $userId): void { - $this->forAllUsers = $forAllUsers; + $this->userId = $userId; } - public function getForAllUsers(): bool + public function getUserId(): ?int { - return $this->forAllUsers; + return $this->userId; } } diff --git a/src/Dto/ConsultationUserTermDto.php b/src/Dto/ConsultationUserTermDto.php index 13242bf..1044b77 100644 --- a/src/Dto/ConsultationUserTermDto.php +++ b/src/Dto/ConsultationUserTermDto.php @@ -5,7 +5,7 @@ class ConsultationUserTermDto extends BaseDto { protected string $term; - protected bool $forAllUsers = false; + protected ?int $userId = null; protected function setTerm(string $term): void { @@ -17,13 +17,13 @@ public function getTerm(): string return $this->term; } - protected function setForAllUsers(bool $forAllUsers): void + protected function setUserId(int $userId): void { - $this->forAllUsers = $forAllUsers; + $this->userId = $userId; } - public function getForAllUsers(): bool + public function getUserId(): ?int { - return $this->forAllUsers; + return $this->userId; } } diff --git a/src/Http/Controllers/Swagger/ConsultationAPISwagger.php b/src/Http/Controllers/Swagger/ConsultationAPISwagger.php index a217ff9..da0ebf2 100644 --- a/src/Http/Controllers/Swagger/ConsultationAPISwagger.php +++ b/src/Http/Controllers/Swagger/ConsultationAPISwagger.php @@ -99,11 +99,11 @@ public function reportTerm(int $orderItemId, ReportTermConsultationRequest $requ * ) * ), * @OA\Parameter( - * name="for_all_users", + * name="user_id", * required=false, * in="query", * @OA\Schema( - * type="boolean" + * type="int" * ) * ), * @OA\Response( @@ -166,11 +166,11 @@ public function approveTerm(ConsultationUserTermRequest $request, int $consultat * ) * ), * @OA\Parameter( - * name="for_all_users", + * name="user_id", * required=false, * in="query", * @OA\Schema( - * type="boolean" + * type="int" * ) * ), * @OA\Response( diff --git a/src/Http/Controllers/Swagger/ConsultationSwagger.php b/src/Http/Controllers/Swagger/ConsultationSwagger.php index 28d3f6b..1b0bbe6 100644 --- a/src/Http/Controllers/Swagger/ConsultationSwagger.php +++ b/src/Http/Controllers/Swagger/ConsultationSwagger.php @@ -398,8 +398,8 @@ public function schedule(int $id, ScheduleConsultationRequest $scheduleConsultat * example="2024-10-31 10:45", * ), * @OA\Property( - * property="for_all_users", - * type="boolean", + * property="user_id", + * type="int", * ), * ) * ), diff --git a/src/Http/Requests/ChangeTermConsultationRequest.php b/src/Http/Requests/ChangeTermConsultationRequest.php index db3a0d3..aa8a45e 100644 --- a/src/Http/Requests/ChangeTermConsultationRequest.php +++ b/src/Http/Requests/ChangeTermConsultationRequest.php @@ -20,7 +20,7 @@ public function rules(): array return [ 'term' => ['required', 'date', new UserTermExist(request('consultationTermId') ? (int) request('consultationTermId') : null)], 'executed_at' => ['required', 'date', 'after_or_equal:now'], - 'for_all_users' => ['boolean'], + 'user_id' => ['nullable', 'exists:users,id'], ]; } } diff --git a/src/Http/Requests/ConsultationUserTermRequest.php b/src/Http/Requests/ConsultationUserTermRequest.php index c7a3e10..40bef7e 100644 --- a/src/Http/Requests/ConsultationUserTermRequest.php +++ b/src/Http/Requests/ConsultationUserTermRequest.php @@ -18,7 +18,7 @@ public function rules(): array return [ 'term' => ['required', 'date', new UserTermExist(request('consultationTermId'))], 'finished_at' => ['nullable', 'date'], - 'for_all_users' => ['nullable', 'boolean'], + 'user_id' => ['nullable', 'exists:users,id'], ]; } } diff --git a/src/Repositories/ConsultationUserTermRepository.php b/src/Repositories/ConsultationUserTermRepository.php index 2d8ea90..a2f918f 100644 --- a/src/Repositories/ConsultationUserTermRepository.php +++ b/src/Repositories/ConsultationUserTermRepository.php @@ -97,11 +97,11 @@ public function getAllUserTermsByConsultationIdAndExecutedAt(int $consultationId ->get(); } - public function getUserTermByConsultationUserIdAndExecutedAt(int $consultationUserId, string $executedAt): ConsultationUserTerm + public function getUserTermByUserIdAndExecutedAt(int $userId, string $executedAt): ConsultationUserTerm { /** @var ConsultationUserTerm $model */ $model = $this->model->newQuery() - ->where('consultation_user_id', '=', $consultationUserId) + ->whereHas('consultationUser', fn (Builder $query) => $query->where('user_id', '=', $userId)) ->where('executed_at', '=', $executedAt) ->firstOrFail(); return $model; diff --git a/src/Repositories/Contracts/ConsultationUserTermRepositoryContract.php b/src/Repositories/Contracts/ConsultationUserTermRepositoryContract.php index f3e39f3..9afb702 100644 --- a/src/Repositories/Contracts/ConsultationUserTermRepositoryContract.php +++ b/src/Repositories/Contracts/ConsultationUserTermRepositoryContract.php @@ -21,7 +21,7 @@ public function allQueryBuilder(?FilterConsultationTermsListDto $filterConsultat */ public function getBusyTerms(int $consultationId, ?string $date = null): Collection; public function getAllUserTermsByConsultationIdAndExecutedAt(int $consultationId, string $executedAt): Collection; - public function getUserTermByConsultationUserIdAndExecutedAt(int $consultationUserId, string $executedAt): ConsultationUserTerm; + public function getUserTermByUserIdAndExecutedAt(int $userId, string $executedAt): ConsultationUserTerm; public function updateModels(Collection $models, array $data): void; public function getByCurrentUserTutor(): Collection; public function updateModel(ConsultationUserTerm $userTerm, array $data): ConsultationUserTerm; diff --git a/src/Services/ConsultationService.php b/src/Services/ConsultationService.php index 2903bfd..24c3be0 100644 --- a/src/Services/ConsultationService.php +++ b/src/Services/ConsultationService.php @@ -167,8 +167,8 @@ public function approveTerm(int $consultationTermId, ConsultationUserTermDto $dt /** @var User $authUser */ $authUser = auth()->user(); - $userTerms = $dto->getForAllUsers() ? $this->consultationUserTermRepository->getAllUserTermsByConsultationIdAndExecutedAt($consultationTerm->consultation_id, $dto->getTerm()) - : collect([$this->consultationUserTermRepository->getUserTermByConsultationUserIdAndExecutedAt($consultationTermId, $dto->getTerm())]); + $userTerms = $dto->getUserId() ? collect([$this->consultationUserTermRepository->getUserTermByUserIdAndExecutedAt($dto->getUserId(), $dto->getTerm())]) + : $this->consultationUserTermRepository->getAllUserTermsByConsultationIdAndExecutedAt($consultationTerm->consultation_id, $dto->getTerm()); DB::transaction(function () use ($userTerms, $authUser) { /** @var ConsultationUserTerm $userTerm */ @@ -191,8 +191,8 @@ public function rejectTerm(int $consultationTermId, ConsultationUserTermDto $dto /** @var User $authUser */ $authUser = auth()->user(); - $userTerms = $dto->getForAllUsers() ? $this->consultationUserTermRepository->getAllUserTermsByConsultationIdAndExecutedAt($consultationTerm->consultation_id, $dto->getTerm()) - : collect([$this->consultationUserTermRepository->getUserTermByConsultationUserIdAndExecutedAt($consultationTermId, $dto->getTerm())]); + $userTerms = $dto->getUserId() ? collect([$this->consultationUserTermRepository->getUserTermByUserIdAndExecutedAt($dto->getUserId(), $dto->getTerm())]) + : $this->consultationUserTermRepository->getAllUserTermsByConsultationIdAndExecutedAt($consultationTerm->consultation_id, $dto->getTerm()); DB::transaction(function () use ($userTerms, $authUser) { /** @var ConsultationUserTerm $userTerm */ @@ -468,8 +468,8 @@ public function changeTerm(int $consultationTermId, ChangeTermConsultationDto $d /** @var ConsultationUserPivot $consultationTerm */ $consultationTerm = $this->consultationUserRepositoryContract->find($consultationTermId); - $userTerms = $dto->getForAllUsers() ? $this->consultationUserTermRepository->getAllUserTermsByConsultationIdAndExecutedAt($consultationTerm->consultation_id, $dto->getTerm()) - : collect([$this->consultationUserTermRepository->getUserTermByConsultationUserIdAndExecutedAt($consultationTermId, $dto->getTerm())]); + $userTerms = $dto->getUserId() ? collect([$this->consultationUserTermRepository->getUserTermByUserIdAndExecutedAt($dto->getUserId(), $dto->getTerm())]) + : $this->consultationUserTermRepository->getAllUserTermsByConsultationIdAndExecutedAt($consultationTerm->consultation_id, $dto->getTerm()); /** @var ConsultationUserTerm $userTerm */ foreach ($userTerms as $userTerm) { diff --git a/tests/APIs/ConsultationChangeTermTest.php b/tests/APIs/ConsultationChangeTermTest.php index 4a5db9b..bdba3af 100644 --- a/tests/APIs/ConsultationChangeTermTest.php +++ b/tests/APIs/ConsultationChangeTermTest.php @@ -57,6 +57,50 @@ public function testChangeTermWithAdmin() Event::assertDispatched(ChangeTerm::class); } + public function testChangeTermForOneUser() + { + Event::fake(); + /** @var ConsultationUserPivot $term */ + $term = $this->consultation->terms()->first(); + + $userTerm = $term->userTerms()->create([ + 'executed_at' => now()->format('Y-m-d H:i:s'), + 'executed_status' => ConsultationTermStatusEnum::REPORTED, + ]); + + $user = User::factory()->create(); + $user->guard_name = 'api'; + $user->assignRole('student'); + + $this->consultation->attachToConsultationPivot([ + 'consultation_id' => $this->consultation->getKey(), + 'user_id' => $user->getKey(), + 'executed_status' => ConsultationTermStatusEnum::NOT_REPORTED, + ]); + + /** @var ConsultationUserPivot $term */ + $changedTerm = $this->consultation->terms()->where('user_id', '=', $user->getKey())->first(); + + $userChangedTerm = $changedTerm->userTerms()->create([ + 'executed_at' => now()->format('Y-m-d H:i:s'), + 'executed_status' => ConsultationTermStatusEnum::REPORTED, + ]); + + $newTerm = now()->modify('+2 hours')->format('Y-m-d H:i:s'); + $this->response = $this->actingAs($this->user, 'api')->post( + '/api/admin/consultations/change-term/' . $term->getKey(), + ['executed_at' => $newTerm, 'term' => $userChangedTerm->executed_at, 'user_id' => $user->getKey()] + ); + $this->response->assertOk(); + $userTerm->refresh(); + $userChangedTerm->refresh(); + $this->assertTrue($userChangedTerm->executed_at === $newTerm); + $this->assertTrue($userChangedTerm->executed_status === ConsultationTermStatusEnum::APPROVED); + $this->assertTrue($userTerm->executed_at !== $newTerm); + $this->assertTrue($userTerm->executed_status === ConsultationTermStatusEnum::REPORTED); + Event::assertDispatched(ChangeTerm::class); + } + public function testChangeTermWithUser() { Event::fake(); diff --git a/tests/APIs/ConsultationReportTermTest.php b/tests/APIs/ConsultationReportTermTest.php index 6e116a4..8368d74 100644 --- a/tests/APIs/ConsultationReportTermTest.php +++ b/tests/APIs/ConsultationReportTermTest.php @@ -256,7 +256,7 @@ public function testConsultationMultipleTermApproved(): void $this->response = $this->actingAs($this->user, 'api')->json( 'GET', '/api/consultations/approve-term/' . $this->consultationUserPivot->getKey(), - ['term' => $now->format('Y-m-d H:i:s'), 'for_all_users' => true] + ['term' => $now->format('Y-m-d H:i:s')] )->assertOk(); $this->consultationUserPivot->refresh(); @@ -296,6 +296,97 @@ public function testConsultationMultipleTermApproved(): void $this->assertTrue($userTermStudent2->executed_status === ConsultationTermStatusEnum::APPROVED); } + public function testConsultationMultipleTermOneApproved(): void + { + Event::fake([ + ApprovedTerm::class, + ApprovedTermWithTrainer::class, + ]); + $this->initVariable(); + $now = now()->modify('+1 day'); + + $this->consultation->update([ + 'max_session_students' => 4, + ]); + + $student1 = User::factory()->create(); + $student1->assignRole('student'); + + $student2 = User::factory()->create(); + $student2->assignRole('student'); + + $student3 = User::factory()->create(); + $student3->assignRole('student'); + + /** @var ConsultationUserPivot $consultationStudent1 */ + $consultationStudent1 = ConsultationUserPivot::factory([ + 'consultation_id' => $this->consultation->getKey(), + 'user_id' => $student1->getKey() + ])->create(); + + $userTermStudent1 = $consultationStudent1->userTerms()->create([ + 'executed_at' => $now->format('Y-m-d H:i:s'), + 'executed_status' => ConsultationTermStatusEnum::REPORTED, + ]); + + $consultationStudent2 = ConsultationUserPivot::factory([ + 'consultation_id' => $this->consultation->getKey(), + 'user_id' => $student2->getKey() + ])->create(); + + $userTermStudent2 = $consultationStudent2->userTerms()->create([ + 'executed_at' => $now->format('Y-m-d H:i:s'), + 'executed_status' => ConsultationTermStatusEnum::REPORTED, + ]); + + $this->consultationUserTerm = $this->consultationUserPivot->userTerms()->create([ + 'executed_at' => $now->format('Y-m-d H:i:s'), + 'executed_status' => ConsultationTermStatusEnum::REPORTED, + ]); + + $this->response = $this->actingAs($this->user, 'api')->json( + 'GET', + '/api/consultations/approve-term/' . $this->consultationUserPivot->getKey(), + ['term' => $now->format('Y-m-d H:i:s'), 'user_id' => $student1->getKey()] + )->assertOk(); + + $this->consultationUserPivot->refresh(); + $this->consultationUserTerm->refresh(); + Event::assertNotDispatched(ApprovedTerm::class, fn (ApprovedTerm $event) => + $event->getUser()->getKey() === $this->user->getKey() && + $event->getConsultationTerm()->getKey() === $this->consultationUserPivot->getKey() + ); + Event::assertNotDispatched(ApprovedTermWithTrainer::class, fn (ApprovedTermWithTrainer $event) => + $event->getUser()->getKey() === $this->user->getKey() && + $event->getConsultationTerm()->getKey() === $this->consultationUserPivot->getKey() + ); + $this->assertTrue($this->consultationUserTerm->executed_status === ConsultationTermStatusEnum::REPORTED); + + $consultationStudent1->refresh(); + $userTermStudent1->refresh(); + Event::assertDispatched(ApprovedTerm::class, fn (ApprovedTerm $event) => + $event->getUser()->getKey() === $student1->getKey() && + $event->getConsultationTerm()->getKey() === $consultationStudent1->getKey() + ); + Event::assertDispatched(ApprovedTermWithTrainer::class, fn (ApprovedTermWithTrainer $event) => + $event->getUser()->getKey() === $this->user->getKey() && + $event->getConsultationTerm()->getKey() === $consultationStudent1->getKey() + ); + $this->assertTrue($userTermStudent1->executed_status === ConsultationTermStatusEnum::APPROVED); + + $consultationStudent2->refresh(); + $userTermStudent2->refresh(); + Event::assertNotDispatched(ApprovedTerm::class, fn (ApprovedTerm $event) => + $event->getUser()->getKey() === $student2->getKey() && + $event->getConsultationTerm()->getKey() === $consultationStudent2->getKey() + ); + Event::assertNotDispatched(ApprovedTermWithTrainer::class, fn (ApprovedTermWithTrainer $event) => + $event->getUser()->getKey() === $this->user->getKey() && + $event->getConsultationTerm()->getKey() === $consultationStudent2->getKey() + ); + $this->assertTrue($userTermStudent2->executed_status === ConsultationTermStatusEnum::REPORTED); + } + public function testConsultationTermApprovedUnauthorized(): void { $this->response = $this->json(