Invoice updates
This commit is contained in:
parent
5c886ebe42
commit
9c4cd0fc43
@ -1,62 +1,62 @@
|
||||
import { onRequest } from "firebase-functions/v2/https";
|
||||
import { Request } from "firebase-functions/v2/https";
|
||||
import { getCorsHandler } from "../../../shared/middleware";
|
||||
import { getAdmin, getLogger } from "../../../shared/config";
|
||||
import { InvoiceService } from "./invoiceService";
|
||||
// import { onRequest } from "firebase-functions/v2/https";
|
||||
// import { Request } from "firebase-functions/v2/https";
|
||||
// import { getCorsHandler } from "../../../shared/middleware";
|
||||
// import { getAdmin, getLogger } from "../../../shared/config";
|
||||
// import { InvoiceService } from "./invoiceService";
|
||||
|
||||
const admin = getAdmin();
|
||||
const logger = getLogger();
|
||||
const corsHandler = getCorsHandler();
|
||||
const invoiceService = new InvoiceService();
|
||||
// const admin = getAdmin();
|
||||
// const logger = getLogger();
|
||||
// const corsHandler = getCorsHandler();
|
||||
// const invoiceService = new InvoiceService();
|
||||
|
||||
export const getInvoiceUrl = onRequest({
|
||||
region: '#{SERVICES_RGN}#'
|
||||
}, async (request: Request, response) => {
|
||||
return corsHandler(request, response, async () => {
|
||||
try {
|
||||
const authHeader = request.headers.authorization || '';
|
||||
if (!authHeader || !authHeader.startsWith('Bearer ')) {
|
||||
response.status(401).json({ error: 'Unauthorized' });
|
||||
return;
|
||||
}
|
||||
// export const getInvoiceUrl = onRequest({
|
||||
// region: '#{SERVICES_RGN}#'
|
||||
// }, async (request: Request, response) => {
|
||||
// return corsHandler(request, response, async () => {
|
||||
// try {
|
||||
// const authHeader = request.headers.authorization || '';
|
||||
// if (!authHeader || !authHeader.startsWith('Bearer ')) {
|
||||
// response.status(401).json({ error: 'Unauthorized' });
|
||||
// return;
|
||||
// }
|
||||
|
||||
const idToken = authHeader.split('Bearer ')[1];
|
||||
// const idToken = authHeader.split('Bearer ')[1];
|
||||
|
||||
try {
|
||||
await admin.auth().verifyIdToken(idToken);
|
||||
// try {
|
||||
// await admin.auth().verifyIdToken(idToken);
|
||||
|
||||
const { invoicePath } = request.query;
|
||||
// const { invoicePath } = request.query;
|
||||
|
||||
if (!invoicePath) {
|
||||
response.status(400).json({
|
||||
success: false,
|
||||
error: 'Missing invoice path'
|
||||
});
|
||||
return;
|
||||
}
|
||||
// if (!invoicePath) {
|
||||
// response.status(400).json({
|
||||
// success: false,
|
||||
// error: 'Missing invoice path'
|
||||
// });
|
||||
// return;
|
||||
// }
|
||||
|
||||
const downloadUrl = await invoiceService.getInvoiceDownloadUrl(invoicePath as string);
|
||||
// const downloadUrl = await invoiceService.getInvoiceDownloadUrl(invoicePath as string);
|
||||
|
||||
response.json({
|
||||
success: true,
|
||||
downloadUrl
|
||||
});
|
||||
// response.json({
|
||||
// success: true,
|
||||
// downloadUrl
|
||||
// });
|
||||
|
||||
} catch (authError: any) {
|
||||
logger.error('Authentication error:', authError);
|
||||
response.status(401).json({
|
||||
success: false,
|
||||
error: 'Invalid authentication token',
|
||||
details: authError.message
|
||||
});
|
||||
}
|
||||
} catch (error: any) {
|
||||
logger.error('Error getting invoice URL:', error);
|
||||
response.status(500).json({
|
||||
success: false,
|
||||
error: 'Failed to get invoice URL',
|
||||
details: error.message
|
||||
});
|
||||
}
|
||||
});
|
||||
});
|
||||
// } catch (authError: any) {
|
||||
// logger.error('Authentication error:', authError);
|
||||
// response.status(401).json({
|
||||
// success: false,
|
||||
// error: 'Invalid authentication token',
|
||||
// details: authError.message
|
||||
// });
|
||||
// }
|
||||
// } catch (error: any) {
|
||||
// logger.error('Error getting invoice URL:', error);
|
||||
// response.status(500).json({
|
||||
// success: false,
|
||||
// error: 'Failed to get invoice URL',
|
||||
// details: error.message
|
||||
// });
|
||||
// }
|
||||
// });
|
||||
// });
|
||||
|
||||
@ -1,13 +1,13 @@
|
||||
import { getInvoiceUrl } from './getInvoiceUrl';
|
||||
// import { getInvoiceUrl } from './getInvoiceUrl';
|
||||
import { InvoiceService } from './invoiceService';
|
||||
import { processInvoice } from './processInvoice';
|
||||
import { sendInvoiceEmail } from './sendInvoiceEmail';
|
||||
// import { processInvoice } from './processInvoice';
|
||||
// import { sendInvoiceEmail } from './sendInvoiceEmail';
|
||||
import { directGenerateInvoice } from './directInvoice';
|
||||
|
||||
export {
|
||||
getInvoiceUrl,
|
||||
// getInvoiceUrl,
|
||||
InvoiceService,
|
||||
processInvoice,
|
||||
sendInvoiceEmail,
|
||||
// processInvoice,
|
||||
// sendInvoiceEmail,
|
||||
directGenerateInvoice,
|
||||
};
|
||||
|
||||
@ -1,83 +1,83 @@
|
||||
import { onRequest } from "firebase-functions/v2/https";
|
||||
import { Request } from "firebase-functions/v2/https";
|
||||
import { getCorsHandler } from "../../../shared/middleware";
|
||||
import { getAdmin, getLogger } from "../../../shared/config";
|
||||
import { InvoiceService } from "./invoiceService";
|
||||
// import { onRequest } from "firebase-functions/v2/https";
|
||||
// import { Request } from "firebase-functions/v2/https";
|
||||
// import { getCorsHandler } from "../../../shared/middleware";
|
||||
// import { getAdmin, getLogger } from "../../../shared/config";
|
||||
// import { InvoiceService } from "./invoiceService";
|
||||
|
||||
const admin = getAdmin();
|
||||
const logger = getLogger();
|
||||
const corsHandler = getCorsHandler();
|
||||
const invoiceService = new InvoiceService();
|
||||
// const admin = getAdmin();
|
||||
// const logger = getLogger();
|
||||
// const corsHandler = getCorsHandler();
|
||||
// const invoiceService = new InvoiceService();
|
||||
|
||||
export const processInvoice = onRequest({
|
||||
region: '#{SERVICES_RGN}#'
|
||||
}, async (request: Request, response) => {
|
||||
return corsHandler(request, response, async () => {
|
||||
try {
|
||||
const authHeader = request.headers.authorization || '';
|
||||
if (!authHeader || !authHeader.startsWith('Bearer ')) {
|
||||
response.status(401).json({ error: 'Unauthorized' });
|
||||
return;
|
||||
}
|
||||
// export const processInvoice = onRequest({
|
||||
// region: '#{SERVICES_RGN}#'
|
||||
// }, async (request: Request, response) => {
|
||||
// return corsHandler(request, response, async () => {
|
||||
// try {
|
||||
// const authHeader = request.headers.authorization || '';
|
||||
// if (!authHeader || !authHeader.startsWith('Bearer ')) {
|
||||
// response.status(401).json({ error: 'Unauthorized' });
|
||||
// return;
|
||||
// }
|
||||
|
||||
const idToken = authHeader.split('Bearer ')[1];
|
||||
// const idToken = authHeader.split('Bearer ')[1];
|
||||
|
||||
try {
|
||||
await admin.auth().verifyIdToken(idToken);
|
||||
// try {
|
||||
// await admin.auth().verifyIdToken(idToken);
|
||||
|
||||
const {
|
||||
membershipId,
|
||||
paymentId,
|
||||
invoiceData,
|
||||
emailOptions
|
||||
} = request.body;
|
||||
// const {
|
||||
// membershipId,
|
||||
// paymentId,
|
||||
// invoiceData,
|
||||
// emailOptions
|
||||
// } = request.body;
|
||||
|
||||
if (!membershipId || !paymentId || !invoiceData) {
|
||||
response.status(400).json({
|
||||
success: false,
|
||||
error: 'Missing required fields'
|
||||
});
|
||||
return;
|
||||
}
|
||||
// if (!membershipId || !paymentId || !invoiceData) {
|
||||
// response.status(400).json({
|
||||
// success: false,
|
||||
// error: 'Missing required fields'
|
||||
// });
|
||||
// return;
|
||||
// }
|
||||
|
||||
const result = await invoiceService.processInvoice(
|
||||
membershipId,
|
||||
paymentId,
|
||||
invoiceData,
|
||||
emailOptions
|
||||
);
|
||||
// const result = await invoiceService.processInvoice(
|
||||
// membershipId,
|
||||
// paymentId,
|
||||
// invoiceData,
|
||||
// emailOptions
|
||||
// );
|
||||
|
||||
if (!result.success) {
|
||||
response.status(400).json({
|
||||
success: false,
|
||||
error: result.error || 'Failed to process invoice'
|
||||
});
|
||||
return;
|
||||
}
|
||||
// if (!result.success) {
|
||||
// response.status(400).json({
|
||||
// success: false,
|
||||
// error: result.error || 'Failed to process invoice'
|
||||
// });
|
||||
// return;
|
||||
// }
|
||||
|
||||
response.json({
|
||||
success: true,
|
||||
message: 'Invoice processed successfully',
|
||||
invoicePath: result.invoicePath,
|
||||
downloadUrl: result.downloadUrl,
|
||||
emailSent: result.emailSent
|
||||
});
|
||||
// response.json({
|
||||
// success: true,
|
||||
// message: 'Invoice processed successfully',
|
||||
// invoicePath: result.invoicePath,
|
||||
// downloadUrl: result.downloadUrl,
|
||||
// emailSent: result.emailSent
|
||||
// });
|
||||
|
||||
} catch (authError: any) {
|
||||
logger.error('Authentication error:', authError);
|
||||
response.status(401).json({
|
||||
success: false,
|
||||
error: 'Invalid authentication token',
|
||||
details: authError.message
|
||||
});
|
||||
}
|
||||
} catch (error: any) {
|
||||
logger.error('Error processing invoice:', error);
|
||||
response.status(500).json({
|
||||
success: false,
|
||||
error: 'Failed to process invoice',
|
||||
details: error.message
|
||||
});
|
||||
}
|
||||
});
|
||||
});
|
||||
// } catch (authError: any) {
|
||||
// logger.error('Authentication error:', authError);
|
||||
// response.status(401).json({
|
||||
// success: false,
|
||||
// error: 'Invalid authentication token',
|
||||
// details: authError.message
|
||||
// });
|
||||
// }
|
||||
// } catch (error: any) {
|
||||
// logger.error('Error processing invoice:', error);
|
||||
// response.status(500).json({
|
||||
// success: false,
|
||||
// error: 'Failed to process invoice',
|
||||
// details: error.message
|
||||
// });
|
||||
// }
|
||||
// });
|
||||
// });
|
||||
|
||||
@ -1,91 +1,91 @@
|
||||
import { onRequest } from "firebase-functions/v2/https";
|
||||
import { Request } from "firebase-functions/v2/https";
|
||||
import { getCorsHandler } from "../../../shared/middleware";
|
||||
import { getAdmin, getLogger } from "../../../shared/config";
|
||||
import { InvoiceService, EmailOptions } from "./invoiceService";
|
||||
// import { onRequest } from "firebase-functions/v2/https";
|
||||
// import { Request } from "firebase-functions/v2/https";
|
||||
// import { getCorsHandler } from "../../../shared/middleware";
|
||||
// import { getAdmin, getLogger } from "../../../shared/config";
|
||||
// import { InvoiceService, EmailOptions } from "./invoiceService";
|
||||
|
||||
const admin = getAdmin();
|
||||
const logger = getLogger();
|
||||
const corsHandler = getCorsHandler();
|
||||
const invoiceService = new InvoiceService();
|
||||
// const admin = getAdmin();
|
||||
// const logger = getLogger();
|
||||
// const corsHandler = getCorsHandler();
|
||||
// const invoiceService = new InvoiceService();
|
||||
|
||||
export const sendInvoiceEmail = onRequest({
|
||||
region: '#{SERVICES_RGN}#'
|
||||
}, async (request: Request, response) => {
|
||||
return corsHandler(request, response, async () => {
|
||||
try {
|
||||
const authHeader = request.headers.authorization || '';
|
||||
if (!authHeader || !authHeader.startsWith('Bearer ')) {
|
||||
response.status(401).json({ error: 'Unauthorized' });
|
||||
return;
|
||||
}
|
||||
// export const sendInvoiceEmail = onRequest({
|
||||
// region: '#{SERVICES_RGN}#'
|
||||
// }, async (request: Request, response) => {
|
||||
// return corsHandler(request, response, async () => {
|
||||
// try {
|
||||
// const authHeader = request.headers.authorization || '';
|
||||
// if (!authHeader || !authHeader.startsWith('Bearer ')) {
|
||||
// response.status(401).json({ error: 'Unauthorized' });
|
||||
// return;
|
||||
// }
|
||||
|
||||
const idToken = authHeader.split('Bearer ')[1];
|
||||
// const idToken = authHeader.split('Bearer ')[1];
|
||||
|
||||
try {
|
||||
await admin.auth().verifyIdToken(idToken);
|
||||
// try {
|
||||
// await admin.auth().verifyIdToken(idToken);
|
||||
|
||||
const {
|
||||
invoicePath,
|
||||
recipientEmail,
|
||||
recipientName,
|
||||
subject,
|
||||
customHtml,
|
||||
gymName,
|
||||
planName,
|
||||
amount,
|
||||
transactionId,
|
||||
paymentDate,
|
||||
paymentMethod
|
||||
} = request.body;
|
||||
// const {
|
||||
// invoicePath,
|
||||
// recipientEmail,
|
||||
// recipientName,
|
||||
// subject,
|
||||
// customHtml,
|
||||
// gymName,
|
||||
// planName,
|
||||
// amount,
|
||||
// transactionId,
|
||||
// paymentDate,
|
||||
// paymentMethod
|
||||
// } = request.body;
|
||||
|
||||
if (!invoicePath || !recipientEmail) {
|
||||
response.status(400).json({
|
||||
success: false,
|
||||
error: 'Missing required fields'
|
||||
});
|
||||
return;
|
||||
}
|
||||
// if (!invoicePath || !recipientEmail) {
|
||||
// response.status(400).json({
|
||||
// success: false,
|
||||
// error: 'Missing required fields'
|
||||
// });
|
||||
// return;
|
||||
// }
|
||||
|
||||
const emailOptions: EmailOptions = {
|
||||
recipientEmail,
|
||||
recipientName,
|
||||
subject,
|
||||
customHtml,
|
||||
additionalData: {
|
||||
gymName,
|
||||
planName,
|
||||
amount,
|
||||
transactionId,
|
||||
paymentDate: paymentDate ? new Date(paymentDate) : undefined,
|
||||
paymentMethod
|
||||
}
|
||||
};
|
||||
// const emailOptions: EmailOptions = {
|
||||
// recipientEmail,
|
||||
// recipientName,
|
||||
// subject,
|
||||
// customHtml,
|
||||
// additionalData: {
|
||||
// gymName,
|
||||
// planName,
|
||||
// amount,
|
||||
// transactionId,
|
||||
// paymentDate: paymentDate ? new Date(paymentDate) : undefined,
|
||||
// paymentMethod
|
||||
// }
|
||||
// };
|
||||
|
||||
const emailSent = await invoiceService.sendInvoiceEmail(invoicePath, emailOptions);
|
||||
const downloadUrl = await invoiceService.getInvoiceDownloadUrl(invoicePath);
|
||||
// const emailSent = await invoiceService.sendInvoiceEmail(invoicePath, emailOptions);
|
||||
// const downloadUrl = await invoiceService.getInvoiceDownloadUrl(invoicePath);
|
||||
|
||||
response.json({
|
||||
success: true,
|
||||
message: emailSent ? 'Invoice email sent successfully' : 'Failed to send email but URL generated',
|
||||
downloadUrl
|
||||
});
|
||||
// response.json({
|
||||
// success: true,
|
||||
// message: emailSent ? 'Invoice email sent successfully' : 'Failed to send email but URL generated',
|
||||
// downloadUrl
|
||||
// });
|
||||
|
||||
} catch (authError: any) {
|
||||
logger.error('Authentication error:', authError);
|
||||
response.status(401).json({
|
||||
success: false,
|
||||
error: 'Invalid authentication token',
|
||||
details: authError.message
|
||||
});
|
||||
}
|
||||
} catch (error: any) {
|
||||
logger.error('Error sending invoice email:', error);
|
||||
response.status(500).json({
|
||||
success: false,
|
||||
error: 'Failed to send invoice email',
|
||||
details: error.message
|
||||
});
|
||||
}
|
||||
});
|
||||
});
|
||||
// } catch (authError: any) {
|
||||
// logger.error('Authentication error:', authError);
|
||||
// response.status(401).json({
|
||||
// success: false,
|
||||
// error: 'Invalid authentication token',
|
||||
// details: authError.message
|
||||
// });
|
||||
// }
|
||||
// } catch (error: any) {
|
||||
// logger.error('Error sending invoice email:', error);
|
||||
// response.status(500).json({
|
||||
// success: false,
|
||||
// error: 'Failed to send invoice email',
|
||||
// details: error.message
|
||||
// });
|
||||
// }
|
||||
// });
|
||||
// });
|
||||
|
||||
@ -142,7 +142,7 @@ export const phonePeWebhook = onRequest({
|
||||
} else if (paymentId) {
|
||||
await processServicePayment(payload, orderData, paymentId);
|
||||
} 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}`);
|
||||
@ -639,6 +639,18 @@ async function processServicePayment(payload: any, orderData: any, paymentId: st
|
||||
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({
|
||||
status: 'ACCEPTED',
|
||||
paymentDetails: {
|
||||
@ -651,9 +663,8 @@ async function processServicePayment(payload: any, orderData: any, paymentId: st
|
||||
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;
|
||||
|
||||
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}`);
|
||||
|
||||
const discountPercentage = orderData.metaInfo?.discount || 0;
|
||||
@ -703,7 +714,7 @@ async function processServicePayment(payload: any, orderData: any, paymentId: st
|
||||
businessName: gymName,
|
||||
address: gymAddress,
|
||||
gstNumber: orderData.metaInfo?.gstNumber,
|
||||
customerName: orderData.metaInfo?.customerName || serviceData?.customerName || '',
|
||||
customerName: orderData.metaInfo?.customerName || serviceData?.normalizedName || '',
|
||||
phoneNumber: orderData.metaInfo?.customerPhone || serviceData?.phoneNumber || '',
|
||||
email: orderData.metaInfo?.customerEmail || serviceData?.email || '',
|
||||
planName: orderData.metaInfo?.serviceName || serviceData?.serviceName || 'Service',
|
||||
|
||||
Loading…
Reference in New Issue
Block a user