feat: plan management

This commit is contained in:
2026-07-17 21:28:41 -03:00
parent d6a4aab52b
commit 8d9a03cd23
21 changed files with 1355 additions and 131 deletions
@@ -2,6 +2,8 @@ import axios from "axios";
import PlanSubscriptionsList from "../../Models/PlanSubscriptions/PlanSubscriptons";
import { MP_SUBS_STATUS } from "../../Models/PlanSubscriptions/PlanSubscriptions.Adapter.Mongoose";
import { connect } from "mongoose";
import dayjs from "dayjs";
import PlanPaymentsList from "../../Models/PlanPayments/PlanPayments";
export class MercadoPagoWebhookService {
public async handleWebhook(body: any): Promise<void> {
@@ -27,28 +29,75 @@ export class MercadoPagoWebhookService {
const paymentData = paymentResponse.data;
const status = paymentData.status; // approved, pending, rejected, etc.
const userId = paymentData.external_reference; // We passed this when creating preference
const preferenceId = paymentData.preference_id || paymentData.order?.id;
let subscription = await PlanSubscriptionsList.planSuscriptions.findOne({
sessionUser: userId,
mpPreferenceId: preferenceId,
mpStatus: MP_SUBS_STATUS.PENDING,
});
if (!subscription && userId && preferenceId) {
subscription = await PlanSubscriptionsList.planSuscriptions.planSuscriptionList.findOne({
userId,
pendingPaymentPreferenceId: preferenceId,
}).exec();
}
if (userId && status === "approved") {
// Update subscription status in DB
const subscription = await PlanSubscriptionsList.planSuscriptions.findOne({
sessionUser: userId,
});
if (subscription) {
const approvedAt = paymentData.date_approved ? new Date(paymentData.date_approved) : new Date();
const billingMonths = subscription.pendingPaymentBillingMonths || subscription.billingMonths || 1;
const isExtensionPayment = subscription.pendingPaymentPreferenceId === preferenceId;
const periodStart = isExtensionPayment && dayjs(subscription.endDate).isAfter(approvedAt)
? subscription.endDate
: approvedAt;
subscription.mpStatus = MP_SUBS_STATUS.AUTHORIZED;
subscription.isActive = true;
// Assuming endDate is correctly set for the months purchased when preference was created
subscription.autoRenew = false;
subscription.startDate = isExtensionPayment ? subscription.startDate : approvedAt;
subscription.endDate = dayjs(periodStart).add(billingMonths, "months").toDate();
subscription.mpPayerId = paymentData.payer?.id || subscription.mpPayerId;
subscription.mpPayerEmail = paymentData.payer?.email || subscription.mpPayerEmail;
subscription.pendingPaymentInitPoint = "";
subscription.pendingPaymentPreferenceId = "";
subscription.pendingPaymentBillingMonths = undefined;
await subscription.save();
await PlanPaymentsList.create({
userId,
subscriptionId: String(subscription._id),
amount: paymentData.transaction_amount || 0,
paymentDate: approvedAt,
paymentMethod: paymentData.payment_method_id || paymentData.payment_type_id || "mercadopago",
status: "completed",
transactionId: String(paymentData.id),
});
}
} else if (userId && status === "rejected") {
const subscription = await PlanSubscriptionsList.planSuscriptions.findOne({
sessionUser: userId,
});
if (subscription) {
const isExtensionPayment = subscription.pendingPaymentPreferenceId === preferenceId;
if (subscription && subscription.mpStatus !== MP_SUBS_STATUS.AUTHORIZED) {
subscription.mpStatus = MP_SUBS_STATUS.CANCELLED;
subscription.isActive = false;
if (isExtensionPayment) {
subscription.pendingPaymentInitPoint = "";
subscription.pendingPaymentPreferenceId = "";
subscription.pendingPaymentBillingMonths = undefined;
} else {
subscription.mpStatus = MP_SUBS_STATUS.CANCELLED;
subscription.isActive = false;
}
await subscription.save();
await PlanPaymentsList.create({
userId,
subscriptionId: String(subscription._id),
amount: paymentData.transaction_amount || 0,
paymentDate: new Date(),
paymentMethod: paymentData.payment_method_id || paymentData.payment_type_id || "mercadopago",
status: "failed",
transactionId: String(paymentData.id),
});
}
}
} catch (error) {