Changes in sending actual SMS via resolve-template endpoint

This commit is contained in:
Ritul Jadhav 2026-03-30 11:20:57 +05:30
parent 1e9947f88c
commit 2f9f469be8

View File

@ -18,7 +18,9 @@ const axios = require('axios');
const MERCHANT_ID = () => process.env.MERCHANT_ID;
function normalizeScopeId(value) {
return typeof value === 'string' ? value.trim() : '';
if (typeof value === 'string') return value.trim();
if (typeof value === 'number' && Number.isFinite(value)) return String(value);
return '';
}
function getCompanyId(req) {
@ -102,6 +104,34 @@ async function findBusinessByApplicationId(merchantId, applicationId) {
return brandMatches[0] || null;
}
async function findBusinessByBrandName(merchantId, brandName) {
const normalizedBrandName = normalizeText(brandName).toLowerCase();
if (!normalizedBrandName) return null;
const businesses = await getIndex(merchantId);
const brandMatches = businesses.filter((business) => normalizeText(business.brandName).toLowerCase() === normalizedBrandName);
if (brandMatches.length > 1) {
throw createHttpError(
409,
'Multiple businesses matched the provided brand name',
{
code: 'AMBIGUOUS_BUSINESS_MATCH',
details: {
companyId: merchantId,
brandName: normalizedBrandName,
matchedBusinesses: brandMatches.map((business) => ({
businessId: business.businessId,
brandName: business.brandName,
})),
},
}
);
}
return brandMatches[0] || null;
}
const PROVIDER_FIELDS = ['providerName', 'senderId', 'dltEntityId', 'authKey'];
function createHttpError(status, message, extra = {}) {
@ -152,6 +182,54 @@ function normalizeProvider(provider = {}, fallbackUpdatedAt = null) {
};
}
function getShipmentPayload(body) {
return body?.payload?.shipment && typeof body.payload.shipment === 'object'
? body.payload.shipment
: null;
}
function getShipmentBrandName(body) {
return normalizeText(body?.payload?.shipment?.bags?.[0]?.brand?.brand_name);
}
function getShipmentEventKey(body) {
return normalizeText(body?.payload?.shipment?.status);
}
function getShipmentToNumber(body) {
return normalizeText(body?.payload?.shipment?.user?.mobile);
}
async function sendResolveTemplateWorkflow({ template, toNumber, sourcePayload }) {
const workflowUrl = normalizeText(process.env.WORKFLOW_URL_RESOLVE_TEMPLATE);
if (!workflowUrl) {
throw createHttpError(500, 'WORKFLOW_URL_RESOLVE_TEMPLATE is not configured');
}
const response = await axios.post(
workflowUrl,
{ template, toNumber, sourcePayload },
{
timeout: 30000,
headers: { 'Content-Type': 'application/json' },
validateStatus: () => true,
}
);
if (response.status < 200 || response.status >= 300) {
throw createHttpError(
502,
`Resolve-template workflow failed with status ${response.status}`,
{ details: response.data }
);
}
return {
statusCode: response.status,
response: response.data,
};
}
function getProviderPatch(input) {
if (!input || typeof input !== 'object') return null;
@ -418,16 +496,20 @@ router.post('/resolve-template', async (req, res) => {
console.log('[ResolveTemplate] Incoming payload:', JSON.stringify(req.body, null, 2));
const companyId = getCompanyId(req);
const applicationId = getApplicationId(req);
const event = normalizeText(req.body?.event);
const shipment = getShipmentPayload(req.body);
const brandName = getShipmentBrandName(req.body);
const event = getShipmentEventKey(req.body);
const toNumber = getShipmentToNumber(req.body);
if (!companyId) return res.status(400).json({ error: 'companyId is required' });
if (!applicationId) return res.status(400).json({ error: 'applicationId is required' });
if (!event) return res.status(400).json({ error: 'event is required' });
if (!shipment) return res.status(400).json({ error: 'payload.shipment is required' });
if (!brandName) return res.status(400).json({ error: 'payload.shipment.bags[0].brand.brand_name is required' });
if (!event) return res.status(400).json({ error: 'payload.shipment.status is required' });
if (!toNumber) return res.status(400).json({ error: 'payload.shipment.user.mobile is required' });
const business = await findBusinessByApplicationId(companyId, applicationId);
const business = await findBusinessByBrandName(companyId, brandName);
if (!business) {
return res.status(404).json({ error: 'Business not found for applicationId' });
return res.status(404).json({ error: 'Business not found for brand name' });
}
const eventSlug = slugify(event);
@ -438,13 +520,22 @@ router.post('/resolve-template', async (req, res) => {
return res.status(404).json({ error: 'Whitelisted template not found' });
}
const workflowResult = await sendResolveTemplateWorkflow({
template: tmpl.selectedTemplate,
toNumber,
sourcePayload: req.body,
});
res.json({
success: true,
companyId,
applicationId,
businessId: business.businessId,
brandName,
event: eventSlug,
templateId: normalizeText(tmpl.templateId),
template: tmpl.selectedTemplate,
toNumber,
workflowResult,
});
} catch (err) {
sendRouteError(res, err);