Changes in sending actual SMS via resolve-template endpoint
This commit is contained in:
parent
1e9947f88c
commit
2f9f469be8
|
|
@ -18,7 +18,9 @@ const axios = require('axios');
|
||||||
const MERCHANT_ID = () => process.env.MERCHANT_ID;
|
const MERCHANT_ID = () => process.env.MERCHANT_ID;
|
||||||
|
|
||||||
function normalizeScopeId(value) {
|
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) {
|
function getCompanyId(req) {
|
||||||
|
|
@ -102,6 +104,34 @@ async function findBusinessByApplicationId(merchantId, applicationId) {
|
||||||
return brandMatches[0] || null;
|
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'];
|
const PROVIDER_FIELDS = ['providerName', 'senderId', 'dltEntityId', 'authKey'];
|
||||||
|
|
||||||
function createHttpError(status, message, extra = {}) {
|
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) {
|
function getProviderPatch(input) {
|
||||||
if (!input || typeof input !== 'object') return null;
|
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));
|
console.log('[ResolveTemplate] Incoming payload:', JSON.stringify(req.body, null, 2));
|
||||||
|
|
||||||
const companyId = getCompanyId(req);
|
const companyId = getCompanyId(req);
|
||||||
const applicationId = getApplicationId(req);
|
const shipment = getShipmentPayload(req.body);
|
||||||
const event = normalizeText(req.body?.event);
|
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 (!companyId) return res.status(400).json({ error: 'companyId is required' });
|
||||||
if (!applicationId) return res.status(400).json({ error: 'applicationId is required' });
|
if (!shipment) return res.status(400).json({ error: 'payload.shipment is required' });
|
||||||
if (!event) return res.status(400).json({ error: 'event 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) {
|
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);
|
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' });
|
return res.status(404).json({ error: 'Whitelisted template not found' });
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const workflowResult = await sendResolveTemplateWorkflow({
|
||||||
|
template: tmpl.selectedTemplate,
|
||||||
|
toNumber,
|
||||||
|
sourcePayload: req.body,
|
||||||
|
});
|
||||||
|
|
||||||
res.json({
|
res.json({
|
||||||
success: true,
|
success: true,
|
||||||
companyId,
|
companyId,
|
||||||
applicationId,
|
businessId: business.businessId,
|
||||||
|
brandName,
|
||||||
event: eventSlug,
|
event: eventSlug,
|
||||||
templateId: normalizeText(tmpl.templateId),
|
templateId: normalizeText(tmpl.templateId),
|
||||||
template: tmpl.selectedTemplate,
|
template: tmpl.selectedTemplate,
|
||||||
|
toNumber,
|
||||||
|
workflowResult,
|
||||||
});
|
});
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
sendRouteError(res, err);
|
sendRouteError(res, err);
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue
Block a user