import Discounts from "../Discounts/Discounts"; import { FindServicesParams, IServicesAdapter, IService, CreateServiceParams, UpdateServiceParams, PaginateServicesParams, PaginateServicesResults, SERVICE_PUBLISHED_STATUS, SysAdminPaginateServicesParams, } from "./Service.Interface"; import mongoose, { Document, Model, Schema, model } from "mongoose"; export interface IServiceDocument extends Omit, Document {} export class ServicesAdapterMongoose implements IServicesAdapter { schema: Schema; serviceList: Model; constructor() { this.schema = new Schema({ companyId: { type: Schema.Types.ObjectId, required: true, ref: "Companie" }, discountId: { type: Schema.Types.ObjectId, required: false, ref: "Discount" }, categoryId: { type: Number, required: false }, name: { type: String, required: true }, description: { type: String, required: true }, price: { type: Number, required: true, default: 0 }, originalPrice: { type: Number, required: false, default: 0 }, length: { type: Number, required: true, default: 0 }, limit: { type: Number, required: true, default: 0 }, image: { type: String, required: false }, color: { type: String, required: false }, fontColor: { type: String, required: false }, fontShadowColor: { type: String, required: false }, block: { type: String, required: false }, city: { type: String, required: false }, state: { type: String, required: false }, country: { type: String, required: false }, zipCode: { type: String, required: false }, latitude: { type: Number, required: false, default: 0 }, longitude: { type: Number, required: false, default: 0 }, published: { type: String, required: false }, banned: { type: Boolean, required: false, default: false }, showPublicScores: { type: Boolean, required: false, default: true }, showPublicOpinions: { type: Boolean, required: false, default: true }, }); this.serviceList = model("Service", this.schema); } public async create(data: CreateServiceParams): Promise { return await this.serviceList.create(data); } public async update(data: UpdateServiceParams): Promise { const updateService = await this.serviceList.findOne({ _id: data.id }); if (!updateService) { throw new Error("Service not found"); } if (data.categoryId) updateService.categoryId = data.categoryId; if (data.name) updateService.name = data.name; if (data.description) updateService.description = data.description; if (data.originalPrice) { updateService.originalPrice = data.originalPrice; //Si tiene un descuento aplicado tenemos que actualizar el precio //aplicando el descuento al precio original if (updateService.discountId) { const discount = await Discounts.discounts.discountsList.findOne({ _id: String(updateService.discountId), companyId: data.companyId, }); if (discount) { updateService.price = updateService.originalPrice - updateService.originalPrice * (discount.value / 100); } } else { updateService.price = updateService.originalPrice; } } if (data.length) updateService.length = data.length; if (data.limit) updateService.limit = data.limit; if (data.image) updateService.image = data.image; if (data.color) updateService.color = data.color; if (data.fontColor) updateService.fontColor = data.fontColor; if (data.fontShadowColor) updateService.fontShadowColor = data.fontShadowColor; if (data.block) updateService.block = data.block; if (data.city) updateService.city = data.city; if (data.state) updateService.state = data.state; if (data.country) updateService.country = data.country; if (data.zipCode) updateService.zipCode = data.zipCode; if (data.latitude) updateService.latitude = data.latitude; if (data.longitude) updateService.longitude = data.longitude; if (data.banned !== undefined) updateService.banned = data.banned; if (data.showPublicScores !== undefined) updateService.showPublicScores = data.showPublicScores; if (data.showPublicOpinions !== undefined) updateService.showPublicOpinions = data.showPublicOpinions; await updateService.save(); } public async delete(id: string): Promise { await this.serviceList.findByIdAndDelete(id).exec(); } public async find(filters: FindServicesParams): Promise { return this.serviceList.find(filters).exec(); } public async findOne(filters: FindServicesParams): Promise { return this.serviceList.findOne(filters).exec(); } public async paginate(filters: PaginateServicesParams): Promise { const { page, limit, ...findFilters } = filters; const count = await this.serviceList.countDocuments(findFilters).exec(); const skip = (page - 1) * limit; const results = await this.serviceList.find(findFilters).skip(skip).limit(limit).exec(); return { data: results, page, pages: Math.ceil(count / limit), }; } // Método para búsqueda con expresiones regulares y paginación public async paginateFiltered(data: PaginateServicesParams): Promise { const skip = (data.page - 1) * data.limit; // Construye los criterios de búsqueda const searchCriteria: mongoose.FilterQuery = {}; // Agrega filtro por query usando expresiones regulares para 'name' y 'description' if (data.query) { const regex = new RegExp(data.query, "i"); searchCriteria.$or = [{ name: regex }, { description: regex }]; } // Filtra por categoryId si está presente if (data.categoryId !== undefined) { searchCriteria.categoryId = data.categoryId; } if (data.companyId !== undefined) { searchCriteria.companyId = data.companyId; } if (data.serviceId !== undefined) { searchCriteria._id = data.serviceId; } // Filtra por rango de precios if (data.priceFrom !== undefined || data.priceTo !== undefined) { searchCriteria.price = {}; if (data.priceFrom !== undefined) searchCriteria.price.$gte = data.priceFrom; if (data.priceTo !== undefined) searchCriteria.price.$lte = data.priceTo; } // Filtra por rango de longitud if (data.lengthFrom !== undefined || data.lengthTo !== undefined) { searchCriteria.length = {}; if (data.lengthFrom !== undefined) searchCriteria.length.$gte = data.lengthFrom; if (data.lengthTo !== undefined) searchCriteria.length.$lte = data.lengthTo; } // Filtra por block si está presente if (data.block) { searchCriteria.block = data.block; } // Filtra por city si está presente if (data.city) { searchCriteria.city = data.city; } // Filtra por state si está presente if (data.state) { searchCriteria.state = data.state; } if (data.published !== undefined) { searchCriteria.published = data.published; if (data.published === SERVICE_PUBLISHED_STATUS.PUBLISHED) { searchCriteria.banned = { $ne: true }; } } // Realiza la consulta con paginación const results = await this.serviceList .find(searchCriteria) .sort({ price: 1 }) // Ordena por precio ascendente .skip(skip) .limit(data.limit) .exec(); // Cuenta el total de documentos que coinciden con los criterios de búsqueda const count = await this.serviceList.countDocuments(searchCriteria).exec(); return { data: results, page: data.page, pages: Math.ceil(count / data.limit), }; } public async sysAdminPaginate(data: SysAdminPaginateServicesParams): Promise { const { page, limit, companyId } = data; const query: any = {}; if (companyId) { query.companyId = companyId; } const count = await this.serviceList.countDocuments(query).exec(); const skip = (page - 1) * limit; const results = await this.serviceList .find(query) .sort({ name: 1 }) .skip(skip) .limit(limit) .exec(); return { data: results, page: page, pages: Math.ceil(count / limit), }; } }