diff --git a/database/factories/ConsultationUserTermFactory.php b/database/factories/ConsultationUserTermFactory.php new file mode 100644 index 0000000..b28f6ae --- /dev/null +++ b/database/factories/ConsultationUserTermFactory.php @@ -0,0 +1,21 @@ +modify('+2 hours'); + return [ + 'executed_at' => $now->format('Y-m-d H:i:s'), + 'executed_status' => $this->faker->randomElement(ConsultationTermStatusEnum::getValues()), + ]; + } +} diff --git a/database/migrations/2024_10_30_053102_add_finished_at_to_consultations_term.php b/database/migrations/2024_10_30_053102_add_finished_at_to_consultations_term.php new file mode 100644 index 0000000..5072f7d --- /dev/null +++ b/database/migrations/2024_10_30_053102_add_finished_at_to_consultations_term.php @@ -0,0 +1,30 @@ +id(); + + $table->dateTime('executed_at')->nullable(); + $table->dateTime('finished_at')->nullable(); + + $table->string('executed_status')->nullable(); + $table->string('reminder_status', 30)->nullable(); + + $table->foreignId('consultation_user_id')->references('id')->on('consultation_user')->onDelete('cascade'); + + $table->timestamps(); + }); + } + + public function down() + { + Schema::dropIfExists('consultation_user_terms'); + } +}; diff --git a/database/migrations/2024_10_31_053102_migrate_consultation_user_data_to_consultation_user_terms.php b/database/migrations/2024_10_31_053102_migrate_consultation_user_data_to_consultation_user_terms.php new file mode 100644 index 0000000..f75fabf --- /dev/null +++ b/database/migrations/2024_10_31_053102_migrate_consultation_user_data_to_consultation_user_terms.php @@ -0,0 +1,26 @@ +whereNotNull('executed_at')->chunk(100, function ($consultationUsers) { + /** @var ConsultationUserPivot $consultationUser */ + foreach ($consultationUsers as $consultationUser) { + $consultationUser->userTerms()->create([ + 'executed_status' => $consultationUser->executed_status, + 'executed_at' => $consultationUser->executed_at, + 'reminder_status' => $consultationUser->reminder_status, + ]); + } + }); + } + + public function down() + { + // + } +}; diff --git a/src/Dto/ChangeTermConsultationDto.php b/src/Dto/ChangeTermConsultationDto.php new file mode 100644 index 0000000..724893d --- /dev/null +++ b/src/Dto/ChangeTermConsultationDto.php @@ -0,0 +1,40 @@ +executedAt = $executedAt; + } + + public function getExecutedAt(): string + { + return $this->executedAt; + } + + protected function setTerm(string $term): void + { + $this->term = $term; + } + + public function getTerm(): string + { + return $this->term; + } + + protected function setForAllUsers(bool $forAllUsers): void + { + $this->forAllUsers = $forAllUsers; + } + + public function getForAllUsers(): bool + { + return $this->forAllUsers; + } +} diff --git a/src/Dto/ConsultationSaveScreenDto.php b/src/Dto/ConsultationSaveScreenDto.php index d96c32a..e80afe2 100644 --- a/src/Dto/ConsultationSaveScreenDto.php +++ b/src/Dto/ConsultationSaveScreenDto.php @@ -11,6 +11,7 @@ class ConsultationSaveScreenDto extends BaseDto protected string $userEmail; protected UploadedFile|string $file; protected string $timestamp; + protected string $executedAt; public function getConsultationId(): int { @@ -36,4 +37,9 @@ public function getTimestamp(): string { return $this->timestamp; } + + public function getExecutedAt(): string + { + return $this->executedAt; + } } diff --git a/src/Dto/ConsultationUserTermDto.php b/src/Dto/ConsultationUserTermDto.php new file mode 100644 index 0000000..13242bf --- /dev/null +++ b/src/Dto/ConsultationUserTermDto.php @@ -0,0 +1,29 @@ +term = $term; + } + + public function getTerm(): string + { + return $this->term; + } + + protected function setForAllUsers(bool $forAllUsers): void + { + $this->forAllUsers = $forAllUsers; + } + + public function getForAllUsers(): bool + { + return $this->forAllUsers; + } +} diff --git a/src/Dto/ConsultationUserTermResourceDto.php b/src/Dto/ConsultationUserTermResourceDto.php new file mode 100644 index 0000000..c22eee7 --- /dev/null +++ b/src/Dto/ConsultationUserTermResourceDto.php @@ -0,0 +1,31 @@ +consultation_user_id = $consultation_user_id; + $this->consultation_id = $consultation_id; + $this->executed_at = $executed_at; + $this->executed_status = $status; + $this->duration = $duration; + $this->users = $users instanceof Collection ? $users : collect(); + $this->author = $author; + $this->finished_at = $finished_at; + } + +} diff --git a/src/Dto/FilterConsultationTermsListDto.php b/src/Dto/FilterConsultationTermsListDto.php index c0ea3fb..a696f61 100644 --- a/src/Dto/FilterConsultationTermsListDto.php +++ b/src/Dto/FilterConsultationTermsListDto.php @@ -4,7 +4,10 @@ use EscolaLms\Consultations\Dto\Contracts\ModelDtoContract; use EscolaLms\Consultations\Models\ConsultationUserPivot; +use EscolaLms\Consultations\Models\ConsultationUserTerm; use EscolaLms\Consultations\Repositories\Criteria\UserExistsCriterion; +use EscolaLms\Consultations\Repositories\Criteria\UserTermConsultationCriterion; +use EscolaLms\Consultations\Repositories\Criteria\UserTermUserExistsCriterion; use EscolaLms\Core\Repositories\Criteria\Primitives\NotNullCriterion; use EscolaLms\Core\Repositories\Criteria\Primitives\WhereCriterion; use EscolaLms\Core\Repositories\Criteria\Primitives\WhereNotInOrIsNullCriterion; @@ -44,19 +47,19 @@ public static function prepareFilters(array $search): self $dto->addToCriteria(new WhereCriterion($dto->model()->getTable() . '.executed_at', $dto->getDateTimeTo(), '<=')); } if ($dto->getConsultationId()) { - $dto->addToCriteria(new EqualCriterion($dto->model()->getTable() . '.consultation_id', $dto->getConsultationId())); + $dto->addToCriteria(new UserTermConsultationCriterion($dto->getConsultationId())); } if ($dto->getReminderStatus()) { $dto->addToCriteria(new WhereNotInOrIsNullCriterion($dto->model()->getTable() . '.reminder_status', $dto->getReminderStatus())); } - $dto->addToCriteria(new UserExistsCriterion()); + $dto->addToCriteria(new UserTermUserExistsCriterion()); return $dto; } - public function model(): ConsultationUserPivot + public function model(): ConsultationUserTerm { // @phpstan-ignore-next-line - return ConsultationUserPivot::newModelInstance(); + return ConsultationUserTerm::newModelInstance(); } public function toArray($filters = false): array diff --git a/src/Dto/FinishTermDto.php b/src/Dto/FinishTermDto.php new file mode 100644 index 0000000..7f9ba4a --- /dev/null +++ b/src/Dto/FinishTermDto.php @@ -0,0 +1,29 @@ +term = $term; + } + + public function getTerm(): string + { + return $this->term; + } + + protected function setFinishedAt(?string $finishedAt): void + { + $this->finishedAt = $finishedAt; + } + + public function getFinishedAt(): ?string + { + return $this->finishedAt; + } +} diff --git a/src/EscolaLmsConsultationsServiceProvider.php b/src/EscolaLmsConsultationsServiceProvider.php index 19831a7..e070243 100644 --- a/src/EscolaLmsConsultationsServiceProvider.php +++ b/src/EscolaLmsConsultationsServiceProvider.php @@ -7,8 +7,10 @@ use EscolaLms\Consultations\Providers\EventServiceProvider; use EscolaLms\Consultations\Repositories\ConsultationRepository; use EscolaLms\Consultations\Repositories\ConsultationUserRepository; +use EscolaLms\Consultations\Repositories\ConsultationUserTermRepository; use EscolaLms\Consultations\Repositories\Contracts\ConsultationRepositoryContract; use EscolaLms\Consultations\Repositories\Contracts\ConsultationUserRepositoryContract; +use EscolaLms\Consultations\Repositories\Contracts\ConsultationUserTermRepositoryContract; use EscolaLms\Consultations\Services\ConsultationService; use EscolaLms\Consultations\Services\Contracts\ConsultationServiceContract; use EscolaLms\Jitsi\EscolaLmsJitsiServiceProvider; @@ -26,7 +28,8 @@ class EscolaLmsConsultationsServiceProvider extends ServiceProvider ]; public const REPOSITORIES = [ ConsultationRepositoryContract::class => ConsultationRepository::class, - ConsultationUserRepositoryContract::class => ConsultationUserRepository::class + ConsultationUserRepositoryContract::class => ConsultationUserRepository::class, + ConsultationUserTermRepositoryContract::class => ConsultationUserTermRepository::class, ]; public $singletons = self::SERVICES + self::REPOSITORIES; diff --git a/src/Events/ConsultationTerm.php b/src/Events/ConsultationTerm.php index 8c619f9..e46f21f 100644 --- a/src/Events/ConsultationTerm.php +++ b/src/Events/ConsultationTerm.php @@ -2,6 +2,7 @@ namespace EscolaLms\Consultations\Events; +use EscolaLms\Consultations\Models\ConsultationUserTerm; use EscolaLms\Core\Models\User; use EscolaLms\Consultations\Models\ConsultationUserPivot; use Illuminate\Foundation\Events\Dispatchable; @@ -13,11 +14,13 @@ abstract class ConsultationTerm private User $user; private ConsultationUserPivot $consultationTerm; + private ?ConsultationUserTerm $consultationUserTerm; - public function __construct(User $user, ConsultationUserPivot $consultationTerm) + public function __construct(User $user, ConsultationUserPivot $consultationTerm, ?ConsultationUserTerm $consultationUserTerm = null) { $this->user = $user; $this->consultationTerm = $consultationTerm; + $this->consultationUserTerm = $consultationUserTerm; } public function getUser(): User @@ -29,4 +32,9 @@ public function getConsultationTerm(): ConsultationUserPivot { return $this->consultationTerm; } + + public function getConsultationUserTerm(): ConsultationUserTerm + { + return $this->consultationUserTerm; + } } diff --git a/src/Events/ReminderAboutTerm.php b/src/Events/ReminderAboutTerm.php index 267cf2a..c55c77b 100644 --- a/src/Events/ReminderAboutTerm.php +++ b/src/Events/ReminderAboutTerm.php @@ -3,15 +3,16 @@ namespace EscolaLms\Consultations\Events; use EscolaLms\Consultations\Models\ConsultationUserPivot; +use EscolaLms\Consultations\Models\ConsultationUserTerm; use EscolaLms\Core\Models\User; class ReminderAboutTerm extends ConsultationTerm { private string $status; - public function __construct(User $user, ConsultationUserPivot $consultationTerm, string $status) + public function __construct(User $user, ConsultationUserPivot $consultationTerm, string $status, ?ConsultationUserTerm $consultationUserTerm = null) { - parent::__construct($user, $consultationTerm); + parent::__construct($user, $consultationTerm, $consultationUserTerm); $this->status = $status; } diff --git a/src/Events/ReminderTrainerAboutTerm.php b/src/Events/ReminderTrainerAboutTerm.php index 193029e..dcc8d8f 100644 --- a/src/Events/ReminderTrainerAboutTerm.php +++ b/src/Events/ReminderTrainerAboutTerm.php @@ -3,15 +3,16 @@ namespace EscolaLms\Consultations\Events; use EscolaLms\Consultations\Models\ConsultationUserPivot; +use EscolaLms\Consultations\Models\ConsultationUserTerm; use EscolaLms\Core\Models\User; class ReminderTrainerAboutTerm extends ConsultationTerm { private string $status; - public function __construct(User $user, ConsultationUserPivot $consultationTerm, string $status) + public function __construct(User $user, ConsultationUserPivot $consultationTerm, string $status, ?ConsultationUserTerm $consultationUserTerm = null) { - parent::__construct($user, $consultationTerm); + parent::__construct($user, $consultationTerm, $consultationUserTerm); $this->status = $status; } diff --git a/src/Http/Controllers/ConsultationAPIController.php b/src/Http/Controllers/ConsultationAPIController.php index 14bc0df..06b7755 100644 --- a/src/Http/Controllers/ConsultationAPIController.php +++ b/src/Http/Controllers/ConsultationAPIController.php @@ -2,10 +2,14 @@ namespace EscolaLms\Consultations\Http\Controllers; +use EscolaLms\Consultations\Dto\ConsultationUserTermDto; use EscolaLms\Consultations\Dto\ConsultationSaveScreenDto; +use EscolaLms\Consultations\Dto\FinishTermDto; use EscolaLms\Consultations\Enum\ConstantEnum; use EscolaLms\Consultations\Http\Controllers\Swagger\ConsultationAPISwagger; +use EscolaLms\Consultations\Http\Requests\ConsultationUserTermRequest; use EscolaLms\Consultations\Http\Requests\ConsultationScreenSaveRequest; +use EscolaLms\Consultations\Http\Requests\FinishTermRequest; use EscolaLms\Consultations\Http\Requests\ListAPIConsultationsRequest; use EscolaLms\Consultations\Http\Requests\ListConsultationsRequest; use EscolaLms\Consultations\Http\Requests\ReportTermConsultationRequest; @@ -67,9 +71,9 @@ public function reportTerm(int $consultationTermId, ReportTermConsultationReques return $this->sendSuccess(__('Consultation reserved term successfully')); } - public function approveTerm(int $consultationTermId): JsonResponse + public function approveTerm(ConsultationUserTermRequest $request, int $consultationTermId): JsonResponse { - $this->consultationServiceContract->approveTerm($consultationTermId); + $this->consultationServiceContract->approveTerm($consultationTermId, new ConsultationUserTermDto($request->all())); $consultationTerms = $this->consultationServiceContract->getConsultationTermsForTutor(); return $this->sendResponse( ConsultationTermsResource::collection($consultationTerms), @@ -77,9 +81,9 @@ public function approveTerm(int $consultationTermId): JsonResponse ); } - public function rejectTerm(int $consultationTermId): JsonResponse + public function rejectTerm(ConsultationUserTermRequest $request, int $consultationTermId): JsonResponse { - $this->consultationServiceContract->rejectTerm($consultationTermId); + $this->consultationServiceContract->rejectTerm($consultationTermId, new ConsultationUserTermDto($request->all())); $consultationTerms = $this->consultationServiceContract->getConsultationTermsForTutor(); return $this->sendResponse( ConsultationTermsResource::collection($consultationTerms), @@ -96,10 +100,10 @@ public function proposedTerms(int $consultationTermId): JsonResponse ); } - public function generateJitsi(int $consultationTermId): JsonResponse + public function generateJitsi(ConsultationUserTermRequest $request, int $consultationTermId): JsonResponse { return $this->sendResponse( - $this->consultationServiceContract->generateJitsi($consultationTermId), + $this->consultationServiceContract->generateJitsi($consultationTermId, new ConsultationUserTermDto($request->all())), __('Consultation updated successfully') ); } @@ -118,4 +122,14 @@ public function screenSave(ConsultationScreenSaveRequest $request): JsonResponse $this->consultationServiceContract->saveScreen(new ConsultationSaveScreenDto($request->all())); return $this->sendSuccess(__('Screen saved successfully')); } + + public function finishTerm(FinishTermRequest $request, int $consultationTermId): JsonResponse + { + $this->consultationServiceContract->finishTerm($consultationTermId, new FinishTermDto($request->all())); + $consultationTerms = $this->consultationServiceContract->getConsultationTermsForTutor(); + return $this->sendResponse( + ConsultationTermsResource::collection($consultationTerms), + __('Consultation term approved successfully') + ); + } } diff --git a/src/Http/Controllers/ConsultationController.php b/src/Http/Controllers/ConsultationController.php index 176636c..4bb0899 100644 --- a/src/Http/Controllers/ConsultationController.php +++ b/src/Http/Controllers/ConsultationController.php @@ -5,6 +5,7 @@ use EscolaLms\Auth\Dtos\Admin\UserAssignableDto; use EscolaLms\Auth\Http\Resources\UserFullResource; use EscolaLms\Auth\Services\Contracts\UserServiceContract; +use EscolaLms\Consultations\Dto\ChangeTermConsultationDto; use EscolaLms\Consultations\Dto\ConsultationDto; use EscolaLms\Consultations\Enum\ConstantEnum; use EscolaLms\Consultations\Enum\ConsultationsPermissionsEnum; @@ -19,6 +20,7 @@ use EscolaLms\Consultations\Http\Requests\UpdateConsultationRequest; use EscolaLms\Consultations\Http\Resources\ConsultationSimpleResource; use EscolaLms\Consultations\Http\Resources\ConsultationTermsResource; +use EscolaLms\Consultations\Http\Resources\ConsultationUserTermsResource; use EscolaLms\Consultations\Services\Contracts\ConsultationServiceContract; use EscolaLms\Core\Dtos\OrderDto; use EscolaLms\Core\Http\Controllers\EscolaLmsBaseController; @@ -55,10 +57,12 @@ public function index(ListConsultationsRequest $listConsultationsRequest): JsonR public function schedule(int $id, ScheduleConsultationRequest $scheduleConsultationRequest): JsonResponse { $search = $scheduleConsultationRequest->except(['limit', 'skip', 'order', 'order_by']); - $consultationTerms = $this->consultationServiceContract + + $consultationUserTerms = $this->consultationServiceContract ->getConsultationTermsByConsultationId($id, $search); + return $this->sendResponseForResource( - ConsultationTermsResource::collection($consultationTerms), + ConsultationUserTermsResource::collection($consultationUserTerms), __('Consultation schedules retrieved successfully') ); } @@ -104,7 +108,7 @@ public function changeTerm(ChangeTermConsultationRequest $changeTermConsultation { $this->consultationServiceContract->changeTerm( $consultationTermId, - $changeTermConsultationRequest->input('executed_at') + new ChangeTermConsultationDto($changeTermConsultationRequest->all()) ); return $this->sendSuccess(__('Consultation term changed successfully')); } diff --git a/src/Http/Controllers/Swagger/ConsultationAPISwagger.php b/src/Http/Controllers/Swagger/ConsultationAPISwagger.php index f3cabf0..a217ff9 100644 --- a/src/Http/Controllers/Swagger/ConsultationAPISwagger.php +++ b/src/Http/Controllers/Swagger/ConsultationAPISwagger.php @@ -2,7 +2,9 @@ namespace EscolaLms\Consultations\Http\Controllers\Swagger; +use EscolaLms\Consultations\Http\Requests\ConsultationUserTermRequest; use EscolaLms\Consultations\Http\Requests\ConsultationScreenSaveRequest; +use EscolaLms\Consultations\Http\Requests\FinishTermRequest; use EscolaLms\Consultations\Http\Requests\ListAPIConsultationsRequest; use EscolaLms\Consultations\Http\Requests\ListConsultationsRequest; use EscolaLms\Consultations\Http\Requests\ReportTermConsultationRequest; @@ -87,6 +89,23 @@ public function reportTerm(int $orderItemId, ReportTermConsultationRequest $requ * type="integer", * ), * ), + * @OA\Parameter( + * name="term", + * required=true, + * in="query", + * @OA\Schema( + * type="string", + * example="2024-10-31 10:45" + * ) + * ), + * @OA\Parameter( + * name="for_all_users", + * required=false, + * in="query", + * @OA\Schema( + * type="boolean" + * ) + * ), * @OA\Response( * response=200, * description="successful operation", @@ -119,7 +138,7 @@ public function reportTerm(int $orderItemId, ReportTermConsultationRequest $requ * ) * ) */ - public function approveTerm(int $consultationTermId): JsonResponse; + public function approveTerm(ConsultationUserTermRequest $request, int $consultationTermId): JsonResponse; /** * @OA\Get( @@ -137,6 +156,23 @@ public function approveTerm(int $consultationTermId): JsonResponse; * type="integer", * ), * ), + * @OA\Parameter( + * name="term", + * required=true, + * in="query", + * @OA\Schema( + * type="string", + * example="2024-10-31 10:45" + * ) + * ), + * @OA\Parameter( + * name="for_all_users", + * required=false, + * in="query", + * @OA\Schema( + * type="boolean" + * ) + * ), * @OA\Response( * response=200, * description="successful operation", @@ -169,7 +205,7 @@ public function approveTerm(int $consultationTermId): JsonResponse; * ) * ) */ - public function rejectTerm(int $consultationTermId): JsonResponse; + public function rejectTerm(ConsultationUserTermRequest $request, int $consultationTermId): JsonResponse; /** * @OA\Get( @@ -187,6 +223,15 @@ public function rejectTerm(int $consultationTermId): JsonResponse; * type="integer", * ), * ), + * @OA\Parameter( + * name="term", + * required=true, + * in="query", + * @OA\Schema( + * type="string", + * example="2024-10-31 10:45" + * ) + * ), * @OA\Response( * response=200, * description="successful operation", @@ -218,7 +263,7 @@ public function rejectTerm(int $consultationTermId): JsonResponse; * ) * ) */ - public function generateJitsi(int $consultationTermId): JsonResponse; + public function generateJitsi(ConsultationUserTermRequest $request, int $consultationTermId): JsonResponse; /** * @OA\Get( @@ -533,7 +578,7 @@ public function show(ShowAPIConsultationRequest $showAPIConsultationRequest, int * @OA\Property( * property="data", * type="array", - * @OA\Items(ref="#/components/schemas/ConsultationTerm") + * @OA\Items(ref="#/components/schemas/ConsultationUserTerm") * ), * @OA\Property( * property="message", @@ -580,6 +625,11 @@ public function schedule(ScheduleConsultationAPIRequest $scheduleConsultationAPI * property="file", * type="string", * format="binary" + * ), + * @OA\Property( + * property="executed_at", + * type="string", + * example="2024-10-04 12:02:12" * ) * ) * ) @@ -616,4 +666,72 @@ public function schedule(ScheduleConsultationAPIRequest $scheduleConsultationAPI * ) */ public function screenSave(ConsultationScreenSaveRequest $request): JsonResponse; + + /** + * @OA\Post( + * path="/api/consultations/finish-term/{consultationTermId}", + * security={ + * {"passport": {}}, + * }, + * summary="Finish consultation term", + * tags={"Consultations"}, + * description="Finish consultation term", + * @OA\Parameter( + * name="consultationTermId", + * required=true, + * in="path", + * @OA\Schema( + * type="integer", + * ), + * ), + * @OA\RequestBody( + * required=true, + * @OA\MediaType( + * mediaType="application/json", + * @OA\Schema( + * @OA\Property( + * property="finished_at", + * type="string", + * example="2024-10-04 12:02:12" + * ), + * @OA\Property( + * property="term", + * type="string", + * example="2024-10-04 12:02:12" + * ) + * ) + * ) + * ), + * @OA\Response( + * response=200, + * description="successful operation", + * @OA\MediaType( + * mediaType="application/json" + * ), + * @OA\Schema( + * type="object", + * @OA\Property( + * property="success", + * type="boolean" + * ), + * @OA\Property( + * property="data", + * type="string" + * ), + * @OA\Property( + * property="message", + * type="string" + * ) + * ) + * ), + * @OA\Response( + * response=404, + * description="Bad request", + * @OA\MediaType( + * mediaType="application/json" + * ) + * ) + * ) + */ + public function finishTerm(FinishTermRequest $request, int $consultationTermId): JsonResponse; } diff --git a/src/Http/Controllers/Swagger/ConsultationSwagger.php b/src/Http/Controllers/Swagger/ConsultationSwagger.php index 7205222..28d3f6b 100644 --- a/src/Http/Controllers/Swagger/ConsultationSwagger.php +++ b/src/Http/Controllers/Swagger/ConsultationSwagger.php @@ -390,7 +390,16 @@ public function schedule(int $id, ScheduleConsultationRequest $scheduleConsultat * @OA\Property( * property="executed_at", * type="string", - * example="New term consultation", + * example="2024-10-31 10:45", + * ), + * @OA\Property( + * property="term", + * type="string", + * example="2024-10-31 10:45", + * ), + * @OA\Property( + * property="for_all_users", + * type="boolean", * ), * ) * ), @@ -440,7 +449,16 @@ public function schedule(int $id, ScheduleConsultationRequest $scheduleConsultat * @OA\Property( * property="executed_at", * type="string", - * example="New term consultation", + * example="2024-10-31 10:45", + * ), + * @OA\Property( + * property="term", + * type="string", + * example="2024-10-31 10:45", + * ), + * @OA\Property( + * property="for_all_users", + * type="boolean", * ), * ) * ), diff --git a/src/Http/Requests/ChangeTermConsultationRequest.php b/src/Http/Requests/ChangeTermConsultationRequest.php index fac8b5c..db3a0d3 100644 --- a/src/Http/Requests/ChangeTermConsultationRequest.php +++ b/src/Http/Requests/ChangeTermConsultationRequest.php @@ -4,6 +4,7 @@ use EscolaLms\Consultations\Enum\ConsultationsPermissionsEnum; use EscolaLms\Consultations\Models\ConsultationUserPivot; +use EscolaLms\Consultations\Rules\UserTermExist; use Illuminate\Foundation\Http\FormRequest; use Illuminate\Support\Facades\Gate; @@ -17,7 +18,9 @@ public function authorize(): bool public function rules(): array { return [ - 'executed_at' => ['date', 'after_or_equal:now'], + 'term' => ['required', 'date', new UserTermExist(request('consultationTermId') ? (int) request('consultationTermId') : null)], + 'executed_at' => ['required', 'date', 'after_or_equal:now'], + 'for_all_users' => ['boolean'], ]; } } diff --git a/src/Http/Requests/ConsultationScreenSaveRequest.php b/src/Http/Requests/ConsultationScreenSaveRequest.php index 81b2bde..ab69563 100644 --- a/src/Http/Requests/ConsultationScreenSaveRequest.php +++ b/src/Http/Requests/ConsultationScreenSaveRequest.php @@ -14,6 +14,7 @@ public function rules(): array 'file' => ['required'], 'user_email' => ['required', 'email', 'exists:users,email'], 'timestamp' => ['required', 'date_format:Y-m-d H:i:s'], + 'executed_at' => ['required'], ]; } } diff --git a/src/Http/Requests/ConsultationUserTermRequest.php b/src/Http/Requests/ConsultationUserTermRequest.php new file mode 100644 index 0000000..c7a3e10 --- /dev/null +++ b/src/Http/Requests/ConsultationUserTermRequest.php @@ -0,0 +1,24 @@ +user(); + return isset($user); + } + + public function rules(): array + { + return [ + 'term' => ['required', 'date', new UserTermExist(request('consultationTermId'))], + 'finished_at' => ['nullable', 'date'], + 'for_all_users' => ['nullable', 'boolean'], + ]; + } +} diff --git a/src/Http/Requests/FinishTermRequest.php b/src/Http/Requests/FinishTermRequest.php new file mode 100644 index 0000000..51d5c1c --- /dev/null +++ b/src/Http/Requests/FinishTermRequest.php @@ -0,0 +1,15 @@ + $this->resource->getKey(), + 'consultation_term_id' => $this->resource->consultation_user_id, 'date' => Carbon::make($this->resource->executed_at) ?? '', 'status' => $this->resource->executed_status ?? '', - 'duration' => $this->resource->consultation->getDuration(), - 'user' => isset($this->resource->user) ? - ConsultationAuthorResource::make($this->resource->user) : - null, + 'duration' => $this->resource->duration, + 'users' => ConsultationAuthorResource::collection($this->resource->users), 'is_started' => $consultationServiceContract->isStarted( $this->resource->executed_at, $this->resource->executed_status, - $this->resource->consultation->getDuration() + $this->resource->duration ), 'is_ended' => $consultationServiceContract->isEnded( $this->resource->executed_at, - $this->resource->consultation->getDuration() + $this->resource->duration ), 'in_coming' => $consultationServiceContract->inComing( $this->resource->executed_at, $this->resource->executed_status, - $this->resource->consultation->getDuration() + $this->resource->duration ), - 'busy_terms' => ConsultationTermResource::collection($consultationServiceContract->getBusyTermsFormatDate($this->resource->consultation->getKey())), - 'author' => $this->resource->consultation->author ? ConsultationAuthorResource::make($this->resource->consultation->author) : null, + 'busy_terms' => ConsultationTermResource::collection($consultationServiceContract->getBusyTermsFormatDate($this->resource->consultation_id)), + 'author' => $this->resource->author ? ConsultationAuthorResource::make($this->resource->author) : null, + 'finished_at' => $this->resource->finished_at, ]; return self::apply($fields, $this); } + + public function getKey(): int + { + return $this->resource->consultation_user_id; + } } diff --git a/src/Http/Resources/ConsultationUserTermsResource.php b/src/Http/Resources/ConsultationUserTermsResource.php new file mode 100644 index 0000000..433879c --- /dev/null +++ b/src/Http/Resources/ConsultationUserTermsResource.php @@ -0,0 +1,106 @@ +resource->consultationUser->consultation; + $fields = [ + 'consultation_term_id' => $this->resource->consultation_user_id, + 'date' => Carbon::make($this->resource->executed_at) ?? '', + 'status' => $this->resource->executed_status ?? '', + 'duration' => $consultation->getDuration(), + 'user' => isset($this->resource->consultationUser->user) ? + ConsultationAuthorResource::make($this->resource->consultationUser->user) : + null, + 'is_started' => $consultationServiceContract->isStarted( + $this->resource->executed_at, + $this->resource->executed_status, + $consultation->getDuration() + ), + 'is_ended' => $consultationServiceContract->isEnded( + $this->resource->executed_at, + $consultation->getDuration() + ), + 'in_coming' => $consultationServiceContract->inComing( + $this->resource->executed_at, + $this->resource->executed_status, + $consultation->getDuration() + ), + 'busy_terms' => ConsultationTermResource::collection($consultationServiceContract->getBusyTermsFormatDate($consultation->getKey())), + 'author' => $consultation->author ? ConsultationAuthorResource::make($consultation->author) : null, + 'finished_at' => $this->resource->finished_at, + ]; + return self::apply($fields, $this); + } +} diff --git a/src/Listeners/ReminderAboutTermListener.php b/src/Listeners/ReminderAboutTermListener.php index 3ab0860..cf51b25 100644 --- a/src/Listeners/ReminderAboutTermListener.php +++ b/src/Listeners/ReminderAboutTermListener.php @@ -27,6 +27,6 @@ public function __construct( */ public function handle(ReminderAboutTerm $event) { - $this->consultationServiceContract->setReminderStatus($event->getConsultationTerm(), $event->getStatus()); + $this->consultationServiceContract->setReminderStatus($event->getConsultationTerm(), $event->getStatus(), $event->getConsultationUserTerm()); } } diff --git a/src/Models/Consultation.php b/src/Models/Consultation.php index a3bde95..f6b3c44 100644 --- a/src/Models/Consultation.php +++ b/src/Models/Consultation.php @@ -244,10 +244,10 @@ public function getLogotypeUrlAttribute(): string return ''; } - public function attachToConsultationPivot(array $data): void + public function attachToConsultationPivot(array $data, ?array $termData = null): void { $consultationServiceContract = app(ConsultationServiceContract::class); - $consultationServiceContract->attachToUser($data); + $consultationServiceContract->attachToUser($data, $termData); } public function getDuration(): string diff --git a/src/Models/ConsultationUserPivot.php b/src/Models/ConsultationUserPivot.php index a5693ec..d879306 100644 --- a/src/Models/ConsultationUserPivot.php +++ b/src/Models/ConsultationUserPivot.php @@ -3,18 +3,22 @@ namespace EscolaLms\Consultations\Models; use EscolaLms\Consultations\Database\Factories\ConsultationUserFactory; +use EscolaLms\Consultations\Enum\ConsultationTermReminderStatusEnum; use EscolaLms\Consultations\Enum\ConsultationTermStatusEnum; use Illuminate\Database\Eloquent\Factories\HasFactory; use Illuminate\Database\Eloquent\Model; use Illuminate\Database\Eloquent\Relations\BelongsTo; +use Illuminate\Database\Eloquent\Relations\HasMany; use Illuminate\Support\Carbon; /** - * @property ConsultationTermStatusEnum $executed_status * @property int $user_id * @property int $consultation_id * @property Consultation $consultation + * * @property Carbon $executed_at + * @property ConsultationTermReminderStatusEnum $reminder_status + * @property ConsultationTermStatusEnum $executed_status */ class ConsultationUserPivot extends Model { @@ -29,6 +33,7 @@ class ConsultationUserPivot extends Model 'consultation_id', 'product_id', 'reminder_status', + 'finished_at', ]; public function user(): BelongsTo @@ -41,16 +46,27 @@ public function consultation(): BelongsTo return $this->belongsTo(Consultation::class); } + /** + * @deprecated + */ public function isApproved(): bool { return $this->executed_status->is(ConsultationTermStatusEnum::APPROVED); } + /** + * @deprecated + */ public function isRejected(): bool { return $this->executed_status->is(ConsultationTermStatusEnum::REJECT); } + public function userTerms(): HasMany + { + return $this->hasMany(ConsultationUserTerm::class, 'consultation_user_id'); + } + protected static function newFactory(): ConsultationUserFactory { return ConsultationUserFactory::new(); diff --git a/src/Models/ConsultationUserTerm.php b/src/Models/ConsultationUserTerm.php new file mode 100644 index 0000000..c716fe8 --- /dev/null +++ b/src/Models/ConsultationUserTerm.php @@ -0,0 +1,43 @@ +belongsTo(ConsultationUserPivot::class, 'consultation_user_id', 'id', 'consultation_user'); + } + + protected static function newFactory(): ConsultationUserTermFactory + { + return ConsultationUserTermFactory::new(); + } +} diff --git a/src/Repositories/ConsultationRepository.php b/src/Repositories/ConsultationRepository.php index c04bbd4..e85723b 100644 --- a/src/Repositories/ConsultationRepository.php +++ b/src/Repositories/ConsultationRepository.php @@ -55,12 +55,13 @@ public function getBoughtConsultationsByQuery(Builder $query): Builder ->select( 'consultations.*', 'consultation_user.id as consultation_user_id', - 'consultation_user.executed_status', - 'consultation_user.executed_at', + 'consultation_user_terms.executed_status', + 'consultation_user_terms.executed_at', 'consultation_user.product_id', 'consultation_user.created_at', ) ->leftJoin('consultation_user', 'consultation_user.consultation_id', '=', 'consultations.id') + ->leftJoin('consultation_user_terms', 'consultation_user_terms.consultation_user_id', '=', 'consultation_user.id') ->where(['consultation_user.user_id' => auth()->user()->getKey()]); } } diff --git a/src/Repositories/ConsultationUserRepository.php b/src/Repositories/ConsultationUserRepository.php index 21f6a6e..a8a168e 100644 --- a/src/Repositories/ConsultationUserRepository.php +++ b/src/Repositories/ConsultationUserRepository.php @@ -55,29 +55,18 @@ public function getIncomingTerm(array $criteria = []): Collection return $query->get(); } - public function getByCurrentUserTutor(): Collection - { - return $this->model->newQuery() - ->whereHas('consultation', fn (Builder $query) => $query - ->whereAuthorId(auth()->user()->getKey()) - ->orWhereHas('teachers', fn (Builder $query) => $query->where('users.id', '=', auth()->user()->getKey())) - )->get(); - } - public function getBusyTerms(int $consultationId, ?string $date = null): Collection { $query = $this->model->newQuery(); $query->where([ 'consultation_id' => $consultationId ]); - $query->whereNotNull('executed_at'); + if ($date) { - $query->where([ - 'executed_at' => $date - ]); + $query->whereHas('userTerms', fn ($query) => $query->where('executed_at', '=', $date)); } - $query->whereIn('executed_status', [ConsultationTermStatusEnum::APPROVED, ConsultationTermStatusEnum::REPORTED]); + $query->whereHas('userTerms', fn ($query) => $query->whereIn('executed_status', [ConsultationTermStatusEnum::APPROVED, ConsultationTermStatusEnum::REPORTED])); + return $query->get(); } - } diff --git a/src/Repositories/ConsultationUserTermRepository.php b/src/Repositories/ConsultationUserTermRepository.php new file mode 100644 index 0000000..2d8ea90 --- /dev/null +++ b/src/Repositories/ConsultationUserTermRepository.php @@ -0,0 +1,158 @@ +fieldSearchable; + } + + public function model() + { + return ConsultationUserTerm::class; + } + + public function createUserTerm(ConsultationUserPivot $consultationUserPivot, array $data): ConsultationUserTerm + { + return $consultationUserPivot->userTerms()->create($data); + } + + public function updateUserTermByExecutedAt(ConsultationUserPivot $consultationUserPivot, string $executedAt, array $data): ConsultationUserTerm + { + /** @var ConsultationUserTerm $userTerm */ + $userTerm = $consultationUserPivot->userTerms()->where('executed_at', '=', $executedAt)->firstOrFail(); + + $userTerm->update($data); + + return $userTerm; + } + + public function updateByConsultationUserIdAndExecutedAt(int $consultationUserId, string $executedAt, array $data): ConsultationUserTerm + { + /** @var ConsultationUserTerm $model */ + $model = $this->model->newQuery() + ->where('consultation_user_id', '=', $consultationUserId) + ->where('executed_at', '=', $executedAt) + ->firstOrFail(); + + $model->fill($data); + $model->save(); + + return $model; + } + + public function allQueryBuilder(?FilterConsultationTermsListDto $filterConsultationTermsListDto = null): Collection + { + $query = $this->model->newQuery(); + + if ($filterConsultationTermsListDto) { + $criteria = $filterConsultationTermsListDto->getCriteria(); + if ($criteria) { + $query = $this->applyCriteria($query, $criteria); + } + } + + return $this->applyPagination($query)->get(); + } + + /** + * @return Collection + */ + public function getBusyTerms(int $consultationId, ?string $date = null): Collection + { + $query = $this->model->newQuery(); + $query->whereHas('consultationUser', fn($query) => $query->where('consultation_id', '=', $consultationId)); + + $query->whereNotNull('executed_at'); + + if ($date) { + $query->where([ + 'executed_at' => $date + ]); + } + $query->whereIn('executed_status', [ConsultationTermStatusEnum::APPROVED, ConsultationTermStatusEnum::REPORTED]); + return $query->get(); + } + + public function getAllUserTermsByConsultationIdAndExecutedAt(int $consultationId, string $executedAt): Collection + { + return $this->model->newQuery() + ->whereHas('consultationUser', fn($query) => $query->where('consultation_id', '=', $consultationId)) + ->where('executed_at', '=', $executedAt) + ->get(); + } + + public function getUserTermByConsultationUserIdAndExecutedAt(int $consultationUserId, string $executedAt): ConsultationUserTerm + { + /** @var ConsultationUserTerm $model */ + $model = $this->model->newQuery() + ->where('consultation_user_id', '=', $consultationUserId) + ->where('executed_at', '=', $executedAt) + ->firstOrFail(); + return $model; + } + + public function updateModels(Collection $models, array $data): void + { + $this->model->newQuery()->whereIn('id', $models->pluck('id'))->update($data); + } + + public function getByCurrentUserTutor(): Collection + { + $result = collect(); + $terms = $this->model->newQuery() + ->whereHas('consultationUser', fn (Builder $query) => $query + ->whereHas('consultation', fn (Builder $query) => $query + ->whereAuthorId(auth()->user()->getKey()) + ->orWhereHas('teachers', fn (Builder $query) => $query->where('users.id', '=', auth()->user()->getKey())) + ) + ) + ->get(); + + /** @var ConsultationUserTerm $term */ + foreach ($terms as $term) { + /** @var ConsultationUserTermResourceDto|null $userTerm */ + // @phpstan-ignore-next-line + $userTerm = $result->first(fn (ConsultationUserTermResourceDto $dto) => $dto->consultation_id === $term->consultationUser->consultation_id && $term->executed_at === $dto->executed_at); + + if ($userTerm) { + $userTerm->users->push($term->consultationUser->user); + } else { + $result->push(new ConsultationUserTermResourceDto( + $term->consultation_user_id, + $term->consultationUser->consultation_id, + $term->executed_at, + $term->executed_status, + $term->consultationUser->consultation->getDuration(), + $term->consultationUser->consultation->author, + $term->finished_at, + collect([$term->consultationUser->user]), + )); + } + } + + return $result; + } + + public function updateModel(ConsultationUserTerm $userTerm, array $data): ConsultationUserTerm + { + $userTerm->fill($data); + $userTerm->save(); + return $userTerm; + } +} diff --git a/src/Repositories/Contracts/ConsultationUserRepositoryContract.php b/src/Repositories/Contracts/ConsultationUserRepositoryContract.php index a3a51ae..b6b4171 100644 --- a/src/Repositories/Contracts/ConsultationUserRepositoryContract.php +++ b/src/Repositories/Contracts/ConsultationUserRepositoryContract.php @@ -16,6 +16,5 @@ public function allQueryBuilder( ): Builder; public function updateModel(ConsultationUserPivot $consultationUserPivot, array $data): ConsultationUserPivot; public function getIncomingTerm(array $criteria = []): Collection; - public function getByCurrentUserTutor(): Collection; public function getBusyTerms(int $consultationId, ?string $date = null): Collection; } diff --git a/src/Repositories/Contracts/ConsultationUserTermRepositoryContract.php b/src/Repositories/Contracts/ConsultationUserTermRepositoryContract.php new file mode 100644 index 0000000..f3e39f3 --- /dev/null +++ b/src/Repositories/Contracts/ConsultationUserTermRepositoryContract.php @@ -0,0 +1,29 @@ + + */ + 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 updateModels(Collection $models, array $data): void; + public function getByCurrentUserTutor(): Collection; + public function updateModel(ConsultationUserTerm $userTerm, array $data): ConsultationUserTerm; + +} diff --git a/src/Repositories/Criteria/UserTermConsultationCriterion.php b/src/Repositories/Criteria/UserTermConsultationCriterion.php new file mode 100644 index 0000000..594a27d --- /dev/null +++ b/src/Repositories/Criteria/UserTermConsultationCriterion.php @@ -0,0 +1,22 @@ +whereHas( + 'consultationUser', + fn (Builder $query) => $query->where('consultation_user.consultation_id', '=', $this->value) + ); + } +} diff --git a/src/Repositories/Criteria/UserTermUserExistsCriterion.php b/src/Repositories/Criteria/UserTermUserExistsCriterion.php new file mode 100644 index 0000000..b35cef1 --- /dev/null +++ b/src/Repositories/Criteria/UserTermUserExistsCriterion.php @@ -0,0 +1,19 @@ +whereHas('consultationUser', fn ($query) => $query->whereHas('user')); + } +} diff --git a/src/Rules/UserTermExist.php b/src/Rules/UserTermExist.php new file mode 100644 index 0000000..5faeef9 --- /dev/null +++ b/src/Rules/UserTermExist.php @@ -0,0 +1,33 @@ +consultationUserId = $consultationUserId; + } + + public function passes($attribute, $value) + { + if (!is_numeric($this->consultationUserId)) { + return false; + } + + return ConsultationUserTerm::query() + ->where('consultation_user_id', '=', $this->consultationUserId) + ->where('executed_at', '=', $value) + ->exists(); + } + + public function message() + { + return __('The consultation user term not found'); + } +} diff --git a/src/Services/ConsultationService.php b/src/Services/ConsultationService.php index c930f8a..2903bfd 100644 --- a/src/Services/ConsultationService.php +++ b/src/Services/ConsultationService.php @@ -4,10 +4,14 @@ use Auth; use Carbon\Carbon; +use DateTime; +use EscolaLms\Consultations\Dto\ChangeTermConsultationDto; +use EscolaLms\Consultations\Dto\ConsultationUserTermDto; use EscolaLms\Consultations\Dto\ConsultationDto; use EscolaLms\Consultations\Dto\ConsultationSaveScreenDto; use EscolaLms\Consultations\Dto\FilterConsultationTermsListDto; use EscolaLms\Consultations\Dto\FilterListDto; +use EscolaLms\Consultations\Dto\FinishTermDto; use EscolaLms\Consultations\Enum\ConstantEnum; use EscolaLms\Consultations\Enum\ConsultationStatusEnum; use EscolaLms\Consultations\Enum\ConsultationTermStatusEnum; @@ -22,15 +26,16 @@ use EscolaLms\Consultations\Exceptions\ChangeTermException; use EscolaLms\Consultations\Exceptions\ConsultationNotFound; use EscolaLms\Consultations\Helpers\StrategyHelper; -use EscolaLms\Consultations\Http\Requests\ConsultationScreenSaveRequest; use EscolaLms\Consultations\Http\Requests\ListConsultationsRequest; use EscolaLms\Consultations\Http\Resources\ConsultationSimpleResource; use EscolaLms\Consultations\Models\Consultation; use EscolaLms\Consultations\Models\ConsultationProposedTerm; use EscolaLms\Consultations\Models\ConsultationUserPivot; +use EscolaLms\Consultations\Models\ConsultationUserTerm; use EscolaLms\Consultations\Models\User; use EscolaLms\Consultations\Repositories\Contracts\ConsultationRepositoryContract; use EscolaLms\Consultations\Repositories\Contracts\ConsultationUserRepositoryContract; +use EscolaLms\Consultations\Repositories\Contracts\ConsultationUserTermRepositoryContract; use EscolaLms\Consultations\Services\Contracts\ConsultationServiceContract; use EscolaLms\Core\Dtos\OrderDto; use EscolaLms\Files\Helpers\FileHelper; @@ -53,15 +58,18 @@ class ConsultationService implements ConsultationServiceContract private ConsultationRepositoryContract $consultationRepositoryContract; private ConsultationUserRepositoryContract $consultationUserRepositoryContract; private JitsiServiceContract $jitsiServiceContract; + protected ConsultationUserTermRepositoryContract $consultationUserTermRepository; public function __construct( ConsultationRepositoryContract $consultationRepositoryContract, ConsultationUserRepositoryContract $consultationUserRepositoryContract, - JitsiServiceContract $jitsiServiceContract + JitsiServiceContract $jitsiServiceContract, + ConsultationUserTermRepositoryContract $consultationUserTermRepository, ) { $this->consultationRepositoryContract = $consultationRepositoryContract; $this->consultationUserRepositoryContract = $consultationUserRepositoryContract; $this->jitsiServiceContract = $jitsiServiceContract; + $this->consultationUserTermRepository = $consultationUserTermRepository; } public function getConsultationsList(array $search = [], bool $onlyActive = false, OrderDto $orderDto = null): Builder @@ -143,51 +151,78 @@ public function reportTerm(int $consultationTermId, string $executedAt): bool 'executed_status' => ConsultationTermStatusEnum::REPORTED, 'executed_at' => Carbon::make($executedAt) ]; - $this->consultationUserRepositoryContract->updateModel($consultationTerm, $data); + + $userTerm = $this->consultationUserTermRepository->createUserTerm($consultationTerm, $data); $author = $consultationTerm->consultation->author; - event(new ReportTerm($author, $consultationTerm)); + event(new ReportTerm($author, $consultationTerm, $userTerm)); return true; }); } - public function approveTerm(int $consultationTermId): bool + public function approveTerm(int $consultationTermId, ConsultationUserTermDto $dto): bool { /** @var ConsultationUserPivot $consultationTerm */ $consultationTerm = $this->consultationUserRepositoryContract->find($consultationTermId); - $this->setStatus($consultationTerm, ConsultationTermStatusEnum::APPROVED); - event(new ApprovedTerm($consultationTerm->user, $consultationTerm)); + /** @var User $authUser */ $authUser = auth()->user(); - event(new ApprovedTermWithTrainer($authUser, $consultationTerm)); + + $userTerms = $dto->getForAllUsers() ? $this->consultationUserTermRepository->getAllUserTermsByConsultationIdAndExecutedAt($consultationTerm->consultation_id, $dto->getTerm()) + : collect([$this->consultationUserTermRepository->getUserTermByConsultationUserIdAndExecutedAt($consultationTermId, $dto->getTerm())]); + + DB::transaction(function () use ($userTerms, $authUser) { + /** @var ConsultationUserTerm $userTerm */ + foreach ($userTerms as $userTerm) { + /** @var ConsultationUserTerm $userTerm */ + $userTerm = $this->consultationUserTermRepository->update(['executed_status' => ConsultationTermStatusEnum::APPROVED], $userTerm->getKey()); + event(new ApprovedTerm($userTerm->consultationUser->user, $userTerm->consultationUser, $userTerm)); + event(new ApprovedTermWithTrainer($authUser, $userTerm->consultationUser, $userTerm)); + } + }); + return true; } - public function rejectTerm(int $consultationTermId): bool + public function rejectTerm(int $consultationTermId, ConsultationUserTermDto $dto): bool { /** @var ConsultationUserPivot $consultationTerm */ $consultationTerm = $this->consultationUserRepositoryContract->find($consultationTermId); - $this->setStatus($consultationTerm, ConsultationTermStatusEnum::REJECT); - event(new RejectTerm($consultationTerm->user, $consultationTerm)); + /** @var User $authUser */ $authUser = auth()->user(); - event(new RejectTermWithTrainer($authUser, $consultationTerm)); + + $userTerms = $dto->getForAllUsers() ? $this->consultationUserTermRepository->getAllUserTermsByConsultationIdAndExecutedAt($consultationTerm->consultation_id, $dto->getTerm()) + : collect([$this->consultationUserTermRepository->getUserTermByConsultationUserIdAndExecutedAt($consultationTermId, $dto->getTerm())]); + + DB::transaction(function () use ($userTerms, $authUser) { + /** @var ConsultationUserTerm $userTerm */ + foreach ($userTerms as $userTerm) { + /** @var ConsultationUserTerm $userTerm */ + $userTerm = $this->consultationUserTermRepository->update(['executed_status' => ConsultationTermStatusEnum::REJECT], $userTerm->getKey()); + event(new RejectTerm($userTerm->consultationUser->user, $userTerm->consultationUser, $userTerm)); + event(new RejectTermWithTrainer($authUser, $userTerm->consultationUser, $userTerm)); + } + }); + return true; } - public function setStatus(ConsultationUserPivot $consultationTerm, string $status): ConsultationUserPivot + public function setStatus(ConsultationUserPivot $consultationTerm, string $status, string $executedAt): ConsultationUserTerm { - return DB::transaction(function () use ($status, $consultationTerm) { - return $this->consultationUserRepositoryContract->updateModel($consultationTerm, ['executed_status' => $status]); + return DB::transaction(function () use ($status, $consultationTerm, $executedAt) { + return $this->consultationUserTermRepository->updateUserTermByExecutedAt($consultationTerm, $executedAt, ['executed_status' => $status]); }); } - public function generateJitsi(int $consultationTermId): array + public function generateJitsi(int $consultationTermId, ConsultationUserTermDto $dto): array { /** @var ConsultationUserPivot $consultationTerm */ $consultationTerm = $this->consultationUserRepositoryContract->find($consultationTermId); + /** @var ConsultationUserTerm $term */ + $term = $consultationTerm->userTerms()->where('executed_at', '=', $dto->getTerm())->firstOrFail(); if (!$this->canGenerateJitsi( - $consultationTerm->executed_at, - $consultationTerm->executed_status, + $term->executed_at, + $term->executed_status, $consultationTerm->consultation->getDuration() )) { throw new NotFoundHttpException(__('Consultation term is not available')); @@ -215,7 +250,7 @@ public function generateJitsi(int $consultationTermId): array $authUser = auth()->user(); return $this->jitsiServiceContract->getChannelData( $authUser, - StringHelper::convertToJitsiSlug($consultationTerm->consultation->name, [], ConstantEnum::DIRECTORY, $consultationTerm->consultation_id, (string) Carbon::make($consultationTerm->executed_at)->getTimestamp()), + StringHelper::convertToJitsiSlug($consultationTerm->consultation->name, [], ConstantEnum::DIRECTORY, $consultationTerm->consultation_id, (string) Carbon::make($term->executed_at)->getTimestamp()), $isModerator, $configOverwrite, $configInterface @@ -227,17 +262,19 @@ public function canGenerateJitsi(?string $executedAt, ?string $status, ?string $ $now = now(); if (isset($executedAt)) { $dateTo = Carbon::make($executedAt); - return in_array($status, [ConsultationTermStatusEnum::APPROVED, ConsultationTermStatusEnum::REJECT]) && + return in_array($status, [ConsultationTermStatusEnum::APPROVED]) && $now->getTimestamp() >= $dateTo->getTimestamp() && !$this->isEnded($executedAt, $duration); } return false; } - public function generateJitsiUrlForEmail(int $consultationTermId, int $userId): ?string + public function generateJitsiUrlForEmail(int $consultationTermId, int $userId, string $executedAt): ?string { /** @var ConsultationUserPivot $consultationTerm */ $consultationTerm = $this->consultationUserRepositoryContract->find($consultationTermId); + /** @var ConsultationUserTerm $term */ + $term = $consultationTerm->userTerms()->where('executed_at', '=', $executedAt)->firstOrFail(); $isModerator = false; $configOverwrite = []; $configInterface = []; @@ -260,7 +297,7 @@ public function generateJitsiUrlForEmail(int $consultationTermId, int $userId): $user = User::find($userId); $result = $this->jitsiServiceContract->getChannelData( $user, - StringHelper::convertToJitsiSlug($consultationTerm->consultation->name, [], ConstantEnum::DIRECTORY, $consultationTerm->consultation_id, (string) Carbon::make($consultationTerm->executed_at)->getTimestamp()), + StringHelper::convertToJitsiSlug($consultationTerm->consultation->name, [], ConstantEnum::DIRECTORY, $consultationTerm->consultation_id, (string) Carbon::make($term->executed_at)->getTimestamp()), $isModerator, $configOverwrite, $configInterface @@ -313,10 +350,9 @@ public function getConsultationTermsByConsultationId(int $consultationId, array $filterConsultationTermsDto = FilterConsultationTermsListDto::prepareFilters( array_merge($search, ['consultation_id' => $consultationId]) ); - return $this->consultationUserRepositoryContract->allQueryBuilder( - $search, - $filterConsultationTermsDto - )->get(); + + return $this->consultationUserTermRepository + ->allQueryBuilder($filterConsultationTermsDto); } public function forCurrentUserResponse( @@ -332,6 +368,7 @@ public function forCurrentUserResponse( } else { $consultationsCollection = ConsultationSimpleResource::collection($consultations->get()); } + ConsultationSimpleResource::extend(function (ConsultationSimpleResource $consultation) { return [ 'consultation_term_id' => $consultation->resource->consultation_user_id, @@ -356,9 +393,13 @@ public function forCurrentUserResponse( return $consultationsCollection; } - public function attachToUser(array $data): void + public function attachToUser(array $data, ?array $termData): void { - $this->consultationUserRepositoryContract->create($data); + /** @var ConsultationUserPivot $consultationUser */ + $consultationUser = $this->consultationUserRepositoryContract->create($data); + if ($termData) { + $consultationUser->userTerms()->create($termData); + } } public function isEnded(?string $executedAt, ?string $duration): bool @@ -382,48 +423,67 @@ public function inComing(?string $executedAt, ?string $status, ?string $duration public function reminderAboutConsultation(string $reminderStatus): void { - foreach ($this->getReminderData($reminderStatus) as $consultationTerm) { + /** @var ConsultationUserTerm $userTerm */ + foreach ($this->getReminderData($reminderStatus) as $userTerm) { event(new ReminderAboutTerm( - $consultationTerm->user, - $consultationTerm, - $reminderStatus + $userTerm->consultationUser->user, + $userTerm->consultationUser, + $reminderStatus, + $userTerm )); - if ($consultationTerm->consultation->teachers) { - $consultationTerm->consultation->teachers->each( + $consultation = $userTerm->consultationUser->consultation; + if ($consultation->teachers->count() > 0) { + $consultation->teachers->each( fn (User $teacher) => event(new ReminderTrainerAboutTerm( $teacher, - $consultationTerm, - $reminderStatus + $userTerm->consultationUser, + $reminderStatus, + $userTerm )) ); } else { event(new ReminderTrainerAboutTerm( - $consultationTerm->consultation->author, - $consultationTerm, - $reminderStatus + $consultation->author, + $userTerm->consultationUser, + $reminderStatus, + $userTerm )); } } } - public function setReminderStatus(ConsultationUserPivot $consultationTerm, string $status): void + public function setReminderStatus(ConsultationUserPivot $consultationTerm, string $status, ?ConsultationUserTerm $userTerm = null): void { - $this->consultationUserRepositoryContract->updateModel($consultationTerm, ['reminder_status' => $status]); + if ($userTerm) { + $this->consultationUserTermRepository->updateModel($userTerm, ['reminder_status' => $status]); + } else { + $this->consultationUserRepositoryContract->updateModel($consultationTerm, ['reminder_status' => $status]); + } } - public function changeTerm(int $consultationTermId, string $executedAt): bool + public function changeTerm(int $consultationTermId, ChangeTermConsultationDto $dto): bool { - DB::transaction(function () use ($consultationTermId, $executedAt) { + DB::transaction(function () use ($consultationTermId, $dto) { try { - /** @var ConsultationUserPivot $consultationUser */ - $consultationUser = $this->consultationUserRepositoryContract->update([ - 'executed_at' => Carbon::make($executedAt), - 'executed_status' => ConsultationTermStatusEnum::APPROVED - ], $consultationTermId); - if (!$consultationUser->user) { - throw new ChangeTermException(__('Term is changed but not executed event because user or term is no exists')); + /** @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())]); + + /** @var ConsultationUserTerm $userTerm */ + foreach ($userTerms as $userTerm) { + /** @var ConsultationUserTerm $consultationUserTerm */ + $consultationUserTerm = $this->consultationUserTermRepository->update([ + 'executed_at' => $dto->getExecutedAt(), + 'executed_status' => ConsultationTermStatusEnum::APPROVED, + ], $userTerm->getKey()); + + if (!$consultationUserTerm->consultationUser->user) { + throw new ChangeTermException(__('Term is changed but not executed event because user or term is no exists')); + } + event(new ChangeTerm($consultationUserTerm->consultationUser->user, $consultationUserTerm->consultationUser, $consultationUserTerm)); } - event(new ChangeTerm($consultationUser->user, $consultationUser)); return true; } catch (Exception $e) { throw new ChangeTermException(__('Term is not changed')); @@ -434,7 +494,7 @@ public function changeTerm(int $consultationTermId, string $executedAt): bool public function getConsultationTermsForTutor(): Collection { - return $this->consultationUserRepositoryContract->getByCurrentUserTutor(); + return $this->consultationUserTermRepository->getByCurrentUserTutor(); } public function termIsBusy(int $consultationId, string $date): bool @@ -464,8 +524,9 @@ public function termIsBusyForUser(int $consultationId, string $date, int $userId public function getBusyTermsFormatDate(int $consultationId): array { - return $this->consultationUserRepositoryContract->getBusyTerms($consultationId)->map( - fn ($term) => Carbon::make($term->executed_at) + return $this->consultationUserTermRepository->getBusyTerms($consultationId)->map( + // @phpstan-ignore-next-line + fn (ConsultationUserTerm $term) => Carbon::make($term->executed_at) )->unique()->toArray(); } @@ -497,9 +558,8 @@ private function getReminderData(string $reminderStatus): Collection 'reminder_status' => $exclusionStatuses, 'status' => [ConsultationTermStatusEnum::APPROVED] ]; - return $this->consultationUserRepositoryContract->getIncomingTerm( - FilterConsultationTermsListDto::prepareFilters($data)->getCriteria() - ); + + return $this->consultationUserTermRepository->allQueryBuilder(FilterConsultationTermsListDto::prepareFilters($data)); } public function saveScreen(ConsultationSaveScreenDto $dto): void @@ -508,15 +568,37 @@ public function saveScreen(ConsultationSaveScreenDto $dto): void $consultationUser = ConsultationUserPivot::query()->where('consultation_id', '=', $dto->getConsultationId())->where('id', '=', $dto->getUserTerminId())->firstOrFail(); $user = User::query()->where('email', '=', $dto->getUserEmail())->firstOrFail(); - if ($user->getKey() !== $consultationUser->user_id || $consultationUser->executed_at === null) { + /** @var ConsultationUserTerm $userTerm */ + $userTerm = $consultationUser->userTerms()->where('executed_at', '=', $dto->getExecutedAt())->firstOrFail(); + + if ($user->getKey() !== $consultationUser->user_id) { throw new NotFoundHttpException(__('Consultation term for this user is not available')); } - $termin = Carbon::make($consultationUser->executed_at); + $termin = Carbon::make($userTerm->executed_at); // consultation_id/term_start_timestamp/user_id/timestamp.jpg $folder = ConstantEnum::DIRECTORY . "/{$dto->getConsultationId()}/{$termin->getTimestamp()}/{$user->getKey()}"; $extension = $dto->getFile() instanceof UploadedFile ? $dto->getFile()->getClientOriginalExtension() : Str::between($dto->getFile(), 'data:image/', ';base64'); Storage::putFileAs($folder, $dto->getFile(), Carbon::make($dto->getTimestamp())->getTimestamp() . '.' . $extension); } + + public function finishTerm(int $consultationTermId, FinishTermDto $dto): bool + { + /** @var ConsultationUserPivot $consultationTerm */ + $consultationTerm = $this->consultationUserRepositoryContract->find($consultationTermId); + + $userTerms = $this->consultationUserTermRepository->getAllUserTermsByConsultationIdAndExecutedAt($consultationTerm->consultation_id, $dto->getTerm()); + + $this->finishTerms($userTerms, $dto->getFinishedAt() ?? now()); + + return true; + } + + public function finishTerms(Collection $usersTerm, DateTime $finishedAt): void + { + DB::transaction(function () use ($usersTerm, $finishedAt) { + $this->consultationUserTermRepository->updateModels($usersTerm, ['finished_at' => $finishedAt]); + }); + } } diff --git a/src/Services/Contracts/ConsultationServiceContract.php b/src/Services/Contracts/ConsultationServiceContract.php index 3bbdd89..c103da8 100644 --- a/src/Services/Contracts/ConsultationServiceContract.php +++ b/src/Services/Contracts/ConsultationServiceContract.php @@ -3,12 +3,15 @@ namespace EscolaLms\Consultations\Services\Contracts; use Carbon\Carbon; +use EscolaLms\Consultations\Dto\ChangeTermConsultationDto; +use EscolaLms\Consultations\Dto\ConsultationUserTermDto; use EscolaLms\Consultations\Dto\ConsultationDto; use EscolaLms\Consultations\Dto\ConsultationSaveScreenDto; -use EscolaLms\Consultations\Http\Requests\ConsultationScreenSaveRequest; +use EscolaLms\Consultations\Dto\FinishTermDto; use EscolaLms\Consultations\Http\Requests\ListConsultationsRequest; use EscolaLms\Consultations\Models\Consultation; use EscolaLms\Consultations\Models\ConsultationUserPivot; +use EscolaLms\Consultations\Models\ConsultationUserTerm; use EscolaLms\Core\Dtos\OrderDto; use Illuminate\Database\Eloquent\Builder; use Illuminate\Foundation\Http\FormRequest; @@ -22,14 +25,14 @@ public function store(ConsultationDto $consultationDto): Consultation; public function update(int $id, ConsultationDto $consultationDto): Consultation; public function show(int $id): Consultation; public function delete(int $id): ?bool; - public function attachToUser(array $data): void; + public function attachToUser(array $data, ?array $termData): void; public function reportTerm(int $orderItemId, string $executedAt): bool; - public function approveTerm(int $consultationTermId): bool; - public function rejectTerm(int $consultationTermId): bool; - public function setStatus(ConsultationUserPivot $consultationTerm, string $status): ConsultationUserPivot; - public function generateJitsi(int $consultationTermId): array; + public function approveTerm(int $consultationTermId, ConsultationUserTermDto $dto): bool; + public function rejectTerm(int $consultationTermId, ConsultationUserTermDto $dto): bool; + public function setStatus(ConsultationUserPivot $consultationTerm, string $status, string $executedAt): ConsultationUserTerm; + public function generateJitsi(int $consultationTermId, ConsultationUserTermDto $dto): array; public function canGenerateJitsi(?string $executedAt, ?string $status, ?string $duration): bool; - public function generateJitsiUrlForEmail(int $consultationTermId, int $userId): ?string; + public function generateJitsiUrlForEmail(int $consultationTermId, int $userId, string $executedAt): ?string; public function proposedTerms(int $consultationTermId): ?array; public function setRelations(Consultation $consultation, array $relations = []): void; public function setFiles(Consultation $consultation, array $files = []): void; @@ -94,12 +97,13 @@ public function isEnded(?string $executedAt, ?string $duration): bool; public function isStarted(?string $executedAt, ?string $status, ?string $duration): bool; public function inComing(?string $executedAt, ?string $status, ?string $duration): bool; public function reminderAboutConsultation(string $reminderStatus): void; - public function setReminderStatus(ConsultationUserPivot $consultationTerm, string $status): void; - public function changeTerm(int $consultationTermId, string $executedAt): bool; + public function setReminderStatus(ConsultationUserPivot $consultationTerm, string $status, ?ConsultationUserTerm $userTerm = null): void; + public function changeTerm(int $consultationTermId, ChangeTermConsultationDto $dto): bool; public function getConsultationTermsForTutor(): Collection; public function termIsBusy(int $consultationId, string $date): bool; public function termIsBusyForUser(int $consultationId, string $date, int $userId): bool; public function getBusyTermsFormatDate(int $consultationId): array; public function updateModelFieldsFromRequest(Consultation $consultation, FormRequest $request): void; public function saveScreen(ConsultationSaveScreenDto $dto): void; + public function finishTerm(int $consultationTermId, FinishTermDto $dto): bool; } diff --git a/src/routes.php b/src/routes.php index 338732d..53f5634 100644 --- a/src/routes.php +++ b/src/routes.php @@ -23,6 +23,7 @@ Route::get('/reject-term/{consultationTermId}', [ConsultationAPIController::class, 'rejectTerm']); Route::get('/generate-jitsi/{consultationTermId}', [ConsultationAPIController::class, 'generateJitsi']); Route::post('/change-term/{consultationTermId}', [ConsultationController::class, 'changeTerm']); + Route::post('/finish-term/{consultationTermId}', [ConsultationAPIController::class, 'finishTerm']); }); Route::group(['prefix' => 'api/consultations'], function () { diff --git a/tests/APIs/ConsultationApiTest.php b/tests/APIs/ConsultationApiTest.php index c241652..3b63e64 100644 --- a/tests/APIs/ConsultationApiTest.php +++ b/tests/APIs/ConsultationApiTest.php @@ -13,6 +13,7 @@ use EscolaLms\Consultations\Enum\ConsultationTermStatusEnum; use EscolaLms\Consultations\Models\Consultation; use EscolaLms\Consultations\Models\ConsultationUserPivot; +use EscolaLms\Consultations\Models\ConsultationUserTerm; use EscolaLms\Consultations\Tests\Models\User; use EscolaLms\Consultations\Tests\TestCase; use EscolaLms\Core\Tests\CreatesUsers; @@ -217,32 +218,36 @@ public function testConsultationSaveScreen(): void /** @var Consultation $consultation */ $consultation = Consultation::factory()->create(); $consultation->author()->associate($this->user); + + /** @var ConsultationUserPivot $consultationUser */ + $consultationUser = ConsultationUserPivot::factory() + ->create([ + 'consultation_id' => $consultation->getKey(), + 'user_id' => $student->getKey(), + ]); + $time = now(); - $data = [ - 'consultation_id' => $consultation->getKey(), - 'user_id' => $student->getKey(), + /** @var ConsultationUserTerm $userTerm */ + $userTerm = $consultationUser->userTerms()->create([ 'executed_status' => ConsultationTermStatusEnum::APPROVED, 'executed_at' => $time, - ]; - $consultation->attachToConsultationPivot($data); - - $consultationUser = ConsultationUserPivot::query() - ->where('user_id', '=', $student->getKey()) - ->where('consultation_id', '=', $consultation->getKey())->first(); + ]); + $screenTime = now()->addMinutes(10); Storage::fake(); $this->response = $this->json('POST', '/api/consultations/save-screen', [ 'consultation_id' => $consultation->getKey(), 'user_email' => $student->email, 'user_termin_id' => $consultationUser->getKey(), 'file' => UploadedFile::fake()->image('image.jpg'), - 'timestamp' => $time->format('Y-m-d H:i:s'), + 'timestamp' => $screenTime->format('Y-m-d H:i:s'), + 'executed_at' => $userTerm->executed_at->format('Y-m-d H:i:s'), ]) ->assertOk(); - $term = Carbon::make($consultationUser->executed_at); + $term = Carbon::make($userTerm->executed_at); // consultation_id/term_start_timestamp/user_id/timestamp.jpg - Storage::assertExists(ConstantEnum::DIRECTORY . "/{$consultation->getKey()}/{$term->getTimestamp()}/{$student->getKey()}/{$time->getTimestamp()}.jpg"); + Storage::assertExists(ConstantEnum::DIRECTORY . "/{$consultation->getKey()}/{$term->getTimestamp()}/{$student->getKey()}/{$screenTime->getTimestamp()}.jpg"); $this->response = $this->json('POST', '/api/consultations/save-screen', [ 'consultation_id' => $consultation->getKey(), @@ -250,6 +255,7 @@ public function testConsultationSaveScreen(): void 'user_termin_id' => $consultationUser->getKey(), 'file' => UploadedFile::fake()->image('image.jpg'), 'timestamp' => $time->format('Y-m-d H:i:s'), + 'executed_at' => $userTerm->executed_at->format('Y-m-d H:i:s'), ])->assertNotFound(); $this->response = $this->json('POST', '/api/consultations/save-screen', [ @@ -258,6 +264,7 @@ public function testConsultationSaveScreen(): void 'user_termin_id' => $consultationUser->getKey() + 1, 'file' => UploadedFile::fake()->image('image.jpg'), 'timestamp' => $time->format('Y-m-d H:i:s'), + 'executed_at' => $userTerm->executed_at->format('Y-m-d H:i:s'), ]) ->assertUnprocessable() ->assertJsonValidationErrors(['user_termin_id']); diff --git a/tests/APIs/ConsultationChangeTermTest.php b/tests/APIs/ConsultationChangeTermTest.php index 93abc41..4a5db9b 100644 --- a/tests/APIs/ConsultationChangeTermTest.php +++ b/tests/APIs/ConsultationChangeTermTest.php @@ -6,6 +6,7 @@ use EscolaLms\Consultations\Enum\ConsultationTermStatusEnum; use EscolaLms\Consultations\Events\ChangeTerm; use EscolaLms\Consultations\Models\Consultation; +use EscolaLms\Consultations\Models\ConsultationUserPivot; use EscolaLms\Consultations\Tests\TestCase; use EscolaLms\Core\Models\User; use Illuminate\Foundation\Testing\DatabaseTransactions; @@ -36,32 +37,46 @@ protected function setUp(): void public function testChangeTermWithAdmin() { 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, + ]); + $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] + ['executed_at' => $newTerm, 'term' => $userTerm->executed_at] ); $this->response->assertOk(); - $term->refresh(); - $this->assertTrue($term->executed_at === $newTerm); - $this->assertTrue($term->executed_status === ConsultationTermStatusEnum::APPROVED); + $userTerm->refresh(); + $this->assertTrue($userTerm->executed_at === $newTerm); + $this->assertTrue($userTerm->executed_status === ConsultationTermStatusEnum::APPROVED); Event::assertDispatched(ChangeTerm::class); } public function testChangeTermWithUser() { 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, + ]); + $newTerm = now()->modify('+2 hours')->format('Y-m-d H:i:s'); $this->response = $this->actingAs($this->user, 'api')->post( '/api/consultations/change-term/' . $term->getKey(), - ['executed_at' => $newTerm] + ['executed_at' => $newTerm, 'term' => $userTerm->executed_at] ); $this->response->assertOk(); - $term->refresh(); - $this->assertTrue($term->executed_at === $newTerm); - $this->assertTrue($term->executed_status === ConsultationTermStatusEnum::APPROVED); + $userTerm->refresh(); + $this->assertTrue($userTerm->executed_at === $newTerm); + $this->assertTrue($userTerm->executed_status === ConsultationTermStatusEnum::APPROVED); Event::assertDispatched(ChangeTerm::class); } diff --git a/tests/APIs/ConsultationGenerateJitsiTest.php b/tests/APIs/ConsultationGenerateJitsiTest.php index cb9593f..07b65d4 100644 --- a/tests/APIs/ConsultationGenerateJitsiTest.php +++ b/tests/APIs/ConsultationGenerateJitsiTest.php @@ -44,13 +44,17 @@ public function testGenerateJitsiUnAuthorized(): void public function testGenerateJitsiWithApprovedTerm(): void { $consultation = Consultation::factory()->create(); + $time = now(); $this->consultationUserPivot = ConsultationUserPivot::factory([ 'consultation_id' => $consultation->getKey(), 'user_id' => $this->user->getKey(), - 'executed_at' => now(), - 'executed_status' => ConsultationTermStatusEnum::APPROVED, ])->create(); + $consultationUserTerm = $this->consultationUserPivot->userTerms()->create([ + 'executed_at' => $time->format('Y-m-d H:i:s'), + 'executed_status' => ConsultationTermStatusEnum::APPROVED, + ]); + $returnData = [ 'data' => [ @@ -69,7 +73,7 @@ public function testGenerateJitsiWithApprovedTerm(): void ]; $jitsiService = $this->mock(JitsiServiceContract::class); $jitsiService->shouldReceive('getChannelData')->once()->andReturn($returnData); - $response = $this->actingAs($this->user, 'api')->json('GET', 'api/consultations/generate-jitsi/' . $this->consultationUserPivot->getKey()); + $response = $this->actingAs($this->user, 'api')->json('GET', 'api/consultations/generate-jitsi/' . $this->consultationUserPivot->getKey(), ['term' => $consultationUserTerm->executed_at]); $response->assertOk(); $response->assertJson( fn (AssertableJson $json) => $json->has('data', @@ -91,7 +95,14 @@ public function testGenerateJitsiWithApprovedTerm(): void public function testGenerateJitsiWithRejectedTerm(): void { $this->initVariable(); - $response = $this->actingAs($this->user, 'api')->json('GET', 'api/consultations/generate-jitsi/' . $this->consultationUserPivot->getKey()); + + $time = now(); + $this->consultationUserPivot->userTerms()->create([ + 'executed_at' => $time->format('Y-m-d H:i:s'), + 'executed_status' => ConsultationTermStatusEnum::REJECT, + ]); + + $response = $this->actingAs($this->user, 'api')->json('GET', 'api/consultations/generate-jitsi/' . $this->consultationUserPivot->getKey(), ['term' => $time->format('Y-m-d H:i:s')]); $response->assertNotFound(); $response->assertJson(fn (AssertableJson $json) => $json->where('message', __('Consultation term is not available'))->etc()); } @@ -99,7 +110,14 @@ public function testGenerateJitsiWithRejectedTerm(): void public function testGenerateJitsiBeforeExecutedAt(): void { $this->initVariable(); - $response = $this->actingAs($this->user, 'api')->json('GET', 'api/consultations/generate-jitsi/' . $this->consultationUserPivot->getKey()); + + $time = now()->addHours(4); + $this->consultationUserPivot->userTerms()->create([ + 'executed_at' => $time->format('Y-m-d H:i:s'), + 'executed_status' => ConsultationTermStatusEnum::APPROVED, + ]); + + $response = $this->actingAs($this->user, 'api')->json('GET', 'api/consultations/generate-jitsi/' . $this->consultationUserPivot->getKey(), ['term' => $time->format('Y-m-d H:i:s')]); $response->assertNotFound(); $response->assertJson(fn (AssertableJson $json) => $json->where('message', __('Consultation term is not available'))->etc()); } diff --git a/tests/APIs/ConsultationReportTermTest.php b/tests/APIs/ConsultationReportTermTest.php index cc6cb9d..6e116a4 100644 --- a/tests/APIs/ConsultationReportTermTest.php +++ b/tests/APIs/ConsultationReportTermTest.php @@ -4,6 +4,7 @@ use EscolaLms\Consultations\Events\ApprovedTermWithTrainer; use EscolaLms\Consultations\Events\RejectTermWithTrainer; +use EscolaLms\Consultations\Models\ConsultationUserTerm; use EscolaLms\Consultations\Tests\Models\User; use EscolaLms\Consultations\Enum\ConsultationTermStatusEnum; use EscolaLms\Consultations\Events\ApprovedTerm; @@ -21,6 +22,7 @@ class ConsultationReportTermTest extends TestCase private string $apiUrl; private Consultation $consultation; private ConsultationUserPivot $consultationUserPivot; + private ConsultationUserTerm $consultationUserTerm; protected function setUp(): void { @@ -36,8 +38,6 @@ private function initVariable(): void $this->consultationUserPivot = ConsultationUserPivot::factory([ 'consultation_id' => $this->consultation->getKey(), 'user_id' => $this->user->getKey(), - 'executed_at' => null, - 'executed_status' => ConsultationTermStatusEnum::NOT_REPORTED, ])->create(); } @@ -53,8 +53,9 @@ public function testConsultationReportTerm(): void ] ); $this->consultationUserPivot->refresh(); - $this->assertTrue($this->consultationUserPivot->executed_at === $now->format('Y-m-d H:i:s')); - $this->assertTrue($this->consultationUserPivot->executed_status === ConsultationTermStatusEnum::REPORTED); + $userTerm = $this->consultationUserPivot->userTerms()->first(); + $this->assertTrue($userTerm->executed_at === $now->format('Y-m-d H:i:s')); + $this->assertTrue($userTerm->executed_status === ConsultationTermStatusEnum::REPORTED); $this->response->assertOk(); } @@ -62,12 +63,16 @@ public function testConsultationReportTermMultipleTerm(): void { $this->initVariable(); $now = now()->modify('+1 day'); - ConsultationUserPivot::factory([ - 'executed_at' => $now->format('Y-m-d H:i:s'), - 'executed_status' => ConsultationTermStatusEnum::APPROVED, + /** @var ConsultationUserPivot $consultationUser */ + $consultationUser = ConsultationUserPivot::factory([ 'consultation_id' => $this->consultationUserPivot->consultation_id, 'user_id' => $this->user->getKey() ])->create(); + + $consultationUser->userTerms()->create([ + 'executed_at' => $now->format('Y-m-d H:i:s'), + 'executed_status' => ConsultationTermStatusEnum::APPROVED, + ]); $this->response = $this->actingAs($this->user, 'api') ->json('POST', '/api/consultations/report-term/' . $this->consultationUserPivot->getKey(), @@ -93,13 +98,17 @@ public function testConsultationReportTermMultipleTermDifferentUsers(): void $user = User::factory()->create(); $user->assignRole('student'); - ConsultationUserPivot::factory([ - 'executed_at' => $now->format('Y-m-d H:i:s'), - 'executed_status' => ConsultationTermStatusEnum::APPROVED, + /** @var ConsultationUserPivot $consultationUser */ + $consultationUser = ConsultationUserPivot::factory([ 'consultation_id' => $this->consultation->getKey(), 'user_id' => $user->getKey() ])->create(); + $consultationUser->userTerms()->create([ + 'executed_at' => $now->format('Y-m-d H:i:s'), + 'executed_status' => ConsultationTermStatusEnum::APPROVED, + ]); + $this->response = $this->actingAs($this->user, 'api') ->json('POST', '/api/consultations/report-term/' . $this->consultationUserPivot->getKey(), @@ -108,8 +117,9 @@ public function testConsultationReportTermMultipleTermDifferentUsers(): void ] )->assertOk(); $this->consultationUserPivot->refresh(); - $this->assertTrue($this->consultationUserPivot->executed_at === $now->format('Y-m-d H:i:s')); - $this->assertTrue($this->consultationUserPivot->executed_status === ConsultationTermStatusEnum::REPORTED); + $userTerm = $this->consultationUserPivot->userTerms()->first(); + $this->assertTrue($userTerm->executed_at === $now->format('Y-m-d H:i:s')); + $this->assertTrue($userTerm->executed_status === ConsultationTermStatusEnum::REPORTED); } public function testConsultationReportTermMultipleTermDifferentUsersLimit(): void @@ -123,13 +133,18 @@ public function testConsultationReportTermMultipleTermDifferentUsersLimit(): voi $user = User::factory()->create(); $user->assignRole('student'); - ConsultationUserPivot::factory([ - 'executed_at' => $now->format('Y-m-d H:i:s'), - 'executed_status' => ConsultationTermStatusEnum::APPROVED, + + /** @var ConsultationUserPivot $consultationUser */ + $consultationUser = ConsultationUserPivot::factory([ 'consultation_id' => $this->consultation->getKey(), 'user_id' => $user->getKey() ])->create(); + $consultationUser->userTerms()->create([ + 'executed_at' => $now->format('Y-m-d H:i:s'), + 'executed_status' => ConsultationTermStatusEnum::APPROVED, + ]); + $this->response = $this->actingAs($this->user, 'api') ->json('POST', '/api/consultations/report-term/' . $this->consultationUserPivot->getKey(), @@ -173,7 +188,8 @@ public function testConsultationTermApproved(): void $this->consultationUserPivot->refresh(); $this->response = $this->actingAs($this->user, 'api')->json( 'GET', - '/api/consultations/approve-term/' . $this->consultationUserPivot->getKey() + '/api/consultations/approve-term/' . $this->consultationUserPivot->getKey(), + ['term' => $now->format('Y-m-d H:i:s')] ); $this->consultationUserPivot->refresh(); $userId = $this->user->getKey(); @@ -187,7 +203,9 @@ public function testConsultationTermApproved(): void ); $this->consultationUserPivot->refresh(); $this->response->assertOk(); - $this->assertTrue($this->consultationUserPivot->executed_status === ConsultationTermStatusEnum::APPROVED); + /** @var ConsultationUserTerm $userTerm */ + $userTerm = $this->consultationUserPivot->userTerms()->first(); + $this->assertTrue($userTerm->executed_status === ConsultationTermStatusEnum::APPROVED); } public function testConsultationMultipleTermApproved(): void @@ -209,31 +227,40 @@ public function testConsultationMultipleTermApproved(): void $student2 = User::factory()->create(); $student2->assignRole('student'); + /** @var ConsultationUserPivot $consultationStudent1 */ $consultationStudent1 = ConsultationUserPivot::factory([ - 'executed_at' => $now->format('Y-m-d H:i:s'), - 'executed_status' => ConsultationTermStatusEnum::REPORTED, 'consultation_id' => $this->consultation->getKey(), 'user_id' => $student1->getKey() ])->create(); - $consultationStudent2 = ConsultationUserPivot::factory([ + $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(); - $this->consultationUserPivot->update([ + $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() + '/api/consultations/approve-term/' . $this->consultationUserPivot->getKey(), + ['term' => $now->format('Y-m-d H:i:s'), 'for_all_users' => true] )->assertOk(); $this->consultationUserPivot->refresh(); + $this->consultationUserTerm->refresh(); Event::assertDispatched(ApprovedTerm::class, fn (ApprovedTerm $event) => $event->getUser()->getKey() === $this->user->getKey() && $event->getConsultationTerm()->getKey() === $this->consultationUserPivot->getKey() @@ -242,14 +269,10 @@ public function testConsultationMultipleTermApproved(): void $event->getUser()->getKey() === $this->user->getKey() && $event->getConsultationTerm()->getKey() === $this->consultationUserPivot->getKey() ); - $this->assertTrue($this->consultationUserPivot->executed_status === ConsultationTermStatusEnum::APPROVED); - - $this->response = $this->actingAs($this->user, 'api')->json( - 'GET', - '/api/consultations/approve-term/' . $consultationStudent1->getKey() - )->assertOk(); + $this->assertTrue($this->consultationUserTerm->executed_status === ConsultationTermStatusEnum::APPROVED); $consultationStudent1->refresh(); + $userTermStudent1->refresh(); Event::assertDispatched(ApprovedTerm::class, fn (ApprovedTerm $event) => $event->getUser()->getKey() === $student1->getKey() && $event->getConsultationTerm()->getKey() === $consultationStudent1->getKey() @@ -258,14 +281,10 @@ public function testConsultationMultipleTermApproved(): void $event->getUser()->getKey() === $this->user->getKey() && $event->getConsultationTerm()->getKey() === $consultationStudent1->getKey() ); - $this->assertTrue($consultationStudent1->executed_status === ConsultationTermStatusEnum::APPROVED); - - $this->response = $this->actingAs($this->user, 'api')->json( - 'GET', - '/api/consultations/approve-term/' . $consultationStudent2->getKey() - )->assertOk(); + $this->assertTrue($userTermStudent1->executed_status === ConsultationTermStatusEnum::APPROVED); $consultationStudent2->refresh(); + $userTermStudent2->refresh(); Event::assertDispatched(ApprovedTerm::class, fn (ApprovedTerm $event) => $event->getUser()->getKey() === $student2->getKey() && $event->getConsultationTerm()->getKey() === $consultationStudent2->getKey() @@ -274,7 +293,7 @@ public function testConsultationMultipleTermApproved(): void $event->getUser()->getKey() === $this->user->getKey() && $event->getConsultationTerm()->getKey() === $consultationStudent2->getKey() ); - $this->assertTrue($consultationStudent2->executed_status === ConsultationTermStatusEnum::APPROVED); + $this->assertTrue($userTermStudent2->executed_status === ConsultationTermStatusEnum::APPROVED); } public function testConsultationTermApprovedUnauthorized(): void @@ -303,7 +322,8 @@ public function testConsultationTermReject(): void $this->consultationUserPivot->refresh(); $this->response = $this->actingAs($this->user, 'api')->json( 'GET', - '/api/consultations/reject-term/' . $this->consultationUserPivot->getKey() + '/api/consultations/reject-term/' . $this->consultationUserPivot->getKey(), + ['term' => $now->format('Y-m-d H:i:s')] ); $userId = $this->user->getKey(); Event::assertDispatched(RejectTerm::class, fn (RejectTerm $event) => @@ -316,7 +336,8 @@ public function testConsultationTermReject(): void ); $this->consultationUserPivot->refresh(); $this->response->assertOk(); - $this->assertTrue($this->consultationUserPivot->executed_status === ConsultationTermStatusEnum::REJECT); + $userTerm = $this->consultationUserPivot->userTerms()->first(); + $this->assertTrue($userTerm->executed_status === ConsultationTermStatusEnum::REJECT); } public function testConsultationTermRejectUnauthorized(): void diff --git a/tests/APIs/ConsultationScheduleTermsTest.php b/tests/APIs/ConsultationScheduleTermsTest.php index 95be0b8..a8e2c91 100644 --- a/tests/APIs/ConsultationScheduleTermsTest.php +++ b/tests/APIs/ConsultationScheduleTermsTest.php @@ -4,6 +4,7 @@ use EscolaLms\Consultations\Http\Resources\ConsultationAuthorResource; use EscolaLms\Consultations\Http\Resources\ConsultationTermResource; +use EscolaLms\Consultations\Models\ConsultationUserTerm; use EscolaLms\Consultations\Services\Contracts\ConsultationServiceContract; use EscolaLms\Consultations\Tests\Models\User; use EscolaLms\Consultations\Database\Seeders\ConsultationsPermissionSeeder; @@ -23,6 +24,7 @@ class ConsultationScheduleTermsTest extends TestCase private ConsultationUserPivot $consultationUserPivot; private string $apiUrl; private User $student; + private ConsultationUserTerm $consultationUserTerm; protected function setUp(): void { @@ -48,9 +50,12 @@ private function initVariable(): void $this->consultationUserPivot = ConsultationUserPivot::factory([ 'consultation_id' => $this->consultation->getKey(), 'user_id' => $this->student->getKey(), + ])->create(); + + $this->consultationUserTerm = $this->consultationUserPivot->userTerms()->create([ 'executed_at' => now()->format('Y-m-d H:i:s'), 'executed_status' => ConsultationTermStatusEnum::APPROVED - ])->create(); + ]); } public function testConsultationTermsListUnauthorized(): void @@ -90,8 +95,8 @@ public function testConsultationScheduleForTutor(): void )->etc()); $this->response->assertJsonFragment([ 'consultation_term_id' => $this->consultationUserPivot->getKey(), - 'date' => isset($this->consultationUserPivot->executed_at) ? Carbon::make($this->consultationUserPivot->executed_at)->format("Y-m-d\TH:i:s.000000\Z") : '', - 'status' => $this->consultationUserPivot->executed_status ?? '', + 'date' => isset($this->consultationUserTerm->executed_at) ? Carbon::make($this->consultationUserTerm->executed_at)->format("Y-m-d\TH:i:s.000000\Z") : '', + 'status' => $this->consultationUserTerm->executed_status ?? '', ]); } diff --git a/tests/APIs/ConsultationScheduleTest.php b/tests/APIs/ConsultationScheduleTest.php index a92f05d..d25ee62 100644 --- a/tests/APIs/ConsultationScheduleTest.php +++ b/tests/APIs/ConsultationScheduleTest.php @@ -48,6 +48,9 @@ public function testFailReminderAboutConsultationWhenStatusOtherApproved() $this->consultationUserPivot = ConsultationUserPivot::factory([ 'consultation_id' => $this->consultation->getKey(), 'user_id' => $this->user->getKey(), + ])->create(); + + $userTerm = $this->consultationUserPivot->userTerms()->create([ 'executed_at' => now()->modify( config( 'escolalms_consultations.modifier_date.' . @@ -58,7 +61,7 @@ public function testFailReminderAboutConsultationWhenStatusOtherApproved() ConsultationTermStatusEnum::REPORTED, ConsultationTermStatusEnum::NOT_REPORTED ]) - ])->create(); + ]); $this->assertTrue($this->consultationUserPivot->reminder_status === null); $job = new ReminderAboutConsultationJob(ConsultationTermReminderStatusEnum::REMINDED_HOUR_BEFORE); $job->handle(); @@ -66,7 +69,7 @@ public function testFailReminderAboutConsultationWhenStatusOtherApproved() Event::assertNotDispatched(ReminderTrainerAboutTerm::class); $this->consultationUserPivot->refresh(); $this->assertTrue( - $this->consultationUserPivot->reminder_status === null + $userTerm->reminder_status === null ); } @@ -76,18 +79,20 @@ public function testReminderAboutConsultationBeforeHour() $this->consultationUserPivot = ConsultationUserPivot::factory([ 'consultation_id' => $this->consultation->getKey(), 'user_id' => $this->user->getKey(), + ])->create(); + $consultationUserTerm = $this->consultationUserPivot->userTerms()->create([ 'executed_at' => now()->modify( config('escolalms_consultations.modifier_date.' . ConsultationTermReminderStatusEnum::REMINDED_HOUR_BEFORE, '+1 hour') )->format('Y-m-d H:i:s'), 'executed_status' => ConsultationTermStatusEnum::APPROVED - ])->create(); - $this->assertTrue($this->consultationUserPivot->reminder_status === null); + ]); + $this->assertTrue($consultationUserTerm->reminder_status === null); $job = new ReminderAboutConsultationJob(ConsultationTermReminderStatusEnum::REMINDED_HOUR_BEFORE); $job->handle(); - $this->consultationUserPivot->refresh(); + $consultationUserTerm->refresh(); $this->assertTrue( - $this->consultationUserPivot->reminder_status === ConsultationTermReminderStatusEnum::REMINDED_HOUR_BEFORE + $consultationUserTerm->reminder_status === ConsultationTermReminderStatusEnum::REMINDED_HOUR_BEFORE ); } @@ -97,16 +102,20 @@ public function testReminderAboutConsultationBeforeDay() $this->consultationUserPivot = ConsultationUserPivot::factory([ 'consultation_id' => $this->consultation->getKey(), 'user_id' => $this->user->getKey(), + ])->create(); + + $consultationUserTerm = $this->consultationUserPivot->userTerms()->create([ 'executed_at' => now()->modify(config('escolalms_consultations.modifier_date.' . ConsultationTermReminderStatusEnum::REMINDED_DAY_BEFORE, '+1 day'))->format('Y-m-d H:i:s'), 'executed_status' => ConsultationTermStatusEnum::APPROVED - ])->create(); - $this->assertTrue($this->consultationUserPivot->reminder_status === null); + ]); + + $this->assertTrue($consultationUserTerm->reminder_status === null); $job = new ReminderAboutConsultationJob(ConsultationTermReminderStatusEnum::REMINDED_DAY_BEFORE); $job->handle(); - $this->consultationUserPivot->refresh(); + $consultationUserTerm->refresh(); $this->assertTrue( - $this->consultationUserPivot->reminder_status === ConsultationTermReminderStatusEnum::REMINDED_DAY_BEFORE + $consultationUserTerm->reminder_status === ConsultationTermReminderStatusEnum::REMINDED_DAY_BEFORE ); } @@ -116,19 +125,23 @@ public function testReminderAboutConsultationBeforeHourWhenConsultationTermRemin $this->consultationUserPivot = ConsultationUserPivot::factory([ 'consultation_id' => $this->consultation->getKey(), 'user_id' => $this->user->getKey(), + ])->create(); + + $consultationUserTerm = $this->consultationUserPivot->userTerms()->create([ 'executed_at' => now()->modify( config('escolalms_consultations.modifier_date.' . ConsultationTermReminderStatusEnum::REMINDED_HOUR_BEFORE, '+1 hour') )->format('Y-m-d H:i:s'), 'executed_status' => ConsultationTermStatusEnum::APPROVED, 'reminder_status' => ConsultationTermReminderStatusEnum::REMINDED_DAY_BEFORE, - ])->create(); - $this->assertTrue($this->consultationUserPivot->reminder_status === ConsultationTermReminderStatusEnum::REMINDED_DAY_BEFORE); + ]); + + $this->assertTrue($consultationUserTerm->reminder_status === ConsultationTermReminderStatusEnum::REMINDED_DAY_BEFORE); $job = new ReminderAboutConsultationJob(ConsultationTermReminderStatusEnum::REMINDED_HOUR_BEFORE); $job->handle(); - $this->consultationUserPivot->refresh(); + $consultationUserTerm->refresh(); $this->assertTrue( - $this->consultationUserPivot->reminder_status === ConsultationTermReminderStatusEnum::REMINDED_HOUR_BEFORE + $consultationUserTerm->reminder_status === ConsultationTermReminderStatusEnum::REMINDED_HOUR_BEFORE ); } @@ -139,21 +152,25 @@ public function testFailReminderAboutConsultationBeforeHourWhenConsultationTermR $this->consultationUserPivot = ConsultationUserPivot::factory([ 'consultation_id' => $this->consultation->getKey(), 'user_id' => $this->user->getKey(), + ])->create(); + + $consultationUserTerm = $this->consultationUserPivot->userTerms()->create([ 'executed_at' => now()->modify( config('escolalms_consultations.modifier_date.' . ConsultationTermReminderStatusEnum::REMINDED_HOUR_BEFORE, '+1 hour') )->format('Y-m-d H:i:s'), 'executed_status' => ConsultationTermStatusEnum::APPROVED, 'reminder_status' => ConsultationTermReminderStatusEnum::REMINDED_HOUR_BEFORE, - ])->create(); - $this->assertTrue($this->consultationUserPivot->reminder_status === ConsultationTermReminderStatusEnum::REMINDED_HOUR_BEFORE); + ]); + + $this->assertTrue($consultationUserTerm->reminder_status === ConsultationTermReminderStatusEnum::REMINDED_HOUR_BEFORE); $job = new ReminderAboutConsultationJob(ConsultationTermReminderStatusEnum::REMINDED_HOUR_BEFORE); $job->handle(); - $this->consultationUserPivot->refresh(); + $consultationUserTerm->refresh(); Event::assertNotDispatched(ReminderAboutTerm::class); Event::assertNotDispatched(ReminderTrainerAboutTerm::class); $this->assertTrue( - $this->consultationUserPivot->reminder_status === ConsultationTermReminderStatusEnum::REMINDED_HOUR_BEFORE + $consultationUserTerm->reminder_status === ConsultationTermReminderStatusEnum::REMINDED_HOUR_BEFORE ); } @@ -164,20 +181,25 @@ public function testFailReminderAboutConsultationBeforeDayWhenLessThanDay() $this->consultationUserPivot = ConsultationUserPivot::factory([ 'consultation_id' => $this->consultation->getKey(), 'user_id' => $this->user->getKey(), + + ])->create(); + + $consultationUserTerm = $this->consultationUserPivot->userTerms()->create([ 'executed_at' => now()->modify( config('escolalms_consultations.modifier_date.' . ConsultationTermReminderStatusEnum::REMINDED_DAY_BEFORE, '+1 day') )->subHour()->format('Y-m-d H:i:s'), 'executed_status' => ConsultationTermStatusEnum::APPROVED, - ])->create(); - $this->assertTrue($this->consultationUserPivot->reminder_status === null); + ]); + + $this->assertTrue($consultationUserTerm->reminder_status === null); $job = new ReminderAboutConsultationJob(ConsultationTermReminderStatusEnum::REMINDED_DAY_BEFORE); $job->handle(); - $this->consultationUserPivot->refresh(); + $consultationUserTerm->refresh(); Event::assertNotDispatched(ReminderAboutTerm::class); Event::assertNotDispatched(ReminderTrainerAboutTerm::class); $this->assertTrue( - $this->consultationUserPivot->reminder_status === null + $consultationUserTerm->reminder_status === null ); } } diff --git a/tests/Services/ConsultationServiceTest.php b/tests/Services/ConsultationServiceTest.php index eb875a7..bc2b05e 100644 --- a/tests/Services/ConsultationServiceTest.php +++ b/tests/Services/ConsultationServiceTest.php @@ -43,13 +43,17 @@ public function test_term_is_busy_for_user_already_approved(): void $this->expectExceptionMessage('Term is busy for this user.'); $date = now()->addDay()->format('Y-m-d H:i:s'); - ConsultationUserPivot::factory([ - 'executed_at' => $date, - 'executed_status' => ConsultationTermStatusEnum::APPROVED, + /** @var ConsultationUserPivot $consultationTerm */ + $consultationTerm = ConsultationUserPivot::factory([ 'consultation_id' => $this->consultation->getKey(), 'user_id' => $this->user->getKey() ])->create(); + $userTerm = $consultationTerm->userTerms()->create([ + 'executed_at' => $date, + 'executed_status' => ConsultationTermStatusEnum::APPROVED, + ]); + $this->consultationService->termIsBusyForUser($this->consultation->getKey(), $date, $this->user->getKey()); } @@ -60,13 +64,17 @@ public function test_term_is_busy_for_user_other_user(): void $user = User::factory()->create(); $user->assignRole('student'); - ConsultationUserPivot::factory([ - 'executed_at' => $date, - 'executed_status' => ConsultationTermStatusEnum::APPROVED, + /** @var ConsultationUserPivot $consultationTerm */ + $consultationTerm = ConsultationUserPivot::factory([ 'consultation_id' => $this->consultation->getKey(), 'user_id' => $user->getKey() ])->create(); + $userTerm = $consultationTerm->userTerms()->create([ + 'executed_at' => $date, + 'executed_status' => ConsultationTermStatusEnum::APPROVED, + ]); + $this->assertTrue($this->consultationService->termIsBusyForUser($this->consultation->getKey(), $date, $this->user->getKey())); } @@ -81,13 +89,17 @@ public function test_term_is_not_busy_for_user_multiple_students(): void 'max_session_students' => 2, ]); - ConsultationUserPivot::factory([ - 'executed_at' => $date, - 'executed_status' => ConsultationTermStatusEnum::APPROVED, + /** @var ConsultationUserPivot $consultationTerm */ + $consultationTerm = ConsultationUserPivot::factory([ 'consultation_id' => $this->consultation->getKey(), 'user_id' => $user->getKey() ])->create(); + $userTerm = $consultationTerm->userTerms()->create([ + 'executed_at' => $date, + 'executed_status' => ConsultationTermStatusEnum::APPROVED, + ]); + $this->assertFalse($this->consultationService->termIsBusyForUser($this->consultation->getKey(), $date, $this->user->getKey())); } }