Files
edr-platform/apps/edr-freight-api/src/modules/companies/companies.repository.ts
2026-06-23 06:45:29 +00:00

102 lines
3.0 KiB
TypeScript

import { Injectable } from '@nestjs/common';
import { InjectRepository } from '@nestjs/typeorm';
import { Repository } from 'typeorm';
import { BaseRepository } from '@edr/api-common';
import { Company } from './entities/company.entity';
import { ListCompaniesQueryDto } from './dto/list-companies-query.dto';
import { CompanyStatsResponseDto } from './dto/company-stats-response.dto';
@Injectable()
export class CompaniesRepository extends BaseRepository<Company> {
constructor(
@InjectRepository(Company)
repo: Repository<Company>,
) {
super(repo);
}
async findByTin(tin: string): Promise<Company | null> {
return this.repository.findOne({ where: { tin } as any });
}
async findByType(type: string): Promise<Company[]> {
return this.repository.find({ where: { type } as any, order: { name: 'ASC' } });
}
async findByName(name: string): Promise<Company[]> {
return this.repository
.createQueryBuilder('company')
.where('company.name ILIKE :name', { name: `%${name}%` })
.getMany();
}
async existsByTin(tin: string): Promise<boolean> {
const count = await this.repository.count({ where: { tin } as any });
return count > 0;
}
async findPaginated(
query: ListCompaniesQueryDto,
): Promise<{ items: Company[]; total: number }> {
const { page = 1, pageSize = 20, search, type, status } = query;
const qb = this.repository
.createQueryBuilder('company')
.leftJoinAndSelect('company.companyProfiles', 'companyProfiles')
.where('company.deleted_at IS NULL');
if (type) {
qb.andWhere('company.type = :type', { type });
}
if (status) {
qb.andWhere('company.status = :status', { status });
}
if (search) {
const term = `%${search.trim()}%`;
qb.andWhere(
`(company.name ILIKE :term
OR company.tin ILIKE :term
OR company.email ILIKE :term
OR EXISTS (
SELECT 1 FROM freight.company_profiles cp
WHERE cp.company_id = company.id
AND cp.reference ILIKE :term
AND cp.deleted_at IS NULL
))`,
{ term },
);
}
const [items, total] = await qb
.orderBy('company.name', 'ASC')
.skip((page - 1) * pageSize)
.take(pageSize)
.getManyAndCount();
return { items, total };
}
async getStats(): Promise<CompanyStatsResponseDto> {
const rows: { status: string; count: string }[] = await this.repository
.createQueryBuilder('company')
.select('company.status', 'status')
.addSelect('COUNT(*)', 'count')
.where('company.deleted_at IS NULL')
.groupBy('company.status')
.getRawMany();
const map = new Map(rows.map((r) => [r.status, parseInt(r.count, 10)]));
const total = rows.reduce((sum, r) => sum + parseInt(r.count, 10), 0);
return {
total,
active: map.get('active') ?? 0,
pending: map.get('pending') ?? 0,
suspended: map.get('suspended') ?? 0,
blacklisted: map.get('blacklisted') ?? 0,
};
}
}