feat: add manual subscription finalization functionality and support for expired plan notifications

This commit is contained in:
2026-07-19 13:20:33 -03:00
parent 78ee86ac48
commit af6c87acb6
20 changed files with 462 additions and 39 deletions
@@ -23,7 +23,6 @@ import {
import axios from "axios";
import PlansList from "../../Models/Plans/Plans";
import dayjs from "dayjs";
import isSameOrAfter from "dayjs/plugin/isSameOrAfter";
import "dayjs/locale/es";
import { isNull } from "../../helpers/IsNull";
import { PlanFeatures } from "../Plans/Plans.interface";
@@ -34,7 +33,6 @@ import { NotificationType } from "../../Models/SystemNotifications/SystemNotific
import { calculateProratedUpgradeAmount } from "./PlanSubscriptions.pricing";
dayjs.locale("es");
dayjs.extend(isSameOrAfter);
const DAY_MS = 24 * 60 * 60 * 1000;
@@ -195,6 +193,11 @@ class PlanSuscriptionsManager implements IPlanSuscriptionsManager {
subscription.autoRenew = false;
subscription.mpStatus = "";
subscription.mpInitPoint = dashboardUrl || "";
subscription.downgradedFromPlanId = undefined;
subscription.downgradedFromPlanName = undefined;
subscription.downgradedFromPlanCode = undefined;
subscription.downgradedAt = undefined;
subscription.downgradeReason = undefined;
await subscription.save();
}
} else {
@@ -381,6 +384,11 @@ class PlanSuscriptionsManager implements IPlanSuscriptionsManager {
currentSubscription.lastPaymentPreferenceId = undefined;
currentSubscription.lastPaymentAt = undefined;
currentSubscription.lastPaymentType = undefined;
currentSubscription.downgradedFromPlanId = undefined;
currentSubscription.downgradedFromPlanName = undefined;
currentSubscription.downgradedFromPlanCode = undefined;
currentSubscription.downgradedAt = undefined;
currentSubscription.downgradeReason = undefined;
currentSubscription.mpInitPoint = subscriptionData.init_point;
await currentSubscription.save();
@@ -409,6 +417,11 @@ class PlanSuscriptionsManager implements IPlanSuscriptionsManager {
currentSubscription.lastPaymentPreferenceId = undefined;
currentSubscription.lastPaymentAt = undefined;
currentSubscription.lastPaymentType = undefined;
currentSubscription.downgradedFromPlanId = undefined;
currentSubscription.downgradedFromPlanName = undefined;
currentSubscription.downgradedFromPlanCode = undefined;
currentSubscription.downgradedAt = undefined;
currentSubscription.downgradeReason = undefined;
currentSubscription.mpInitPoint = subscriptionData.init_point;
await currentSubscription.save();
@@ -447,6 +460,11 @@ class PlanSuscriptionsManager implements IPlanSuscriptionsManager {
lastPaymentPreferenceId: undefined,
lastPaymentAt: undefined,
lastPaymentType: undefined,
downgradedFromPlanId: undefined,
downgradedFromPlanName: undefined,
downgradedFromPlanCode: undefined,
downgradedAt: undefined,
downgradeReason: undefined,
});
await NotificationsManager.sendSystemNotification({
@@ -493,12 +511,13 @@ class PlanSuscriptionsManager implements IPlanSuscriptionsManager {
// We just cancel it locally if not paid, or change to free plan if paid.
}
const dateNow = dayjs(new Date()).endOf("day");
const dateEnd = dayjs(subscription.endDate);
const dateNow = new Date();
const dateEnd = new Date(subscription.endDate);
if (dateNow.isSameOrAfter(dateEnd)) {
if (dateNow > dateEnd) {
await this.toFreePlan({
sessionUser: data.sessionUser,
downgradeReason: "expired",
});
} else {
subscription.mpStatus = MP_SUBS_STATUS.CANCELLED;
@@ -573,6 +592,10 @@ class PlanSuscriptionsManager implements IPlanSuscriptionsManager {
//console.log("guardando el plan gratuito...");
//try {
const downgradedFromPlan = data.downgradeReason === "expired"
? await PlansList.plans.findOne({ _id: String(subscription.planId) })
: null;
console.log("cambiando al free plan:", freePlan.id);
subscription.planId = freePlan.id;
subscription.mpStatus = "";
@@ -593,6 +616,19 @@ class PlanSuscriptionsManager implements IPlanSuscriptionsManager {
subscription.pendingPaymentPeriodEndDate = undefined;
subscription.startDate = new Date();
subscription.endDate = dayjs(new Date()).add(10, "years").toDate();
if (data.downgradeReason === "expired" && downgradedFromPlan) {
subscription.downgradedFromPlanId = String(downgradedFromPlan.id || downgradedFromPlan._id);
subscription.downgradedFromPlanName = downgradedFromPlan.name;
subscription.downgradedFromPlanCode = downgradedFromPlan.code;
subscription.downgradedAt = new Date();
subscription.downgradeReason = "expired";
} else {
subscription.downgradedFromPlanId = undefined;
subscription.downgradedFromPlanName = undefined;
subscription.downgradedFromPlanCode = undefined;
subscription.downgradedAt = undefined;
subscription.downgradeReason = undefined;
}
await subscription.save();
// console.log("plan gratuito guardado:", freePlan.id);
@@ -621,6 +657,11 @@ class PlanSuscriptionsManager implements IPlanSuscriptionsManager {
lastPaymentPreferenceId: subscription.lastPaymentPreferenceId,
lastPaymentAt: subscription.lastPaymentAt,
lastPaymentType: subscription.lastPaymentType,
downgradedFromPlanId: subscription.downgradedFromPlanId,
downgradedFromPlanName: subscription.downgradedFromPlanName,
downgradedFromPlanCode: subscription.downgradedFromPlanCode,
downgradedAt: subscription.downgradedAt,
downgradeReason: subscription.downgradeReason,
};
io.to(`user:${String(subscription.userId)}`).emit("suscription_status_updated", susInfo);
@@ -637,12 +678,13 @@ class PlanSuscriptionsManager implements IPlanSuscriptionsManager {
return null;
}
const dateNow = dayjs(new Date()).endOf("day");
const dateEnd = dayjs(subscription.endDate);
const dateNow = new Date();
const dateEnd = new Date(subscription.endDate);
if (dateNow.isSameOrAfter(dateEnd) && this.shouldDowngradeExpiredSubscription(subscription)) {
if (dateNow > dateEnd && this.shouldDowngradeExpiredSubscription(subscription)) {
await this.toFreePlan({
sessionUser: data.sessionUser,
downgradeReason: "expired",
});
}
@@ -658,12 +700,13 @@ class PlanSuscriptionsManager implements IPlanSuscriptionsManager {
return null;
}
const dateNow = dayjs(new Date()).endOf("day");
const dateEnd = dayjs(subscription.endDate);
const dateNow = new Date();
const dateEnd = new Date(subscription.endDate);
if (dateNow.isSameOrAfter(dateEnd) && this.shouldDowngradeExpiredSubscription(subscription)) {
if (dateNow > dateEnd && this.shouldDowngradeExpiredSubscription(subscription)) {
await this.toFreePlan({
sessionUser: data.sessionUser,
downgradeReason: "expired",
});
return this.getSubscriptionByUser(data);
}
@@ -701,6 +744,11 @@ class PlanSuscriptionsManager implements IPlanSuscriptionsManager {
lastPaymentPreferenceId: subscription.lastPaymentPreferenceId,
lastPaymentAt: subscription.lastPaymentAt,
lastPaymentType: subscription.lastPaymentType,
downgradedFromPlanId: subscription.downgradedFromPlanId,
downgradedFromPlanName: subscription.downgradedFromPlanName,
downgradedFromPlanCode: subscription.downgradedFromPlanCode,
downgradedAt: subscription.downgradedAt,
downgradeReason: subscription.downgradeReason,
};
}