diff --git a/lambdas/account-scoped/src/scheduled-jobs/create-schedule.ts b/lambdas/account-scoped/src/scheduled-jobs/create-schedule.ts index f028316ad6..891f1e3763 100644 --- a/lambdas/account-scoped/src/scheduled-jobs/create-schedule.ts +++ b/lambdas/account-scoped/src/scheduled-jobs/create-schedule.ts @@ -18,10 +18,14 @@ import { ScheduledJobType } from '@tech-matters/scheduled-jobs/dist/scheduled-jo import { AccountScopedHandler, HttpError } from '../httpTypes'; import { newErr, newOk, Result } from '@tech-matters/result-type'; import { createScheduledJob, isValidVoicemailTask } from '@tech-matters/scheduled-jobs'; -import { addHours } from 'date-fns/addHours'; +import { addMinutes } from 'date-fns/addMinutes'; +import { retrieveServiceConfigurationAttributes } from '../configuration/aseloConfiguration'; +import { getTwilioClient } from '@tech-matters/twilio-configuration'; const supportedJobType: ScheduledJobType['jobType'][] = ['create-voicemail-schedule']; +const DEFAULT_MINUTES_VOICEMAIL_SCHEDULE = 1440; // 24 hours + export const handleCreateScheduleJob: AccountScopedHandler = async ( request, accountSid, @@ -39,7 +43,7 @@ export const handleCreateScheduleJob: AccountScopedHandler = async ( } if (jobType === 'create-voicemail-schedule') { - const { voicemailTask } = request.body; + const voicemailTask = { ...(request.body.voicemailTask ?? {}), accountSid }; if (!isValidVoicemailTask(voicemailTask)) { return newErr({ @@ -48,6 +52,10 @@ export const handleCreateScheduleJob: AccountScopedHandler = async ( }); } + // eslint-disable-next-line @typescript-eslint/naming-convention + const { voicemail_schedule_retry_later_minutes } = + await retrieveServiceConfigurationAttributes(await getTwilioClient(accountSid)); + const scheduleName = `${jobType}-${voicemailTask.attributes.callSid}`; const { workflowSid, @@ -56,7 +64,7 @@ export const handleCreateScheduleJob: AccountScopedHandler = async ( from, name, routingAttributes, - callbackAttemptsMade, + callbackAttempts, maxCallbackAttempts, }, } = voicemailTask; @@ -65,7 +73,7 @@ export const handleCreateScheduleJob: AccountScopedHandler = async ( voicemailTask: { accountSid, attributes: { - callbackAttemptsMade, + callbackAttempts, from, callSid, routingAttributes, @@ -75,7 +83,12 @@ export const handleCreateScheduleJob: AccountScopedHandler = async ( workflowSid, }, }; - const scheduleExpression = `at(${addHours(Date.now(), 24).toISOString().slice(0, 19)})`; // 24 hours later + const scheduleExpression = `at(${addMinutes( + Date.now(), + voicemail_schedule_retry_later_minutes ?? DEFAULT_MINUTES_VOICEMAIL_SCHEDULE, + ) + .toISOString() + .slice(0, 19)})`; await createScheduledJob({ scheduledJob, diff --git a/lambdas/account-scoped/src/voicemail/recordingCompleteCallback.ts b/lambdas/account-scoped/src/voicemail/recordingCompleteCallback.ts index 9d02b3e835..59729db4bd 100644 --- a/lambdas/account-scoped/src/voicemail/recordingCompleteCallback.ts +++ b/lambdas/account-scoped/src/voicemail/recordingCompleteCallback.ts @@ -77,7 +77,7 @@ export const recordingCompleteCallback: AccountScopedHandler = async ( accountSid, routingAttributes: body.routingAttributes ? JSON.parse(body.routingAttributes) : {}, receivedTime: receivedTime.toISOString(), - callbackAttemptsMade: 0, + callbackAttempts: [], maxCallbackAttempts: maxCallbackAttempts, callSid, from, diff --git a/lambdas/account-scoped/tests/unit/voicemail/recordingCompleteCallback.test.ts b/lambdas/account-scoped/tests/unit/voicemail/recordingCompleteCallback.test.ts index 849905d004..a780229353 100644 --- a/lambdas/account-scoped/tests/unit/voicemail/recordingCompleteCallback.test.ts +++ b/lambdas/account-scoped/tests/unit/voicemail/recordingCompleteCallback.test.ts @@ -130,7 +130,7 @@ describe('recordingCompleteCallback', () => { callSid: TEST_CALL_SID, channelType: channelTypes.VOICEMAIL, customChannelType: channelTypes.VOICEMAIL, - callbackAttemptsMade: 0, + callbackAttempts: [], maxCallbackAttempts: 3, receivedTime: RECORDING_START_TIME.toISOString(), }); diff --git a/lambdas/packages/hrm-form-definitions/form-definitions/as/v1/CallTypeButtons.json b/lambdas/packages/hrm-form-definitions/form-definitions/as/v1/CallTypeButtons.json index d3a5ce2130..fa9e8d6a12 100644 --- a/lambdas/packages/hrm-form-definitions/form-definitions/as/v1/CallTypeButtons.json +++ b/lambdas/packages/hrm-form-definitions/form-definitions/as/v1/CallTypeButtons.json @@ -1,50 +1,56 @@ [ - { - "name": "child", - "label": "Child calling about self", - "type": "button", - "category": "data" - }, - { - "name": "caller", - "label": "Someone calling about a child", - "type": "button", - "category": "data" - }, - { - "name": "silent", - "label": "Silent", - "type": "button", - "category": "non-data" - }, - { - "name": "hangup", - "label": "Hang up", - "type": "button", - "category": "non-data" - }, - { - "name": "abusive", - "label": "Abusive", - "type": "button", - "category": "non-data" - }, - { - "name": "thanks", - "label": "Thank you", - "type": "button", - "category": "non-data" - }, - { - "name": "questions", - "label": "Questions", - "type": "button", - "category": "non-data" - }, - { - "name": "emergency", - "label": "Emergency", - "type": "button", - "category": "non-data" - } + { + "name": "child", + "label": "Child calling about self", + "type": "button", + "category": "data" + }, + { + "name": "caller", + "label": "Someone calling about a child", + "type": "button", + "category": "data" + }, + { + "name": "silent", + "label": "Silent", + "type": "button", + "category": "non-data" + }, + { + "name": "hangup", + "label": "Hang up", + "type": "button", + "category": "non-data" + }, + { + "name": "abusive", + "label": "Abusive", + "type": "button", + "category": "non-data" + }, + { + "name": "thanks", + "label": "Thank you", + "type": "button", + "category": "non-data" + }, + { + "name": "questions", + "label": "Questions", + "type": "button", + "category": "non-data" + }, + { + "name": "emergency", + "label": "Emergency", + "type": "button", + "category": "non-data" + }, + { + "name": "voicemail", + "label": "Complete Voicemail", + "type": "button", + "category": "non-data" + } ] diff --git a/lambdas/packages/hrm-form-definitions/form-definitions/clhs/v1/customStrings/Substitutions.json b/lambdas/packages/hrm-form-definitions/form-definitions/clhs/v1/customStrings/Substitutions.json index f6ec295e91..31b0a5d883 100644 --- a/lambdas/packages/hrm-form-definitions/form-definitions/clhs/v1/customStrings/Substitutions.json +++ b/lambdas/packages/hrm-form-definitions/form-definitions/clhs/v1/customStrings/Substitutions.json @@ -135,7 +135,7 @@ "BottomBar-CancelNewCaseAndClose": "Sí, Cancelar el Nueva ECUPHS y Cierre", "BottomBar-AddThisContactToExistingCase": "Agregar esta Conversación a ECUPHS existente", "ResumeContactButtonText": "Reanudar la Conversación Fuera de Línea", - "CallType-CloseContact": "Cerrar Conversación", + "CallType-SaveDialog-CloseContact": "Cerrar Conversación", "ConnectDialog-Caller": "¿Copiar información del llamante de este registro a un nueva conversación?", "ContactDetails-GeneralDetails-ContactSummary": "Resumen de Conversación", "ContactDetails-UnsavedContact": "Conversación no guardada", diff --git a/lambdas/packages/hrm-form-definitions/form-definitions/nz/v1/customStrings/Substitutions.json b/lambdas/packages/hrm-form-definitions/form-definitions/nz/v1/customStrings/Substitutions.json index 55ac333968..835739a076 100644 --- a/lambdas/packages/hrm-form-definitions/form-definitions/nz/v1/customStrings/Substitutions.json +++ b/lambdas/packages/hrm-form-definitions/form-definitions/nz/v1/customStrings/Substitutions.json @@ -246,7 +246,7 @@ "CallType-blank": "Blank", "CallType-caller": "Someone contacting about a person of concern ", "CallType-child": "Person contacting about self", - "CallType-CloseContact": "Close Contact", + "CallType-SaveDialog-CloseContact": "Close Contact", "CallType-hangup": "Hang up", "CallType-joke": "Joke", "CallType-silent": "Silent", diff --git a/lambdas/packages/hrm-form-definitions/form-definitions/sg/v1/customStrings/Substitutions.json b/lambdas/packages/hrm-form-definitions/form-definitions/sg/v1/customStrings/Substitutions.json index f5484a37ca..f00f723a0a 100644 --- a/lambdas/packages/hrm-form-definitions/form-definitions/sg/v1/customStrings/Substitutions.json +++ b/lambdas/packages/hrm-form-definitions/form-definitions/sg/v1/customStrings/Substitutions.json @@ -53,7 +53,7 @@ "SearchResultsIndex-ViewContacts": "View Interactions", "SearchResultsIndex-NonDataContacts": "Non-Data Interactions", "SearchForm-Counselor": "Tinkle Friend", - "CallType-CloseContact": "Close Interaction", + "CallType-SaveDialog-CloseContact": "Close Interaction", "CallTypeButtons-Categorize": "categorize this interaction", "CallTypeButtons-Or": "Or was this interaction…", "ConnectDialog-Child": "Copy client information from this record to new interaction?", diff --git a/lambdas/packages/hrm-form-definitions/form-definitions/uscr/v1/customStrings/Substitutions.json b/lambdas/packages/hrm-form-definitions/form-definitions/uscr/v1/customStrings/Substitutions.json index 2896517353..810ed3ee68 100644 --- a/lambdas/packages/hrm-form-definitions/form-definitions/uscr/v1/customStrings/Substitutions.json +++ b/lambdas/packages/hrm-form-definitions/form-definitions/uscr/v1/customStrings/Substitutions.json @@ -21,7 +21,7 @@ "CallType-hangup": "Hang up", "CallType-wrongnumber": "Wrong Number", "CallType-abusive": "Abusive", - "CallType-CloseContact": "Close Event", + "CallType-SaveDialog-CloseContact": "Close Event", "CallTypeButtons-Categorize": "categorize this event", "CallTypeButtons-Or": "Or was this event…", "ConnectDialog-Child": "Copy person information from this record to new event?", diff --git a/lambdas/packages/hrm-form-definitions/form-definitions/usnc/v1/customStrings/Substitutions.json b/lambdas/packages/hrm-form-definitions/form-definitions/usnc/v1/customStrings/Substitutions.json index e33ca8dfdb..00851bf10f 100644 --- a/lambdas/packages/hrm-form-definitions/form-definitions/usnc/v1/customStrings/Substitutions.json +++ b/lambdas/packages/hrm-form-definitions/form-definitions/usnc/v1/customStrings/Substitutions.json @@ -22,7 +22,7 @@ "CallType-hangup": "Hang up", "CallType-wrongnumber": "Wrong Number", "CallType-abusive": "Abusive", - "CallType-CloseContact": "Close Contact", + "CallType-SaveDialog-CloseContact": "Close Contact", "CallTypeButtons-Categorize": "categorize this contact", "CallTypeButtons-Or": "Or was this contact…", "ConnectDialog-Child": "Copy support seeker information from this record to new contact?", @@ -500,7 +500,6 @@ "BottomBar-SaveOnClose": "Save Changes?", "BottomBar-DontSave": "No, Don't Save", "BottomBar-Save": "Yes, Save", - "Toolkit-ConfirmTextOne": "You will be redirected to an external knowledge management system.", "Toolkit-ConfirmTextTwo": "Are you sure you want to continue?", "MaskIdentifiers": "XXXXXX", "UnmaskPhoneNumber": "Phone Number Revealed", diff --git a/lambdas/packages/hrm-form-definitions/form-definitions/usnm/v1/customStrings/Substitutions.json b/lambdas/packages/hrm-form-definitions/form-definitions/usnm/v1/customStrings/Substitutions.json index 0a7e494bc7..383516d4f6 100644 --- a/lambdas/packages/hrm-form-definitions/form-definitions/usnm/v1/customStrings/Substitutions.json +++ b/lambdas/packages/hrm-form-definitions/form-definitions/usnm/v1/customStrings/Substitutions.json @@ -7,7 +7,7 @@ "CallSummary-Counselor": "Specialist: ", "CallType-child": "Help Seeker calling about self", "CallType-caller": "Someone calling about a help seeker", - "CallType-CloseContact": "Close Connection", + "CallType-SaveDialog-CloseContact": "Close Connection", "CallTypeButtons-Categorize": "categorize this connection", "CallTypeButtons-Or": "Or was this connection…", "ConnectDialog-Child": "Copy help seeker information from this record to new connection?", diff --git a/lambdas/packages/scheduled-jobs/src/scheduled-job.ts b/lambdas/packages/scheduled-jobs/src/scheduled-job.ts index 44961c7b80..2fb56ae118 100644 --- a/lambdas/packages/scheduled-jobs/src/scheduled-job.ts +++ b/lambdas/packages/scheduled-jobs/src/scheduled-job.ts @@ -23,40 +23,66 @@ export type CreateVoicemailSchedule = { callSid: string; from: string; name: string; - callbackAttemptsMade: number; + callbackAttempts: [string, string][]; maxCallbackAttempts?: number; routingAttributes?: Record; }; workflowSid: string; }; }; + export const isValidVoicemailTask = ( task: any, ): task is CreateVoicemailSchedule['voicemailTask'] => { - if (!task || typeof task !== 'object') return false; - if (!task.accountSid || typeof task.accountSid !== 'string') return false; - if (!task.workflowSid || typeof task.workflowSid !== 'string') return false; - if (!task.attributes || typeof task.attributes !== 'object') return false; - if (!task.attributes || typeof task.attributes !== 'object') return false; - if (!task.attributes.callSid || typeof task.attributes.callSid !== 'string') + if (!task || typeof task !== 'object') { + console.debug('isValidVoicemailTask: invalid task'); + return false; + } + if (!task.accountSid || typeof task.accountSid !== 'string') { + console.debug('isValidVoicemailTask: invalid task.accountSid'); + return false; + } + if (!task.workflowSid || typeof task.workflowSid !== 'string') { + console.debug('isValidVoicemailTask: invalid task.workflowSid'); + return false; + } + if (!task.attributes || typeof task.attributes !== 'object') { + console.debug('isValidVoicemailTask: invalid task.attributes'); + return false; + } + if (!task.attributes.callSid || typeof task.attributes.callSid !== 'string') { + console.debug('isValidVoicemailTask: invalid task.attributes.callSid'); + return false; + } + if (!task.attributes.from || typeof task.attributes.from !== 'string') { + console.debug('isValidVoicemailTask: invalid task.attributes.from'); + return false; + } + if (!task.attributes.name || typeof task.attributes.name !== 'string') { + console.debug('isValidVoicemailTask: invalid task.attributes.name'); return false; - if (!task.attributes.from || typeof task.attributes.from !== 'string') return false; - if (!task.attributes.name || typeof task.attributes.name !== 'string') return false; + } if ( - !task.attributes.callbackAttemptsMade || - typeof task.attributes.callbackAttemptsMade !== 'number' - ) + !task.attributes.callbackAttempts || + !Array.isArray(task.attributes.callbackAttempts) + ) { + console.debug('isValidVoicemailTask: invalid task.attributes.callbackAttempts'); return false; + } if ( task.attributes.maxCallbackAttempts && typeof task.attributes.maxCallbackAttempts !== 'number' - ) + ) { + console.debug('isValidVoicemailTask: invalid task.attributes.maxCallbackAttempts'); return false; + } if ( - task.attributes.routingAttributes || + task.attributes.routingAttributes && typeof task.attributes.routingAttributes !== 'object' - ) + ) { + console.debug('isValidVoicemailTask: invalid task.attributes.routingAttributes'); return false; + } return true; }; diff --git a/lambdas/packages/voicemail/src/createVoicemailTask.ts b/lambdas/packages/voicemail/src/createVoicemailTask.ts index 04964b1ab3..7b4ae4a094 100644 --- a/lambdas/packages/voicemail/src/createVoicemailTask.ts +++ b/lambdas/packages/voicemail/src/createVoicemailTask.ts @@ -23,7 +23,7 @@ export const DEFAULT_MAX_CALLBACK_ATTEMPTS = 3; export const createVoicemailTask = async ({ accountSid, workflowSid, - callbackAttemptsMade, + callbackAttempts, receivedTime, from, name, @@ -33,7 +33,7 @@ export const createVoicemailTask = async ({ }: { accountSid: AccountSID; receivedTime: string; - callbackAttemptsMade: number; + callbackAttempts: [string, string][]; maxCallbackAttempts?: number; callSid: string; from: string; @@ -52,7 +52,7 @@ export const createVoicemailTask = async ({ isVoicemail: true, routingAttributes: routingAttributes ?? {}, receivedTime, - callbackAttemptsMade, + callbackAttempts, maxCallbackAttempts: maxCallbackAttempts ?? DEFAULT_MAX_CALLBACK_ATTEMPTS, callSid, from, diff --git a/lambdas/scheduled-jobs-processor/src/index.ts b/lambdas/scheduled-jobs-processor/src/index.ts index c4840d180a..39a4388f52 100644 --- a/lambdas/scheduled-jobs-processor/src/index.ts +++ b/lambdas/scheduled-jobs-processor/src/index.ts @@ -31,7 +31,7 @@ const handleCreateVoicemailJob = async ({ callSid: attributes.callSid, from: attributes.from, receivedTime: new Date().toISOString(), - callbackAttemptsMade: attributes.callbackAttemptsMade, + callbackAttempts: attributes.callbackAttempts, workflowSid, }); diff --git a/plugin-hrm-form/src/HrmFormPlugin.tsx b/plugin-hrm-form/src/HrmFormPlugin.tsx index 4f239aa9fc..46319cc8c1 100644 --- a/plugin-hrm-form/src/HrmFormPlugin.tsx +++ b/plugin-hrm-form/src/HrmFormPlugin.tsx @@ -99,6 +99,7 @@ const setUpComponents = (featureFlags: FeatureFlags, setupObject: ReturnType ({ const mockStore = configureMockStore([]); -const task = { +let task = { sid: 'reservation-task-sid', taskSid: 'task-sid', attributes: {}, @@ -72,6 +71,14 @@ const themeConf = { const withEndCall =