feat: agregar soporte para plantillas de correo electrónico y contexto en el envío de notificaciones
This commit is contained in:
Generated
+26
@@ -20,6 +20,7 @@
|
||||
"@types/jest": "^30.0.0",
|
||||
"@types/mongoose": "^5.11.96",
|
||||
"@types/node": "^24.3.3",
|
||||
"cross-env": "^10.1.0",
|
||||
"jest": "^30.4.2",
|
||||
"ts-jest": "^29.4.11",
|
||||
"ts-node": "^10.9.2",
|
||||
@@ -600,6 +601,13 @@
|
||||
"tslib": "^2.4.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@epic-web/invariant": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/@epic-web/invariant/-/invariant-1.0.0.tgz",
|
||||
"integrity": "sha512-lrTPqgvfFQtR/eY/qkIzp98OGdNJu0m5ji3q/nJI8v3SXkRKEnWiOxMmbvcSoAIzv/cGiuvRy57k4suKQSAdwA==",
|
||||
"dev": true,
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/@isaacs/cliui": {
|
||||
"version": "8.0.2",
|
||||
"resolved": "https://registry.npmjs.org/@isaacs/cliui/-/cliui-8.0.2.tgz",
|
||||
@@ -2322,6 +2330,24 @@
|
||||
"dev": true,
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/cross-env": {
|
||||
"version": "10.1.0",
|
||||
"resolved": "https://registry.npmjs.org/cross-env/-/cross-env-10.1.0.tgz",
|
||||
"integrity": "sha512-GsYosgnACZTADcmEyJctkJIoqAhHjttw7RsFrVoJNXbsWWqaq6Ym+7kZjq6mS45O0jij6vtiReppKQEtqWy6Dw==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@epic-web/invariant": "^1.0.0",
|
||||
"cross-spawn": "^7.0.6"
|
||||
},
|
||||
"bin": {
|
||||
"cross-env": "dist/bin/cross-env.js",
|
||||
"cross-env-shell": "dist/bin/cross-env-shell.js"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=20"
|
||||
}
|
||||
},
|
||||
"node_modules/cross-spawn": {
|
||||
"version": "7.0.6",
|
||||
"resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz",
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
"type": "module",
|
||||
"main": "index.js",
|
||||
"scripts": {
|
||||
"dev": "NODE_NO_WARNINGS=1 DOTENV_DISABLE_TELEMETRY=1 node --loader ts-node/esm src/index.ts",
|
||||
"dev": "cross-env NODE_NO_WARNINGS=1 DOTENV_DISABLE_TELEMETRY=1 node --loader ts-node/esm src/index.ts",
|
||||
"build": "tsc",
|
||||
"start": "node dist/index.js",
|
||||
"test": "jest --config jest.config.cjs"
|
||||
@@ -18,6 +18,7 @@
|
||||
"@types/jest": "^30.0.0",
|
||||
"@types/mongoose": "^5.11.96",
|
||||
"@types/node": "^24.3.3",
|
||||
"cross-env": "^10.1.0",
|
||||
"jest": "^30.4.2",
|
||||
"ts-jest": "^29.4.11",
|
||||
"ts-node": "^10.9.2",
|
||||
|
||||
@@ -91,12 +91,17 @@ export async function dispatchEmail(params: {
|
||||
systemToken: string;
|
||||
type: string;
|
||||
email: string;
|
||||
subject: string;
|
||||
message: string;
|
||||
subject?: string;
|
||||
message?: string;
|
||||
templateId?: string;
|
||||
context?: Record<string, unknown>;
|
||||
}): Promise<DispatchResult> {
|
||||
try {
|
||||
if (!params.email.trim() || !params.subject.trim() || !params.message.trim()) {
|
||||
return { success: false, error: "Email dispatch requires email, subject, and message" };
|
||||
const hasContent = Boolean(params.subject?.trim() && params.message?.trim());
|
||||
const hasTemplate = Boolean(params.templateId?.trim() && params.context);
|
||||
|
||||
if (!params.email.trim() || (!hasContent && !hasTemplate)) {
|
||||
return { success: false, error: "Email dispatch requires email and either subject/message or templateId/context" };
|
||||
}
|
||||
|
||||
// Send worker-rendered content directly so cancellation jobs survive appointment deletion.
|
||||
@@ -106,8 +111,10 @@ export async function dispatchEmail(params: {
|
||||
{
|
||||
systemToken: params.systemToken,
|
||||
email: params.email,
|
||||
subject: params.subject,
|
||||
message: params.message,
|
||||
...(params.subject ? { subject: params.subject } : {}),
|
||||
...(params.message ? { message: params.message } : {}),
|
||||
...(params.templateId ? { templateId: params.templateId } : {}),
|
||||
...(params.context ? { context: params.context } : {}),
|
||||
},
|
||||
{
|
||||
headers: { "Content-Type": "application/json" },
|
||||
|
||||
@@ -202,6 +202,8 @@ export class JobProcessor {
|
||||
email: content.email || "",
|
||||
subject: content.subject,
|
||||
message: content.message,
|
||||
templateId: content.emailTemplateId,
|
||||
context: content.emailContext,
|
||||
});
|
||||
break;
|
||||
case "system":
|
||||
|
||||
@@ -45,6 +45,8 @@ export interface ResolvedNotificationContent {
|
||||
companyOwnerId?: string;
|
||||
subject: string;
|
||||
message: string;
|
||||
emailTemplateId?: string;
|
||||
emailContext?: Record<string, unknown>;
|
||||
}
|
||||
|
||||
const appointmentSchema = new Schema(
|
||||
@@ -169,6 +171,8 @@ export async function resolveNotificationContent(job: INotificationJobDocument):
|
||||
companyOwnerId: companyOwnerId ? String(companyOwnerId) : undefined,
|
||||
subject: fallbackSubject.trim(),
|
||||
message: fallbackMessage.trim(),
|
||||
emailTemplateId: job.payload.emailTemplateId?.trim(),
|
||||
emailContext: job.payload.emailContext,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
@@ -15,6 +15,8 @@ export interface NotificationJobPayload {
|
||||
message?: string;
|
||||
emailSubject?: string;
|
||||
emailMessage?: string;
|
||||
emailTemplateId?: string;
|
||||
emailContext?: Record<string, unknown>;
|
||||
wapMessage?: string;
|
||||
systemSubject?: string;
|
||||
systemMessage?: string;
|
||||
|
||||
@@ -43,6 +43,30 @@ describe("ChannelDispatchers", () => {
|
||||
);
|
||||
});
|
||||
|
||||
it("sends email template data when provided", async () => {
|
||||
await dispatchEmail({
|
||||
appointmentId: "appointment-1",
|
||||
systemToken: "system-token",
|
||||
type: "reminder",
|
||||
email: "client@example.com",
|
||||
templateId: "template-1",
|
||||
context: { username: "Client Name" },
|
||||
});
|
||||
|
||||
expect(mockedAxios.post).toHaveBeenCalledWith(
|
||||
"https://api.example.com/notifications/send-email",
|
||||
{
|
||||
systemToken: "system-token",
|
||||
email: "client@example.com",
|
||||
templateId: "template-1",
|
||||
context: { username: "Client Name" },
|
||||
},
|
||||
{
|
||||
headers: { "Content-Type": "application/json" },
|
||||
}
|
||||
);
|
||||
});
|
||||
|
||||
it("sends the job type in the WhatsApp system notification payload", async () => {
|
||||
await dispatchWhatsApp({
|
||||
companyId: "company-1",
|
||||
|
||||
Reference in New Issue
Block a user