@memberjunction/actions-bizapps-crm
Version:
CRM system integration actions for MemberJunction
261 lines (238 loc) • 10.3 kB
text/typescript
import { RegisterClass } from '@memberjunction/global';
import { HubSpotBaseAction } from '../hubspot-base.action';
import { ActionParam, ActionResultSimple, RunActionParams } from '@memberjunction/actions-base';
import { BaseAction } from '@memberjunction/actions';
/**
* Action to log activities (calls, emails, meetings, notes) in HubSpot
*/
(BaseAction, 'LogActivityAction')
export class LogActivityAction extends HubSpotBaseAction {
/**
* Log an activity (engagement) in HubSpot
*/
protected async InternalRunAction(params: RunActionParams): Promise<ActionResultSimple> {
const { Params, ContextUser } = params;
this.params = Params; // Set params for base class to use
try {
// Extract and validate parameters
const activityType = this.getParamValue(Params, 'ActivityType');
const subject = this.getParamValue(Params, 'Subject');
const body = this.getParamValue(Params, 'Body');
const status = this.getParamValue(Params, 'Status') || 'COMPLETED';
const activityDate = this.getParamValue(Params, 'ActivityDate');
const durationMilliseconds = this.getParamValue(Params, 'DurationMilliseconds');
const contactIds = this.getParamValue(Params, 'ContactIds');
const companyIds = this.getParamValue(Params, 'CompanyIds');
const dealIds = this.getParamValue(Params, 'DealIds');
const ownerId = this.getParamValue(Params, 'OwnerId');
const metadata = this.getParamValue(Params, 'Metadata');
if (!activityType) {
return {
Success: false,
ResultCode: 'VALIDATION_ERROR',
Message: 'ActivityType is required',
Params
};
}
const validTypes = ['EMAIL', 'CALL', 'MEETING', 'NOTE'];
if (!validTypes.includes(activityType.toUpperCase())) {
return {
Success: false,
ResultCode: 'VALIDATION_ERROR',
Message: `Invalid ActivityType. Must be one of: ${validTypes.join(', ')}`,
Params
};
}
// Prepare engagement properties based on type
const engagementProperties: any = {
type: activityType.toUpperCase()
};
// Set activity date (default to now)
const timestamp = activityDate ? new Date(activityDate).getTime() : Date.now();
engagementProperties.timestamp = timestamp;
// Add common properties
if (ownerId) engagementProperties.ownerId = ownerId;
// Prepare metadata based on activity type
const engagementMetadata: any = {};
switch (activityType.toUpperCase()) {
case 'EMAIL':
engagementMetadata.subject = subject || 'Email activity';
engagementMetadata.html = body || '';
engagementMetadata.status = status;
if (metadata?.from) engagementMetadata.from = metadata.from;
if (metadata?.to) engagementMetadata.to = metadata.to;
if (metadata?.cc) engagementMetadata.cc = metadata.cc;
if (metadata?.bcc) engagementMetadata.bcc = metadata.bcc;
break;
case 'CALL':
engagementMetadata.title = subject || 'Call activity';
engagementMetadata.body = body || '';
engagementMetadata.status = status;
if (durationMilliseconds) engagementMetadata.durationMilliseconds = durationMilliseconds;
if (metadata?.toNumber) engagementMetadata.toNumber = metadata.toNumber;
if (metadata?.fromNumber) engagementMetadata.fromNumber = metadata.fromNumber;
if (metadata?.recordingUrl) engagementMetadata.recordingUrl = metadata.recordingUrl;
break;
case 'MEETING':
engagementMetadata.title = subject || 'Meeting';
engagementMetadata.body = body || '';
engagementMetadata.startTime = timestamp;
if (durationMilliseconds) {
engagementMetadata.endTime = timestamp + durationMilliseconds;
}
if (metadata?.location) engagementMetadata.location = metadata.location;
if (metadata?.meetingOutcome) engagementMetadata.meetingOutcome = metadata.meetingOutcome;
break;
case 'NOTE':
engagementMetadata.body = body || subject || 'Note';
break;
}
// Prepare associations
const associations: any = {};
if (contactIds && Array.isArray(contactIds) && contactIds.length > 0) {
associations.contactIds = contactIds;
}
if (companyIds && Array.isArray(companyIds) && companyIds.length > 0) {
associations.companyIds = companyIds;
}
if (dealIds && Array.isArray(dealIds) && dealIds.length > 0) {
associations.dealIds = dealIds;
}
// Create the engagement
const engagementBody = {
engagement: engagementProperties,
associations,
metadata: engagementMetadata
};
const engagement = await this.makeHubSpotRequest<any>(
'engagements',
'POST',
engagementBody,
ContextUser
);
// Format activity details
const activityDetails = {
engagementId: engagement.engagement.id,
type: engagement.engagement.type,
subject: subject || engagementMetadata.title || engagementMetadata.body,
timestamp: new Date(engagement.engagement.timestamp).toISOString(),
ownerId: engagement.engagement.ownerId,
createdAt: new Date(engagement.engagement.createdAt).toISOString(),
updatedAt: new Date(engagement.engagement.updatedAt).toISOString(),
portalUrl: `https://app.hubspot.com/contacts/engagements/${engagement.engagement.id}`,
associations: engagement.associations
};
// Create summary
const summary = {
activityId: activityDetails.engagementId,
type: activityDetails.type,
subject: activityDetails.subject,
timestamp: activityDetails.timestamp,
associatedContacts: contactIds?.length || 0,
associatedCompanies: companyIds?.length || 0,
associatedDeals: dealIds?.length || 0,
portalUrl: activityDetails.portalUrl
};
// Update output parameters
const outputParams = [...Params];
const activityDetailsParam = outputParams.find(p => p.Name === 'ActivityDetails');
if (activityDetailsParam) activityDetailsParam.Value = activityDetails;
const summaryParam = outputParams.find(p => p.Name === 'Summary');
if (summaryParam) summaryParam.Value = summary;
return {
Success: true,
ResultCode: 'SUCCESS',
Message: `Successfully logged ${activityType.toLowerCase()} activity`,
Params: outputParams
};
} catch (error) {
const errorMessage = error instanceof Error ? error.message : 'Unknown error occurred';
return {
Success: false,
ResultCode: 'ERROR',
Message: `Error logging activity: ${errorMessage}`,
Params
};
}
}
/**
* Define the parameters this action expects
*/
public get Params(): ActionParam[] {
const baseParams = this.getCommonCRMParams();
const specificParams: ActionParam[] = [
{
Name: 'ActivityType',
Type: 'Input',
Value: null
},
{
Name: 'Subject',
Type: 'Input',
Value: null
},
{
Name: 'Body',
Type: 'Input',
Value: null
},
{
Name: 'Status',
Type: 'Input',
Value: 'COMPLETED'
},
{
Name: 'ActivityDate',
Type: 'Input',
Value: null
},
{
Name: 'DurationMilliseconds',
Type: 'Input',
Value: null
},
{
Name: 'ContactIds',
Type: 'Input',
Value: null
},
{
Name: 'CompanyIds',
Type: 'Input',
Value: null
},
{
Name: 'DealIds',
Type: 'Input',
Value: null
},
{
Name: 'OwnerId',
Type: 'Input',
Value: null
},
{
Name: 'Metadata',
Type: 'Input',
Value: null
},
{
Name: 'ActivityDetails',
Type: 'Output',
Value: null
},
{
Name: 'Summary',
Type: 'Output',
Value: null
}
];
return [...baseParams, ...specificParams];
}
/**
* Metadata about this action
*/
public get Description(): string {
return 'Logs activities (calls, emails, meetings, notes) in HubSpot with optional associations to contacts, companies, and deals';
}
}