2019-11-06 22:06:19 -08:00
import {
IExecuteSingleFunctions ,
} from 'n8n-core' ;
import {
IDataObject ,
INodeTypeDescription ,
INodeExecutionData ,
INodeType ,
ILoadOptionsFunctions ,
INodePropertyOptions ,
} from 'n8n-workflow' ;
import {
2019-11-08 07:41:10 -08:00
freshdeskApiRequest ,
validateJSON ,
capitalize
2019-11-06 22:06:19 -08:00
} from './GenericFunctions' ;
enum Status {
Open = 1 ,
Pending = 2 ,
Resolved = 3 ,
Closed = 4
}
enum Priority {
Low = 1 ,
Medium = 2 ,
High = 3 ,
Urgent = 4
}
2019-11-07 10:07:29 -08:00
enum Source {
Email = 1 ,
Portal = 2 ,
Phone = 3 ,
Chat = 4 ,
Mobihelp = 5 ,
FeedbackWidget = 6 ,
2019-11-08 07:41:10 -08:00
OutboundEmail = 7
2019-11-07 10:07:29 -08:00
}
2019-11-06 22:06:19 -08:00
interface ICreateTicketBody {
name? : string ;
requester_id? : number ;
email? : string ;
facebook_id? : string ;
phone? : string ;
twitter_id? : string ;
2019-11-07 10:07:29 -08:00
unique_external_id? : string ;
2019-11-08 07:41:10 -08:00
subject? : string | null ;
2019-11-07 10:07:29 -08:00
type ? : string ;
status : Status ;
priority : Priority ;
description? : string ;
responder_id? : number ;
2019-11-06 22:06:19 -08:00
cc_emails ? : [ string ] ;
custom_fields? : IDataObject ;
due_by? : string ;
email_config_id? : number ;
fr_due_by? : string ;
group_id? : number ;
product_id? : number ;
2019-11-07 10:07:29 -08:00
source : Source ;
2019-11-08 07:41:10 -08:00
tags ? : [ string ] ;
company_id? : number ;
2019-11-06 22:06:19 -08:00
}
export class Freshdesk implements INodeType {
description : INodeTypeDescription = {
displayName : 'Freshdesk' ,
name : 'freshdesk' ,
icon : 'file:freshdesk.png' ,
group : [ 'output' ] ,
version : 1 ,
subtitle : '={{$parameter["operation"] + ": " + $parameter["resource"]}}' ,
description : 'Consume Freshdesk API' ,
defaults : {
name : 'Freshdesk' ,
color : '#c02428' ,
} ,
inputs : [ 'main' ] ,
outputs : [ 'main' ] ,
credentials : [
{
name : 'freshdeskApi' ,
required : true ,
}
] ,
properties : [
{
displayName : 'Resource' ,
name : 'resource' ,
type : 'options' ,
required : true ,
options : [
{
name : 'Ticket' ,
value : 'ticket' ,
} ,
] ,
default : 'ticket' ,
description : 'The resource to operate on.' ,
} ,
{
displayName : 'Operation' ,
name : 'operation' ,
type : 'options' ,
required : true ,
displayOptions : {
show : {
resource : [
'ticket' ,
]
} ,
} ,
options : [
{
name : 'Create' ,
value : 'create' ,
description : 'Create a new ticket' ,
}
] ,
default : 'create' ,
description : 'The operation to perform.' ,
} ,
{
displayName : 'Requester Identification' ,
name : 'requester' ,
type : 'options' ,
required : true ,
displayOptions : {
show : {
resource : [
'ticket' ,
] ,
operation : [
'create'
]
} ,
} ,
options : [
{
name : 'Requester Id' ,
value : 'requesterId' ,
description : ` User ID of the requester. For existing contacts, the requester_id can be passed instead of the requester's email. ` ,
} ,
{
name : 'Email' ,
value : 'email' ,
description : ` Email address of the requester. If no contact exists with this email address in Freshdesk, it will be added as a new contact. ` ,
} ,
{
name : 'Facebook Id' ,
value : 'facebookId' ,
description : ` Facebook ID of the requester. If no contact exists with this facebook_id, then a new contact will be created. ` ,
} ,
{
name : 'Phone' ,
value : 'phone' ,
description : ` Phone number of the requester. If no contact exists with this phone number in Freshdesk, it will be added as a new contact. If the phone number is set and the email address is not, then the name attribute is mandatory. ` ,
} ,
{
name : 'Twitter Id' ,
value : 'twitterId' ,
description : ` Twitter handle of the requester. If no contact exists with this handle in Freshdesk, it will be added as a new contact. ` ,
} ,
{
name : 'Unique External Id' ,
value : 'uniqueExternalId' ,
description : ` External ID of the requester. If no contact exists with this external ID in Freshdesk, they will be added as a new contact. ` ,
} ,
] ,
default : 'requesterId' ,
description : 'Requester Identification' ,
} ,
{
displayName : 'Value' ,
name : 'requesterIdentificationValue' ,
type : 'string' ,
required : true ,
displayOptions : {
show : {
resource : [
'ticket' ,
] ,
operation : [
'create'
]
} ,
} ,
default : '' ,
description : ` Value of the identification selected ` ,
} ,
{
displayName : 'Status' ,
name : 'status' ,
type : 'options' ,
required : true ,
displayOptions : {
show : {
resource : [
'ticket' ,
] ,
operation : [
'create'
]
} ,
} ,
options : [
{
name : 'Open' ,
value : 'open' ,
} ,
{
name : 'Pending' ,
value : 'pending' ,
} ,
{
name : 'Resolved' ,
value : 'resolved' ,
} ,
{
name : 'Closed' ,
value : 'closed' ,
}
] ,
default : 'pending' ,
description : 'Status' ,
} ,
{
displayName : 'Priority' ,
name : 'priority' ,
type : 'options' ,
required : true ,
displayOptions : {
show : {
resource : [
'ticket' ,
] ,
operation : [
'create'
]
} ,
} ,
options : [
{
name : 'Low' ,
value : 'low' ,
} ,
{
name : 'Medium' ,
value : 'medium' ,
} ,
{
name : 'High' ,
value : 'high' ,
} ,
{
name : 'Urgent' ,
value : 'urgent' ,
}
] ,
default : 'low' ,
description : 'Priority' ,
} ,
2019-11-07 10:07:29 -08:00
{
displayName : 'Source' ,
name : 'source' ,
type : 'options' ,
required : true ,
displayOptions : {
show : {
resource : [
'ticket' ,
] ,
operation : [
'create'
]
} ,
} ,
options : [
{
name : 'Email' ,
value : 'email' ,
} ,
{
name : 'Portal' ,
value : 'portal' ,
} ,
{
name : 'Phone' ,
value : 'phone' ,
} ,
{
name : 'Chat' ,
value : 'chat' ,
} ,
{
name : 'Mobihelp' ,
value : 'mobileHelp' ,
} ,
{
name : 'Feedback Widget' ,
value : 'feedbackWidget' ,
} ,
{
name : 'Outbound Email' ,
value : 'OutboundEmail' ,
}
] ,
default : 'portal' ,
description : 'The channel through which the ticket was created.' ,
} ,
2019-11-08 07:41:10 -08:00
// {
// displayName: 'JSON Parameters',
// name: 'jsonParameters',
// type: 'boolean',
// default: false,
// description: '',
// displayOptions: {
// show: {
// resource: [
// 'ticket'
// ],
// operation: [
// 'create',
// ]
// },
// },
// },
2019-11-06 22:06:19 -08:00
{
displayName : 'Options' ,
name : 'options' ,
type : 'collection' ,
placeholder : 'Add Option' ,
default : { } ,
displayOptions : {
show : {
resource : [
'ticket'
] ,
operation : [
'create'
] ,
} ,
} ,
options : [
{
displayName : 'Name' ,
name : 'name' ,
type : 'string' ,
default : '' ,
placeholder : '' ,
description : 'Name of the requester' ,
} ,
{
displayName : 'Subject' ,
name : 'subject' ,
type : 'string' ,
default : '' ,
placeholder : '' ,
description : 'Subject of the ticket.' ,
} ,
{
displayName : 'Type' ,
name : 'type' ,
2019-11-08 07:41:10 -08:00
type : 'options' ,
default : 'Question' ,
2019-11-06 22:06:19 -08:00
description : 'Helps categorize the ticket according to the different kinds of issues your support team deals with.' ,
2019-11-08 07:41:10 -08:00
options : [
{
name : 'Question' ,
value : 'Question'
} ,
{
name : 'Incident' ,
value : 'Incident'
} ,
{
name : 'Problem' ,
value : 'Problem'
} ,
{
name : 'Feature Request' ,
value : 'Feature Request'
} ,
{
name : 'Refund' ,
value : 'Refund'
} ,
]
2019-11-06 22:06:19 -08:00
} ,
{
displayName : 'Description' ,
name : 'description' ,
type : 'string' ,
2019-11-07 10:07:29 -08:00
required : false ,
2019-11-06 22:06:19 -08:00
default : '' ,
typeOptions : {
rows : 5 ,
alwaysOpenEditWindow : true ,
} ,
description : 'HTML content of the ticket.' ,
} ,
{
displayName : 'Agent' ,
name : 'agent' ,
type : 'options' ,
2019-11-07 10:07:29 -08:00
required : false ,
2019-11-06 22:06:19 -08:00
default : '' ,
typeOptions : {
loadOptionsMethod : 'getAgents'
} ,
description : 'ID of the agent to whom the ticket has been assigned' ,
} ,
{
displayName : 'CC Emails' ,
name : 'ccEmails' ,
2019-11-07 10:07:29 -08:00
required : false ,
2019-11-06 22:06:19 -08:00
type : 'string' ,
default : '' ,
description : ` separated by , email addresses added in the 'cc' field of the incoming ticket email ` ,
} ,
2019-11-07 10:07:29 -08:00
{
displayName : 'Tags' ,
name : 'tags' ,
required : false ,
type : 'string' ,
default : '' ,
description : ` separated by , tags that have been associated with the ticket ` ,
} ,
{
displayName : 'Due By' ,
name : 'dueBy' ,
required : false ,
type : 'dateTime' ,
default : '' ,
description : ` Timestamp that denotes when the ticket is due to be resolved ` ,
} ,
{
displayName : 'Email config Id' ,
name : 'emailConfigId' ,
type : 'number' ,
required : false ,
default : '' ,
description : ` ID of email config which is used for this ticket. (i.e., support@yourcompany.com/sales@yourcompany.com)
If product_id is given and email_config_id is not given , product ' s primary email_config_id will be set ` ,
} ,
{
displayName : 'FR Due By' ,
name : 'frDueBy' ,
2019-11-08 07:41:10 -08:00
type : 'dateTime' ,
2019-11-07 10:07:29 -08:00
required : false ,
default : '' ,
description : ` Timestamp that denotes when the first response is due ` ,
} ,
{
displayName : 'Group' ,
name : 'group' ,
required : false ,
type : 'options' ,
default : '' ,
typeOptions : {
loadOptionsMethod : 'getGroups'
} ,
description : ` ID of the group to which the ticket has been assigned. The default value is the ID of the group that is associated with the given email_config_id ` ,
} ,
{
displayName : 'Product' ,
name : 'product' ,
required : false ,
type : 'options' ,
default : '' ,
typeOptions : {
loadOptionsMethod : 'getProducts'
} ,
description : ` ID of the product to which the ticket is associated.
It will be ignored if the email_config_id attribute is set in the request . ` ,
} ,
{
displayName : 'Company' ,
name : 'company' ,
required : false ,
type : 'options' ,
default : '' ,
typeOptions : {
loadOptionsMethod : 'getCompanies'
} ,
description : ` Company ID of the requester. This attribute can only be set if the Multiple Companies feature is enabled (Estate plan and above) ` ,
} ,
2019-11-06 22:06:19 -08:00
]
} ,
2019-11-08 07:41:10 -08:00
// {
// displayName: 'Custom Fields',
// name: 'customFieldsUi',
// placeholder: 'Add Custom fields',
// type: 'fixedCollection',
// required: false,
// default: '',
// typeOptions: {
// multipleValues: true,
// },
// displayOptions: {
// show: {
// resource: [
// 'ticket'
// ],
// operation: [
// 'create'
// ],
// jsonParameters: [
// false,
// ],
// },
// },
// description: 'Key value pairs containing the names and values of custom fields.',
// options: [
// {
// name: 'customFieldsValues',
// displayName: 'Custom fields',
// values: [
// {
// displayName: 'Key',
// required: false,
// name: 'key',
// type: 'string',
// default: '',
// },
// {
// displayName: 'Value',
// name: 'value',
// type: 'string',
// required: false,
// default: '',
// },
// ],
// },
// ],
// },
// {
// displayName: 'Custom Fields',
// name: 'customFieldsJson',
// type: 'json',
// typeOptions: {
// alwaysOpenEditWindow: true,
// },
// displayOptions: {
// show: {
// resource: [
// 'ticket'
// ],
// operation: [
// 'create'
// ],
// jsonParameters: [
// true,
// ],
// },
// },
// default: '',
// required: false,
// placeholder: `{
// "gadget":"Cold Welder"
// }`,
// description: 'Key value pairs containing the names and values of custom fields.',
// },
2019-11-06 22:06:19 -08:00
]
} ;
methods = {
loadOptions : {
// Get all the agents to display them to user so that he can
// select them easily
async getAgents ( this : ILoadOptionsFunctions ) : Promise < INodePropertyOptions [ ] > {
const returnData : INodePropertyOptions [ ] = [ ] ;
let agents ;
try {
agents = await freshdeskApiRequest . call ( this , '/agents' , 'GET' ) ;
} catch ( err ) {
2019-11-07 10:07:29 -08:00
throw new Error ( ` Freshdesk Error: ${ err } ` ) ;
2019-11-06 22:06:19 -08:00
}
for ( const agent of agents ) {
const agentName = agent . contact . name ;
const agentId = agent . id ;
returnData . push ( {
name : agentName ,
value : agentId ,
} ) ;
}
2019-11-07 10:07:29 -08:00
return returnData ;
} ,
2019-11-06 22:06:19 -08:00
2019-11-07 10:07:29 -08:00
// Get all the groups to display them to user so that he can
// select them easily
async getGroups ( this : ILoadOptionsFunctions ) : Promise < INodePropertyOptions [ ] > {
const returnData : INodePropertyOptions [ ] = [ ] ;
let groups ;
try {
groups = await freshdeskApiRequest . call ( this , '/groups' , 'GET' ) ;
} catch ( err ) {
throw new Error ( ` Freshdesk Error: ${ err } ` ) ;
}
for ( const group of groups ) {
const groupName = group . name ;
const groupId = group . id ;
returnData . push ( {
name : groupName ,
value : groupId ,
} ) ;
}
2019-11-06 22:06:19 -08:00
return returnData ;
2019-11-07 10:07:29 -08:00
} ,
// Get all the products to display them to user so that he can
// select them easily
async getProducts ( this : ILoadOptionsFunctions ) : Promise < INodePropertyOptions [ ] > {
const returnData : INodePropertyOptions [ ] = [ ] ;
let products ;
try {
products = await freshdeskApiRequest . call ( this , '/products' , 'GET' ) ;
} catch ( err ) {
throw new Error ( ` Freshdesk Error: ${ err } ` ) ;
}
for ( const product of products ) {
const productName = product . name ;
const productId = product . id ;
returnData . push ( {
name : productName ,
value : productId ,
} ) ;
}
return returnData ;
} ,
// Get all the companies to display them to user so that he can
// select them easily
async getCompanies ( this : ILoadOptionsFunctions ) : Promise < INodePropertyOptions [ ] > {
const returnData : INodePropertyOptions [ ] = [ ] ;
let companies ;
try {
companies = await freshdeskApiRequest . call ( this , '/companies' , 'GET' ) ;
} catch ( err ) {
throw new Error ( ` Freshdesk Error: ${ err } ` ) ;
}
for ( const company of companies ) {
const companyName = company . name ;
const companyId = company . id ;
returnData . push ( {
name : companyName ,
value : companyId ,
} ) ;
}
return returnData ;
} ,
2019-11-06 22:06:19 -08:00
} ,
} ;
async executeSingle ( this : IExecuteSingleFunctions ) : Promise < INodeExecutionData > {
2019-11-08 07:41:10 -08:00
const resource = this . getNodeParameter ( 'resource' ) as string ;
const opeation = this . getNodeParameter ( 'operation' ) as string ;
let response ;
if ( resource === 'ticket' ) {
if ( opeation === 'create' ) {
const requester = this . getNodeParameter ( 'requester' ) as string ;
const value = this . getNodeParameter ( 'requesterIdentificationValue' ) as string ;
const status = this . getNodeParameter ( 'status' ) as string ;
const priority = this . getNodeParameter ( 'priority' ) as string ;
const source = this . getNodeParameter ( 'source' ) as string ;
const options = this . getNodeParameter ( 'options' ) as IDataObject ;
//const jsonActive = this.getNodeParameter('jsonParameters') as boolean;
const body : ICreateTicketBody = {
// @ts-ignore
status : Status [ capitalize ( status ) ] ,
// @ts-ignore
priority : Priority [ capitalize ( priority ) ] ,
// @ts-ignore
source : Source [ capitalize ( source ) ]
} ;
if ( requester === 'requesterId' ) {
// @ts-ignore
if ( isNaN ( value ) ) {
throw new Error ( 'Requester Id must be a number' ) ;
}
body . requester_id = parseInt ( value , 10 ) ;
} else if ( requester === 'email' ) {
body . email = value ;
} else if ( requester === 'facebookId' ) {
body . facebook_id = value ;
} else if ( requester === 'phone' ) {
body . phone = value ;
} else if ( requester === 'twitterId' ) {
body . twitter_id = value ;
} else if ( requester === 'uniqueExternalId' ) {
body . unique_external_id = value ;
}
// if (!jsonActive) {
// const customFieldsUi = this.getNodeParameter('customFieldsUi') as IDataObject;
// if (Object.keys(customFieldsUi).length > 0) {
// const aux: IDataObject = {};
// // @ts-ignore
// customFieldsUi.customFieldsValues.forEach( o => {
// aux[`${o.key}`] = o.value;
// return aux;
// });
// body.custom_fields = aux;
// } else {
// body.custom_fields = validateJSON(this.getNodeParameter('customFielsJson') as string);
// }
if ( options . name ) {
body . name = options . name as string ;
}
if ( options . subject ) {
body . subject = options . subject as string ;
} else {
body . subject = 'null' ;
}
if ( options . type ) {
body . type = options . type as string ;
}
if ( options . description ) {
body . description = options . description as string ;
} else {
body . description = 'null' ;
}
if ( options . agent ) {
options . responder_id = options . agent as number ;
}
if ( options . company ) {
options . company_id = options . company as number ;
}
if ( options . product ) {
options . product_id = options . product as number ;
}
if ( options . group ) {
options . group_id = options . group as number ;
}
if ( options . frDueBy ) {
options . fr_due_by = options . frDueBy as string ;
}
if ( options . emailConfigId ) {
options . email_config_id = options . emailConfigId as number ;
}
if ( options . dueBy ) {
options . due_by = options . dueBy as string ;
}
if ( options . ccEmails ) {
// @ts-ignore
options . cc_emails = options . ccEmails . split ( ',' ) as [ string ] ;
}
try {
response = await freshdeskApiRequest . call ( this , '/tickets' , 'POST' , body ) ;
} catch ( err ) {
throw new Error ( ` Freskdesk Error: ${ JSON . stringify ( err ) } ` ) ;
}
}
}
2019-11-06 22:06:19 -08:00
return {
2019-11-08 07:41:10 -08:00
json : response
2019-11-07 10:07:29 -08:00
} ;
2019-11-06 22:06:19 -08:00
}
}