From 8f63ee93f315098d7563de806277a89de20fdf0a Mon Sep 17 00:00:00 2001 From: praneeth-devrev Date: Wed, 15 May 2024 11:03:24 +0530 Subject: [PATCH] added email channel to csat example --- .../code/src/functions/common/constants.ts | 3 + 12-csat/code/src/functions/common/utils.ts | 165 +++++++++- .../code/src/functions/post_survey/index.ts | 292 +++++++++++------- .../src/functions/process_response/index.ts | 37 ++- 4 files changed, 375 insertions(+), 122 deletions(-) diff --git a/12-csat/code/src/functions/common/constants.ts b/12-csat/code/src/functions/common/constants.ts index 228747d..4b83e4e 100644 --- a/12-csat/code/src/functions/common/constants.ts +++ b/12-csat/code/src/functions/common/constants.ts @@ -19,6 +19,9 @@ export const SurveysSubmitAPIMethodPath = '/surveys.submit'; export const SurveysListAPIMethodPath = '/surveys.list'; export const SurveysSendAPIMethodPath = '/surveys.send'; +// Snap-kit Action +export const SnapKitActionCreateDeferredAPIMethodPath = '/snap-kit-action.create.deferred'; + export const EMAIL = 'email'; export const EmailSubject = 'Support experience feedback for '; export const PLUG = 'plug'; diff --git a/12-csat/code/src/functions/common/utils.ts b/12-csat/code/src/functions/common/utils.ts index 66d43ea..682de6f 100644 --- a/12-csat/code/src/functions/common/utils.ts +++ b/12-csat/code/src/functions/common/utils.ts @@ -8,9 +8,11 @@ import { WorksGetAPIMethodPath, } from './constants'; +export const SurveysEmailCsatResponsePath = '/survey-response'; const SnapKitActionID = 'rating'; const SnapInActionName = 'survey'; +export const dispatchIdAndRatingDeliminator = '::'; export async function doDevRevPostAPICall(apiBase: string, method: string, data: object, auth: string) { const url = apiBase + method; @@ -51,10 +53,10 @@ interface snapKitButtonJson { export function getSnapKitBody(objId: string, snap_in_id: string, survey_text_header: string, survey_text: string, surveyRespScale: string, visibility: string, members: string[], expires_at :string, - label: string) { + dispatchId: string, label: string) { let buttonsText = getButtonsText(surveyRespScale); - const buttons = generateButtonJson(buttonsText); + const buttons = generateButtonJson(buttonsText, dispatchId); let snapKitBody: { [key: string]: any } = {}; @@ -137,7 +139,7 @@ function getButtonsText(surveyRespScale: string) { return buttonsText; } -function generateButtonJson(buttonsText: string[]): snapKitButtonJson[] { +function generateButtonJson(buttonsText: string[], dispatchId: string): snapKitButtonJson[] { const result: snapKitButtonJson[] = []; const maxScale = 5; @@ -151,7 +153,7 @@ function generateButtonJson(buttonsText: string[]): snapKitButtonJson[] { type: 'plain_text', }, type: 'button', - value: (maxScale - i).toString(), + value: `${dispatchId}${dispatchIdAndRatingDeliminator}` + (maxScale - i).toString(), }); } @@ -205,6 +207,17 @@ export function getTimelineCommentBody(objId: string, bodyText :string, visibili return timelineBody; } +export function getEmailBody(subject: string, sender: string, recipients: string[], htmlBodyStr: string) { + return { + 'email': { + 'subject': subject, + 'body': htmlBodyStr, + 'recipients': recipients, + 'sender': sender, + }, + }; +} + export function getSnapKitActionCreateBody(baseObj: string, snapIn: string, channel: string, dispatchedTo: string ) { return { 'base_object': baseObj, @@ -223,6 +236,150 @@ export function getExpiryTimestamp(timeInMin : number) { return new Date(numberOfMlSeconds + addMlSeconds); } +// TODO: isTicket, ticketTitle, ticketDescription are the fields which are added for the tiket only. Ideally this is not scalable. But as +// currently there is no support for HTML given snap-kit this is stop gap solution. +export function getHtmlSurveyString(apiDomain:string, dispatchId: string, emailId: string, surveyTextHeader: string, + surveyText: string, surveyRespScale: string, isTicket: boolean, + ticketDisplayId: string, ticketTitle: string, ticketDescription: string): string { + + let buttonsText = getButtonsText(surveyRespScale); + + const apiPrefix = 'https://support.'; + const hoverText = 'Select this rating'; + + const rating1 = `${apiPrefix}${apiDomain}${SurveysEmailCsatResponsePath}?uuid=${dispatchId}&id=${SnapKitActionID}&value=${dispatchId}${dispatchIdAndRatingDeliminator}1`; + const rating2 = `${apiPrefix}${apiDomain}${SurveysEmailCsatResponsePath}?uuid=${dispatchId}&id=${SnapKitActionID}&value=${dispatchId}${dispatchIdAndRatingDeliminator}2`; + const rating3 = `${apiPrefix}${apiDomain}${SurveysEmailCsatResponsePath}?uuid=${dispatchId}&id=${SnapKitActionID}&value=${dispatchId}${dispatchIdAndRatingDeliminator}3`; + const rating4 = `${apiPrefix}${apiDomain}${SurveysEmailCsatResponsePath}?uuid=${dispatchId}&id=${SnapKitActionID}&value=${dispatchId}${dispatchIdAndRatingDeliminator}4`; + const rating5 = `${apiPrefix}${apiDomain}${SurveysEmailCsatResponsePath}?uuid=${dispatchId}&id=${SnapKitActionID}&value=${dispatchId}${dispatchIdAndRatingDeliminator}5`; + + return ` + + + + + + + + + + + + + +
+ + + + + + + + +
+

