erp-construccion-backend/dist/modules/contracts/services/subcontractor.service.js

187 lines
6.7 KiB
JavaScript

"use strict";
/**
* SubcontractorService - Servicio de gestión de subcontratistas
*
* Catálogo de subcontratistas con evaluaciones.
*
* @module Contracts
*/
Object.defineProperty(exports, "__esModule", { value: true });
exports.SubcontractorService = void 0;
class SubcontractorService {
subcontractorRepository;
constructor(subcontractorRepository) {
this.subcontractorRepository = subcontractorRepository;
}
generateCode() {
const now = new Date();
const year = now.getFullYear().toString().slice(-2);
const random = Math.random().toString(36).substring(2, 6).toUpperCase();
return `SC-${year}-${random}`;
}
async findWithFilters(ctx, filters = {}, page = 1, limit = 20) {
const skip = (page - 1) * limit;
const queryBuilder = this.subcontractorRepository
.createQueryBuilder('sc')
.leftJoinAndSelect('sc.createdBy', 'createdBy')
.where('sc.tenant_id = :tenantId', { tenantId: ctx.tenantId })
.andWhere('sc.deleted_at IS NULL');
if (filters.specialty) {
queryBuilder.andWhere('sc.primary_specialty = :specialty', { specialty: filters.specialty });
}
if (filters.status) {
queryBuilder.andWhere('sc.status = :status', { status: filters.status });
}
if (filters.search) {
queryBuilder.andWhere('(sc.business_name ILIKE :search OR sc.trade_name ILIKE :search OR sc.rfc ILIKE :search)', { search: `%${filters.search}%` });
}
if (filters.minRating !== undefined) {
queryBuilder.andWhere('sc.average_rating >= :minRating', { minRating: filters.minRating });
}
queryBuilder
.orderBy('sc.business_name', 'ASC')
.skip(skip)
.take(limit);
const [data, total] = await queryBuilder.getManyAndCount();
return {
data,
meta: {
total,
page,
limit,
totalPages: Math.ceil(total / limit),
},
};
}
async findById(ctx, id) {
return this.subcontractorRepository.findOne({
where: {
id,
tenantId: ctx.tenantId,
deletedAt: null,
},
});
}
async findByRfc(ctx, rfc) {
return this.subcontractorRepository.findOne({
where: {
rfc: rfc.toUpperCase(),
tenantId: ctx.tenantId,
deletedAt: null,
},
});
}
async create(ctx, dto) {
// Check for existing RFC
const existing = await this.findByRfc(ctx, dto.rfc);
if (existing) {
throw new Error('A subcontractor with this RFC already exists');
}
const subcontractor = this.subcontractorRepository.create({
tenantId: ctx.tenantId,
createdById: ctx.userId,
code: this.generateCode(),
businessName: dto.businessName,
tradeName: dto.tradeName,
rfc: dto.rfc.toUpperCase(),
address: dto.address,
phone: dto.phone,
email: dto.email,
contactName: dto.contactName,
contactPhone: dto.contactPhone,
primarySpecialty: dto.primarySpecialty,
secondarySpecialties: dto.secondarySpecialties,
bankName: dto.bankName,
bankAccount: dto.bankAccount,
clabe: dto.clabe,
notes: dto.notes,
status: 'active',
});
return this.subcontractorRepository.save(subcontractor);
}
async update(ctx, id, dto) {
const subcontractor = await this.findById(ctx, id);
if (!subcontractor) {
return null;
}
Object.assign(subcontractor, {
...dto,
updatedById: ctx.userId || '',
});
return this.subcontractorRepository.save(subcontractor);
}
async updateRating(ctx, id, rating) {
const subcontractor = await this.findById(ctx, id);
if (!subcontractor) {
return null;
}
// Calculate new average rating
const totalRatings = subcontractor.completedContracts;
const currentTotal = subcontractor.averageRating * totalRatings;
const newTotal = currentTotal + rating;
subcontractor.averageRating = newTotal / (totalRatings + 1);
subcontractor.updatedById = ctx.userId || '';
return this.subcontractorRepository.save(subcontractor);
}
async incrementContracts(ctx, id, completed = false) {
const subcontractor = await this.findById(ctx, id);
if (!subcontractor) {
return null;
}
subcontractor.totalContracts += 1;
if (completed) {
subcontractor.completedContracts += 1;
}
subcontractor.updatedById = ctx.userId || '';
return this.subcontractorRepository.save(subcontractor);
}
async incrementIncidents(ctx, id) {
const subcontractor = await this.findById(ctx, id);
if (!subcontractor) {
return null;
}
subcontractor.totalIncidents += 1;
subcontractor.updatedById = ctx.userId || '';
return this.subcontractorRepository.save(subcontractor);
}
async deactivate(ctx, id) {
const subcontractor = await this.findById(ctx, id);
if (!subcontractor) {
return null;
}
subcontractor.status = 'inactive';
subcontractor.updatedById = ctx.userId || '';
return this.subcontractorRepository.save(subcontractor);
}
async blacklist(ctx, id, reason) {
const subcontractor = await this.findById(ctx, id);
if (!subcontractor) {
return null;
}
subcontractor.status = 'blacklisted';
subcontractor.notes = `${subcontractor.notes || ''}\n[BLACKLISTED] ${reason}`;
subcontractor.updatedById = ctx.userId || '';
return this.subcontractorRepository.save(subcontractor);
}
async softDelete(ctx, id) {
const subcontractor = await this.findById(ctx, id);
if (!subcontractor) {
return false;
}
await this.subcontractorRepository.update({ id, tenantId: ctx.tenantId }, { deletedAt: new Date(), deletedById: ctx.userId || '' });
return true;
}
async getBySpecialty(ctx, specialty) {
return this.subcontractorRepository.find({
where: {
tenantId: ctx.tenantId,
primarySpecialty: specialty,
status: 'active',
deletedAt: null,
},
order: { averageRating: 'DESC' },
});
}
}
exports.SubcontractorService = SubcontractorService;
//# sourceMappingURL=subcontractor.service.js.map