diff --git a/apps/core-rest-api/http/appointment-client.http b/apps/core-rest-api/http/appointment-client.http new file mode 100644 index 0000000..428d4a8 --- /dev/null +++ b/apps/core-rest-api/http/appointment-client.http @@ -0,0 +1,21 @@ +@authToken = {{$dotenv AUTH_TOKEN}} +@apiKey = {{$dotenv API_KEY}} + +# @appointmentDate = {{require "./appointmentDate.js"}} +#### + +# @name create_appointment +POST http://localhost:3333/core/appointment/create HTTP/1.1 +Content-Type: application/json +Authorization: Bearer {{authToken}} + +{ + "psychologistId": "{{$dotenv PSYCHOLOGIST_ID}}", + "clinicId": "{{$dotenv CLINIC_ID}}", + "patientId": "{{$dotenv PATIENT_ID}}", + "paymentMethod": "CREDIT_CARD", + "online": false, + "confirmed": true, + "cancelled": false, + "date": "2024-01-19T08:30:54" +} diff --git a/apps/core-rest-api/src/app/adapters/controllers/api/api.module.ts b/apps/core-rest-api/src/app/adapters/controllers/api/api.module.ts index 42f4505..187b957 100644 --- a/apps/core-rest-api/src/app/adapters/controllers/api/api.module.ts +++ b/apps/core-rest-api/src/app/adapters/controllers/api/api.module.ts @@ -20,6 +20,8 @@ import { AuthenticatePsychologistController } from './use-cases/psychologist/aut import { CreatePsychologistController } from './use-cases/psychologist/create-psychologist/create-psychologist.controller'; import { DeletePsychologistController } from './use-cases/psychologist/delete-psychologist/delete-psychologist.controller'; +import { CreateAppointmentController } from './use-cases/appointment/create-appointment/create-appointment.controller'; +import { NestjsCreateAppointmentService } from './use-cases/appointment/create-appointment/nestjs-create-appointment.service'; import { NestjsCreateClinicService } from './use-cases/clinic/create-clinic/nestjs-create-clinic.service'; import { NestjsDeleteClinicService } from './use-cases/clinic/delete-clinic/nestjs-delete-clinic.service'; import { NestjsUpdateClinicService } from './use-cases/clinic/update-clinic/nestjs-update-clinic.service'; @@ -53,7 +55,8 @@ import { NestjsUpdatePsychologistService } from './use-cases/psychologist/update DeleteClinicController, CreatePatientController, DeletePatientController, - CreatePatientAppointmentRegistryController + CreatePatientAppointmentRegistryController, + CreateAppointmentController ], providers: [ BcryptHasherService, @@ -67,7 +70,8 @@ import { NestjsUpdatePsychologistService } from './use-cases/psychologist/update NestjsDeleteClinicService, NestjsCreatePatientService, NestjsDeletePatientService, - NestjsCreatePatientAppointmentRegistryService + NestjsCreatePatientAppointmentRegistryService, + NestjsCreateAppointmentService ], }) export class ApiModule {} diff --git a/apps/core-rest-api/src/app/adapters/controllers/api/use-cases/appointment/create-appointment/create-appointment.controller.ts b/apps/core-rest-api/src/app/adapters/controllers/api/use-cases/appointment/create-appointment/create-appointment.controller.ts new file mode 100644 index 0000000..168009f --- /dev/null +++ b/apps/core-rest-api/src/app/adapters/controllers/api/use-cases/appointment/create-appointment/create-appointment.controller.ts @@ -0,0 +1,31 @@ +import { Body, Controller, Post } from "@nestjs/common"; +import { ApiBearerAuth, ApiTags } from "@nestjs/swagger"; +import { GlobalAppHttpException } from '../../../../../../shared/errors/globalAppHttpException'; +import { CreateSingleAppointmentInputDto } from "./dto"; +import { NestjsCreateAppointmentService } from "./nestjs-create-appointment.service"; + +interface CreateAppointmentResponse { + message: string; +} +@ApiTags('Appointment') +@ApiBearerAuth() +@Controller({ + path: 'appointment', +}) +export class CreateAppointmentController { + constructor(private createAppointmentService: NestjsCreateAppointmentService) {} + + @Post('create') + // @ApiOperation(postMethodDocs) + async execute(@Body() createAppointmentDto: CreateSingleAppointmentInputDto): Promise{ + try { + await this.createAppointmentService.execute({...createAppointmentDto, date: new Date(createAppointmentDto.date)}); + + return { + message: 'Appointment created successfully', + } + } catch (error) { + throw new GlobalAppHttpException(error); + } + } +} diff --git a/apps/core-rest-api/src/app/adapters/controllers/api/use-cases/appointment/create-appointment/create-appointment.e2e-spec.ts b/apps/core-rest-api/src/app/adapters/controllers/api/use-cases/appointment/create-appointment/create-appointment.e2e-spec.ts new file mode 100644 index 0000000..bf50a88 --- /dev/null +++ b/apps/core-rest-api/src/app/adapters/controllers/api/use-cases/appointment/create-appointment/create-appointment.e2e-spec.ts @@ -0,0 +1,62 @@ +import { faker } from "@faker-js/faker"; +import { INestApplication } from "@nestjs/common"; +import request from 'supertest'; +import { makeAppointment } from '../../../../../../../../tests/factories/make-appointment'; +import { setupE2ETest } from '../../../../../../../../tests/utils/e2e-tests-initial-setup'; +import { AppointmentEntity } from '../../../../../../core/domains/appointment/entities/appointment/entity'; +import { PaymentMethod } from '../../../../../../core/shared/interfaces/payments'; +import { PostgreSqlPrismaOrmService } from '../../../../../database/infra/prisma/prisma.service'; + +describe('[E2E] - Create New Appointment', () => { + let app: INestApplication; + let prisma: PostgreSqlPrismaOrmService; + + let access_token: string; + + let psychologistId: string; + let clinicId: string; + let patientId: string; + + + beforeAll(async () => { + const setup = await setupE2ETest(); + + app = setup.app; + prisma = setup.prisma; + + access_token = setup.access_token; + + clinicId = setup.clinic.id; + psychologistId = setup.psychologist.id; + + patientId = setup.patient.id; + }); + + it('[POST] - Should successfully create a new appointment', async () => { + const newAppointment: AppointmentEntity = makeAppointment({ + psychologistId, + clinicId, + patientId, + date: faker.date.recent({ days: 10 }), + cancelled: false, + confirmationDate: null, + confirmed: true, + online: false, + paymentMethod: PaymentMethod.CREDIT_CARD + }); + const response = await request(app.getHttpServer()) + .post('/appointment/create') + .set('Authorization', `Bearer ${access_token}`) + .send(newAppointment); + + const appointmentOnDatabase = await prisma.appointment.findFirst({ + where: { + patientId: newAppointment.patientId, + }, + }); + + expect(response.statusCode).toBe(201); + expect(response.body.message).toBe('Appointment created successfully'); + expect(appointmentOnDatabase).toBeTruthy(); + }); +}) diff --git a/apps/core-rest-api/src/app/adapters/controllers/api/use-cases/appointment/create-appointment/dto.ts b/apps/core-rest-api/src/app/adapters/controllers/api/use-cases/appointment/create-appointment/dto.ts new file mode 100644 index 0000000..8fa9a73 --- /dev/null +++ b/apps/core-rest-api/src/app/adapters/controllers/api/use-cases/appointment/create-appointment/dto.ts @@ -0,0 +1,32 @@ +import { IsBoolean, IsDate, IsEnum, IsOptional, IsString } from 'class-validator'; +import { PaymentMethod } from '../../../../../../core/shared/interfaces/payments'; + +export class CreateSingleAppointmentInputDto { + @IsString() + psychologistId!: string; + + @IsString() + patientId!: string; + + @IsString() + date!: string; + + @IsBoolean() + online!: boolean; + + @IsString() + clinicId!: string; + + @IsBoolean() + confirmed!: boolean; + + @IsDate() + @IsOptional() + confirmationDate?: Date | null; + + @IsBoolean() + cancelled!: boolean; + + @IsEnum(PaymentMethod) + paymentMethod!: PaymentMethod; +} diff --git a/apps/core-rest-api/src/app/adapters/controllers/api/use-cases/appointment/create-appointment/nestjs-create-appointment.service.ts b/apps/core-rest-api/src/app/adapters/controllers/api/use-cases/appointment/create-appointment/nestjs-create-appointment.service.ts new file mode 100644 index 0000000..2f83cc1 --- /dev/null +++ b/apps/core-rest-api/src/app/adapters/controllers/api/use-cases/appointment/create-appointment/nestjs-create-appointment.service.ts @@ -0,0 +1,10 @@ +import { Injectable } from '@nestjs/common'; +import { AppointmentDatabaseRepository } from '../../../../../../core/domains/appointment/repositories/database-repository'; +import { CreateSingleAppointmentService } from '../../../../../../core/domains/appointment/use-cases/create-single-appointment/create-single-appointment.service'; + +@Injectable() +export class NestjsCreateAppointmentService extends CreateSingleAppointmentService { + constructor(appointmentDatabaseRepository: AppointmentDatabaseRepository) { + super(appointmentDatabaseRepository); + } +} diff --git a/apps/core-rest-api/src/app/adapters/controllers/api/use-cases/clinic/delete-clinic/delete-clinic.e2e-spec.ts b/apps/core-rest-api/src/app/adapters/controllers/api/use-cases/clinic/delete-clinic/delete-clinic.e2e-spec.ts index 4e5d29f..f96ad78 100644 --- a/apps/core-rest-api/src/app/adapters/controllers/api/use-cases/clinic/delete-clinic/delete-clinic.e2e-spec.ts +++ b/apps/core-rest-api/src/app/adapters/controllers/api/use-cases/clinic/delete-clinic/delete-clinic.e2e-spec.ts @@ -69,9 +69,6 @@ describe('[E2E] - Delete Clinic', () => { const deletedClinic = await prisma['clinic'].findUnique({ where: { id: clinic.id }, }); - - console.log('DELETED CLINIC ---->', deletedClinic); - expect(deletedClinic).toBeNull(); }); }); diff --git a/apps/core-rest-api/src/app/adapters/database/mappers/postgresql-prisma-appointment-mapper.ts b/apps/core-rest-api/src/app/adapters/database/mappers/postgresql-prisma-appointment-mapper.ts new file mode 100644 index 0000000..427ccf9 --- /dev/null +++ b/apps/core-rest-api/src/app/adapters/database/mappers/postgresql-prisma-appointment-mapper.ts @@ -0,0 +1,42 @@ +import { + Prisma, + Appointment as PrismaAppointmentDto, + PaymentMethod as PrismaPaymentMethod, +} from '@prisma/client'; + +import { AppointmentEntity } from '../../../core/domains/appointment/entities/appointment/entity'; +import { CreateSingleAppointmentDto } from '../../../core/domains/appointment/use-cases/create-single-appointment/create-single-appointment-dto'; +import { UpdateAppointmentInfoDto } from '../../../core/domains/appointment/use-cases/update-appointment-info/update-appointment-info-dto'; +import { PaymentMethod } from '../../../core/shared/interfaces/payments'; + +export class PostgresqlPrismaAppointmentMapper { + static toDomain(raw: PrismaAppointmentDto): AppointmentEntity { + return new AppointmentEntity({ + ...raw, + paymentMethod: raw.paymentMethod as unknown as PaymentMethod, + date: (raw.date).toString() + }); + } + + static toPrismaCreate(raw: CreateSingleAppointmentDto): Prisma.AppointmentCreateArgs { + return { + data: { + ...raw, + paymentMethod: raw.paymentMethod as unknown as PrismaPaymentMethod, + date: new Date(raw.date) + }, + }; + } + + static toPrismaUpdate(raw: UpdateAppointmentInfoDto): Prisma.AppointmentUpdateArgs { + return { + data: { + ...raw, + done: raw.done as boolean + }, + where: { + id: raw.id, + }, + }; + } +} diff --git a/apps/core-rest-api/src/app/adapters/database/repositories/appointment/postgres-prisma-orm-appointment-repository.ts b/apps/core-rest-api/src/app/adapters/database/repositories/appointment/postgres-prisma-orm-appointment-repository.ts new file mode 100644 index 0000000..201770f --- /dev/null +++ b/apps/core-rest-api/src/app/adapters/database/repositories/appointment/postgres-prisma-orm-appointment-repository.ts @@ -0,0 +1,104 @@ +import { ConflictException, Injectable } from '@nestjs/common'; +import { AppointmentEntity } from '../../../../core/domains/appointment/entities/appointment/entity'; +import { AppointmentDatabaseRepository } from '../../../../core/domains/appointment/repositories/database-repository'; +import { CreateSingleAppointmentDto } from '../../../../core/domains/appointment/use-cases/create-single-appointment/create-single-appointment-dto'; +import { UpdatedAppointmentDateDto } from '../../../../core/domains/appointment/use-cases/update-appointment-date/update-appointment-date-dto'; +import { UpdateAppointmentInfoDto } from '../../../../core/domains/appointment/use-cases/update-appointment-info/update-appointment-info-dto'; +import { APPOINTMENT_ERROR_MESSAGES } from '../../../../shared/errors/error-messages'; +import { PostgreSqlPrismaOrmService } from "../../infra/prisma/prisma.service"; +import { PostgresqlPrismaAppointmentMapper } from '../../mappers/postgresql-prisma-appointment-mapper'; + +@Injectable() +export class PostgresqlPrismaOrmAppointmentRepository implements AppointmentDatabaseRepository { + constructor(private postgresqlPrismaOrmService: PostgreSqlPrismaOrmService) {} + + async findSingleAppointmentById(appointmentId: string): Promise { + const appointment = await this.postgresqlPrismaOrmService['appointment'].findUnique({where: { + id: appointmentId + }}) + if (!appointment) { + return null; + } + + return PostgresqlPrismaAppointmentMapper.toDomain(appointment); + } + + async findSingleAppointmentByDate(appointmentDate: Date): Promise { + const appointment = await this.postgresqlPrismaOrmService['appointment'].findFirst({ + where: { + date: appointmentDate, + } + }) + + if (!appointment) { + return null; + } + + return PostgresqlPrismaAppointmentMapper.toDomain(appointment); + } + + async createSingleAppointment(appointment: CreateSingleAppointmentDto): Promise { + const isAppointmentExists = await this.findSingleAppointmentByDate(new Date(appointment.date)); + + if (isAppointmentExists) { + throw new ConflictException(APPOINTMENT_ERROR_MESSAGES['CONFLICTING_DATE_TIME']); + } + + const toPrismaEntity = PostgresqlPrismaAppointmentMapper.toPrismaCreate({ + ...appointment, + }); + + const newAppointment = + await this.postgresqlPrismaOrmService['appointment'].create(toPrismaEntity); + + return PostgresqlPrismaAppointmentMapper.toDomain(newAppointment); + } + + async getAppointments(): Promise { + const appointments = await this.postgresqlPrismaOrmService['appointment'].findMany(); + + return appointments.map((appointment) => PostgresqlPrismaAppointmentMapper.toDomain(appointment)) + } + + async updateAppointmentInfo(newAppointmentInfo: UpdateAppointmentInfoDto): Promise { + const oldAppointmentInfo = await this.findSingleAppointmentById(newAppointmentInfo.id); + + if (!oldAppointmentInfo) { + throw new ConflictException(APPOINTMENT_ERROR_MESSAGES['APPOINTMENT_NOT_FOUND']); + } + + const toPrismaEntity = PostgresqlPrismaAppointmentMapper.toPrismaUpdate({ + ...newAppointmentInfo, + }); + + await this.postgresqlPrismaOrmService['appointment'].update(toPrismaEntity); + } + + async updateAppointmentDate(newAppointmentInfo: UpdatedAppointmentDateDto): Promise { + const oldAppointmentInfo = await this.findSingleAppointmentById(newAppointmentInfo.id); + + if (!oldAppointmentInfo) { + throw new ConflictException(APPOINTMENT_ERROR_MESSAGES['APPOINTMENT_NOT_FOUND']); + } + + const toPrismaEntity = PostgresqlPrismaAppointmentMapper.toPrismaUpdate({ + ...newAppointmentInfo, + }); + + await this.postgresqlPrismaOrmService['appointment'].update(toPrismaEntity); + } + + async deleteSingleAppointment(appointmentId: string): Promise { + const isAppointmentExists = await this.findSingleAppointmentById(appointmentId); + + if (!isAppointmentExists) { + throw new ConflictException(APPOINTMENT_ERROR_MESSAGES['APPOINTMENT_NOT_FOUND']); + } + + await this.postgresqlPrismaOrmService['appointment'].delete({ + where: { + id: appointmentId, + }, + }); + } +} diff --git a/apps/core-rest-api/src/app/adapters/database/repositories/repositories.module.ts b/apps/core-rest-api/src/app/adapters/database/repositories/repositories.module.ts index 46c3394..69611da 100644 --- a/apps/core-rest-api/src/app/adapters/database/repositories/repositories.module.ts +++ b/apps/core-rest-api/src/app/adapters/database/repositories/repositories.module.ts @@ -4,8 +4,10 @@ import { ClinicDatabaseRepository } from '../../../core/domains/clinic/repositor import { PatientDatabaseRepository } from '../../../core/domains/patient/repositories/database-repository'; import { PsychologistDatabaseRepository } from '../../../core/domains/psychologist/repositories/database-repository'; +import { AppointmentDatabaseRepository } from '../../../core/domains/appointment/repositories/database-repository'; import { PatientAppointmentRegistryDatabaseRepository } from '../../../core/domains/patient-appointment-registry/repositories/database-repository'; import { PostgreSqlPrismaOrmService } from '../infra/prisma/prisma.service'; +import { PostgresqlPrismaOrmAppointmentRepository } from './appointment/postgres-prisma-orm-appointment-repository'; import { PostgresqlPrismaOrmClinicRepository } from './clinic/postgres-prisma-orm-clinic-repository'; import { PostgresqlPrismaOrmPatientAppointmentRegistryRepository } from './patient-appointment-registry/postgresql-prisma-orm-registry-repository'; import { PostgresqlPrismaOrmPatientRepository } from './patient/postgres-prisma-orm-patient-repository'; @@ -32,6 +34,10 @@ import { PostgresqlPrismaOrmPsychologistRepository } from './psychologist/postgr provide: PatientAppointmentRegistryDatabaseRepository, useClass: PostgresqlPrismaOrmPatientAppointmentRegistryRepository, }, + { + provide: AppointmentDatabaseRepository, + useClass: PostgresqlPrismaOrmAppointmentRepository, + }, ], exports: [ PostgreSqlPrismaOrmService, @@ -51,6 +57,10 @@ import { PostgresqlPrismaOrmPsychologistRepository } from './psychologist/postgr provide: PatientAppointmentRegistryDatabaseRepository, useClass: PostgresqlPrismaOrmPatientAppointmentRegistryRepository, }, + { + provide: AppointmentDatabaseRepository, + useClass: PostgresqlPrismaOrmAppointmentRepository, + }, ], }) export class DatabaseRepositoriesModule {} diff --git a/apps/core-rest-api/src/app/core/domains/appointment/repositories/database-in-memory-repository.ts b/apps/core-rest-api/src/app/core/domains/appointment/repositories/database-in-memory-repository.ts index e21861a..a80eed9 100644 --- a/apps/core-rest-api/src/app/core/domains/appointment/repositories/database-in-memory-repository.ts +++ b/apps/core-rest-api/src/app/core/domains/appointment/repositories/database-in-memory-repository.ts @@ -3,7 +3,7 @@ import { APPOINTMENT_ERROR_MESSAGES } from '../../../../shared/errors/error-mess import { AppointmentEntity } from '../entities/appointment/entity'; import { CreateSingleAppointmentDto } from '../use-cases/create-single-appointment/create-single-appointment-dto'; import { UpdatedAppointmentDateDto } from '../use-cases/update-appointment-date/update-appointment-date-dto'; -import { UpdatedAppointmentInfoDto } from '../use-cases/update-appointment-info/update-appointment-info-dto'; +import { UpdateAppointmentInfoDto } from '../use-cases/update-appointment-info/update-appointment-info-dto'; import { AppointmentDatabaseRepository } from './database-repository'; export class InMemoryAppointmentDatabaseRepository @@ -49,7 +49,7 @@ export class InMemoryAppointmentDatabaseRepository } async updateAppointmentInfo( - newAppointmentInfo: UpdatedAppointmentInfoDto, + newAppointmentInfo: UpdateAppointmentInfoDto, ): Promise { const oldAppointmentInfo = await this.findSingleAppointmentById( newAppointmentInfo.id, diff --git a/apps/core-rest-api/src/app/core/domains/appointment/repositories/database-repository.ts b/apps/core-rest-api/src/app/core/domains/appointment/repositories/database-repository.ts index cb1af23..b894895 100644 --- a/apps/core-rest-api/src/app/core/domains/appointment/repositories/database-repository.ts +++ b/apps/core-rest-api/src/app/core/domains/appointment/repositories/database-repository.ts @@ -1,7 +1,7 @@ import { AppointmentEntity } from '../entities/appointment/entity'; import { CreateSingleAppointmentDto } from '../use-cases/create-single-appointment/create-single-appointment-dto'; import { UpdatedAppointmentDateDto } from '../use-cases/update-appointment-date/update-appointment-date-dto'; -import { UpdatedAppointmentInfoDto } from '../use-cases/update-appointment-info/update-appointment-info-dto'; +import { UpdateAppointmentInfoDto } from '../use-cases/update-appointment-info/update-appointment-info-dto'; export abstract class AppointmentDatabaseRepository { abstract createSingleAppointment( @@ -15,7 +15,7 @@ export abstract class AppointmentDatabaseRepository { ): Promise; abstract getAppointments(): Promise; abstract updateAppointmentInfo( - newAppointmentInfo: UpdatedAppointmentInfoDto + newAppointmentInfo: UpdateAppointmentInfoDto ): Promise; abstract updateAppointmentDate( newAppointmentInfo: UpdatedAppointmentDateDto diff --git a/apps/core-rest-api/src/app/core/domains/appointment/use-cases/create-single-appointment/create-single-appointment-dto.ts b/apps/core-rest-api/src/app/core/domains/appointment/use-cases/create-single-appointment/create-single-appointment-dto.ts index 01951db..c267a10 100644 --- a/apps/core-rest-api/src/app/core/domains/appointment/use-cases/create-single-appointment/create-single-appointment-dto.ts +++ b/apps/core-rest-api/src/app/core/domains/appointment/use-cases/create-single-appointment/create-single-appointment-dto.ts @@ -1,4 +1,4 @@ -import { IsBoolean, IsDate, IsEnum, IsString } from 'class-validator'; +import { IsBoolean, IsDate, IsEnum, IsOptional, IsString } from 'class-validator'; import { PaymentMethod } from '../../../../shared/interfaces/payments'; export class CreateSingleAppointmentDto { @@ -21,7 +21,8 @@ export class CreateSingleAppointmentDto { confirmed!: boolean; @IsDate() - confirmationDate!: Date | null; + @IsOptional() + confirmationDate?: Date | null; @IsBoolean() cancelled!: boolean; diff --git a/apps/core-rest-api/src/app/core/domains/appointment/use-cases/create-single-appointment/create-single-appointment.service.ts b/apps/core-rest-api/src/app/core/domains/appointment/use-cases/create-single-appointment/create-single-appointment.service.ts index cf4b6a6..0812c57 100644 --- a/apps/core-rest-api/src/app/core/domains/appointment/use-cases/create-single-appointment/create-single-appointment.service.ts +++ b/apps/core-rest-api/src/app/core/domains/appointment/use-cases/create-single-appointment/create-single-appointment.service.ts @@ -18,7 +18,7 @@ export class CreateSingleAppointmentService { const createSingleAppointmentDtoInstance = plainToInstance( CreateSingleAppointmentDto, createSingleAppointmentDto - ); + ); await applicationValidateOrReject(createSingleAppointmentDtoInstance); @@ -26,7 +26,6 @@ export class CreateSingleAppointmentService { await this.appointmentDatabaseRepository.findSingleAppointmentByDate( createSingleAppointmentDto.date ); - if (isAppointmentExist) { throw new ConflictException(APPOINTMENT_ERROR_MESSAGES['CONFLICTING_DATE_TIME']); } @@ -36,7 +35,6 @@ export class CreateSingleAppointmentService { await this.appointmentDatabaseRepository.createSingleAppointment( createSingleAppointmentDto ); - return createSingleAppointment; } } diff --git a/apps/core-rest-api/src/app/core/domains/appointment/use-cases/create-single-appointment/create-single-appointment.spec.ts b/apps/core-rest-api/src/app/core/domains/appointment/use-cases/create-single-appointment/create-single-appointment.spec.ts index c15d7ed..7d86d46 100644 --- a/apps/core-rest-api/src/app/core/domains/appointment/use-cases/create-single-appointment/create-single-appointment.spec.ts +++ b/apps/core-rest-api/src/app/core/domains/appointment/use-cases/create-single-appointment/create-single-appointment.spec.ts @@ -1,4 +1,3 @@ -import { fakerPT_BR as faker } from '@faker-js/faker'; import { CreateSingleAppointmentService } from './create-single-appointment.service'; import { ConflictException } from '@nestjs/common'; @@ -12,11 +11,11 @@ describe('[appointment] Create Single Appointment Service', () => { const fakeAppointment: CreateSingleAppointmentDto = { psychologistId: randomUUID(), patientId: randomUUID(), - date: faker.date.recent({ days: 10 }), + date: new Date(), online: false, clinicId: randomUUID(), confirmed: true, - confirmationDate: faker.date.recent({ days: 5 }), + confirmationDate: new Date(), cancelled: false, paymentMethod: PaymentMethod.CREDIT_CARD, }; diff --git a/apps/core-rest-api/src/app/core/domains/appointment/use-cases/update-appointment-info/update-appointment-info-dto.ts b/apps/core-rest-api/src/app/core/domains/appointment/use-cases/update-appointment-info/update-appointment-info-dto.ts index b4c418e..cc4d5ad 100644 --- a/apps/core-rest-api/src/app/core/domains/appointment/use-cases/update-appointment-info/update-appointment-info-dto.ts +++ b/apps/core-rest-api/src/app/core/domains/appointment/use-cases/update-appointment-info/update-appointment-info-dto.ts @@ -7,7 +7,7 @@ import { } from 'class-validator'; import { PaymentMethod } from '../../../../shared/interfaces/payments'; -export class UpdatedAppointmentInfoDto { +export class UpdateAppointmentInfoDto { @IsString() id!: string; diff --git a/apps/core-rest-api/src/app/core/domains/appointment/use-cases/update-appointment-info/update-appointment-info.service.ts b/apps/core-rest-api/src/app/core/domains/appointment/use-cases/update-appointment-info/update-appointment-info.service.ts index 2521979..06ded5b 100644 --- a/apps/core-rest-api/src/app/core/domains/appointment/use-cases/update-appointment-info/update-appointment-info.service.ts +++ b/apps/core-rest-api/src/app/core/domains/appointment/use-cases/update-appointment-info/update-appointment-info.service.ts @@ -3,15 +3,15 @@ import { plainToInstance } from 'class-transformer'; import { APPOINTMENT_ERROR_MESSAGES } from '../../../../../shared/errors/error-messages'; import { applicationValidateOrReject } from '../../../../../shared/validators/validate-or-reject'; import { AppointmentDatabaseRepository } from '../../repositories/database-repository'; -import { UpdatedAppointmentInfoDto } from './update-appointment-info-dto'; +import { UpdateAppointmentInfoDto } from './update-appointment-info-dto'; export class UpdateAppointmentInfoService { constructor(private appointmentDatabaseRepository: AppointmentDatabaseRepository) {} - async execute(newAppointmentInfo: UpdatedAppointmentInfoDto): Promise { + async execute(newAppointmentInfo: UpdateAppointmentInfoDto): Promise { // Validate props types const updateAppointmentDtoInstance = plainToInstance( - UpdatedAppointmentInfoDto, + UpdateAppointmentInfoDto, newAppointmentInfo, ); diff --git a/apps/core-rest-api/src/app/core/domains/appointment/use-cases/update-appointment-info/update-appointment-info.spec.ts b/apps/core-rest-api/src/app/core/domains/appointment/use-cases/update-appointment-info/update-appointment-info.spec.ts index 4afda24..169b306 100644 --- a/apps/core-rest-api/src/app/core/domains/appointment/use-cases/update-appointment-info/update-appointment-info.spec.ts +++ b/apps/core-rest-api/src/app/core/domains/appointment/use-cases/update-appointment-info/update-appointment-info.spec.ts @@ -6,7 +6,7 @@ import { PaymentMethod } from '../../../../shared/interfaces/payments'; import { InMemoryAppointmentDatabaseRepository } from '../../repositories/database-in-memory-repository'; import { AppointmentDatabaseRepository } from '../../repositories/database-repository'; import { CreateSingleAppointmentDto } from '../create-single-appointment/create-single-appointment-dto'; -import { UpdatedAppointmentInfoDto } from './update-appointment-info-dto'; +import { UpdateAppointmentInfoDto } from './update-appointment-info-dto'; import { UpdateAppointmentInfoService } from './update-appointment-info.service'; describe('[appointment] Update Appointment Info Service', () => { @@ -34,7 +34,7 @@ describe('[appointment] Update Appointment Info Service', () => { const createAppointment = await databaseRepository.createSingleAppointment(fakeAppointment); - const newAppointmentInfo: UpdatedAppointmentInfoDto = { + const newAppointmentInfo: UpdateAppointmentInfoDto = { id: createAppointment.id, paid: true, paymentMethod: PaymentMethod.PIX, @@ -57,7 +57,7 @@ describe('[appointment] Update Appointment Info Service', () => { }); it('should throw error if appointment does not exist', async () => { - const newAppointmentInfo: UpdatedAppointmentInfoDto = { + const newAppointmentInfo: UpdateAppointmentInfoDto = { id: randomUUID(), paid: true, paymentMethod: PaymentMethod.PIX, diff --git a/apps/core-rest-api/tests/factories/make-appointment.ts b/apps/core-rest-api/tests/factories/make-appointment.ts new file mode 100644 index 0000000..b82337d --- /dev/null +++ b/apps/core-rest-api/tests/factories/make-appointment.ts @@ -0,0 +1,42 @@ +import { fakerPT_BR as faker } from '@faker-js/faker'; +import { Injectable } from '@nestjs/common'; + +import { PostgreSqlPrismaOrmService } from '../../src/app/adapters/database/infra/prisma/prisma.service'; + +import { PostgresqlPrismaAppointmentMapper } from '../../src/app/adapters/database/mappers/postgresql-prisma-appointment-mapper'; +import { AppointmentEntity } from '../../src/app/core/domains/appointment/entities/appointment/entity'; +import { CreateSingleAppointmentDto } from '../../src/app/core/domains/appointment/use-cases/create-single-appointment/create-single-appointment-dto'; +import { PaymentMethod } from '../../src/app/core/shared/interfaces/payments'; + +export function makeAppointment(override: Partial = {}): AppointmentEntity { + const newAppointment = new AppointmentEntity({ + psychologistId: faker.string.uuid(), + patientId: faker.string.uuid(), + date: faker.date.future(), + online: false, + clinicId: faker.string.uuid(), + confirmed: true, + paymentMethod: PaymentMethod.CREDIT_CARD, + cancelled: false, + ...override, + }); + + return newAppointment; +} + +@Injectable() +export class AppointmentFactory { + constructor(private postgreSqlPrismaOrmService: PostgreSqlPrismaOrmService) {} + + async makePrismaAppointment( + appointment: Partial = {}, + ): Promise { + const newPrismaAppointment = makeAppointment(appointment); + + await this.postgreSqlPrismaOrmService['appointment'].create( + PostgresqlPrismaAppointmentMapper.toPrismaCreate(newPrismaAppointment), + ); + + return newPrismaAppointment; + } +}