diff --git a/packages/nodes-base/nodes/AgileCrm/AgileCrm.node.ts b/packages/nodes-base/nodes/AgileCrm/AgileCrm.node.ts index 4fecdcd94d..c1417a8e07 100644 --- a/packages/nodes-base/nodes/AgileCrm/AgileCrm.node.ts +++ b/packages/nodes-base/nodes/AgileCrm/AgileCrm.node.ts @@ -10,6 +10,12 @@ import { contactOperations, contactFields } from './ContactDescription'; + +import { + companyOperations, + companyFields +} from './CompanyDescription'; + import { agileCrmApiRequest, validateJSON, agileCrmApiRequestUpdate} from './GenericFunctions'; import { IContact, IProperty, IContactUpdate } from './ContactInterface'; @@ -45,7 +51,11 @@ export class AgileCrm implements INodeType { { name: 'Contact', value: 'contact' - } + }, + { + name: 'Company', + value: 'company' + }, ], default: 'contact', description: 'Resource to consume.', @@ -53,6 +63,10 @@ export class AgileCrm implements INodeType { // CONTACT ...contactOperations, ...contactFields, + + // COMPANY + ...companyOperations, + ...companyFields ], }; @@ -70,10 +84,11 @@ export class AgileCrm implements INodeType { for (let i = 0; i < length; i++) { - if(resource === 'contact'){ + if(resource === 'contact' || resource === 'company'){ + let idGetter = resource === 'contact' ? 'contactId' : 'companyId'; if(operation === 'get'){ - const contactId = this.getNodeParameter('contactId', i) as string; + const contactId = this.getNodeParameter(idGetter, i) as string; const endpoint = `api/contacts/${contactId}`; responseData = await agileCrmApiRequest.call(this, 'GET', endpoint, {}); @@ -81,7 +96,7 @@ export class AgileCrm implements INodeType { } if(operation === 'delete'){ - const contactId = this.getNodeParameter('contactId', i) as string; + const contactId = this.getNodeParameter(idGetter, i) as string; const endpoint = `api/contacts/${contactId}`; responseData = await agileCrmApiRequest.call(this, 'DELETE', endpoint, {}); @@ -91,14 +106,26 @@ export class AgileCrm implements INodeType { if(operation === 'getAll'){ const returnAll = this.getNodeParameter('returnAll', i) as boolean; - if (returnAll) { - const endpoint = `api/contacts`; - responseData = await agileCrmApiRequest.call(this, 'GET', endpoint, {}); + if(resource === 'contact'){ + if (returnAll) { + const endpoint = `api/contacts`; + responseData = await agileCrmApiRequest.call(this, 'GET', endpoint, {}); + } else { + const limit = this.getNodeParameter('limit', i) as number; + const endpoint = `api/contacts?page_size=${limit}`; + responseData = await agileCrmApiRequest.call(this, 'GET', endpoint, {}); + } } else { - const limit = this.getNodeParameter('limit', i) as number; - const endpoint = `api/contacts?page_size=${limit}`; - responseData = await agileCrmApiRequest.call(this, 'GET', endpoint, {}); + if (returnAll) { + const endpoint = `api/contacts/companies/list`; + responseData = await agileCrmApiRequest.call(this, 'POST', endpoint, {}); + } else { + const limit = this.getNodeParameter('limit', i) as number; + const endpoint = `api/contacts/companies/list?page_size=${limit}`; + responseData = await agileCrmApiRequest.call(this, 'POST', endpoint, {}); + } } + } if(operation === 'create'){ @@ -124,6 +151,10 @@ export class AgileCrm implements INodeType { const additionalFields = this.getNodeParameter('additionalFields', i) as IDataObject; + // if company, add 'company' as type. default is person + if(resource === 'company'){ + body.type = 'COMPANY'; + } if (additionalFields.starValue) { body.star_value = additionalFields.starValue as string; } @@ -133,56 +164,98 @@ export class AgileCrm implements INodeType { if (additionalFields.tags) { body.tags = additionalFields.tags as string[]; } - if(additionalFields.firstName){ - properties.push({ - type: 'SYSTEM', - name: 'first_name', - value: additionalFields.firstName as string - } as IDataObject); - } - if(additionalFields.lastName){ - properties.push({ - type: 'SYSTEM', - name: 'last_name', - value: additionalFields.lastName as string - } as IDataObject); - } - if(additionalFields.company){ - properties.push({ - type: 'SYSTEM', - name: 'company', - value: additionalFields.company as string - } as IDataObject); - } - if(additionalFields.title){ - properties.push({ - type: 'SYSTEM', - name: 'title', - value: additionalFields.title as string - } as IDataObject); - } - if(additionalFields.emailOptions){ - //@ts-ignore - additionalFields.emailOptions.emailProperties.map(property => { + + // Contact specific properties + if(resource === 'contact'){ + if(additionalFields.firstName){ + properties.push({ + type: 'SYSTEM', + name: 'first_name', + value: additionalFields.firstName as string + } as IDataObject); + } + if(additionalFields.lastName){ + properties.push({ + type: 'SYSTEM', + name: 'last_name', + value: additionalFields.lastName as string + } as IDataObject); + } + if(additionalFields.company){ + properties.push({ + type: 'SYSTEM', + name: 'company', + value: additionalFields.company as string + } as IDataObject); + } + if(additionalFields.title){ + properties.push({ + type: 'SYSTEM', + name: 'title', + value: additionalFields.title as string + } as IDataObject); + } + if(additionalFields.emailOptions){ + //@ts-ignore + additionalFields.emailOptions.emailProperties.map(property => { + properties.push({ + type: 'SYSTEM', + subtype: property.subtype as string, + name: 'email', + value: property.email as string + } as IDataObject); + }) + } + if(additionalFields.addressOptions){ + //@ts-ignore + additionalFields.addressOptions.addressProperties.map(property => { + properties.push({ + type: 'SYSTEM', + subtype: property.subtype as string, + name: 'address', + value: property.address as string + } as IDataObject); + }) + } + + if(additionalFields.phoneOptions){ + //@ts-ignore + additionalFields.phoneOptions.phoneProperties.map(property => { + properties.push({ + type: 'SYSTEM', + subtype: property.subtype as string, + name: 'phone', + value: property.number as string + } as IDataObject); + }) + } + } else if (resource === 'company') { + if(additionalFields.email){ properties.push({ type: 'SYSTEM', - subtype: property.subtype as string, name: 'email', - value: property.email as string + value: additionalFields.email as string } as IDataObject); - }) - } - if(additionalFields.addressOptions){ - //@ts-ignore - additionalFields.addressOptions.addressProperties.map(property => { + } + + if(additionalFields.address){ properties.push({ type: 'SYSTEM', - subtype: property.subtype as string, name: 'address', - value: property.address as string + value: additionalFields.address as string } as IDataObject); - }) + } + + if(additionalFields.phone){ + properties.push({ + type: 'SYSTEM', + name: 'phone', + value: additionalFields.phone as string + } as IDataObject); + } + } + if(additionalFields.websiteOptions){ //@ts-ignore additionalFields.websiteOptions.websiteProperties.map(property => { @@ -194,17 +267,7 @@ export class AgileCrm implements INodeType { } as IDataObject); }) } - if(additionalFields.phoneOptions){ - //@ts-ignore - additionalFields.phoneOptions.phoneProperties.map(property => { - properties.push({ - type: 'SYSTEM', - subtype: property.subtype as string, - name: 'phone', - value: property.number as string - } as IDataObject); - }) - } + if(additionalFields.customProperties){ //@ts-ignore additionalFields.customProperties.customProperty.map(property => { @@ -223,8 +286,8 @@ export class AgileCrm implements INodeType { responseData = await agileCrmApiRequest.call(this, 'POST', endpoint, body); } - if(operation === "update") { - const contactId = this.getNodeParameter('contactId', i) as string; + if(operation === 'update') { + const contactId = this.getNodeParameter(idGetter, i) as string; let contactUpdatePayload : IContactUpdate = {id: contactId}; const jsonParameters = this.getNodeParameter('jsonParameters', i) as boolean; const body: IContact = {}; @@ -255,56 +318,98 @@ export class AgileCrm implements INodeType { if (additionalFields.tags) { body.tags = additionalFields.tags as string[]; } - if(additionalFields.firstName){ - properties.push({ - type: 'SYSTEM', - name: 'first_name', - value: additionalFields.firstName as string - } as IDataObject); - } - if(additionalFields.lastName){ - properties.push({ - type: 'SYSTEM', - name: 'last_name', - value: additionalFields.lastName as string - } as IDataObject); - } - if(additionalFields.company){ - properties.push({ - type: 'SYSTEM', - name: 'company', - value: additionalFields.company as string - } as IDataObject); - } - if(additionalFields.title){ - properties.push({ - type: 'SYSTEM', - name: 'title', - value: additionalFields.title as string - } as IDataObject); - } - if(additionalFields.emailOptions){ - //@ts-ignore - additionalFields.emailOptions.emailProperties.map(property => { + + // Contact specific properties + if(resource === 'contact'){ + if(additionalFields.firstName){ + properties.push({ + type: 'SYSTEM', + name: 'first_name', + value: additionalFields.firstName as string + } as IDataObject); + } + if(additionalFields.lastName){ + properties.push({ + type: 'SYSTEM', + name: 'last_name', + value: additionalFields.lastName as string + } as IDataObject); + } + if(additionalFields.company){ + properties.push({ + type: 'SYSTEM', + name: 'company', + value: additionalFields.company as string + } as IDataObject); + } + if(additionalFields.title){ + properties.push({ + type: 'SYSTEM', + name: 'title', + value: additionalFields.title as string + } as IDataObject); + } + if(additionalFields.emailOptions){ + //@ts-ignore + additionalFields.emailOptions.emailProperties.map(property => { + properties.push({ + type: 'SYSTEM', + subtype: property.subtype as string, + name: 'email', + value: property.email as string + } as IDataObject); + }) + } + if(additionalFields.addressOptions){ + //@ts-ignore + additionalFields.addressOptions.addressProperties.map(property => { + properties.push({ + type: 'SYSTEM', + subtype: property.subtype as string, + name: 'address', + value: property.address as string + } as IDataObject); + }) + } + + if(additionalFields.phoneOptions){ + //@ts-ignore + additionalFields.phoneOptions.phoneProperties.map(property => { + properties.push({ + type: 'SYSTEM', + subtype: property.subtype as string, + name: 'phone', + value: property.number as string + } as IDataObject); + }) + } + } else if (resource === 'company') { + if(additionalFields.email){ properties.push({ type: 'SYSTEM', - subtype: property.subtype as string, name: 'email', - value: property.email as string + value: additionalFields.email as string } as IDataObject); - }) - } - if(additionalFields.addressOptions){ - //@ts-ignore - additionalFields.addressOptions.addressProperties.map(property => { + } + + if(additionalFields.address){ properties.push({ type: 'SYSTEM', - subtype: property.subtype as string, name: 'address', - value: property.address as string + value: additionalFields.address as string } as IDataObject); - }) + } + + if(additionalFields.phone){ + properties.push({ + type: 'SYSTEM', + name: 'phone', + value: additionalFields.phone as string + } as IDataObject); + } + } + if(additionalFields.websiteOptions){ //@ts-ignore additionalFields.websiteOptions.websiteProperties.map(property => { @@ -316,17 +421,6 @@ export class AgileCrm implements INodeType { } as IDataObject); }) } - if(additionalFields.phoneOptions){ - //@ts-ignore - additionalFields.phoneOptions.phoneProperties.map(property => { - properties.push({ - type: 'SYSTEM', - subtype: property.subtype as string, - name: 'phone', - value: property.number as string - } as IDataObject); - }) - } if(additionalFields.customProperties){ //@ts-ignore additionalFields.customProperties.customProperty.map(property => { @@ -339,9 +433,6 @@ export class AgileCrm implements INodeType { }) } body.properties = properties; - - - } Object.assign(contactUpdatePayload, body); @@ -356,7 +447,7 @@ export class AgileCrm implements INodeType { returnData.push(responseData as IDataObject); } } - + } return [this.helpers.returnJsonArray(returnData)]; diff --git a/packages/nodes-base/nodes/AgileCrm/CompanyDescription.ts b/packages/nodes-base/nodes/AgileCrm/CompanyDescription.ts new file mode 100644 index 0000000000..56db0f4abc --- /dev/null +++ b/packages/nodes-base/nodes/AgileCrm/CompanyDescription.ts @@ -0,0 +1,732 @@ +import { + INodeProperties, + } from 'n8n-workflow'; + +export const companyOperations = [ + { + displayName: 'Operation', + name: 'operation', + type: 'options', + displayOptions: { + show: { + resource: [ + 'company', + ], + }, + }, + options: [ + { + name: 'Get', + value: 'get', + description: 'Get a company', + }, + { + name: 'Get All', + value: 'getAll', + description: 'Get all companies', + }, + { + name: 'Create', + value: 'create', + description: 'Create a new company', + }, + { + name: 'Update', + value: 'update', + description: 'Update company properties', + }, + { + name: 'Delete', + value: 'delete', + description: 'Delete a company', + }, + ], + default: 'get', + description: 'The operation to perform.', + }, +] as INodeProperties[]; + +export const companyFields = [ +/* -------------------------------------------------------------------------- */ +/* company:get */ +/* -------------------------------------------------------------------------- */ + { + displayName: 'company ID', + name: 'companyId', + type: 'string', + required: true, + displayOptions: { + show: { + resource: [ + 'company', + ], + operation: [ + 'get', + ], + }, + }, + default: '', + description: 'Unique identifier for a particular company', + }, + + +/* -------------------------------------------------------------------------- */ +/* company:get all */ +/* -------------------------------------------------------------------------- */ + { + displayName: 'Return All', + name: 'returnAll', + type: 'boolean', + displayOptions: { + show: { + resource: [ + 'company', + ], + operation: [ + 'getAll', + ], + }, + }, + default: false, + description: 'If all results should be returned or only up to a given limit.', + }, + { + displayName: 'Limit', + name: 'limit', + type: 'number', + default: 20, + displayOptions: { + show: { + resource: [ + 'company', + ], + operation: [ + 'getAll', + ], + returnAll: [ + false, + ], + }, + } + }, + +/* -------------------------------------------------------------------------- */ +/* company:create */ +/* -------------------------------------------------------------------------- */ + +{ + displayName: 'JSON Parameters', + name: 'jsonParameters', + type: 'boolean', + default: false, + description: '', + displayOptions: { + show: { + resource: [ + 'company', + ], + operation: [ + 'create', + ], + }, + }, +}, +{ + displayName: ' Additional Fields', + name: 'additionalFieldsJson', + type: 'json', + typeOptions: { + alwaysOpenEditWindow: true, + }, + default: '', + displayOptions: { + show: { + resource: [ + 'company', + ], + operation: [ + 'create', + ], + jsonParameters: [ + true, + ], + }, + }, + + description: `Object of values to set as described here.`, +}, + +{ + displayName: 'Additional Fields', + name: 'additionalFields', + type: 'collection', + placeholder: 'Add Field', + default: {}, + displayOptions: { + show: { + resource: [ + 'company', + ], + operation: [ + 'create', + ], + jsonParameters: [ + false, + ], + }, + }, + options: [ + { + displayName: 'Star Value', + name: 'starValue', + type: 'options', + default: '', + required: false, + description: 'Rating of company (Max value 5). This is not applicable for companies.', + options: [ + { + name: '0', + value: 0 + }, + { + name: '1', + value: 1 + }, + { + name: '2', + value: 2 + }, + { + name: '3', + value: 3 + }, + { + name: '4', + value: 4 + }, + { + name: '5', + value: 5 + }, + ] + }, + { + displayName: 'Lead Score', + name: 'leadScore', + type: 'number', + default: '', + description: 'Score of company. This is not applicable for companies.', + required: false, + typeOptions: { + minValue: 0 + } + }, + { + displayName: 'Tags', + name: 'tags', + type: 'string', + typeOptions: { + multipleValues: true, + multipleValueButtonText: 'Add Tag', + }, + default: [], + placeholder: 'Tag', + description: 'Unique identifiers added to company, for easy management of companys. This is not applicable for companies.', + }, + { + displayName: 'Name', + name: 'name', + type: 'string', + required: false, + default: "", + placeholder: 'Company name', + description: 'Company name.', + }, + { + displayName: 'Email', + name: 'email', + type: 'string', + required: false, + default: '', + placeholder: 'Company email', + description: 'Company email.', + }, + { + displayName: 'Address', + name: 'email', + type: 'string', + required: false, + default: '', + placeholder: 'Company address', + description: 'Company address.', + }, + { + displayName: 'Website', + name: 'websiteOptions', + type: 'fixedCollection', + required: false, + description: 'companys websites.', + typeOptions: { + multipleValues: true, + }, + options: [ + { + displayName: 'Website properties.', + name: 'websiteProperties', + values: [ + { + displayName: 'Type', + name: 'subtype', + type: 'options', + required: true, + default: "", + placeholder: '', + description: 'Type of website.', + options: [ + { + name: 'URL', + value: 'url', + }, + { + name: 'SKYPE', + value: 'skype', + }, + { + name: 'TWITTER', + value: 'twitter', + }, + { + name: 'LINKEDIN', + value: 'linkedin', + }, + { + name: 'FACEBOOK', + value: 'facebook', + }, + { + name: 'XING', + value: 'xing', + }, + { + name: 'FEED', + value: 'feed', + }, + { + name: 'GOOGLE_PLUS', + value: 'googlePlus', + }, + { + name: 'FLICKR', + value: 'flickr', + }, + { + name: 'GITHUB', + value: 'github', + }, + { + name: 'YOUTUBE', + value: 'youtube', + }, + ] + }, + { + displayName: 'URL', + name: 'url', + type: 'string', + required: true, + default: "", + placeholder: '', + description: 'Website URL', + } + ] + }, + + ] + }, + { + displayName: 'Phone', + name: 'phone', + type: 'string', + required: false, + default: '', + placeholder: 'Company phone', + description: 'Company phone.', + }, + { + displayName: 'Custom Properties', + name: 'customProperties', + type: 'fixedCollection', + required: false, + description: 'Custom Properties', + typeOptions: { + multipleValues: true, + }, + options: [ + { + displayName: 'Property', + name: 'customProperty', + values: [ + { + displayName: 'Name', + name: 'name', + type: 'string', + required: true, + default: "", + placeholder: '', + description: 'Property name.' + }, + { + displayName: 'Sub Type', + name: 'subtype', + type: 'string', + required: false, + default: "", + placeholder: '', + description: 'Property sub type.', + }, + { + displayName: 'Value', + name: 'value', + type: 'string', + required: false, + default: "", + placeholder: '', + description: 'Property value.', + } + ] + }, + + ] + }, + ], +}, +/* -------------------------------------------------------------------------- */ +/* company:delete */ +/* -------------------------------------------------------------------------- */ +{ + displayName: 'company ID', + name: 'companyId', + type: 'string', + required: true, + displayOptions: { + show: { + resource: [ + 'company', + ], + operation: [ + 'delete', + ], + }, + }, + default: '', + description: 'Unique identifier for a particular company', +}, +/* -------------------------------------------------------------------------- */ +/* company:update */ +/* -------------------------------------------------------------------------- */ +{ + displayName: 'company ID', + name: 'companyId', + type: 'string', + required: true, + displayOptions: { + show: { + resource: [ + 'company', + ], + operation: [ + 'update', + ], + }, + }, + default: '', + description: 'Unique identifier for a particular company', +}, +{ + displayName: 'JSON Parameters', + name: 'jsonParameters', + type: 'boolean', + default: false, + description: '', + displayOptions: { + show: { + resource: [ + 'company', + ], + operation: [ + 'update', + ], + }, + }, +}, +{ + displayName: ' Additional Fields', + name: 'additionalFieldsJson', + type: 'json', + typeOptions: { + alwaysOpenEditWindow: true, + }, + default: '', + displayOptions: { + show: { + resource: [ + 'company', + ], + operation: [ + 'update', + ], + jsonParameters: [ + true, + ], + }, + }, + + description: `Object of values to set as described here.`, +}, + +{ + displayName: 'Additional Fields', + name: 'additionalFields', + type: 'collection', + placeholder: 'Add Field', + default: {}, + displayOptions: { + show: { + resource: [ + 'company', + ], + operation: [ + 'update', + ], + jsonParameters: [ + false, + ], + }, + }, + options: [ + { + displayName: 'Star Value', + name: 'starValue', + type: 'options', + default: '', + required: false, + description: 'Rating of company (Max value 5). This is not applicable for companies.', + options: [ + { + name: '0', + value: 0 + }, + { + name: '1', + value: 1 + }, + { + name: '2', + value: 2 + }, + { + name: '3', + value: 3 + }, + { + name: '4', + value: 4 + }, + { + name: '5', + value: 5 + }, + ] + }, + { + displayName: 'Lead Score', + name: 'leadScore', + type: 'number', + default: '', + description: 'Score of company. This is not applicable for companies.', + required: false, + typeOptions: { + minValue: 0 + } + }, + { + displayName: 'Tags', + name: 'tags', + type: 'string', + typeOptions: { + multipleValues: true, + multipleValueButtonText: 'Add Tag', + }, + default: [], + placeholder: 'Tag', + description: 'Unique identifiers added to company, for easy management of companys. This is not applicable for companies.', + }, + { + displayName: 'Name', + name: 'name', + type: 'string', + required: false, + default: "", + placeholder: 'Company name', + description: 'Company name.', + }, + { + displayName: 'Email', + name: 'email', + type: 'string', + required: false, + default: '', + placeholder: 'Company email', + description: 'Company email.', + }, + { + displayName: 'Address', + name: 'email', + type: 'string', + required: false, + default: '', + placeholder: 'Company address', + description: 'Company address.', + }, + { + displayName: 'Website', + name: 'websiteOptions', + type: 'fixedCollection', + required: false, + description: 'companys websites.', + typeOptions: { + multipleValues: true, + }, + options: [ + { + displayName: 'Website properties.', + name: 'websiteProperties', + values: [ + { + displayName: 'Type', + name: 'subtype', + type: 'options', + required: true, + default: "", + placeholder: '', + description: 'Type of website.', + options: [ + { + name: 'URL', + value: 'url', + }, + { + name: 'SKYPE', + value: 'skype', + }, + { + name: 'TWITTER', + value: 'twitter', + }, + { + name: 'LINKEDIN', + value: 'linkedin', + }, + { + name: 'FACEBOOK', + value: 'facebook', + }, + { + name: 'XING', + value: 'xing', + }, + { + name: 'FEED', + value: 'feed', + }, + { + name: 'GOOGLE_PLUS', + value: 'googlePlus', + }, + { + name: 'FLICKR', + value: 'flickr', + }, + { + name: 'GITHUB', + value: 'github', + }, + { + name: 'YOUTUBE', + value: 'youtube', + }, + ] + }, + { + displayName: 'URL', + name: 'url', + type: 'string', + required: true, + default: "", + placeholder: '', + description: 'Website URL', + } + ] + }, + + ] + }, + { + displayName: 'Phone', + name: 'phone', + type: 'string', + required: false, + default: '', + placeholder: 'Company phone', + description: 'Company phone.', + }, + { + displayName: 'Custom Properties', + name: 'customProperties', + type: 'fixedCollection', + required: false, + description: 'Custom Properties', + typeOptions: { + multipleValues: true, + }, + options: [ + { + displayName: 'Property', + name: 'customProperty', + values: [ + { + displayName: 'Name', + name: 'name', + type: 'string', + required: true, + default: "", + placeholder: '', + description: 'Property name.' + }, + { + displayName: 'Sub Type', + name: 'subtype', + type: 'string', + required: false, + default: "", + placeholder: '', + description: 'Property sub type.', + }, + { + displayName: 'Value', + name: 'value', + type: 'string', + required: false, + default: "", + placeholder: '', + description: 'Property value.', + } + ] + }, + + ] + }, + ], +}, + +] as INodeProperties[]; diff --git a/packages/nodes-base/nodes/AgileCrm/ContactDescription.ts b/packages/nodes-base/nodes/AgileCrm/ContactDescription.ts index e37dc65e38..96d0dfd3d0 100644 --- a/packages/nodes-base/nodes/AgileCrm/ContactDescription.ts +++ b/packages/nodes-base/nodes/AgileCrm/ContactDescription.ts @@ -111,7 +111,7 @@ export const contactFields = [ }, /* -------------------------------------------------------------------------- */ -/* ticket:create */ +/* contact:create */ /* -------------------------------------------------------------------------- */ { diff --git a/packages/nodes-base/nodes/AgileCrm/ContactInterface.ts b/packages/nodes-base/nodes/AgileCrm/ContactInterface.ts index ae384df943..656b95d3ac 100644 --- a/packages/nodes-base/nodes/AgileCrm/ContactInterface.ts +++ b/packages/nodes-base/nodes/AgileCrm/ContactInterface.ts @@ -10,6 +10,7 @@ import { } export interface IContact { + type?: string, star_value?: string; lead_score?: string; tags?: string[];