"use strict"; /** * LoteService - Gestión de lotes/terrenos * * CRUD de lotes con soporte multi-tenant. * * @module Construction */ Object.defineProperty(exports, "__esModule", { value: true }); exports.LoteService = void 0; const typeorm_1 = require("typeorm"); class LoteService { repository; constructor(repository) { this.repository = repository; } /** * Listar lotes */ async findAll(options) { const { tenantId, manzanaId, prototipoId, page = 1, limit = 20, search, status } = options; const query = this.repository .createQueryBuilder('l') .where('l.tenant_id = :tenantId', { tenantId }) .andWhere('l.deleted_at IS NULL'); if (manzanaId) { query.andWhere('l.manzana_id = :manzanaId', { manzanaId }); } if (prototipoId) { query.andWhere('l.prototipo_id = :prototipoId', { prototipoId }); } if (search) { query.andWhere('(l.code ILIKE :search OR l.official_number ILIKE :search)', { search: `%${search}%` }); } if (status) { query.andWhere('l.status = :status', { status }); } const total = await query.getCount(); const items = await query .leftJoinAndSelect('l.prototipo', 'prototipo') .skip((page - 1) * limit) .take(limit) .orderBy('l.code', 'ASC') .getMany(); return { items, total }; } /** * Obtener lote por ID */ async findById(id, tenantId) { return this.repository.findOne({ where: { id, tenantId, deletedAt: (0, typeorm_1.IsNull)() }, relations: ['prototipo', 'manzana'], }); } /** * Obtener lote por código dentro de una manzana */ async findByCode(code, manzanaId, tenantId) { return this.repository.findOne({ where: { code, manzanaId, tenantId, deletedAt: (0, typeorm_1.IsNull)() }, }); } /** * Crear lote */ async create(tenantId, dto, createdBy) { const existing = await this.findByCode(dto.code, dto.manzanaId, tenantId); if (existing) { throw new Error('Lot code already exists in this block'); } return this.repository.save(this.repository.create({ tenantId, ...dto, createdBy, status: dto.status || 'available', })); } /** * Actualizar lote */ async update(id, tenantId, dto, updatedBy) { const lote = await this.findById(id, tenantId); if (!lote) { throw new Error('Lot not found'); } // Verificar código único si se está cambiando if (dto.code && dto.code !== lote.code) { const existing = await this.findByCode(dto.code, lote.manzanaId, tenantId); if (existing) { throw new Error('Lot code already exists in this block'); } } await this.repository.update(id, { ...dto, updatedBy, updatedAt: new Date(), }); return this.findById(id, tenantId); } /** * Eliminar lote (soft delete) */ async delete(id, tenantId, _deletedBy) { const lote = await this.findById(id, tenantId); if (!lote) { throw new Error('Lot not found'); } // Verificar que no esté vendido if (lote.status === 'sold') { throw new Error('Cannot delete a sold lot'); } await this.repository.update(id, { deletedAt: new Date(), }); } /** * Obtener lotes por manzana */ async findByManzana(manzanaId, tenantId) { return this.repository.find({ where: { manzanaId, tenantId, deletedAt: (0, typeorm_1.IsNull)() }, order: { code: 'ASC' }, relations: ['prototipo'], }); } /** * Asignar prototipo a lote */ async assignPrototipo(id, tenantId, prototipoId, updatedBy) { const lote = await this.findById(id, tenantId); if (!lote) { throw new Error('Lot not found'); } await this.repository.update(id, { prototipoId, updatedBy, updatedAt: new Date(), }); return this.findById(id, tenantId); } /** * Cambiar estado del lote */ async changeStatus(id, tenantId, status, updatedBy) { const lote = await this.findById(id, tenantId); if (!lote) { throw new Error('Lot not found'); } await this.repository.update(id, { status, updatedBy, updatedAt: new Date(), }); return this.findById(id, tenantId); } /** * Obtener estadísticas de lotes por estado */ async getStatsByStatus(tenantId, manzanaId) { const query = this.repository .createQueryBuilder('l') .select('l.status', 'status') .addSelect('COUNT(*)', 'count') .where('l.tenant_id = :tenantId', { tenantId }) .andWhere('l.deleted_at IS NULL') .groupBy('l.status'); if (manzanaId) { query.andWhere('l.manzana_id = :manzanaId', { manzanaId }); } return query.getRawMany(); } } exports.LoteService = LoteService; //# sourceMappingURL=lote.service.js.map