Compare commits
49 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
3e1d74196d | ||
|
|
9c4cd0fc43 | ||
|
|
5c886ebe42 | ||
|
|
1c0951b47b | ||
|
|
e670f8cab6 | ||
|
|
63fc973064 | ||
|
|
6fbda2b35b | ||
|
|
375937ed5e | ||
|
|
168e909c77 | ||
|
|
fd5f5f55d2 | ||
|
|
fb68d82024 | ||
|
|
26a03c193c | ||
|
|
62f1130d3e | ||
|
|
7f4ca23cb8 | ||
|
|
bb720e6f78 | ||
|
|
c271e73c3c | ||
|
|
f0f2cd3411 | ||
|
|
4817424c71 | ||
|
|
2fb0280e87 | ||
|
|
bd601d896d | ||
|
|
0402e307df | ||
|
|
5fe4d30502 | ||
|
|
d0b2d29925 | ||
|
|
8ad307f3a9 | ||
|
|
083485d7de | ||
|
|
4ed6790de3 | ||
|
|
1a40513cc4 | ||
|
|
ed33fe3c46 | ||
|
|
e8523b9cdb | ||
|
|
354881d5bf | ||
|
|
df404e405c | ||
|
|
63044e517e | ||
|
|
89b9ba897a | ||
|
|
5824e1984a | ||
|
|
18afada52a | ||
|
|
d73f02726e | ||
|
|
dd060fb963 | ||
|
|
5a17380f66 | ||
|
|
623ebc84df | ||
|
|
3d64e11a05 | ||
|
|
af8617a4a9 | ||
|
|
c252ba8620 | ||
|
|
2cca695f2f | ||
|
|
5d138e5937 | ||
|
|
85e8dea5f1 | ||
|
|
66a65aed38 | ||
|
|
4ce107c4af | ||
|
|
95492d304f | ||
|
|
de9ea73dcd |
@ -1,62 +1,62 @@
|
|||||||
import { onRequest } from "firebase-functions/v2/https";
|
// import { onRequest } from "firebase-functions/v2/https";
|
||||||
import { Request } from "firebase-functions/v2/https";
|
// import { Request } from "firebase-functions/v2/https";
|
||||||
import { getCorsHandler } from "../../../shared/middleware";
|
// import { getCorsHandler } from "../../../shared/middleware";
|
||||||
import { getAdmin, getLogger } from "../../../shared/config";
|
// import { getAdmin, getLogger } from "../../../shared/config";
|
||||||
import { InvoiceService } from "./invoiceService";
|
// import { InvoiceService } from "./invoiceService";
|
||||||
|
|
||||||
const admin = getAdmin();
|
// const admin = getAdmin();
|
||||||
const logger = getLogger();
|
// const logger = getLogger();
|
||||||
const corsHandler = getCorsHandler();
|
// const corsHandler = getCorsHandler();
|
||||||
const invoiceService = new InvoiceService();
|
// const invoiceService = new InvoiceService();
|
||||||
|
|
||||||
export const getInvoiceUrl = onRequest({
|
// export const getInvoiceUrl = onRequest({
|
||||||
region: '#{SERVICES_RGN}#'
|
// region: '#{SERVICES_RGN}#'
|
||||||
}, async (request: Request, response) => {
|
// }, async (request: Request, response) => {
|
||||||
return corsHandler(request, response, async () => {
|
// return corsHandler(request, response, async () => {
|
||||||
try {
|
// try {
|
||||||
const authHeader = request.headers.authorization || '';
|
// const authHeader = request.headers.authorization || '';
|
||||||
if (!authHeader || !authHeader.startsWith('Bearer ')) {
|
// if (!authHeader || !authHeader.startsWith('Bearer ')) {
|
||||||
response.status(401).json({ error: 'Unauthorized' });
|
// response.status(401).json({ error: 'Unauthorized' });
|
||||||
return;
|
// return;
|
||||||
}
|
// }
|
||||||
|
|
||||||
const idToken = authHeader.split('Bearer ')[1];
|
// const idToken = authHeader.split('Bearer ')[1];
|
||||||
|
|
||||||
try {
|
// try {
|
||||||
await admin.auth().verifyIdToken(idToken);
|
// await admin.auth().verifyIdToken(idToken);
|
||||||
|
|
||||||
const { invoicePath } = request.query;
|
// const { invoicePath } = request.query;
|
||||||
|
|
||||||
if (!invoicePath) {
|
// if (!invoicePath) {
|
||||||
response.status(400).json({
|
// response.status(400).json({
|
||||||
success: false,
|
// success: false,
|
||||||
error: 'Missing invoice path'
|
// error: 'Missing invoice path'
|
||||||
});
|
// });
|
||||||
return;
|
// return;
|
||||||
}
|
// }
|
||||||
|
|
||||||
const downloadUrl = await invoiceService.getInvoiceDownloadUrl(invoicePath as string);
|
// const downloadUrl = await invoiceService.getInvoiceDownloadUrl(invoicePath as string);
|
||||||
|
|
||||||
response.json({
|
// response.json({
|
||||||
success: true,
|
// success: true,
|
||||||
downloadUrl
|
// downloadUrl
|
||||||
});
|
// });
|
||||||
|
|
||||||
} catch (authError: any) {
|
// } catch (authError: any) {
|
||||||
logger.error('Authentication error:', authError);
|
// logger.error('Authentication error:', authError);
|
||||||
response.status(401).json({
|
// response.status(401).json({
|
||||||
success: false,
|
// success: false,
|
||||||
error: 'Invalid authentication token',
|
// error: 'Invalid authentication token',
|
||||||
details: authError.message
|
// details: authError.message
|
||||||
});
|
// });
|
||||||
}
|
// }
|
||||||
} catch (error: any) {
|
// } catch (error: any) {
|
||||||
logger.error('Error getting invoice URL:', error);
|
// logger.error('Error getting invoice URL:', error);
|
||||||
response.status(500).json({
|
// response.status(500).json({
|
||||||
success: false,
|
// success: false,
|
||||||
error: 'Failed to get invoice URL',
|
// error: 'Failed to get invoice URL',
|
||||||
details: error.message
|
// details: error.message
|
||||||
});
|
// });
|
||||||
}
|
// }
|
||||||
});
|
// });
|
||||||
});
|
// });
|
||||||
|
|||||||
@ -1,13 +1,13 @@
|
|||||||
import { getInvoiceUrl } from './getInvoiceUrl';
|
// import { getInvoiceUrl } from './getInvoiceUrl';
|
||||||
import { InvoiceService } from './invoiceService';
|
import { InvoiceService } from './invoiceService';
|
||||||
import { processInvoice } from './processInvoice';
|
// import { processInvoice } from './processInvoice';
|
||||||
import { sendInvoiceEmail } from './sendInvoiceEmail';
|
// import { sendInvoiceEmail } from './sendInvoiceEmail';
|
||||||
import { directGenerateInvoice } from './directInvoice';
|
import { directGenerateInvoice } from './directInvoice';
|
||||||
|
|
||||||
export {
|
export {
|
||||||
getInvoiceUrl,
|
// getInvoiceUrl,
|
||||||
InvoiceService,
|
InvoiceService,
|
||||||
processInvoice,
|
// processInvoice,
|
||||||
sendInvoiceEmail,
|
// sendInvoiceEmail,
|
||||||
directGenerateInvoice,
|
directGenerateInvoice,
|
||||||
};
|
};
|
||||||
|
|||||||
@ -1,83 +1,83 @@
|
|||||||
import { onRequest } from "firebase-functions/v2/https";
|
// import { onRequest } from "firebase-functions/v2/https";
|
||||||
import { Request } from "firebase-functions/v2/https";
|
// import { Request } from "firebase-functions/v2/https";
|
||||||
import { getCorsHandler } from "../../../shared/middleware";
|
// import { getCorsHandler } from "../../../shared/middleware";
|
||||||
import { getAdmin, getLogger } from "../../../shared/config";
|
// import { getAdmin, getLogger } from "../../../shared/config";
|
||||||
import { InvoiceService } from "./invoiceService";
|
// import { InvoiceService } from "./invoiceService";
|
||||||
|
|
||||||
const admin = getAdmin();
|
// const admin = getAdmin();
|
||||||
const logger = getLogger();
|
// const logger = getLogger();
|
||||||
const corsHandler = getCorsHandler();
|
// const corsHandler = getCorsHandler();
|
||||||
const invoiceService = new InvoiceService();
|
// const invoiceService = new InvoiceService();
|
||||||
|
|
||||||
export const processInvoice = onRequest({
|
// export const processInvoice = onRequest({
|
||||||
region: '#{SERVICES_RGN}#'
|
// region: '#{SERVICES_RGN}#'
|
||||||
}, async (request: Request, response) => {
|
// }, async (request: Request, response) => {
|
||||||
return corsHandler(request, response, async () => {
|
// return corsHandler(request, response, async () => {
|
||||||
try {
|
// try {
|
||||||
const authHeader = request.headers.authorization || '';
|
// const authHeader = request.headers.authorization || '';
|
||||||
if (!authHeader || !authHeader.startsWith('Bearer ')) {
|
// if (!authHeader || !authHeader.startsWith('Bearer ')) {
|
||||||
response.status(401).json({ error: 'Unauthorized' });
|
// response.status(401).json({ error: 'Unauthorized' });
|
||||||
return;
|
// return;
|
||||||
}
|
// }
|
||||||
|
|
||||||
const idToken = authHeader.split('Bearer ')[1];
|
// const idToken = authHeader.split('Bearer ')[1];
|
||||||
|
|
||||||
try {
|
// try {
|
||||||
await admin.auth().verifyIdToken(idToken);
|
// await admin.auth().verifyIdToken(idToken);
|
||||||
|
|
||||||
const {
|
// const {
|
||||||
membershipId,
|
// membershipId,
|
||||||
paymentId,
|
// paymentId,
|
||||||
invoiceData,
|
// invoiceData,
|
||||||
emailOptions
|
// emailOptions
|
||||||
} = request.body;
|
// } = request.body;
|
||||||
|
|
||||||
if (!membershipId || !paymentId || !invoiceData) {
|
// if (!membershipId || !paymentId || !invoiceData) {
|
||||||
response.status(400).json({
|
// response.status(400).json({
|
||||||
success: false,
|
// success: false,
|
||||||
error: 'Missing required fields'
|
// error: 'Missing required fields'
|
||||||
});
|
// });
|
||||||
return;
|
// return;
|
||||||
}
|
// }
|
||||||
|
|
||||||
const result = await invoiceService.processInvoice(
|
// const result = await invoiceService.processInvoice(
|
||||||
membershipId,
|
// membershipId,
|
||||||
paymentId,
|
// paymentId,
|
||||||
invoiceData,
|
// invoiceData,
|
||||||
emailOptions
|
// emailOptions
|
||||||
);
|
// );
|
||||||
|
|
||||||
if (!result.success) {
|
// if (!result.success) {
|
||||||
response.status(400).json({
|
// response.status(400).json({
|
||||||
success: false,
|
// success: false,
|
||||||
error: result.error || 'Failed to process invoice'
|
// error: result.error || 'Failed to process invoice'
|
||||||
});
|
// });
|
||||||
return;
|
// return;
|
||||||
}
|
// }
|
||||||
|
|
||||||
response.json({
|
// response.json({
|
||||||
success: true,
|
// success: true,
|
||||||
message: 'Invoice processed successfully',
|
// message: 'Invoice processed successfully',
|
||||||
invoicePath: result.invoicePath,
|
// invoicePath: result.invoicePath,
|
||||||
downloadUrl: result.downloadUrl,
|
// downloadUrl: result.downloadUrl,
|
||||||
emailSent: result.emailSent
|
// emailSent: result.emailSent
|
||||||
});
|
// });
|
||||||
|
|
||||||
} catch (authError: any) {
|
// } catch (authError: any) {
|
||||||
logger.error('Authentication error:', authError);
|
// logger.error('Authentication error:', authError);
|
||||||
response.status(401).json({
|
// response.status(401).json({
|
||||||
success: false,
|
// success: false,
|
||||||
error: 'Invalid authentication token',
|
// error: 'Invalid authentication token',
|
||||||
details: authError.message
|
// details: authError.message
|
||||||
});
|
// });
|
||||||
}
|
// }
|
||||||
} catch (error: any) {
|
// } catch (error: any) {
|
||||||
logger.error('Error processing invoice:', error);
|
// logger.error('Error processing invoice:', error);
|
||||||
response.status(500).json({
|
// response.status(500).json({
|
||||||
success: false,
|
// success: false,
|
||||||
error: 'Failed to process invoice',
|
// error: 'Failed to process invoice',
|
||||||
details: error.message
|
// details: error.message
|
||||||
});
|
// });
|
||||||
}
|
// }
|
||||||
});
|
// });
|
||||||
});
|
// });
|
||||||
|
|||||||
@ -1,91 +1,91 @@
|
|||||||
import { onRequest } from "firebase-functions/v2/https";
|
// import { onRequest } from "firebase-functions/v2/https";
|
||||||
import { Request } from "firebase-functions/v2/https";
|
// import { Request } from "firebase-functions/v2/https";
|
||||||
import { getCorsHandler } from "../../../shared/middleware";
|
// import { getCorsHandler } from "../../../shared/middleware";
|
||||||
import { getAdmin, getLogger } from "../../../shared/config";
|
// import { getAdmin, getLogger } from "../../../shared/config";
|
||||||
import { InvoiceService, EmailOptions } from "./invoiceService";
|
// import { InvoiceService, EmailOptions } from "./invoiceService";
|
||||||
|
|
||||||
const admin = getAdmin();
|
// const admin = getAdmin();
|
||||||
const logger = getLogger();
|
// const logger = getLogger();
|
||||||
const corsHandler = getCorsHandler();
|
// const corsHandler = getCorsHandler();
|
||||||
const invoiceService = new InvoiceService();
|
// const invoiceService = new InvoiceService();
|
||||||
|
|
||||||
export const sendInvoiceEmail = onRequest({
|
// export const sendInvoiceEmail = onRequest({
|
||||||
region: '#{SERVICES_RGN}#'
|
// region: '#{SERVICES_RGN}#'
|
||||||
}, async (request: Request, response) => {
|
// }, async (request: Request, response) => {
|
||||||
return corsHandler(request, response, async () => {
|
// return corsHandler(request, response, async () => {
|
||||||
try {
|
// try {
|
||||||
const authHeader = request.headers.authorization || '';
|
// const authHeader = request.headers.authorization || '';
|
||||||
if (!authHeader || !authHeader.startsWith('Bearer ')) {
|
// if (!authHeader || !authHeader.startsWith('Bearer ')) {
|
||||||
response.status(401).json({ error: 'Unauthorized' });
|
// response.status(401).json({ error: 'Unauthorized' });
|
||||||
return;
|
// return;
|
||||||
}
|
// }
|
||||||
|
|
||||||
const idToken = authHeader.split('Bearer ')[1];
|
// const idToken = authHeader.split('Bearer ')[1];
|
||||||
|
|
||||||
try {
|
// try {
|
||||||
await admin.auth().verifyIdToken(idToken);
|
// await admin.auth().verifyIdToken(idToken);
|
||||||
|
|
||||||
const {
|
// const {
|
||||||
invoicePath,
|
// invoicePath,
|
||||||
recipientEmail,
|
// recipientEmail,
|
||||||
recipientName,
|
// recipientName,
|
||||||
subject,
|
// subject,
|
||||||
customHtml,
|
// customHtml,
|
||||||
gymName,
|
// gymName,
|
||||||
planName,
|
// planName,
|
||||||
amount,
|
// amount,
|
||||||
transactionId,
|
// transactionId,
|
||||||
paymentDate,
|
// paymentDate,
|
||||||
paymentMethod
|
// paymentMethod
|
||||||
} = request.body;
|
// } = request.body;
|
||||||
|
|
||||||
if (!invoicePath || !recipientEmail) {
|
// if (!invoicePath || !recipientEmail) {
|
||||||
response.status(400).json({
|
// response.status(400).json({
|
||||||
success: false,
|
// success: false,
|
||||||
error: 'Missing required fields'
|
// error: 'Missing required fields'
|
||||||
});
|
// });
|
||||||
return;
|
// return;
|
||||||
}
|
// }
|
||||||
|
|
||||||
const emailOptions: EmailOptions = {
|
// const emailOptions: EmailOptions = {
|
||||||
recipientEmail,
|
// recipientEmail,
|
||||||
recipientName,
|
// recipientName,
|
||||||
subject,
|
// subject,
|
||||||
customHtml,
|
// customHtml,
|
||||||
additionalData: {
|
// additionalData: {
|
||||||
gymName,
|
// gymName,
|
||||||
planName,
|
// planName,
|
||||||
amount,
|
// amount,
|
||||||
transactionId,
|
// transactionId,
|
||||||
paymentDate: paymentDate ? new Date(paymentDate) : undefined,
|
// paymentDate: paymentDate ? new Date(paymentDate) : undefined,
|
||||||
paymentMethod
|
// paymentMethod
|
||||||
}
|
// }
|
||||||
};
|
// };
|
||||||
|
|
||||||
const emailSent = await invoiceService.sendInvoiceEmail(invoicePath, emailOptions);
|
// const emailSent = await invoiceService.sendInvoiceEmail(invoicePath, emailOptions);
|
||||||
const downloadUrl = await invoiceService.getInvoiceDownloadUrl(invoicePath);
|
// const downloadUrl = await invoiceService.getInvoiceDownloadUrl(invoicePath);
|
||||||
|
|
||||||
response.json({
|
// response.json({
|
||||||
success: true,
|
// success: true,
|
||||||
message: emailSent ? 'Invoice email sent successfully' : 'Failed to send email but URL generated',
|
// message: emailSent ? 'Invoice email sent successfully' : 'Failed to send email but URL generated',
|
||||||
downloadUrl
|
// downloadUrl
|
||||||
});
|
// });
|
||||||
|
|
||||||
} catch (authError: any) {
|
// } catch (authError: any) {
|
||||||
logger.error('Authentication error:', authError);
|
// logger.error('Authentication error:', authError);
|
||||||
response.status(401).json({
|
// response.status(401).json({
|
||||||
success: false,
|
// success: false,
|
||||||
error: 'Invalid authentication token',
|
// error: 'Invalid authentication token',
|
||||||
details: authError.message
|
// details: authError.message
|
||||||
});
|
// });
|
||||||
}
|
// }
|
||||||
} catch (error: any) {
|
// } catch (error: any) {
|
||||||
logger.error('Error sending invoice email:', error);
|
// logger.error('Error sending invoice email:', error);
|
||||||
response.status(500).json({
|
// response.status(500).json({
|
||||||
success: false,
|
// success: false,
|
||||||
error: 'Failed to send invoice email',
|
// error: 'Failed to send invoice email',
|
||||||
details: error.message
|
// details: error.message
|
||||||
});
|
// });
|
||||||
}
|
// }
|
||||||
});
|
// });
|
||||||
});
|
// });
|
||||||
|
|||||||
@ -142,7 +142,7 @@ export const phonePeWebhook = onRequest({
|
|||||||
} else if (paymentId) {
|
} else if (paymentId) {
|
||||||
await processServicePayment(payload, orderData, paymentId);
|
await processServicePayment(payload, orderData, paymentId);
|
||||||
} else {
|
} else {
|
||||||
logger.error(`No membershipId, bookingId, or serviceId found in metaInfo for order: ${payload.merchantOrderId}`);
|
logger.error(`No membershipId, bookingId, or paymentId found in metaInfo for order: ${payload.merchantOrderId}`);
|
||||||
}
|
}
|
||||||
|
|
||||||
logger.info(`Payment data updated for completed payment: ${payload.merchantOrderId}`);
|
logger.info(`Payment data updated for completed payment: ${payload.merchantOrderId}`);
|
||||||
@ -639,6 +639,18 @@ async function processServicePayment(payload: any, orderData: any, paymentId: st
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const serviceData = serviceDoc.data();
|
||||||
|
|
||||||
|
if (serviceData?.status === 'ACCEPTED' && serviceData?.paymentDetails?.merchantOrderId) {
|
||||||
|
logger.warn(`Service payment already processed for serviceId: ${paymentId}, merchantOrderId: ${serviceData.paymentDetails.merchantOrderId}`);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (serviceData?.invoicePath && serviceData?.invoiceNumber) {
|
||||||
|
logger.warn(`Invoice already exists for serviceId: ${paymentId}, invoicePath: ${serviceData.invoicePath}`);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
await serviceRef.update({
|
await serviceRef.update({
|
||||||
status: 'ACCEPTED',
|
status: 'ACCEPTED',
|
||||||
paymentDetails: {
|
paymentDetails: {
|
||||||
@ -651,9 +663,8 @@ async function processServicePayment(payload: any, orderData: any, paymentId: st
|
|||||||
updatedAt: admin.firestore.FieldValue.serverTimestamp()
|
updatedAt: admin.firestore.FieldValue.serverTimestamp()
|
||||||
});
|
});
|
||||||
|
|
||||||
logger.info(`Updated service booking status to 'CONFIRMED' for serviceId: ${paymentId}`);
|
logger.info(`Updated service booking status to 'CONFIRMED' for paymentId: ${paymentId}`);
|
||||||
|
|
||||||
const serviceData = serviceDoc.data();
|
|
||||||
const gymId = orderData.metaInfo?.gymId || serviceData?.gymId;
|
const gymId = orderData.metaInfo?.gymId || serviceData?.gymId;
|
||||||
|
|
||||||
if (gymId) {
|
if (gymId) {
|
||||||
@ -681,7 +692,7 @@ async function processServicePayment(payload: any, orderData: any, paymentId: st
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const invoiceNumber = `SRV-${payload.merchantOrderId.substring(0, 8)}`;
|
const invoiceNumber = `INV-${payload.merchantOrderId.substring(0, 8)}`;
|
||||||
logger.info(`Generated invoice number for service: ${invoiceNumber}`);
|
logger.info(`Generated invoice number for service: ${invoiceNumber}`);
|
||||||
|
|
||||||
const discountPercentage = orderData.metaInfo?.discount || 0;
|
const discountPercentage = orderData.metaInfo?.discount || 0;
|
||||||
@ -703,7 +714,7 @@ async function processServicePayment(payload: any, orderData: any, paymentId: st
|
|||||||
businessName: gymName,
|
businessName: gymName,
|
||||||
address: gymAddress,
|
address: gymAddress,
|
||||||
gstNumber: orderData.metaInfo?.gstNumber,
|
gstNumber: orderData.metaInfo?.gstNumber,
|
||||||
customerName: orderData.metaInfo?.customerName || serviceData?.customerName || '',
|
customerName: orderData.metaInfo?.customerName || serviceData?.normalizedName || '',
|
||||||
phoneNumber: orderData.metaInfo?.customerPhone || serviceData?.phoneNumber || '',
|
phoneNumber: orderData.metaInfo?.customerPhone || serviceData?.phoneNumber || '',
|
||||||
email: orderData.metaInfo?.customerEmail || serviceData?.email || '',
|
email: orderData.metaInfo?.customerEmail || serviceData?.email || '',
|
||||||
planName: orderData.metaInfo?.serviceName || serviceData?.serviceName || 'Service',
|
planName: orderData.metaInfo?.serviceName || serviceData?.serviceName || 'Service',
|
||||||
|
|||||||
@ -21,7 +21,7 @@ interface EmailRequest {
|
|||||||
|
|
||||||
interface Attachment {
|
interface Attachment {
|
||||||
filename: string;
|
filename: string;
|
||||||
content: string | Buffer; // Base64 encoded string or Buffer
|
content: string | Buffer;
|
||||||
contentType?: string;
|
contentType?: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -32,7 +32,7 @@ const stripHtml = (html: string): string => {
|
|||||||
|
|
||||||
async function sendSimpleEmail(data: EmailRequest, recipients: string[]) {
|
async function sendSimpleEmail(data: EmailRequest, recipients: string[]) {
|
||||||
const ses = new SESClient({
|
const ses = new SESClient({
|
||||||
region: 'ap-south-1',
|
region: process.env.AWS_REGION,
|
||||||
credentials: {
|
credentials: {
|
||||||
accessKeyId: process.env.AWS_ACCESS_KEY_ID || '',
|
accessKeyId: process.env.AWS_ACCESS_KEY_ID || '',
|
||||||
secretAccessKey: process.env.AWS_SECRET_ACCESS_KEY || ''
|
secretAccessKey: process.env.AWS_SECRET_ACCESS_KEY || ''
|
||||||
@ -58,7 +58,7 @@ async function sendSimpleEmail(data: EmailRequest, recipients: string[]) {
|
|||||||
|
|
||||||
async function sendEmailWithAttachments(data: EmailRequest, recipients: string[]) {
|
async function sendEmailWithAttachments(data: EmailRequest, recipients: string[]) {
|
||||||
const ses = new SESClient({
|
const ses = new SESClient({
|
||||||
region: 'ap-south-1',
|
region: process.env.AWS_REGION,
|
||||||
credentials: {
|
credentials: {
|
||||||
accessKeyId: process.env.AWS_ACCESS_KEY_ID || '',
|
accessKeyId: process.env.AWS_ACCESS_KEY_ID || '',
|
||||||
secretAccessKey: process.env.AWS_SECRET_ACCESS_KEY || ''
|
secretAccessKey: process.env.AWS_SECRET_ACCESS_KEY || ''
|
||||||
@ -72,26 +72,21 @@ async function sendEmailWithAttachments(data: EmailRequest, recipients: string[]
|
|||||||
rawMessage += `MIME-Version: 1.0\n`;
|
rawMessage += `MIME-Version: 1.0\n`;
|
||||||
rawMessage += `Content-Type: multipart/mixed; boundary="${boundary}"\n\n`;
|
rawMessage += `Content-Type: multipart/mixed; boundary="${boundary}"\n\n`;
|
||||||
|
|
||||||
// Add email body (multipart/alternative)
|
|
||||||
rawMessage += `--${boundary}\n`;
|
rawMessage += `--${boundary}\n`;
|
||||||
rawMessage += `Content-Type: multipart/alternative; boundary="alt_${boundary}"\n\n`;
|
rawMessage += `Content-Type: multipart/alternative; boundary="alt_${boundary}"\n\n`;
|
||||||
|
|
||||||
// Text part
|
|
||||||
if (data.text) {
|
if (data.text) {
|
||||||
rawMessage += `--alt_${boundary}\n`;
|
rawMessage += `--alt_${boundary}\n`;
|
||||||
rawMessage += `Content-Type: text/plain; charset=UTF-8\n\n`;
|
rawMessage += `Content-Type: text/plain; charset=UTF-8\n\n`;
|
||||||
rawMessage += `${data.text}\n\n`;
|
rawMessage += `${data.text}\n\n`;
|
||||||
}
|
}
|
||||||
|
|
||||||
// HTML part
|
|
||||||
rawMessage += `--alt_${boundary}\n`;
|
rawMessage += `--alt_${boundary}\n`;
|
||||||
rawMessage += `Content-Type: text/html; charset=UTF-8\n\n`;
|
rawMessage += `Content-Type: text/html; charset=UTF-8\n\n`;
|
||||||
rawMessage += `${data.html}\n\n`;
|
rawMessage += `${data.html}\n\n`;
|
||||||
|
|
||||||
// Close alternative part
|
|
||||||
rawMessage += `--alt_${boundary}--\n\n`;
|
rawMessage += `--alt_${boundary}--\n\n`;
|
||||||
|
|
||||||
// Add attachments
|
|
||||||
for (const attachment of data.attachments || []) {
|
for (const attachment of data.attachments || []) {
|
||||||
const contentType = attachment.contentType ||
|
const contentType = attachment.contentType ||
|
||||||
mime.lookup(attachment.filename) ||
|
mime.lookup(attachment.filename) ||
|
||||||
@ -109,7 +104,6 @@ async function sendEmailWithAttachments(data: EmailRequest, recipients: string[]
|
|||||||
rawMessage += contentBuffer.toString('base64') + '\n\n';
|
rawMessage += contentBuffer.toString('base64') + '\n\n';
|
||||||
}
|
}
|
||||||
|
|
||||||
// Close message
|
|
||||||
rawMessage += `--${boundary}--`;
|
rawMessage += `--${boundary}--`;
|
||||||
|
|
||||||
const command = new SendRawEmailCommand({
|
const command = new SendRawEmailCommand({
|
||||||
@ -140,7 +134,6 @@ export async function sendEmailWithAttachmentUtil(
|
|||||||
try {
|
try {
|
||||||
logger.info(`Sending email with attachment to: ${toAddress}`);
|
logger.info(`Sending email with attachment to: ${toAddress}`);
|
||||||
|
|
||||||
// Initialize data with basic fields
|
|
||||||
const data: EmailRequest = {
|
const data: EmailRequest = {
|
||||||
to: toAddress,
|
to: toAddress,
|
||||||
html: message,
|
html: message,
|
||||||
@ -151,13 +144,11 @@ export async function sendEmailWithAttachmentUtil(
|
|||||||
attachments: []
|
attachments: []
|
||||||
};
|
};
|
||||||
|
|
||||||
// Handle file URL if provided
|
|
||||||
if (fileUrl && fileName) {
|
if (fileUrl && fileName) {
|
||||||
logger.info(`Downloading attachment from URL: ${fileUrl}`);
|
logger.info(`Downloading attachment from URL: ${fileUrl}`);
|
||||||
try {
|
try {
|
||||||
const fileContent = await downloadFileFromUrl(fileUrl);
|
const fileContent = await downloadFileFromUrl(fileUrl);
|
||||||
|
|
||||||
// Add the downloaded file as an attachment
|
|
||||||
data.attachments!.push({
|
data.attachments!.push({
|
||||||
filename: fileName,
|
filename: fileName,
|
||||||
content: fileContent,
|
content: fileContent,
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user