Your Feedback Matters!

+
image
+
+ + + + + + +
+

Hi,

+

${surveyTextHeader}

+
+
+
${ticketDisplayId}
+
${ticketTitle}
+
+
${ticketDescription}
+
+
+ + + + + + +
+

${surveyText}

+ + + + + + +
+ + + + + + +
${buttonsText[0]}
+ + + + + + +
${buttonsText[1]}
+ + + + + + +
${buttonsText[2]}
+ + + + + + +
${buttonsText[3]}
+ + + + + + +
${buttonsText[4]}
+
+
+ + + + + + +
+ + + + + + +
+

Your response will be recorded. We'll use it only for the purpose of improving our services!

+

This email was sent to ${emailId}. If you're not them, please ignore it.

+
+ + + + + + +
+
+ + + + `; +} + export async function getSurveyId(apiBase: string, auth: string, name: string) { try { console.log(`Listing surveys with name: [${name}]`); diff --git a/12-csat/code/src/functions/post_survey/index.ts b/12-csat/code/src/functions/post_survey/index.ts index a182bf3..fa4acf4 100644 --- a/12-csat/code/src/functions/post_survey/index.ts +++ b/12-csat/code/src/functions/post_survey/index.ts @@ -2,8 +2,11 @@ import { doDevRevPostAPICall, getAPIBase, getSnapKitBody, + getEmailBody, + getHtmlSurveyString, getTimelineCommentBody, getAPIDomain, + getSnapKitActionCreateBody, getExpiryTimestamp, getSurveyId, getWork, @@ -15,28 +18,31 @@ import { PLUG, PORTAL, CHAT, + EmailSubject, INTERNAL, PRIVATE, + SurveysSendAPIMethodPath, TimelineEntriesCreateAPIMethodPath, + SnapKitActionCreateDeferredAPIMethodPath, DefaultCSATName, TimelineLabelDisplayCustomerChat, } from '../common/constants'; - + interface Stakeholder { id?: string; email_id?: string; } - + const commentExpireAt2Min = getExpiryTimestamp(2).toISOString(); - - + + export class PostSurvey { constructor() {} - + async PostSurvey(event: any) { - console.log('Creating survey on event payload: ', JSON.stringify(event.payload)); - console.log('Event Context: ', JSON.stringify(event.context)); - try { + console.log('Creating survey on event payload: ', JSON.stringify(event.payload)); + console.log('Event Context: ', JSON.stringify(event.context)); + try { const payload = event.payload; const executionMetadata = event.execution_metadata; const apiBase = getAPIBase(executionMetadata); @@ -46,11 +52,11 @@ export class PostSurvey { let objId = ''; let objDisplayID = ''; let objType = ''; - + let isTicket = false; let ticketTitle = ''; let ticketDescription = ''; - + console.log('Event Context auth service account token: ', auth); // Global configuration values let surveyExpiresAfterInMin = parseInt(event.input_data.global_values.survey_expires_after); @@ -59,47 +65,47 @@ export class PostSurvey { const surveyRespScale = event.input_data.global_values.survey_resp_scale; const surveyChannels = event.input_data.global_values.survey_channel; let commandChannel = ''; - + if (surveyExpiresAfterInMin < 1) { - console.log(`Invalid survey expiry time: [${surveyExpiresAfterInMin}min]. Setting to default [1min]`); - surveyExpiresAfterInMin = 1; + console.log(`Invalid survey expiry time: [${surveyExpiresAfterInMin}min]. Setting to default [1min]`); + surveyExpiresAfterInMin = 1; } - + let surveyStakeholders : Stakeholder[] = []; - + // This condition means snap-in is triggered by command. if (payload.hasOwnProperty('command_id')) { - objId = payload.source_id; - - if (payload.parameters !== '') { + objId = payload.source_id; + + if (payload.parameters !== '') { let commandParams = getCommandParameters(payload.parameters); if (commandParams == null) { - let bodyMsgDev = `Unexpected request:\nExpected: chat/email survey question\nReceived: ${payload.parameters}.`; - let postBodyDev = getTimelineCommentBody(objId, bodyMsgDev, INTERNAL, null, commentExpireAt2Min, null); - try { + let bodyMsgDev = `Unexpected request:\nExpected: chat/email survey question\nReceived: ${payload.parameters}.`; + let postBodyDev = getTimelineCommentBody(objId, bodyMsgDev, INTERNAL, null, commentExpireAt2Min, null); + try { console.log('Posting invalid parameters comment on timeline for Dev Org'); const resp = await doDevRevPostAPICall(apiBase, TimelineEntriesCreateAPIMethodPath, postBodyDev, auth); if (resp.ok) { - console.log('Successfully added invalid parameters comment on timeline for Dev Org.'); + console.log('Successfully added invalid parameters comment on timeline for Dev Org.'); } else { - let body = await resp.text(); - console.error('Error while posting invalid parameters comment on timeline for Dev Org: ', resp.status, body); - return; + let body = await resp.text(); + console.error('Error while posting invalid parameters comment on timeline for Dev Org: ', resp.status, body); + return; } console.log('Invalid parameters comment sent successfully to timeline for Dev Org.'); - } catch (error) { + } catch (error) { console.error('Error: ', error); - } - return; + } + return; } commandChannel = commandParams[0].toLowerCase(); surveyText = commandParams[1]; - } - - if (objId.includes('ticket')) { + } + + if (objId.includes('ticket')) { const work = await getWork(apiBase, auth, objId); if (work == null) { - return; + return; } console.log(`ticket information for object ID: [${objId}] ,`, JSON.stringify(work)); objType = work.type; @@ -108,36 +114,36 @@ export class PostSurvey { isTicket = true; ticketTitle = work.title; ticketDescription = work.body; - } else { + } else { const conversation = await getConversation(apiBase, auth, objId); if (conversation == null) { - return; + return; } console.log(`conversation information for object ID: [${objId}] ,`, JSON.stringify(conversation)); objType = conversation.type; objDisplayID = conversation.display_id; surveyStakeholders = this.getStakeholders(conversation.members); - } + } } else { - let isTypeMatched = false; - if (payload.hasOwnProperty('conversation_updated')) { + let isTypeMatched = false; + if (payload.hasOwnProperty('conversation_updated')) { objType = 'conversation'; let conversation = payload.conversation_updated.conversation; let old_conversation = payload.conversation_updated.old_conversation; if (conversation.state != 'closed' || conversation.status != 'closed') { - console.log(`State: [${conversation.state}], Status: [${conversation.status}]. Conversation is not closed. returning...`); - return; + console.log(`State: [${conversation.state}], Status: [${conversation.status}]. Conversation is not closed. returning...`); + return; } if (conversation.state == 'closed' && conversation.status == 'closed' && - old_conversation.state == 'closed' && old_conversation.status == 'closed') { - console.log(`State: [${conversation.state}], Status: [${conversation.status}]. Conversation is already closed. returning...`); - return; + old_conversation.state == 'closed' && old_conversation.status == 'closed') { + console.log(`State: [${conversation.state}], Status: [${conversation.status}]. Conversation is already closed. returning...`); + return; } isTypeMatched = true; objId = conversation.id; objDisplayID = conversation.display_id; surveyStakeholders = this.getStakeholders(conversation.members); - } else if (payload.hasOwnProperty('work_updated')) { + } else if (payload.hasOwnProperty('work_updated')) { let work = payload.work_updated.work; let stage = work.stage.name; let state = work.state; @@ -145,19 +151,19 @@ export class PostSurvey { let old_stage = old_work.stage.name; let old_state = old_work.state; objType = 'ticket'; - + let type = work.type.toLowerCase(); if (type != 'ticket') { - console.log(`Work Type is [${type}]. Not a ticket. returning...`); - return; + console.log(`Work Type is [${type}]. Not a ticket. returning...`); + return; } if (stage != 'resolved' || state != 'closed') { - console.log(`Stage: [${stage}], State: [${state}]. Ticket is not resolved. returning...`); - return; + console.log(`Stage: [${stage}], State: [${state}]. Ticket is not resolved. returning...`); + return; } if (stage == 'resolved' && state == 'closed' && old_stage == 'resolved' && old_state == 'closed') { - console.log(`Stage: [${stage}], State: [${state}]. Ticket is already resolved. returning...`); - return; + console.log(`Stage: [${stage}], State: [${state}]. Ticket is already resolved. returning...`); + return; } isTypeMatched = true; objId = work.id; @@ -166,118 +172,182 @@ export class PostSurvey { isTicket = true; ticketTitle = work.title; ticketDescription = work.body; - } - - if (!isTypeMatched) { + } + + if (!isTypeMatched) { console.log('Event type is neither [conversation_updated] nor [work_updated]. returning...'); return; - } + } } - + const surveyId = await getSurveyId(apiBase, auth, DefaultCSATName); if (surveyId == null) { - console.log('SurveyId is null cannot proceed with processing. returning...'); - return; + console.log('SurveyId is null cannot proceed with processing. returning...'); + return; } - + console.log(`Posting survey on survey channels ${surveyChannels} with SurveyId [${surveyId}] for an Object [${objId}].`); let isSurveySent = false; for (let i = 0; i < surveyStakeholders.length; i++) { - // To track on which channels survey is actually sent. - let surveySentOnChannels : string[] = []; - for (let channel = 0; channel < surveyChannels.length; channel++) { + const deferredUUID = await this.getSnapInExecutionDeferredUUID(apiBase, auth, objId, snapInId, + surveyStakeholders[i].id!!); + // Just a conservative check in case this happens + if (deferredUUID === '') { + continue; + } + + // To track on which channels survey is actually sent. + let surveySentOnChannels : string[] = []; + for (let channel = 0; channel < surveyChannels.length; channel++) { let surveyChannel = surveyChannels[channel].toLowerCase(); - + if (payload.hasOwnProperty('command_id')) { - // In case of commands send survey only on channel described in command - if ( - ((surveyChannel === PLUG || surveyChannel === PORTAL) && commandChannel !== CHAT) - ) { + // In case of commands send survey only on channel described in command + if ( + ((surveyChannel === PLUG || surveyChannel === PORTAL) && commandChannel !== CHAT) || + (surveyChannel === EMAIL && commandChannel !== EMAIL) + ) { console.log(`Survey is not sent on command as config channel: [${surveyChannel}] and command channel: [${commandChannel}].`); continue; - } + } } - + switch (surveyChannel) { - case PLUG: - case PORTAL: { + case EMAIL: { + if (surveyStakeholders[i].email_id !== undefined) { + console.log(`Posting survey on survey channel [${surveyChannel}].`); + await this.sendEmail(apiBase, auth, deferredUUID, surveyStakeholders[i].email_id!, + objDisplayID, surveyTextHeader, surveyText, surveyRespScale, isTicket, ticketTitle, + ticketDescription); + surveySentOnChannels.push(surveyChannel); + } + break; + } + case PLUG: + case PORTAL: { console.log(`Posting survey on survey channel [${surveyChannel}].`); const expiresAt = getExpiryTimestamp(surveyExpiresAfterInMin); const snapKitBody = getSnapKitBody(objId, snapInId, surveyTextHeader, - surveyText, surveyRespScale, PRIVATE, [surveyStakeholders[i].id!], expiresAt.toISOString(), TimelineLabelDisplayCustomerChat); + surveyText, surveyRespScale, PRIVATE, [surveyStakeholders[i].id!], expiresAt.toISOString(), + deferredUUID, TimelineLabelDisplayCustomerChat); const resp = await doDevRevPostAPICall(apiBase, TimelineEntriesCreateAPIMethodPath, snapKitBody, auth); if (resp.ok) { - console.log(`Successfully posted message on [${objId}] for User [${surveyStakeholders[i].id!}]`); - surveySentOnChannels.push(surveyChannel); + console.log(`Successfully posted message on [${objId}] for User [${surveyStakeholders[i].id!}]`); + surveySentOnChannels.push(surveyChannel); } else { - let body = await resp.text(); - console.error(`Error while posting message on [${objId}] for User [${surveyStakeholders[i].id!}] `, resp.status, body); + let body = await resp.text(); + console.error(`Error while posting message on [${objId}] for User [${surveyStakeholders[i].id!}] `, resp.status, body); } break; - } + } } - } - - if (surveySentOnChannels.length > 0) { + } + + if (surveySentOnChannels.length > 0) { isSurveySent = true; - } + } } - + if (isSurveySent) { - let bodyMsgDev = `Customer feedback has been requested for this ${objType}.`; - const expiresAt = getExpiryTimestamp(surveyExpiresAfterInMin); - let postBodyDev = getTimelineCommentBody(objId, bodyMsgDev, INTERNAL, null, expiresAt.toISOString(), TimelineLabelDisplayCustomerChat); - try { + let bodyMsgDev = `Customer feedback has been requested for this ${objType}.`; + const expiresAt = getExpiryTimestamp(surveyExpiresAfterInMin); + let postBodyDev = getTimelineCommentBody(objId, bodyMsgDev, INTERNAL, null, expiresAt.toISOString(), TimelineLabelDisplayCustomerChat); + try { console.log('Posting survey sent message on timeline for Dev Org'); const resp = await doDevRevPostAPICall(apiBase, TimelineEntriesCreateAPIMethodPath, postBodyDev, auth); if (resp.ok) { - console.log('Successfully added survey sent message on timeline for Dev Org.'); + console.log('Successfully added survey sent message on timeline for Dev Org.'); } else { - let body = await resp.text(); - console.error('Error while posting survey sent message on timeline for Dev Org: ', resp.status, body); - return; + let body = await resp.text(); + console.error('Error while posting survey sent message on timeline for Dev Org: ', resp.status, body); + return; } console.log('Survey sent message successfully to timeline for Dev Org.'); - } catch (error) { + } catch (error) { console.error('Error: ', error); - } + } } - } catch (error) { + } catch (error) { console.error('Error: ', error); - } + } + } + + async getSnapInExecutionDeferredUUID(apiBase: string, auth: string, objID: string, snapInID: string, stakeholderID: string) { + const actionReqBody = getSnapKitActionCreateBody(objID, snapInID, 'App', stakeholderID); + const actionResp = await doDevRevPostAPICall(apiBase, SnapKitActionCreateDeferredAPIMethodPath, actionReqBody, auth); + if (actionResp.ok) { + console.log(`Successfully created deferred UUID for User [${stakeholderID}].`); + let respJsonBody = await actionResp.json(); + if (respJsonBody.hasOwnProperty('execution')) { + let execution = respJsonBody.execution; + if (execution.hasOwnProperty('id')) { + console.log(`Deferred UUID for User [${stakeholderID}] is UUID [${execution.id}]`); + return execution.id; + } else { + console.error(`Missing "ID" in snap-kit-execution-create-deferred response [${respJsonBody}]`); + } + } else { + console.error(`Missing "Execution" in snap-kit-execution-create-deferred response [${respJsonBody}]`); + } + } else { + let body = await actionResp.text(); + console.error(`Error while creating snap-kit-execution-create-deferred for User [${stakeholderID}] , Response: [${body}]`); + } + return ''; + } + + async sendEmail(apiBase: string, auth: string, deferredUUID: string, emailId: string, objDisplayID: string, + surveyTextHeader: string, surveyText: string, surveyRespScale: string, + isTicket: boolean, ticketTitle: string, ticketDescription: string) { + const apiDomain = getAPIDomain(apiBase); + const htmlString = getHtmlSurveyString(apiDomain, deferredUUID, emailId, surveyTextHeader, surveyText, + surveyRespScale, isTicket, objDisplayID, ticketTitle, ticketDescription); + const emailSender = `Support Experience `; + + const htmlBody = getEmailBody(`${EmailSubject} ${objDisplayID}`, emailSender, [emailId], htmlString); + if (htmlBody == null) { + return; + } + const resp = await doDevRevPostAPICall(apiBase, SurveysSendAPIMethodPath, htmlBody, auth); + if (resp.ok) { + console.log(`Successfully sent an email to User [${emailId}]`); + } else { + let body = await resp.text(); + console.error(`Error while sending an email to User [${emailId}] `, resp.status, body); + } } - + getStakeholders(stakeholdersFromObj: any[]): Stakeholder[] { - console.log('stakeholders from object: ', JSON.stringify(stakeholdersFromObj)); - let stakeholders : Stakeholder[] = []; - for (let i = 0; i < stakeholdersFromObj.length; i++) { + console.log('stakeholders from object: ', JSON.stringify(stakeholdersFromObj)); + let stakeholders : Stakeholder[] = []; + for (let i = 0; i < stakeholdersFromObj.length; i++) { console.log('stakeholders: ', JSON.stringify(stakeholdersFromObj[i])); const stakeholder : Stakeholder = {}; if (stakeholdersFromObj[i].type == 'rev_user') { - stakeholder.id = stakeholdersFromObj[i].id; - if (stakeholdersFromObj[i].hasOwnProperty('email')) { + stakeholder.id = stakeholdersFromObj[i].id; + if (stakeholdersFromObj[i].hasOwnProperty('email')) { stakeholder.email_id = stakeholdersFromObj[i].email; - } + } } stakeholders.push(stakeholder); - } - console.log('stakeholders after filtering: ', JSON.stringify(stakeholders)); - return stakeholders; + } + console.log('stakeholders after filtering: ', JSON.stringify(stakeholders)); + return stakeholders; } - - + + } - + export const run = async (events: any[]) => { - + console.log('Running SnapIn for survey - post_survey', events); - + const postSurvey = new PostSurvey(); for (let event of events) { - await postSurvey.PostSurvey(event); + await postSurvey.PostSurvey(event); } - + console.info('events', events); }; - + export default run; \ No newline at end of file diff --git a/12-csat/code/src/functions/process_response/index.ts b/12-csat/code/src/functions/process_response/index.ts index 9a79041..e68ece8 100644 --- a/12-csat/code/src/functions/process_response/index.ts +++ b/12-csat/code/src/functions/process_response/index.ts @@ -1,9 +1,9 @@ import { - doDevRevGetAPICall, doDevRevPostAPICall, getAPIBase, getSurveyId, getTimelineCommentBody, getExpiryTimestamp, + dispatchIdAndRatingDeliminator, } from '../common/utils'; import { @@ -11,7 +11,7 @@ import { TimelineEntriesCreateAPIMethodPath, TimelineEntriesDeleteAPIMethodPath, SurveysSubmitAPIMethodPath, - RevUsersGetAPIMethodPath, TimelineLabelDisplayCustomerChat, + TimelineLabelDisplayCustomerChat, } from '../common/constants'; @@ -24,13 +24,23 @@ async function ProcessSurveyResponse(event: any) { const auth = event.context.secrets.service_account_token; const actorAuth = event.context.secrets.actor_session_token; const actorId = payload.actor_id; - const rating = parseInt(payload.action.value); + const dispatchIdAndRating = splitDispatchIdAndRating(payload.action.value); + let dispatchId = ''; + let rating = 0; let privateToRev = [actorId]; const surveyRespText = event.input_data.global_values.survey_resp_text; let sourceChannel = getSourceChannel(payload); // Currently hardcoded with 30minutes const commentExpireAt = getExpiryTimestamp(30).toISOString(); + if (dispatchIdAndRating) { + [dispatchId, rating] = dispatchIdAndRating; + + } else { + console.log('Invalid dispatch ID and Rating. returning...'); + return; + } + let parentObjId = ''; if (payload.context.hasOwnProperty('parent_core_object_id')) { parentObjId = payload.context.parent_core_object_id; @@ -47,7 +57,7 @@ async function ProcessSurveyResponse(event: any) { console.log(`SurveyId: [${surveyId}]`); // STEP-1 Submit survey for database storage. - const postBodyForSurveyResp = getSurveyResponseBody(surveyId, parentObjId, rating, sourceChannel); + const postBodyForSurveyResp = getSurveyResponseBody(surveyId, parentObjId, rating, dispatchId, sourceChannel); try { console.log('Posting survey response chosen by user to database.'); const resp = await doDevRevPostAPICall(apiBase, SurveysSubmitAPIMethodPath, postBodyForSurveyResp, actorAuth); @@ -138,7 +148,6 @@ async function ProcessSurveyResponse(event: any) { } // STEP-4 Add response score provide by user on timeline for Devs. - // const donv1RevUser = await donv2ActorToDonv1Actor(apiBase, auth, actorId); console.log(`Annotating Rev-User : [${actorId}] `); let bodyMsgDev = `\<${actorId}\> CSAT rating: ${rating}.`; let postBodyDev = getTimelineCommentBody(parentObjId, bodyMsgDev, INTERNAL, null, commentExpireAt, null); @@ -164,8 +173,8 @@ function getDeleteTimelineEntryBody(entryId: string) { }; } -function getSurveyResponseBody(surveyId: string, objId: string, rating: number, sourceChannel: string) { - console.log(`SurveyId: [${surveyId}], ObjectId: [${objId}], Rating: [${rating}]`); +function getSurveyResponseBody(surveyId: string, objId: string, rating: number, dispatchId: string, sourceChannel: string) { + console.log(`SurveyId: [${surveyId}], ObjectId: [${objId}], Rating: [${rating}], DispatchId: [${dispatchId}]`); let respBody: { [key: string]: any } = {}; @@ -175,11 +184,25 @@ function getSurveyResponseBody(surveyId: string, objId: string, rating: number, 'rating': rating, }; respBody.response_score = rating; + respBody.dispatch_id = dispatchId; respBody.source_channel = sourceChannel; return respBody; } +function splitDispatchIdAndRating(input: string): [string, number] | null { + const tokens = input.split(dispatchIdAndRatingDeliminator); + //case when only rating is present (for backward compatibility) + if (tokens.length === 1) { + return ['', parseInt(tokens[0])]; + } + //case when dispatch id and rating is present + if (tokens.length === 2) { + return [tokens[0], parseInt(tokens[1])]; + } + return null; +} + function getSourceChannel(payload: any) { let sourceChannel = EMAIL; if (payload.context.hasOwnProperty('parent_core_object_id')) {