import { Document, Model, Schema, model } from "mongoose"; import { CreatePlanUsageCycleParams, FindPlanUsageCycleParams, IPlanUsageCycle, IPlanUsageCycleAdapter, UpdatePlanUsageCycleParams, } from "./PlanUsageCycle.Interface"; export interface IPlanUsageCycleDocument extends Omit, Document {} export class PlanUsageCycleAdapterMongoose implements IPlanUsageCycleAdapter { schema: Schema; planUsageCycleList: Model; constructor() { this.schema = new Schema({ userId: { type: Schema.Types.ObjectId, required: true, ref: "User" }, subscriptionId: { type: Schema.Types.ObjectId, required: false, ref: "PlanSuscription" }, planId: { type: Schema.Types.ObjectId, required: true, ref: "Plan" }, cycleStart: { type: Date, required: true }, cycleEnd: { type: Date, required: true }, appointmentsCount: { type: Number, required: true, default: 0 }, creationDate: { type: Date, required: true, default: Date.now }, updateDate: { type: Date, required: true, default: Date.now }, }); this.schema.index({ userId: 1, subscriptionId: 1, planId: 1, cycleStart: 1 }, { unique: true }); this.planUsageCycleList = model("PlanUsageCycle", this.schema); } public async findOne(filters: FindPlanUsageCycleParams): Promise { return await this.planUsageCycleList.findOne(filters); } public async create(data: CreatePlanUsageCycleParams): Promise { return await this.planUsageCycleList.create({ ...data, appointmentsCount: data.appointmentsCount || 0, updateDate: new Date(), }); } public async getOrCreateCurrent(data: UpdatePlanUsageCycleParams): Promise { const now = new Date(); return await this.planUsageCycleList.findOneAndUpdate( { userId: data.userId, subscriptionId: data.subscriptionId, planId: data.planId, cycleStart: data.cycleStart, }, { $setOnInsert: { userId: data.userId, subscriptionId: data.subscriptionId, planId: data.planId, cycleStart: data.cycleStart, cycleEnd: data.cycleEnd, creationDate: now, }, $set: { updateDate: now }, }, { new: true, upsert: true } ); } public async incrementAppointments( data: UpdatePlanUsageCycleParams & { quantity: number } ): Promise { const now = new Date(); return await this.planUsageCycleList.findOneAndUpdate( { userId: data.userId, subscriptionId: data.subscriptionId, planId: data.planId, cycleStart: data.cycleStart, }, { $setOnInsert: { userId: data.userId, subscriptionId: data.subscriptionId, planId: data.planId, cycleStart: data.cycleStart, cycleEnd: data.cycleEnd, creationDate: now, }, $inc: { appointmentsCount: data.quantity }, $set: { updateDate: now }, }, { new: true, upsert: true } ); } public async incrementAppointmentsIfWithinLimit( data: UpdatePlanUsageCycleParams & { quantity: number; limit: number } ): Promise { const now = new Date(); return await this.planUsageCycleList.findOneAndUpdate( { userId: data.userId, subscriptionId: data.subscriptionId, planId: data.planId, cycleStart: data.cycleStart, appointmentsCount: { $lte: data.limit - data.quantity }, }, { $setOnInsert: { userId: data.userId, subscriptionId: data.subscriptionId, planId: data.planId, cycleStart: data.cycleStart, cycleEnd: data.cycleEnd, creationDate: now, }, $inc: { appointmentsCount: data.quantity }, $set: { updateDate: now }, }, { new: true } ); } public async setAppointmentsCount( data: UpdatePlanUsageCycleParams & { appointmentsCount: number } ): Promise { const now = new Date(); return await this.planUsageCycleList.findOneAndUpdate( { userId: data.userId, subscriptionId: data.subscriptionId, planId: data.planId, cycleStart: data.cycleStart, }, { $setOnInsert: { userId: data.userId, subscriptionId: data.subscriptionId, planId: data.planId, cycleStart: data.cycleStart, cycleEnd: data.cycleEnd, creationDate: now, }, $set: { appointmentsCount: Math.max(data.appointmentsCount, 0), updateDate: now, }, }, { new: true, upsert: true } ); } }