"use strict"; var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) { var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d; if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc); else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r; return c > 3 && r && Object.defineProperty(target, key, r), r; }; var __metadata = (this && this.__metadata) || function (k, v) { if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v); }; var __param = (this && this.__param) || function (paramIndex, decorator) { return function (target, key) { decorator(target, key, paramIndex); } }; Object.defineProperty(exports, "__esModule", { value: true }); exports.InventoryService = void 0; const common_1 = require("@nestjs/common"); const typeorm_1 = require("@nestjs/typeorm"); const typeorm_2 = require("typeorm"); const inventory_movement_entity_1 = require("./entities/inventory-movement.entity"); const stock_alert_entity_1 = require("./entities/stock-alert.entity"); const product_entity_1 = require("../products/entities/product.entity"); let InventoryService = class InventoryService { constructor(movementRepo, alertRepo, productRepo) { this.movementRepo = movementRepo; this.alertRepo = alertRepo; this.productRepo = productRepo; } async createMovement(tenantId, dto, userId) { const product = await this.productRepo.findOne({ where: { id: dto.productId, tenantId }, }); if (!product) { throw new common_1.NotFoundException('Producto no encontrado'); } const quantityBefore = Number(product.stockQuantity); const quantityAfter = quantityBefore + dto.quantity; if (quantityAfter < 0) { throw new common_1.BadRequestException(`Stock insuficiente. Disponible: ${quantityBefore}, Solicitado: ${Math.abs(dto.quantity)}`); } const movement = this.movementRepo.create({ tenantId, productId: dto.productId, movementType: dto.movementType, quantity: dto.quantity, quantityBefore, quantityAfter, unitCost: dto.unitCost, referenceType: dto.referenceType, referenceId: dto.referenceId, notes: dto.notes, createdBy: userId, }); await this.movementRepo.save(movement); product.stockQuantity = quantityAfter; await this.productRepo.save(product); await this.checkStockAlerts(tenantId, product); return movement; } async adjustStock(tenantId, dto, userId) { const product = await this.productRepo.findOne({ where: { id: dto.productId, tenantId }, }); if (!product) { throw new common_1.NotFoundException('Producto no encontrado'); } const quantityBefore = Number(product.stockQuantity); const difference = dto.newQuantity - quantityBefore; return this.createMovement(tenantId, { productId: dto.productId, movementType: inventory_movement_entity_1.MovementType.ADJUSTMENT, quantity: difference, notes: dto.reason || `Ajuste de inventario: ${quantityBefore} -> ${dto.newQuantity}`, }, userId); } async getMovements(tenantId, productId, limit = 50) { const where = { tenantId }; if (productId) { where.productId = productId; } return this.movementRepo.find({ where, relations: ['product'], order: { createdAt: 'DESC' }, take: limit, }); } async getProductHistory(tenantId, productId) { return this.movementRepo.find({ where: { tenantId, productId }, order: { createdAt: 'DESC' }, }); } async checkStockAlerts(tenantId, product) { const currentStock = Number(product.stockQuantity); const threshold = Number(product.lowStockThreshold); if (currentStock > threshold) { await this.alertRepo.update({ productId: product.id, status: stock_alert_entity_1.AlertStatus.ACTIVE }, { status: stock_alert_entity_1.AlertStatus.RESOLVED, resolvedAt: new Date() }); return; } const existingAlert = await this.alertRepo.findOne({ where: { productId: product.id, status: stock_alert_entity_1.AlertStatus.ACTIVE }, }); if (existingAlert) { existingAlert.currentStock = currentStock; await this.alertRepo.save(existingAlert); return; } const alertType = currentStock <= 0 ? stock_alert_entity_1.AlertType.OUT_OF_STOCK : stock_alert_entity_1.AlertType.LOW_STOCK; const alert = this.alertRepo.create({ tenantId, productId: product.id, alertType, currentStock, threshold, }); await this.alertRepo.save(alert); } async getActiveAlerts(tenantId) { return this.alertRepo.find({ where: { tenantId, status: stock_alert_entity_1.AlertStatus.ACTIVE }, relations: ['product'], order: { createdAt: 'DESC' }, }); } async dismissAlert(tenantId, alertId) { const alert = await this.alertRepo.findOne({ where: { id: alertId, tenantId }, }); if (!alert) { throw new common_1.NotFoundException('Alerta no encontrada'); } alert.status = stock_alert_entity_1.AlertStatus.DISMISSED; return this.alertRepo.save(alert); } async getLowStockProducts(tenantId) { return this.productRepo .createQueryBuilder('product') .where('product.tenant_id = :tenantId', { tenantId }) .andWhere('product.track_inventory = true') .andWhere('product.stock_quantity <= product.low_stock_threshold') .andWhere("product.status = 'active'") .orderBy('product.stock_quantity', 'ASC') .getMany(); } async getOutOfStockProducts(tenantId) { return this.productRepo.find({ where: { tenantId, trackInventory: true, stockQuantity: (0, typeorm_2.LessThanOrEqual)(0), status: 'active', }, order: { name: 'ASC' }, }); } async getInventoryStats(tenantId) { const products = await this.productRepo.find({ where: { tenantId, trackInventory: true, status: 'active' }, }); let totalValue = 0; let lowStockCount = 0; let outOfStockCount = 0; for (const product of products) { const stock = Number(product.stockQuantity); const cost = Number(product.costPrice) || 0; totalValue += stock * cost; if (stock <= 0) { outOfStockCount++; } else if (stock <= Number(product.lowStockThreshold)) { lowStockCount++; } } const activeAlerts = await this.alertRepo.count({ where: { tenantId, status: stock_alert_entity_1.AlertStatus.ACTIVE }, }); return { totalProducts: products.length, totalValue, lowStockCount, outOfStockCount, activeAlerts, }; } }; exports.InventoryService = InventoryService; exports.InventoryService = InventoryService = __decorate([ (0, common_1.Injectable)(), __param(0, (0, typeorm_1.InjectRepository)(inventory_movement_entity_1.InventoryMovement)), __param(1, (0, typeorm_1.InjectRepository)(stock_alert_entity_1.StockAlert)), __param(2, (0, typeorm_1.InjectRepository)(product_entity_1.Product)), __metadata("design:paramtypes", [typeorm_2.Repository, typeorm_2.Repository, typeorm_2.Repository]) ], InventoryService); //# sourceMappingURL=inventory.service.js.map