"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.MarketplaceService = void 0; const common_1 = require("@nestjs/common"); const typeorm_1 = require("@nestjs/typeorm"); const typeorm_2 = require("typeorm"); const supplier_entity_1 = require("./entities/supplier.entity"); const supplier_product_entity_1 = require("./entities/supplier-product.entity"); const supplier_order_entity_1 = require("./entities/supplier-order.entity"); const supplier_order_item_entity_1 = require("./entities/supplier-order-item.entity"); const supplier_review_entity_1 = require("./entities/supplier-review.entity"); let MarketplaceService = class MarketplaceService { constructor(supplierRepo, productRepo, orderRepo, orderItemRepo, reviewRepo, dataSource) { this.supplierRepo = supplierRepo; this.productRepo = productRepo; this.orderRepo = orderRepo; this.orderItemRepo = orderItemRepo; this.reviewRepo = reviewRepo; this.dataSource = dataSource; } async findSuppliers(options) { const query = this.supplierRepo.createQueryBuilder('supplier') .where('supplier.status = :status', { status: supplier_entity_1.SupplierStatus.ACTIVE }) .orderBy('supplier.rating', 'DESC') .addOrderBy('supplier.total_orders', 'DESC'); if (options?.category) { query.andWhere(':category = ANY(supplier.categories)', { category: options.category, }); } if (options?.zipCode) { query.andWhere('(supplier.coverage_zones = \'{}\' OR :zipCode = ANY(supplier.coverage_zones))', { zipCode: options.zipCode }); } if (options?.search) { query.andWhere('(supplier.name ILIKE :search OR supplier.description ILIKE :search)', { search: `%${options.search}%` }); } if (options?.limit) { query.limit(options.limit); } return query.getMany(); } async getSupplier(id) { const supplier = await this.supplierRepo.findOne({ where: { id }, relations: ['products', 'reviews'], }); if (!supplier) { throw new common_1.NotFoundException('Proveedor no encontrado'); } return supplier; } async getSupplierProducts(supplierId, options) { const query = this.productRepo.createQueryBuilder('product') .where('product.supplier_id = :supplierId', { supplierId }) .andWhere('product.active = true') .orderBy('product.category', 'ASC') .addOrderBy('product.name', 'ASC'); if (options?.category) { query.andWhere('product.category = :category', { category: options.category }); } if (options?.search) { query.andWhere('(product.name ILIKE :search OR product.description ILIKE :search)', { search: `%${options.search}%` }); } if (options?.inStock !== undefined) { query.andWhere('product.in_stock = :inStock', { inStock: options.inStock }); } return query.getMany(); } async createOrder(tenantId, dto) { const supplier = await this.supplierRepo.findOne({ where: { id: dto.supplierId, status: supplier_entity_1.SupplierStatus.ACTIVE }, }); if (!supplier) { throw new common_1.NotFoundException('Proveedor no encontrado o no activo'); } const productIds = dto.items.map((item) => item.productId); const products = await this.productRepo.findByIds(productIds); if (products.length !== productIds.length) { throw new common_1.BadRequestException('Algunos productos no fueron encontrados'); } const productMap = new Map(products.map((p) => [p.id, p])); let subtotal = 0; for (const item of dto.items) { const product = productMap.get(item.productId); if (!product) { throw new common_1.BadRequestException(`Producto ${item.productId} no encontrado`); } if (item.quantity < product.minQuantity) { throw new common_1.BadRequestException(`Cantidad minima para ${product.name} es ${product.minQuantity}`); } if (!product.inStock) { throw new common_1.BadRequestException(`${product.name} no esta disponible`); } let unitPrice = Number(product.unitPrice); if (product.tieredPricing && product.tieredPricing.length > 0) { for (const tier of product.tieredPricing.sort((a, b) => b.min - a.min)) { if (item.quantity >= tier.min) { unitPrice = tier.price; break; } } } subtotal += unitPrice * item.quantity; } let deliveryFee = Number(supplier.deliveryFee); if (supplier.freeDeliveryMin && subtotal >= Number(supplier.freeDeliveryMin)) { deliveryFee = 0; } if (subtotal < Number(supplier.minOrderAmount)) { throw new common_1.BadRequestException(`Pedido minimo es $${supplier.minOrderAmount}`); } const total = subtotal + deliveryFee; const order = this.orderRepo.create({ tenantId, supplierId: dto.supplierId, status: supplier_order_entity_1.SupplierOrderStatus.PENDING, subtotal, deliveryFee, total, deliveryAddress: dto.deliveryAddress, deliveryCity: dto.deliveryCity, deliveryZip: dto.deliveryZip, deliveryPhone: dto.deliveryPhone, deliveryContact: dto.deliveryContact, requestedDate: dto.requestedDate ? new Date(dto.requestedDate) : null, notes: dto.notes, }); await this.orderRepo.save(order); for (const item of dto.items) { const product = productMap.get(item.productId); let unitPrice = Number(product.unitPrice); if (product.tieredPricing && product.tieredPricing.length > 0) { for (const tier of product.tieredPricing.sort((a, b) => b.min - a.min)) { if (item.quantity >= tier.min) { unitPrice = tier.price; break; } } } const orderItem = this.orderItemRepo.create({ orderId: order.id, productId: item.productId, productName: product.name, productSku: product.sku, quantity: item.quantity, unitPrice, total: unitPrice * item.quantity, notes: item.notes, }); await this.orderItemRepo.save(orderItem); } return this.getOrder(order.id); } async getOrder(id) { const order = await this.orderRepo.findOne({ where: { id }, relations: ['items', 'supplier'], }); if (!order) { throw new common_1.NotFoundException('Pedido no encontrado'); } return order; } async getOrders(tenantId, options) { const query = this.orderRepo.createQueryBuilder('order') .where('order.tenant_id = :tenantId', { tenantId }) .leftJoinAndSelect('order.supplier', 'supplier') .leftJoinAndSelect('order.items', 'items') .orderBy('order.created_at', 'DESC'); if (options?.status) { query.andWhere('order.status = :status', { status: options.status }); } if (options?.supplierId) { query.andWhere('order.supplier_id = :supplierId', { supplierId: options.supplierId }); } if (options?.limit) { query.limit(options.limit); } return query.getMany(); } async updateOrderStatus(id, status, notes) { const order = await this.getOrder(id); const validTransitions = { [supplier_order_entity_1.SupplierOrderStatus.PENDING]: [supplier_order_entity_1.SupplierOrderStatus.CONFIRMED, supplier_order_entity_1.SupplierOrderStatus.CANCELLED, supplier_order_entity_1.SupplierOrderStatus.REJECTED], [supplier_order_entity_1.SupplierOrderStatus.CONFIRMED]: [supplier_order_entity_1.SupplierOrderStatus.PREPARING, supplier_order_entity_1.SupplierOrderStatus.CANCELLED], [supplier_order_entity_1.SupplierOrderStatus.PREPARING]: [supplier_order_entity_1.SupplierOrderStatus.SHIPPED, supplier_order_entity_1.SupplierOrderStatus.CANCELLED], [supplier_order_entity_1.SupplierOrderStatus.SHIPPED]: [supplier_order_entity_1.SupplierOrderStatus.DELIVERED, supplier_order_entity_1.SupplierOrderStatus.CANCELLED], [supplier_order_entity_1.SupplierOrderStatus.DELIVERED]: [], [supplier_order_entity_1.SupplierOrderStatus.CANCELLED]: [], [supplier_order_entity_1.SupplierOrderStatus.REJECTED]: [], }; if (!validTransitions[order.status].includes(status)) { throw new common_1.BadRequestException(`No se puede cambiar estado de ${order.status} a ${status}`); } order.status = status; if (status === supplier_order_entity_1.SupplierOrderStatus.CONFIRMED) { order.confirmedDate = new Date(); } if (status === supplier_order_entity_1.SupplierOrderStatus.DELIVERED) { order.deliveredAt = new Date(); } if (status === supplier_order_entity_1.SupplierOrderStatus.CANCELLED || status === supplier_order_entity_1.SupplierOrderStatus.REJECTED) { order.cancelledAt = new Date(); order.cancelReason = notes; } if (notes) { order.supplierNotes = notes; } return this.orderRepo.save(order); } async cancelOrder(id, tenantId, reason) { const order = await this.getOrder(id); if (order.tenantId !== tenantId) { throw new common_1.BadRequestException('No autorizado'); } if (![supplier_order_entity_1.SupplierOrderStatus.PENDING, supplier_order_entity_1.SupplierOrderStatus.CONFIRMED].includes(order.status)) { throw new common_1.BadRequestException('No se puede cancelar el pedido en este estado'); } order.status = supplier_order_entity_1.SupplierOrderStatus.CANCELLED; order.cancelledAt = new Date(); order.cancelReason = reason; order.cancelledBy = 'tenant'; return this.orderRepo.save(order); } async createReview(tenantId, dto) { const supplier = await this.supplierRepo.findOne({ where: { id: dto.supplierId }, }); if (!supplier) { throw new common_1.NotFoundException('Proveedor no encontrado'); } let verified = false; if (dto.orderId) { const order = await this.orderRepo.findOne({ where: { id: dto.orderId, tenantId, supplierId: dto.supplierId }, }); if (!order) { throw new common_1.BadRequestException('Orden no encontrada'); } if (order.status === supplier_order_entity_1.SupplierOrderStatus.DELIVERED) { verified = true; } } const review = this.reviewRepo.create({ tenantId, supplierId: dto.supplierId, orderId: dto.orderId, rating: dto.rating, title: dto.title, comment: dto.comment, ratingQuality: dto.ratingQuality, ratingDelivery: dto.ratingDelivery, ratingPrice: dto.ratingPrice, verified, }); return this.reviewRepo.save(review); } async getReviews(supplierId, options) { return this.reviewRepo.find({ where: { supplierId, status: 'active' }, order: { createdAt: 'DESC' }, take: options?.limit || 20, skip: options?.offset || 0, }); } async addFavorite(tenantId, supplierId) { await this.dataSource.query(`INSERT INTO marketplace.supplier_favorites (tenant_id, supplier_id) VALUES ($1, $2) ON CONFLICT DO NOTHING`, [tenantId, supplierId]); } async removeFavorite(tenantId, supplierId) { await this.dataSource.query(`DELETE FROM marketplace.supplier_favorites WHERE tenant_id = $1 AND supplier_id = $2`, [tenantId, supplierId]); } async getFavorites(tenantId) { const result = await this.dataSource.query(`SELECT s.* FROM marketplace.suppliers s JOIN marketplace.supplier_favorites f ON s.id = f.supplier_id WHERE f.tenant_id = $1`, [tenantId]); return result; } async getMarketplaceStats() { const result = await this.dataSource.query(`SELECT * FROM marketplace.get_marketplace_stats()`); return result[0] || { total_suppliers: 0, active_suppliers: 0, total_products: 0, total_orders: 0, total_gmv: 0, avg_rating: 0, }; } }; exports.MarketplaceService = MarketplaceService; exports.MarketplaceService = MarketplaceService = __decorate([ (0, common_1.Injectable)(), __param(0, (0, typeorm_1.InjectRepository)(supplier_entity_1.Supplier)), __param(1, (0, typeorm_1.InjectRepository)(supplier_product_entity_1.SupplierProduct)), __param(2, (0, typeorm_1.InjectRepository)(supplier_order_entity_1.SupplierOrder)), __param(3, (0, typeorm_1.InjectRepository)(supplier_order_item_entity_1.SupplierOrderItem)), __param(4, (0, typeorm_1.InjectRepository)(supplier_review_entity_1.SupplierReview)), __metadata("design:paramtypes", [typeorm_2.Repository, typeorm_2.Repository, typeorm_2.Repository, typeorm_2.Repository, typeorm_2.Repository, typeorm_2.DataSource]) ], MarketplaceService); //# sourceMappingURL=marketplace.service.js.map