erp-construccion-backend/dist/modules/infonavit/services/asignacion.service.js

210 lines
8.3 KiB
JavaScript

"use strict";
/**
* AsignacionService - Servicio de asignaciones de vivienda INFONAVIT
*
* Gestión de asignaciones de vivienda a derechohabientes.
*
* @module Infonavit
*/
Object.defineProperty(exports, "__esModule", { value: true });
exports.AsignacionService = void 0;
class AsignacionService {
asignacionRepository;
ofertaRepository;
derechohabienteRepository;
constructor(asignacionRepository, ofertaRepository, derechohabienteRepository) {
this.asignacionRepository = asignacionRepository;
this.ofertaRepository = ofertaRepository;
this.derechohabienteRepository = derechohabienteRepository;
}
generateAssignmentNumber() {
const now = new Date();
const year = now.getFullYear().toString().slice(-2);
const month = (now.getMonth() + 1).toString().padStart(2, '0');
const random = Math.random().toString(36).substring(2, 8).toUpperCase();
return `ASG-${year}${month}-${random}`;
}
async findWithFilters(ctx, filters = {}, page = 1, limit = 20) {
const skip = (page - 1) * limit;
const queryBuilder = this.asignacionRepository
.createQueryBuilder('asig')
.leftJoinAndSelect('asig.oferta', 'oferta')
.leftJoinAndSelect('asig.derechohabiente', 'derechohabiente')
.leftJoinAndSelect('asig.createdBy', 'createdBy')
.where('asig.tenant_id = :tenantId', { tenantId: ctx.tenantId });
if (filters.ofertaId) {
queryBuilder.andWhere('asig.oferta_id = :ofertaId', { ofertaId: filters.ofertaId });
}
if (filters.derechohabienteId) {
queryBuilder.andWhere('asig.derechohabiente_id = :derechohabienteId', {
derechohabienteId: filters.derechohabienteId,
});
}
if (filters.status) {
queryBuilder.andWhere('asig.status = :status', { status: filters.status });
}
if (filters.dateFrom) {
queryBuilder.andWhere('asig.assignment_date >= :dateFrom', { dateFrom: filters.dateFrom });
}
if (filters.dateTo) {
queryBuilder.andWhere('asig.assignment_date <= :dateTo', { dateTo: filters.dateTo });
}
queryBuilder
.orderBy('asig.assignment_date', 'DESC')
.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.asignacionRepository.findOne({
where: {
id,
tenantId: ctx.tenantId,
},
});
}
async findWithDetails(ctx, id) {
return this.asignacionRepository.findOne({
where: {
id,
tenantId: ctx.tenantId,
},
relations: ['oferta', 'oferta.registro', 'derechohabiente', 'createdBy'],
});
}
async create(ctx, dto) {
// Validate oferta exists and is available
const oferta = await this.ofertaRepository.findOne({
where: {
id: dto.ofertaId,
tenantId: ctx.tenantId,
},
});
if (!oferta) {
throw new Error('Housing offer not found');
}
if (oferta.status !== 'available' && oferta.status !== 'reserved') {
throw new Error('Housing offer is not available for assignment');
}
// Validate derechohabiente exists and is qualified
const derechohabiente = await this.derechohabienteRepository.findOne({
where: {
id: dto.derechohabienteId,
tenantId: ctx.tenantId,
deletedAt: null,
},
});
if (!derechohabiente) {
throw new Error('Worker not found');
}
if (derechohabiente.status !== 'qualified' && derechohabiente.status !== 'pre_qualified') {
throw new Error('Worker must be pre-qualified or qualified for assignment');
}
// Create assignment
const asignacion = this.asignacionRepository.create({
tenantId: ctx.tenantId,
createdById: ctx.userId,
ofertaId: dto.ofertaId,
derechohabienteId: dto.derechohabienteId,
assignmentNumber: this.generateAssignmentNumber(),
assignmentDate: dto.assignmentDate,
creditAmount: dto.creditAmount,
subsidyAmount: dto.subsidyAmount || 0,
downPayment: dto.downPayment || 0,
notes: dto.notes,
status: 'pending',
});
const saved = await this.asignacionRepository.save(asignacion);
// Update oferta status
oferta.status = 'reserved';
await this.ofertaRepository.save(oferta);
return saved;
}
async approve(ctx, id) {
const asignacion = await this.findWithDetails(ctx, id);
if (!asignacion) {
return null;
}
if (asignacion.status !== 'pending') {
throw new Error('Can only approve pending assignments');
}
asignacion.status = 'approved';
asignacion.approvalDate = new Date();
asignacion.updatedById = ctx.userId || '';
// Update oferta status
asignacion.oferta.status = 'assigned';
await this.ofertaRepository.save(asignacion.oferta);
// Update derechohabiente status
await this.derechohabienteRepository.update({ id: asignacion.derechohabienteId }, { status: 'assigned', updatedById: ctx.userId || '' });
return this.asignacionRepository.save(asignacion);
}
async formalize(ctx, id, dto) {
const asignacion = await this.findWithDetails(ctx, id);
if (!asignacion) {
return null;
}
if (asignacion.status !== 'approved') {
throw new Error('Can only formalize approved assignments');
}
asignacion.status = 'formalized';
asignacion.formalizationDate = dto.formalizationDate;
asignacion.notaryName = dto.notaryName;
asignacion.notaryNumber = dto.notaryNumber;
asignacion.deedNumber = dto.deedNumber;
asignacion.deedDate = dto.deedDate;
asignacion.updatedById = ctx.userId || '';
return this.asignacionRepository.save(asignacion);
}
async deliver(ctx, id, deliveryDate) {
const asignacion = await this.findWithDetails(ctx, id);
if (!asignacion) {
return null;
}
if (asignacion.status !== 'formalized') {
throw new Error('Can only deliver formalized assignments');
}
asignacion.status = 'delivered';
asignacion.deliveryDate = deliveryDate;
asignacion.updatedById = ctx.userId || '';
// Update oferta status
asignacion.oferta.status = 'delivered';
await this.ofertaRepository.save(asignacion.oferta);
return this.asignacionRepository.save(asignacion);
}
async cancel(ctx, id, reason) {
const asignacion = await this.findWithDetails(ctx, id);
if (!asignacion) {
return null;
}
if (asignacion.status === 'delivered') {
throw new Error('Cannot cancel delivered assignments');
}
const previousStatus = asignacion.status;
asignacion.status = 'cancelled';
asignacion.notes = `${asignacion.notes || ''}\n[CANCELLED] ${reason}`;
asignacion.updatedById = ctx.userId || '';
// Revert oferta status if it was assigned/reserved
if (previousStatus === 'approved' || previousStatus === 'formalized') {
asignacion.oferta.status = 'available';
await this.ofertaRepository.save(asignacion.oferta);
// Revert derechohabiente status
await this.derechohabienteRepository.update({ id: asignacion.derechohabienteId }, { status: 'qualified', updatedById: ctx.userId || '' });
}
else if (previousStatus === 'pending') {
asignacion.oferta.status = 'available';
await this.ofertaRepository.save(asignacion.oferta);
}
return this.asignacionRepository.save(asignacion);
}
}
exports.AsignacionService = AsignacionService;
//# sourceMappingURL=asignacion.service.js.map