feat: agregar envío de correos electrónicos para planes aprobados y mejorar el formato de fecha y monto
This commit is contained in:
@@ -6,6 +6,9 @@ import dayjs from "dayjs";
|
|||||||
import PlanPaymentsList from "../../Models/PlanPayments/PlanPayments";
|
import PlanPaymentsList from "../../Models/PlanPayments/PlanPayments";
|
||||||
import { IPlanSuscriptionDocument } from "../../Models/PlanSubscriptions/PlanSubscriptions.Adapter.Mongoose";
|
import { IPlanSuscriptionDocument } from "../../Models/PlanSubscriptions/PlanSubscriptions.Adapter.Mongoose";
|
||||||
import { VerifyPendingPlanPaymentResponse } from "../../Models/PlanSubscriptions/PlanSubscriptions.interface";
|
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 = {
|
type MercadoPagoPaymentData = {
|
||||||
id: string | number;
|
id: string | number;
|
||||||
@@ -41,6 +44,66 @@ type MercadoPagoPaymentVerification = {
|
|||||||
const REJECTED_PAYMENT_STATUSES = ["rejected", "cancelled", "failed"];
|
const REJECTED_PAYMENT_STATUSES = ["rejected", "cancelled", "failed"];
|
||||||
|
|
||||||
export class MercadoPagoWebhookService {
|
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> {
|
public async handleWebhook(body: any): Promise<void> {
|
||||||
await connect(`${process.env.DATABASE_CONNECTION}`);
|
await connect(`${process.env.DATABASE_CONNECTION}`);
|
||||||
|
|
||||||
@@ -300,6 +363,9 @@ export class MercadoPagoWebhookService {
|
|||||||
const periodStart = isExtensionPayment && dayjs(subscription.endDate).isAfter(approvedAt)
|
const periodStart = isExtensionPayment && dayjs(subscription.endDate).isAfter(approvedAt)
|
||||||
? subscription.endDate
|
? subscription.endDate
|
||||||
: approvedAt;
|
: approvedAt;
|
||||||
|
const transactionId = String(paymentData.id);
|
||||||
|
const existingPayments = await PlanPaymentsList.find({ transactionId });
|
||||||
|
const shouldSendApprovedPaymentEmail = existingPayments.length === 0;
|
||||||
|
|
||||||
if (isUpgradePayment && subscription.pendingPaymentPlanId) {
|
if (isUpgradePayment && subscription.pendingPaymentPlanId) {
|
||||||
subscription.planId = subscription.pendingPaymentPlanId;
|
subscription.planId = subscription.pendingPaymentPlanId;
|
||||||
@@ -342,8 +408,12 @@ export class MercadoPagoWebhookService {
|
|||||||
paymentDate: approvedAt,
|
paymentDate: approvedAt,
|
||||||
paymentMethod: paymentData.payment_method_id || paymentData.payment_type_id || "mercadopago",
|
paymentMethod: paymentData.payment_method_id || paymentData.payment_type_id || "mercadopago",
|
||||||
status: "completed",
|
status: "completed",
|
||||||
transactionId: String(paymentData.id),
|
transactionId,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
if (shouldSendApprovedPaymentEmail) {
|
||||||
|
await this.sendApprovedPaidPlanEmail(subscription, paymentData, userId, approvedAt, periodStart);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private async applyRejectedPayment(
|
private async applyRejectedPayment(
|
||||||
|
|||||||
Reference in New Issue
Block a user