diff --git a/prisma/schema.prisma b/prisma/schema.prisma index 422860f..ab8dcf1 100644 --- a/prisma/schema.prisma +++ b/prisma/schema.prisma @@ -76,6 +76,7 @@ enum EventType { PET_REGISTERED ADOPTION_REQUESTED ADOPTION_APPROVED + ADOPTION_REJECTED ADOPTION_COMPLETED CUSTODY_STARTED CUSTODY_RETURNED diff --git a/src/adoption/adoption.controller.ts b/src/adoption/adoption.controller.ts index 4b0820d..1336be4 100644 --- a/src/adoption/adoption.controller.ts +++ b/src/adoption/adoption.controller.ts @@ -24,6 +24,7 @@ import { DocumentsService } from '../documents/documents.service'; import { FilesInterceptor } from '@nestjs/platform-express'; import { EventsService } from '../events/events.service'; import { EventEntityType, EventType } from '@prisma/client'; +import { RejectAdoptionDto } from './dto/reject-adoption.dto'; interface AuthRequest extends Request { user: { userId: string; email: string; role: string; sub?: string }; @@ -61,9 +62,22 @@ export class AdoptionController { @UseGuards(RolesGuard) @Roles(Role.ADMIN) approveAdoption(@Req() req: AuthRequest, @Param('id') id: string) { - return this.adoptionService.updateAdoptionStatus(id, req.user.userId, { - status: 'APPROVED', - }); + return this.adoptionService.approveAdoption(id, req.user.userId); + } + + @Patch(':id/reject') + @UseGuards(RolesGuard) + @Roles(Role.ADMIN) + rejectAdoption( + @Req() req: AuthRequest, + @Param('id') id: string, + @Body() dto: RejectAdoptionDto, + ) { + return this.adoptionService.rejectAdoption( + id, + req.user.userId, + dto.reason, + ); } /** diff --git a/src/adoption/adoption.service.ts b/src/adoption/adoption.service.ts index 24a4629..a4cef94 100644 --- a/src/adoption/adoption.service.ts +++ b/src/adoption/adoption.service.ts @@ -32,7 +32,7 @@ export class AdoptionService { private readonly events: EventsService, @Optional() private readonly notificationQueueService?: NotificationQueueService, - ) {} + ) { } /** * Creates an adoption request and fires an ADOPTION_REQUESTED event. @@ -174,4 +174,86 @@ export class AdoptionService { return updated; } + + async approveAdoption(adoptionId: string, adminId: string) { + return this.prisma.$transaction(async (tx) => { + const adoption = await tx.adoption.findUnique({ + where: { id: adoptionId }, + include: { pet: true }, + }); + + if (!adoption) { + throw new NotFoundException(`Adoption not found`); + } + + if (adoption.status !== AdoptionStatus.PENDING) { + throw new BadRequestException('Adoption is not pending'); + } + + // Approve adoption + const updated = await tx.adoption.update({ + where: { id: adoptionId }, + data: { + status: AdoptionStatus.APPROVED, + }, + include: { pet: true, adopter: true, owner: true }, + }); + + // Optional: log event (VERY important in your system) + await tx.eventLog.create({ + data: { + entityType: EventEntityType.ADOPTION, + entityId: adoptionId, + eventType: EventType.ADOPTION_APPROVED, + actorId: adminId, + payload: {}, + }, + }); + + return updated; + }); + } + + async rejectAdoption( + adoptionId: string, + adminId: string, + reason?: string, + ) { + return this.prisma.$transaction(async (tx) => { + const adoption = await tx.adoption.findUnique({ + where: { id: adoptionId }, + }); + + if (!adoption) { + throw new NotFoundException('Adoption not found'); + } + + if (adoption.status !== AdoptionStatus.PENDING) { + throw new BadRequestException('Adoption is not pending'); + } + + const updated = await tx.adoption.update({ + where: { id: adoptionId }, + data: { + status: AdoptionStatus.REJECTED, + notes: reason, + }, + include: { pet: true, adopter: true, owner: true }, + }); + + // Log event + await tx.eventLog.create({ + data: { + entityType: EventEntityType.ADOPTION, + entityId: adoptionId, + eventType: EventType.ADOPTION_REQUESTED, // or define REJECTED if missing + actorId: adminId, + payload: { reason }, + }, + }); + + return updated; + }); + } + } diff --git a/src/adoption/dto/reject-adoption.dto.ts b/src/adoption/dto/reject-adoption.dto.ts new file mode 100644 index 0000000..31715df --- /dev/null +++ b/src/adoption/dto/reject-adoption.dto.ts @@ -0,0 +1,7 @@ +import { IsOptional, IsString } from 'class-validator'; + +export class RejectAdoptionDto { + @IsOptional() + @IsString() + reason?: string; +} diff --git a/src/prisma/prisma.service.ts b/src/prisma/prisma.service.ts index f93cf56..ff367a0 100644 --- a/src/prisma/prisma.service.ts +++ b/src/prisma/prisma.service.ts @@ -13,6 +13,10 @@ export class PrismaService extends PrismaClient implements OnModuleInit, OnModuleDestroy { + adoption: any; + $transaction(arg0: (tx: any) => Promise) { + throw new Error('Method not implemented.'); + } private readonly logger = new Logger(PrismaService.name); constructor() {