feat: agregar envío de correos electrónicos para planes aprobados y mejorar el formato de fecha y monto

This commit is contained in:
2026-08-19 15:05:45 -03:00
parent c8029a6762
commit e4441fa476
@@ -6,6 +6,9 @@ import dayjs from "dayjs";
import PlanPaymentsList from "../../Models/PlanPayments/PlanPayments";
import { IPlanSuscriptionDocument } from "../../Models/PlanSubscriptions/PlanSubscriptions.Adapter.Mongoose";
import { VerifyPendingPlanPaymentResponse } from "../../Models/PlanSubscriptions/PlanSubscriptions.interface";
import PlansList from "../../Models/Plans/Plans";
import UserList from "../../Models/Users/Users";
import { NotificationsManager } from "../../Models/Notifications/Notifications";
type MercadoPagoPaymentData = {
id: string | number;
@@ -41,6 +44,66 @@ type MercadoPagoPaymentVerification = {
const REJECTED_PAYMENT_STATUSES = ["rejected", "cancelled", "failed"];
export class MercadoPagoWebhookService {
private formatTemplateDate(date: Date): string {
return new Intl.DateTimeFormat("es-AR", {
day: "2-digit",
month: "2-digit",
year: "numeric",
}).format(date);
}
private formatTemplateAmount(amount: number): string {
return new Intl.NumberFormat("es-AR", {
style: "currency",
currency: "ARS",
}).format(amount);
}
private async sendApprovedPaidPlanEmail(
subscription: IPlanSuscriptionDocument,
paymentData: MercadoPagoPaymentData,
userId: string,
approvedAt: Date,
periodStart: Date
): Promise<void> {
try {
const plan = await PlansList.findOne({ _id: String(subscription.planId) });
if (plan.price <= 0) {
return;
}
const user = await UserList.users.findOne({ _id: userId });
if (!user) {
return;
}
await NotificationsManager.sendEmail({
email: user.email,
templateId: "6a85ebb1323720a53d0cfd3f",
context: {
username: user.firstName || user.email,
nombre_plan: plan.name,
importe: this.formatTemplateAmount(paymentData.transaction_amount || 0),
fecha_pago: this.formatTemplateDate(approvedAt),
periodo_desde: this.formatTemplateDate(periodStart),
periodo_hasta: this.formatTemplateDate(subscription.endDate),
},
});
} catch (e) {
if (axios.isAxiosError(e)) {
console.error("Error enviando email de pago de plan aprobado:", {
status: e.response?.status,
data: e.response?.data,
});
return;
}
console.error("Error enviando email de pago de plan aprobado:", e);
}
}
public async handleWebhook(body: any): Promise<void> {
await connect(`${process.env.DATABASE_CONNECTION}`);
@@ -300,6 +363,9 @@ export class MercadoPagoWebhookService {
const periodStart = isExtensionPayment && dayjs(subscription.endDate).isAfter(approvedAt)
? subscription.endDate
: approvedAt;
const transactionId = String(paymentData.id);
const existingPayments = await PlanPaymentsList.find({ transactionId });
const shouldSendApprovedPaymentEmail = existingPayments.length === 0;
if (isUpgradePayment && subscription.pendingPaymentPlanId) {
subscription.planId = subscription.pendingPaymentPlanId;
@@ -342,8 +408,12 @@ export class MercadoPagoWebhookService {
paymentDate: approvedAt,
paymentMethod: paymentData.payment_method_id || paymentData.payment_type_id || "mercadopago",
status: "completed",
transactionId: String(paymentData.id),
transactionId,
});
if (shouldSendApprovedPaymentEmail) {
await this.sendApprovedPaidPlanEmail(subscription, paymentData, userId, approvedAt, periodStart);
}
}
private async applyRejectedPayment(