Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions prisma/schema.prisma
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,7 @@ enum EventType {
PET_REGISTERED
ADOPTION_REQUESTED
ADOPTION_APPROVED
ADOPTION_REJECTED
ADOPTION_COMPLETED
CUSTODY_STARTED
CUSTODY_RETURNED
Expand Down
20 changes: 17 additions & 3 deletions src/adoption/adoption.controller.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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 };
Expand Down Expand Up @@ -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,
);
}

/**
Expand Down
84 changes: 83 additions & 1 deletion src/adoption/adoption.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down Expand Up @@ -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;
});
}

}
7 changes: 7 additions & 0 deletions src/adoption/dto/reject-adoption.dto.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
import { IsOptional, IsString } from 'class-validator';

export class RejectAdoptionDto {
@IsOptional()
@IsString()
reason?: string;
}
4 changes: 4 additions & 0 deletions src/prisma/prisma.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,10 @@ export class PrismaService
extends PrismaClient
implements OnModuleInit, OnModuleDestroy
{
adoption: any;
$transaction(arg0: (tx: any) => Promise<any>) {
throw new Error('Method not implemented.');
}
private readonly logger = new Logger(PrismaService.name);

constructor() {
Expand Down