All files / src/modules/projects projects.service.ts

86.66% Statements 26/30
68.18% Branches 15/22
75% Functions 3/4
85.71% Lines 24/28

Press n or j to go to the next uncovered block, b, p or k for the previous block.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 852x 2x 2x 2x         2x   2x 2x       1x     1x       1x         1x 1x 1x         1x                     1x 1x         1x 1x       1x 1x   2x               2x 2x   1x                            
import { Injectable } from '@nestjs/common';
import { PrismaService } from '@app/modules/prisma/prisma.service';
import { InjectQueue } from '@nestjs/bullmq';
import { Queue } from 'bullmq';
import { CreateProjectDto } from '@app/modules/projects/dto/create-project.dto';
import { AddUnitsDto } from '@modules/projects/dto/add-units.dto';
 
@Injectable()
export class ProjectsService {
  constructor(
    private readonly prisma: PrismaService,
    @InjectQueue('listingIndex') private readonly indexQueue: Queue,
  ) {}
 
  async createProject(dto: CreateProjectDto, developerUserId: number) {
    const { heroMediaId, addressId, ...data } = dto;
 
    // Lookup developer company owned by the user
    const devCompany = await this.prisma.client.developerCompany.findUnique({
      where: { ownerId: developerUserId },
      select: { id: true },
    });
    Iif (!devCompany) {
      throw new Error('Developer does not own a developerCompany record');
    }
 
    // validate heroMedia ownership
    if (heroMediaId) {
      const media = await this.prisma.client.media.findUnique({ where: { id: heroMediaId } });
      Iif (!media || media.ownerId !== developerUserId) {
        throw new Error('heroMediaId does not belong to developer');
      }
    }
 
    const createData: any = {
      name: data.name,
      description: data.description,
      addressId,
      developerCompanyId: devCompany.id,
      status: data.status ?? 'PRE_SALE',
      completionDate: data.completionDate ? new Date(data.completionDate) : undefined,
      heroMediaId: heroMediaId || undefined,
    };
 
    // @ts-ignore prisma generated
    const project = await this.prisma.client.project.create({ data: createData });
    return project;
  }
 
  async addUnits(projectId: number, dto: AddUnitsDto, developerUserId: number) {
    // validation: project belongs to developer-user
    const project = await this.prisma.client.project.findUnique({ where: { id: projectId }, select: { developerCompany: { select: { ownerId: true } } } });
    Iif (!project || project.developerCompany.ownerId !== developerUserId) {
      throw new Error('Forbidden');
    }
 
    let count = 0;
    for (const unit of dto.units) {
       
      const listing = await this.prisma.client.listing.create({
        data: {
          ...unit,
          status: 'DRAFT',
          projectId,
          userId: developerUserId,
        },
      });
      await this.indexQueue.add('index', { listingId: listing.id });
      count++;
    }
    return count;
  }
 
  async getPublic(projectId: number) {
    // @ts-ignore prisma generated fields pending
    return (this.prisma as any).project.findUnique({
      where: { id: projectId },
      include: {
        heroMedia: true,
        address: true,
        listings: { where: { status: 'PUBLISHED', deletedAt: null as any } },
      },
    });
  }
}