"use strict"; /** * PresupuestoService - Gestión de Presupuestos de Obra * * Gestiona presupuestos de obra con sus partidas. * Soporta versionamiento y aprobación. * * @module Budgets */ Object.defineProperty(exports, "__esModule", { value: true }); exports.PresupuestoService = void 0; const base_service_1 = require("../../../shared/services/base.service"); class PresupuestoService extends base_service_1.BaseService { partidaRepository; constructor(repository, partidaRepository) { super(repository); this.partidaRepository = partidaRepository; } /** * Crear nuevo presupuesto */ async createPresupuesto(ctx, data) { return this.create(ctx, { ...data, version: 1, isActive: true, totalAmount: 0, }); } /** * Obtener presupuestos por fraccionamiento */ async findByFraccionamiento(ctx, fraccionamientoId, page = 1, limit = 20) { return this.findAll(ctx, { page, limit, where: { fraccionamientoId, isActive: true }, }); } /** * Obtener presupuesto con sus partidas */ async findWithPartidas(ctx, id) { return this.repository.findOne({ where: { id, tenantId: ctx.tenantId, deletedAt: null, }, relations: ['partidas', 'partidas.concepto'], }); } /** * Agregar partida al presupuesto */ async addPartida(ctx, presupuestoId, data) { const presupuesto = await this.findById(ctx, presupuestoId); if (!presupuesto) { throw new Error('Presupuesto not found'); } const partida = this.partidaRepository.create({ tenantId: ctx.tenantId, presupuestoId, conceptoId: data.conceptoId, quantity: data.quantity, unitPrice: data.unitPrice, sequence: data.sequence || 0, createdById: ctx.userId, }); const savedPartida = await this.partidaRepository.save(partida); await this.recalculateTotal(ctx, presupuestoId); return savedPartida; } /** * Actualizar partida */ async updatePartida(ctx, partidaId, data) { const partida = await this.partidaRepository.findOne({ where: { id: partidaId, tenantId: ctx.tenantId, deletedAt: null, }, }); if (!partida) { return null; } const updated = this.partidaRepository.merge(partida, { ...data, updatedById: ctx.userId, }); const saved = await this.partidaRepository.save(updated); await this.recalculateTotal(ctx, partida.presupuestoId); return saved; } /** * Eliminar partida */ async removePartida(ctx, partidaId) { const partida = await this.partidaRepository.findOne({ where: { id: partidaId, tenantId: ctx.tenantId, }, }); if (!partida) { return false; } await this.partidaRepository.update({ id: partidaId }, { deletedAt: new Date(), deletedById: ctx.userId, }); await this.recalculateTotal(ctx, partida.presupuestoId); return true; } /** * Recalcular total del presupuesto */ async recalculateTotal(ctx, presupuestoId) { const result = await this.partidaRepository .createQueryBuilder('p') .select('SUM(p.quantity * p.unit_price)', 'total') .where('p.presupuesto_id = :presupuestoId', { presupuestoId }) .andWhere('p.deleted_at IS NULL') .getRawOne(); const total = parseFloat(result?.total || '0'); await this.repository.update({ id: presupuestoId }, { totalAmount: total, updatedById: ctx.userId }); } /** * Crear nueva versión del presupuesto */ async createNewVersion(ctx, presupuestoId) { const original = await this.findWithPartidas(ctx, presupuestoId); if (!original) { throw new Error('Presupuesto not found'); } // Desactivar versión anterior await this.repository.update({ id: presupuestoId }, { isActive: false, updatedById: ctx.userId }); // Crear nueva versión const newVersion = await this.create(ctx, { code: original.code, name: original.name, description: original.description, fraccionamientoId: original.fraccionamientoId, prototipoId: original.prototipoId, currencyId: original.currencyId, version: original.version + 1, isActive: true, totalAmount: original.totalAmount, }); // Copiar partidas for (const partida of original.partidas) { await this.partidaRepository.save(this.partidaRepository.create({ tenantId: ctx.tenantId, presupuestoId: newVersion.id, conceptoId: partida.conceptoId, quantity: partida.quantity, unitPrice: partida.unitPrice, sequence: partida.sequence, createdById: ctx.userId, })); } return newVersion; } /** * Aprobar presupuesto */ async approve(ctx, presupuestoId) { const presupuesto = await this.findById(ctx, presupuestoId); if (!presupuesto) { return null; } return this.update(ctx, presupuestoId, { approvedAt: new Date(), approvedById: ctx.userId, }); } } exports.PresupuestoService = PresupuestoService; //# sourceMappingURL=presupuesto.service.js.map