From e9631b336f783a7fcd036314d2154b9d1b0fa705 Mon Sep 17 00:00:00 2001 From: Alexander Gekov <40495748+alexander-gekov@users.noreply.github.com> Date: Thu, 28 May 2026 18:18:48 +0300 Subject: [PATCH] fix(Pipedrive Node): Map user_id to owner_id for v2 deal and activity requests (#30890) --- .../test/v2/node/activity/create.test.ts | 1 + .../v2/node/activity/create.workflow.json | 1 + .../test/v2/node/activity/getAll.test.ts | 2 +- .../v2/node/activity/getAll.workflow.json | 4 +- .../test/v2/node/activity/update.test.ts | 1 + .../v2/node/activity/update.workflow.json | 1 + .../test/v2/node/deal/create.test.ts | 1 + .../test/v2/node/deal/create.workflow.json | 3 +- .../test/v2/node/deal/getAll.test.ts | 2 +- .../test/v2/node/deal/getAll.workflow.json | 4 +- .../test/v2/node/deal/update.test.ts | 1 + .../test/v2/node/deal/update.workflow.json | 1 + .../Pipedrive/test/v2/userIdRemap.test.ts | 184 ++++++++++++++++++ .../v2/actions/activity/create.operation.ts | 7 + .../v2/actions/activity/getAll.operation.ts | 4 +- .../v2/actions/activity/update.operation.ts | 7 + .../v2/actions/deal/create.operation.ts | 7 + .../v2/actions/deal/getAll.operation.ts | 4 +- .../v2/actions/deal/update.operation.ts | 7 + 19 files changed, 235 insertions(+), 7 deletions(-) create mode 100644 packages/nodes-base/nodes/Pipedrive/test/v2/userIdRemap.test.ts diff --git a/packages/nodes-base/nodes/Pipedrive/test/v2/node/activity/create.test.ts b/packages/nodes-base/nodes/Pipedrive/test/v2/node/activity/create.test.ts index a7a0d90413f..6b8d912ade7 100644 --- a/packages/nodes-base/nodes/Pipedrive/test/v2/node/activity/create.test.ts +++ b/packages/nodes-base/nodes/Pipedrive/test/v2/node/activity/create.test.ts @@ -15,6 +15,7 @@ describe('Test PipedriveV2, activity => create', () => { deal_id: 8, person_id: 10, org_id: 7, + owner_id: 25455458, due_date: '2026-04-01', }) .reply(200, { diff --git a/packages/nodes-base/nodes/Pipedrive/test/v2/node/activity/create.workflow.json b/packages/nodes-base/nodes/Pipedrive/test/v2/node/activity/create.workflow.json index 6f1d9f4e012..35787e1bca3 100644 --- a/packages/nodes-base/nodes/Pipedrive/test/v2/node/activity/create.workflow.json +++ b/packages/nodes-base/nodes/Pipedrive/test/v2/node/activity/create.workflow.json @@ -21,6 +21,7 @@ "deal_id": 8, "person_id": 10, "org_id": 7, + "user_id": 25455458, "due_date": "2026-04-01T00:00:00.000Z" } }, diff --git a/packages/nodes-base/nodes/Pipedrive/test/v2/node/activity/getAll.test.ts b/packages/nodes-base/nodes/Pipedrive/test/v2/node/activity/getAll.test.ts index e92f4c06012..4d669aa6e89 100644 --- a/packages/nodes-base/nodes/Pipedrive/test/v2/node/activity/getAll.test.ts +++ b/packages/nodes-base/nodes/Pipedrive/test/v2/node/activity/getAll.test.ts @@ -9,7 +9,7 @@ describe('Test PipedriveV2, activity => getAll', () => { nock('https://api.pipedrive.com/api/v2') .get('/activities') - .query({ limit: 2 }) + .query({ limit: 2, owner_id: 25455458 }) .reply(200, { success: true, data: [ diff --git a/packages/nodes-base/nodes/Pipedrive/test/v2/node/activity/getAll.workflow.json b/packages/nodes-base/nodes/Pipedrive/test/v2/node/activity/getAll.workflow.json index e0811c72b3d..9c6d82bc299 100644 --- a/packages/nodes-base/nodes/Pipedrive/test/v2/node/activity/getAll.workflow.json +++ b/packages/nodes-base/nodes/Pipedrive/test/v2/node/activity/getAll.workflow.json @@ -16,7 +16,9 @@ "operation": "getAll", "returnAll": false, "limit": 2, - "filters": {} + "filters": { + "user_id": 25455458 + } }, "id": "e5e5e5e5-f6f6-a7a7-b8b8-c9c9c9c9c9c9", "name": "Pipedrive", diff --git a/packages/nodes-base/nodes/Pipedrive/test/v2/node/activity/update.test.ts b/packages/nodes-base/nodes/Pipedrive/test/v2/node/activity/update.test.ts index d1b74e8018c..5852590bbfc 100644 --- a/packages/nodes-base/nodes/Pipedrive/test/v2/node/activity/update.test.ts +++ b/packages/nodes-base/nodes/Pipedrive/test/v2/node/activity/update.test.ts @@ -11,6 +11,7 @@ describe('Test PipedriveV2, activity => update', () => { .patch('/activities/10', { subject: 'Updated call', done: true, + owner_id: 25455458, due_date: '2026-04-02', }) .reply(200, { diff --git a/packages/nodes-base/nodes/Pipedrive/test/v2/node/activity/update.workflow.json b/packages/nodes-base/nodes/Pipedrive/test/v2/node/activity/update.workflow.json index 76d4539e530..9fcd0a8676e 100644 --- a/packages/nodes-base/nodes/Pipedrive/test/v2/node/activity/update.workflow.json +++ b/packages/nodes-base/nodes/Pipedrive/test/v2/node/activity/update.workflow.json @@ -18,6 +18,7 @@ "updateFields": { "subject": "Updated call", "done": true, + "user_id": 25455458, "due_date": "2026-04-02T00:00:00.000Z" } }, diff --git a/packages/nodes-base/nodes/Pipedrive/test/v2/node/deal/create.test.ts b/packages/nodes-base/nodes/Pipedrive/test/v2/node/deal/create.test.ts index e90a266ff8b..69cd0fc7cda 100644 --- a/packages/nodes-base/nodes/Pipedrive/test/v2/node/deal/create.test.ts +++ b/packages/nodes-base/nodes/Pipedrive/test/v2/node/deal/create.test.ts @@ -15,6 +15,7 @@ describe('Test PipedriveV2, deal => create', () => { value: 5000, currency: 'USD', status: 'open', + owner_id: 25455458, }) .reply(200, { success: true, diff --git a/packages/nodes-base/nodes/Pipedrive/test/v2/node/deal/create.workflow.json b/packages/nodes-base/nodes/Pipedrive/test/v2/node/deal/create.workflow.json index a4a3c5a12ae..1cc82cc3de8 100644 --- a/packages/nodes-base/nodes/Pipedrive/test/v2/node/deal/create.workflow.json +++ b/packages/nodes-base/nodes/Pipedrive/test/v2/node/deal/create.workflow.json @@ -21,7 +21,8 @@ "person_id": 10, "value": 5000, "currency": "USD", - "status": "open" + "status": "open", + "user_id": 25455458 } }, "id": "bb222222-cc33-dd44-ee55-ff6666666666", diff --git a/packages/nodes-base/nodes/Pipedrive/test/v2/node/deal/getAll.test.ts b/packages/nodes-base/nodes/Pipedrive/test/v2/node/deal/getAll.test.ts index 8e778c4aa1c..e4100b057e9 100644 --- a/packages/nodes-base/nodes/Pipedrive/test/v2/node/deal/getAll.test.ts +++ b/packages/nodes-base/nodes/Pipedrive/test/v2/node/deal/getAll.test.ts @@ -9,7 +9,7 @@ describe('Test PipedriveV2, deal => getAll', () => { nock('https://api.pipedrive.com/api/v2') .get('/deals') - .query({ limit: 2 }) + .query({ limit: 2, owner_id: 25455458 }) .reply(200, { success: true, data: [ diff --git a/packages/nodes-base/nodes/Pipedrive/test/v2/node/deal/getAll.workflow.json b/packages/nodes-base/nodes/Pipedrive/test/v2/node/deal/getAll.workflow.json index 80c2c2d102a..aa3b230c8f5 100644 --- a/packages/nodes-base/nodes/Pipedrive/test/v2/node/deal/getAll.workflow.json +++ b/packages/nodes-base/nodes/Pipedrive/test/v2/node/deal/getAll.workflow.json @@ -16,7 +16,9 @@ "operation": "getAll", "returnAll": false, "limit": 2, - "filters": {} + "filters": { + "user_id": 25455458 + } }, "id": "b2b2b2b2-1111-2222-3333-444444444444", "name": "Pipedrive", diff --git a/packages/nodes-base/nodes/Pipedrive/test/v2/node/deal/update.test.ts b/packages/nodes-base/nodes/Pipedrive/test/v2/node/deal/update.test.ts index 1db3626160c..61590f546a8 100644 --- a/packages/nodes-base/nodes/Pipedrive/test/v2/node/deal/update.test.ts +++ b/packages/nodes-base/nodes/Pipedrive/test/v2/node/deal/update.test.ts @@ -11,6 +11,7 @@ describe('Test PipedriveV2, deal => update', () => { .patch('/deals/10', { title: 'Updated Deal', value: 7500, + owner_id: 25455458, expected_close_date: '2026-04-13', }) .reply(200, { diff --git a/packages/nodes-base/nodes/Pipedrive/test/v2/node/deal/update.workflow.json b/packages/nodes-base/nodes/Pipedrive/test/v2/node/deal/update.workflow.json index d3b00679896..e3f395e33e6 100644 --- a/packages/nodes-base/nodes/Pipedrive/test/v2/node/deal/update.workflow.json +++ b/packages/nodes-base/nodes/Pipedrive/test/v2/node/deal/update.workflow.json @@ -18,6 +18,7 @@ "updateFields": { "title": "Updated Deal", "value": 7500, + "user_id": 25455458, "expected_close_date": "2026-04-13T00:00:00.000Z" } }, diff --git a/packages/nodes-base/nodes/Pipedrive/test/v2/userIdRemap.test.ts b/packages/nodes-base/nodes/Pipedrive/test/v2/userIdRemap.test.ts new file mode 100644 index 00000000000..be26caa858f --- /dev/null +++ b/packages/nodes-base/nodes/Pipedrive/test/v2/userIdRemap.test.ts @@ -0,0 +1,184 @@ +import type { IDataObject, IExecuteFunctions } from 'n8n-workflow'; + +import { execute as activityCreateExecute } from '../../v2/actions/activity/create.operation'; +import { execute as activityGetAllExecute } from '../../v2/actions/activity/getAll.operation'; +import { execute as activityUpdateExecute } from '../../v2/actions/activity/update.operation'; +import { execute as dealCreateExecute } from '../../v2/actions/deal/create.operation'; +import { execute as dealGetAllExecute } from '../../v2/actions/deal/getAll.operation'; +import { execute as dealUpdateExecute } from '../../v2/actions/deal/update.operation'; +import { + pipedriveApiRequest, + pipedriveApiRequestAllItemsCursor, + pipedriveGetCustomProperties, +} from '../../v2/transport'; + +jest.mock('../../v2/transport', () => ({ + pipedriveApiRequest: { call: jest.fn() }, + pipedriveApiRequestAllItemsCursor: { call: jest.fn() }, + pipedriveApiRequestAllItemsOffset: { call: jest.fn() }, + pipedriveGetCustomProperties: { call: jest.fn() }, +})); + +const mockApiRequest = pipedriveApiRequest as unknown as { call: jest.Mock }; +const mockApiRequestAllItemsCursor = pipedriveApiRequestAllItemsCursor as unknown as { + call: jest.Mock; +}; +const mockGetCustomProperties = pipedriveGetCustomProperties as unknown as { call: jest.Mock }; + +function buildContext(params: Record): IExecuteFunctions { + return { + getInputData: jest.fn(() => [{ json: {} }]), + getNodeParameter: jest.fn((name: string, _i?: number, defaultValue?: unknown) => { + if (Object.prototype.hasOwnProperty.call(params, name)) return params[name]; + return defaultValue; + }), + continueOnFail: jest.fn(() => false), + helpers: { + returnJsonArray: jest.fn((data: unknown) => (Array.isArray(data) ? data : [data])), + constructExecutionMetaData: jest.fn((items: unknown) => items), + }, + getNode: jest.fn(() => ({})), + } as unknown as IExecuteFunctions; +} + +describe('Pipedrive v2 maps user_id parameter to owner_id on outgoing requests', () => { + beforeEach(() => { + mockApiRequest.call.mockReset().mockResolvedValue({ data: {}, additionalData: {} }); + mockApiRequestAllItemsCursor.call.mockReset().mockResolvedValue({ data: [] }); + mockGetCustomProperties.call.mockReset().mockResolvedValue({}); + }); + + it('deal/create sends owner_id in body', async () => { + const ctx = buildContext({ + rawCustomFieldKeys: true, + title: 'Test Deal', + associateWith: 'organization', + org_id: 7, + additionalFields: { user_id: 25455458 }, + }); + + await dealCreateExecute.call(ctx); + + const [, method, endpoint, body] = mockApiRequest.call.mock.calls[0] as [ + unknown, + string, + string, + IDataObject, + ]; + expect(method).toBe('POST'); + expect(endpoint).toBe('/deals'); + expect(body.owner_id).toBe(25455458); + expect(body).not.toHaveProperty('user_id'); + }); + + it('deal/update sends owner_id in body', async () => { + const ctx = buildContext({ + rawCustomFieldKeys: true, + dealId: 10, + updateFields: { user_id: 25455458 }, + }); + + await dealUpdateExecute.call(ctx); + + const [, method, endpoint, body] = mockApiRequest.call.mock.calls[0] as [ + unknown, + string, + string, + IDataObject, + ]; + expect(method).toBe('PATCH'); + expect(endpoint).toBe('/deals/10'); + expect(body.owner_id).toBe(25455458); + expect(body).not.toHaveProperty('user_id'); + }); + + it('deal/getAll sends owner_id as query filter', async () => { + const ctx = buildContext({ + rawCustomFieldOutput: true, + returnAll: false, + limit: 50, + filters: { user_id: 25455458 }, + }); + + await dealGetAllExecute.call(ctx); + + const [, method, endpoint, , qs] = mockApiRequest.call.mock.calls[0] as [ + unknown, + string, + string, + IDataObject, + IDataObject, + ]; + expect(method).toBe('GET'); + expect(endpoint).toBe('/deals'); + expect(qs.owner_id).toBe(25455458); + expect(qs).not.toHaveProperty('user_id'); + }); + + it('activity/create sends owner_id in body', async () => { + const ctx = buildContext({ + rawCustomFieldKeys: true, + subject: 'Call client', + done: false, + type: 'call', + additionalFields: { user_id: 25455458 }, + }); + + await activityCreateExecute.call(ctx); + + const [, method, endpoint, body] = mockApiRequest.call.mock.calls[0] as [ + unknown, + string, + string, + IDataObject, + ]; + expect(method).toBe('POST'); + expect(endpoint).toBe('/activities'); + expect(body.owner_id).toBe(25455458); + expect(body).not.toHaveProperty('user_id'); + }); + + it('activity/update sends owner_id in body', async () => { + const ctx = buildContext({ + rawCustomFieldKeys: true, + activityId: 10, + updateFields: { user_id: 25455458 }, + }); + + await activityUpdateExecute.call(ctx); + + const [, method, endpoint, body] = mockApiRequest.call.mock.calls[0] as [ + unknown, + string, + string, + IDataObject, + ]; + expect(method).toBe('PATCH'); + expect(endpoint).toBe('/activities/10'); + expect(body.owner_id).toBe(25455458); + expect(body).not.toHaveProperty('user_id'); + }); + + it('activity/getAll sends owner_id as query filter', async () => { + const ctx = buildContext({ + rawCustomFieldOutput: true, + returnAll: false, + limit: 50, + filters: { user_id: 25455458 }, + }); + + await activityGetAllExecute.call(ctx); + + const [, method, endpoint, , qs] = mockApiRequest.call.mock.calls[0] as [ + unknown, + string, + string, + IDataObject, + IDataObject, + ]; + expect(method).toBe('GET'); + expect(endpoint).toBe('/activities'); + expect(qs.owner_id).toBe(25455458); + expect(qs).not.toHaveProperty('user_id'); + }); +}); diff --git a/packages/nodes-base/nodes/Pipedrive/v2/actions/activity/create.operation.ts b/packages/nodes-base/nodes/Pipedrive/v2/actions/activity/create.operation.ts index bd486e4e84b..d553ae366d0 100644 --- a/packages/nodes-base/nodes/Pipedrive/v2/actions/activity/create.operation.ts +++ b/packages/nodes-base/nodes/Pipedrive/v2/actions/activity/create.operation.ts @@ -137,6 +137,13 @@ export async function execute(this: IExecuteFunctions): Promise