fix(HubSpot Node): Require DueDate for task creation (#18799)

This commit is contained in:
yehorkardash
2025-08-27 11:43:22 +03:00
committed by GitHub
parent 4dcb22048d
commit e665cbf278
7 changed files with 201 additions and 23 deletions

View File

@@ -76,6 +76,22 @@ export const engagementFields: INodeProperties[] = [
}, },
default: '', default: '',
}, },
{
displayName: 'Due Date',
name: 'dueDate',
type: 'dateTime',
required: true,
description: 'The due date for the task',
displayOptions: {
show: {
resource: ['engagement'],
operation: ['create'],
type: ['task'],
'@version': [{ _cnd: { gte: 2.2 } }],
},
},
default: '',
},
{ {
displayName: 'Metadata', displayName: 'Metadata',
name: 'metadata', name: 'metadata',

View File

@@ -39,6 +39,7 @@ import {
} from './GenericFunctions'; } from './GenericFunctions';
import { ticketFields, ticketOperations } from './TicketDescription'; import { ticketFields, ticketOperations } from './TicketDescription';
import { generatePairedItemData } from '../../../utils/utilities'; import { generatePairedItemData } from '../../../utils/utilities';
import { parseToTimestamp } from './utils/parseToTimestamp';
export class HubspotV2 implements INodeType { export class HubspotV2 implements INodeType {
description: INodeTypeDescription; description: INodeTypeDescription;
@@ -1144,7 +1145,7 @@ export class HubspotV2 implements INodeType {
const qs: IDataObject = {}; const qs: IDataObject = {};
const resource = this.getNodeParameter('resource', 0); const resource = this.getNodeParameter('resource', 0);
const operation = this.getNodeParameter('operation', 0); const operation = this.getNodeParameter('operation', 0);
const version = this.getNode().typeVersion;
//https://legacydocs.hubspot.com/docs/methods/lists/contact-lists-overview //https://legacydocs.hubspot.com/docs/methods/lists/contact-lists-overview
if (resource === 'contactList') { if (resource === 'contactList') {
try { try {
@@ -2742,7 +2743,7 @@ export class HubspotV2 implements INodeType {
: undefined; : undefined;
const body: { const body: {
engagement: { type: string; ownerId?: number }; engagement: { type: string; ownerId?: number; timestamp?: number };
metadata: IDataObject; metadata: IDataObject;
associations: IDataObject; associations: IDataObject;
} = { } = {
@@ -2760,6 +2761,13 @@ export class HubspotV2 implements INodeType {
if (type === 'task') { if (type === 'task') {
body.metadata = getTaskMetadata(metadata); body.metadata = getTaskMetadata(metadata);
if (version >= 2.2) {
const dueDateParameter = this.getNodeParameter('dueDate', i, null);
if (dueDateParameter) {
const timestamp = parseToTimestamp(dueDateParameter);
body.engagement.timestamp = timestamp;
}
}
} }
if (type === 'meeting') { if (type === 'meeting') {

View File

@@ -0,0 +1,12 @@
import moment from 'moment-timezone';
export function parseToTimestamp(dateString: unknown): number {
if (typeof dateString !== 'string') {
throw new Error('Invalid date string');
}
const timestamp = moment(dateString).valueOf();
if (isNaN(timestamp)) {
throw new Error('Invalid date string');
}
return timestamp;
}

View File

@@ -356,14 +356,12 @@ describe('Hubspot Node', () => {
describe('engagements', () => { describe('engagements', () => {
beforeAll(() => { beforeAll(() => {
hubspotNock hubspotNock
.post('/engagements/v1/engagements', function checkOwnerIdIsDefined(body) { .post('/engagements/v1/engagements', engagements.request.createWithOwnerId)
return body.engagement.ownerId === engagements.request[0].engagement.ownerId; .reply(200, engagements.response.createWithOwnerId)
}) .post('/engagements/v1/engagements', engagements.request.createWithoutOwnerId)
.reply(200, engagements.response[0]) .reply(200, engagements.response.createWithoutOwnerId)
.post('/engagements/v1/engagements', function checkOwnerIdIsNotDefined(body) { .post('/engagements/v1/engagements', engagements.request.createV2_1)
return body.engagement.ownerId === undefined; .reply(200, engagements.response.createV2_1);
})
.reply(200, engagements.response[1]);
}); });
afterAll(() => hubspotNock.done()); afterAll(() => hubspotNock.done());

View File

@@ -6,6 +6,7 @@
"authentication": "appToken", "authentication": "appToken",
"resource": "engagement", "resource": "engagement",
"type": "task", "type": "task",
"dueDate": "2025-08-31T13:12:56",
"metadata": { "metadata": {
"body": "Hello world", "body": "Hello world",
"subject": "Title" "subject": "Title"
@@ -33,6 +34,7 @@
"authentication": "appToken", "authentication": "appToken",
"resource": "engagement", "resource": "engagement",
"type": "task", "type": "task",
"dueDate": "2025-08-31T13:12:56",
"metadata": { "metadata": {
"body": "Hello world", "body": "Hello world",
"subject": "Title" "subject": "Title"
@@ -51,6 +53,29 @@
} }
} }
}, },
{
"parameters": {
"authentication": "appToken",
"resource": "engagement",
"type": "task",
"metadata": {
"body": "Hello world",
"subject": "Title"
},
"additionalFields": {}
},
"type": "n8n-nodes-base.hubspot",
"typeVersion": 2.1,
"position": [0, 400],
"id": "7fb51d0d-28b5-450d-b910-f6d91e69e935",
"name": "HubSpot - Engagement - Create 2.1",
"credentials": {
"hubspotAppToken": {
"id": "vWZfuQawMAWdxKms",
"name": "HubSpot account"
}
}
},
{ {
"parameters": {}, "parameters": {},
"type": "n8n-nodes-base.manualTrigger", "type": "n8n-nodes-base.manualTrigger",
@@ -73,7 +98,7 @@
"lastUpdated": 1756127696406, "lastUpdated": 1756127696406,
"ownerId": 123456789, "ownerId": 123456789,
"type": "TASK", "type": "TASK",
"timestamp": 1756127696406, "timestamp": 1756645976000,
"allAccessibleTeamIds": [], "allAccessibleTeamIds": [],
"bodyPreview": "Hello world", "bodyPreview": "Hello world",
"queueMembershipIds": [], "queueMembershipIds": [],
@@ -120,7 +145,54 @@
"createdAt": 1756127766844, "createdAt": 1756127766844,
"lastUpdated": 1756127766844, "lastUpdated": 1756127766844,
"type": "TASK", "type": "TASK",
"timestamp": 1756127766844, "timestamp": 1756645976000,
"allAccessibleTeamIds": [],
"bodyPreview": "Hello world",
"queueMembershipIds": [],
"bodyPreviewIsTruncated": false,
"bodyPreviewHtml": "<html>\n <head></head>\n <body>\n Hello world\n </body>\n</html>"
},
"associations": {
"contactIds": [],
"companyIds": [],
"dealIds": [],
"ownerIds": [],
"workflowIds": [],
"ticketIds": [],
"contentIds": [],
"quoteIds": [],
"marketingEventIds": [],
"partnerClientIds": [],
"orderIds": [],
"cartIds": []
},
"attachments": [],
"scheduledTasks": [],
"metadata": {
"body": "Hello world",
"status": "NOT_STARTED",
"forObjectType": "OWNER",
"subject": "Title",
"taskType": "TODO",
"reminders": [],
"priority": "NONE",
"isAllDay": false
}
}
}
],
"HubSpot - Engagement - Create 2.1": [
{
"json": {
"associationCreateFailures": [],
"engagement": {
"id": 274123775164,
"portalId": 146787276,
"active": true,
"createdAt": 1756127766844,
"lastUpdated": 1756127766844,
"type": "TASK",
"timestamp": 1756645976000,
"allAccessibleTeamIds": [], "allAccessibleTeamIds": [],
"bodyPreview": "Hello world", "bodyPreview": "Hello world",
"queueMembershipIds": [], "queueMembershipIds": [],
@@ -170,6 +242,11 @@
"node": "HubSpot - Engagement - Create", "node": "HubSpot - Engagement - Create",
"type": "main", "type": "main",
"index": 0 "index": 0
},
{
"node": "HubSpot - Engagement - Create 2.1",
"type": "main",
"index": 0
} }
] ]
] ]

View File

@@ -1,18 +1,23 @@
{ {
"request": [ "request": {
{ "createWithOwnerId": {
"engagement": { "type": "TASK", "ownerId": 123456789 }, "engagement": { "type": "TASK", "ownerId": 123456789, "timestamp": 1756645976000 },
"metadata": { "body": "Hello world", "subject": "Title" }, "metadata": { "body": "Hello world", "subject": "Title" },
"associations": {} "associations": {}
}, },
{ "createWithoutOwnerId": {
"engagement": { "type": "TASK", "timestamp": 1756645976000 },
"metadata": { "body": "Hello world", "subject": "Title" },
"associations": {}
},
"createV2_1": {
"engagement": { "type": "TASK" }, "engagement": { "type": "TASK" },
"metadata": { "body": "Hello world", "subject": "Title" }, "metadata": { "body": "Hello world", "subject": "Title" },
"associations": {} "associations": {}
} }
], },
"response": [ "response": {
{ "createWithOwnerId": {
"associationCreateFailures": [], "associationCreateFailures": [],
"engagement": { "engagement": {
"id": 274361144556, "id": 274361144556,
@@ -22,7 +27,7 @@
"lastUpdated": 1756127696406, "lastUpdated": 1756127696406,
"ownerId": 123456789, "ownerId": 123456789,
"type": "TASK", "type": "TASK",
"timestamp": 1756127696406, "timestamp": 1756645976000,
"allAccessibleTeamIds": [], "allAccessibleTeamIds": [],
"bodyPreview": "Hello world", "bodyPreview": "Hello world",
"queueMembershipIds": [], "queueMembershipIds": [],
@@ -56,7 +61,7 @@
"isAllDay": false "isAllDay": false
} }
}, },
{ "createWithoutOwnerId": {
"associationCreateFailures": [], "associationCreateFailures": [],
"engagement": { "engagement": {
"id": 274123775164, "id": 274123775164,
@@ -65,7 +70,50 @@
"createdAt": 1756127766844, "createdAt": 1756127766844,
"lastUpdated": 1756127766844, "lastUpdated": 1756127766844,
"type": "TASK", "type": "TASK",
"timestamp": 1756127766844, "timestamp": 1756645976000,
"allAccessibleTeamIds": [],
"bodyPreview": "Hello world",
"queueMembershipIds": [],
"bodyPreviewIsTruncated": false,
"bodyPreviewHtml": "<html>\n <head></head>\n <body>\n Hello world\n </body>\n</html>"
},
"associations": {
"contactIds": [],
"companyIds": [],
"dealIds": [],
"ownerIds": [],
"workflowIds": [],
"ticketIds": [],
"contentIds": [],
"quoteIds": [],
"marketingEventIds": [],
"partnerClientIds": [],
"orderIds": [],
"cartIds": []
},
"attachments": [],
"scheduledTasks": [],
"metadata": {
"body": "Hello world",
"status": "NOT_STARTED",
"forObjectType": "OWNER",
"subject": "Title",
"taskType": "TODO",
"reminders": [],
"priority": "NONE",
"isAllDay": false
}
},
"createV2_1": {
"associationCreateFailures": [],
"engagement": {
"id": 274123775164,
"portalId": 146787276,
"active": true,
"createdAt": 1756127766844,
"lastUpdated": 1756127766844,
"type": "TASK",
"timestamp": 1756645976000,
"allAccessibleTeamIds": [], "allAccessibleTeamIds": [],
"bodyPreview": "Hello world", "bodyPreview": "Hello world",
"queueMembershipIds": [], "queueMembershipIds": [],
@@ -99,5 +147,5 @@
"isAllDay": false "isAllDay": false
} }
} }
] }
} }

View File

@@ -0,0 +1,19 @@
import { parseToTimestamp } from '../../V2/utils/parseToTimestamp';
describe('parseToTimestamp', () => {
it('should convert a valid date string to a UTC Unix timestamp', () => {
const dateString = '2023-10-05T14:48:00Z';
const expectedTimestamp = 1696517280000;
expect(parseToTimestamp(dateString)).toBe(expectedTimestamp);
});
it('should throw an error for an invalid date string', () => {
const invalidDateString = 'invalid-date';
expect(() => parseToTimestamp(invalidDateString)).toThrow('Invalid date string');
});
it('should throw an error when input is not a string', () => {
const invalidDateString = 1234567890;
expect(() => parseToTimestamp(invalidDateString)).toThrow('Invalid date string');
});
});