Add vendor contacts to n8n

Signed-off-by: Sacha Al Himdani <sacha@getprobo.com>
This commit is contained in:
Sacha Al Himdani
2026-02-23 14:06:18 +01:00
parent 4b4070bb46
commit 71b01bf20e
7 changed files with 523 additions and 0 deletions

1
package-lock.json generated
View File

@@ -14347,6 +14347,7 @@
"os": [
"darwin"
],
"peer": true,
"engines": {
"node": "^8.16.0 || ^10.6.0 || >=11.0.0"
}

View File

@@ -0,0 +1,114 @@
import type { INodeProperties, IExecuteFunctions, INodeExecutionData } from 'n8n-workflow';
import { proboApiRequest } from '../../GenericFunctions';
export const description: INodeProperties[] = [
{
displayName: 'Vendor ID',
name: 'vendorId',
type: 'string',
displayOptions: {
show: {
resource: ['vendor'],
operation: ['createContact'],
},
},
default: '',
description: 'The ID of the vendor',
required: true,
},
{
displayName: 'Full Name',
name: 'fullName',
type: 'string',
displayOptions: {
show: {
resource: ['vendor'],
operation: ['createContact'],
},
},
default: '',
description: 'The full name of the contact',
},
{
displayName: 'Email',
name: 'email',
type: 'string',
placeholder: 'name@email.com',
displayOptions: {
show: {
resource: ['vendor'],
operation: ['createContact'],
},
},
default: '',
description: 'The email address of the contact',
},
{
displayName: 'Phone',
name: 'phone',
type: 'string',
displayOptions: {
show: {
resource: ['vendor'],
operation: ['createContact'],
},
},
default: '',
description: 'The phone number of the contact',
},
{
displayName: 'Role',
name: 'role',
type: 'string',
displayOptions: {
show: {
resource: ['vendor'],
operation: ['createContact'],
},
},
default: '',
description: 'The role of the contact',
},
];
export async function execute(
this: IExecuteFunctions,
itemIndex: number,
): Promise<INodeExecutionData> {
const vendorId = this.getNodeParameter('vendorId', itemIndex) as string;
const fullName = this.getNodeParameter('fullName', itemIndex, '') as string;
const email = this.getNodeParameter('email', itemIndex, '') as string;
const phone = this.getNodeParameter('phone', itemIndex, '') as string;
const role = this.getNodeParameter('role', itemIndex, '') as string;
const query = `
mutation CreateVendorContact($input: CreateVendorContactInput!) {
createVendorContact(input: $input) {
vendorContactEdge {
node {
id
fullName
email
phone
role
createdAt
updatedAt
}
}
}
}
`;
const input: Record<string, unknown> = { vendorId };
if (fullName) input.fullName = fullName;
if (email) input.email = email;
if (phone) input.phone = phone;
if (role) input.role = role;
const responseData = await proboApiRequest.call(this, query, { input });
return {
json: responseData,
pairedItem: { item: itemIndex },
};
}

View File

@@ -0,0 +1,41 @@
import type { INodeProperties, IExecuteFunctions, INodeExecutionData } from 'n8n-workflow';
import { proboApiRequest } from '../../GenericFunctions';
export const description: INodeProperties[] = [
{
displayName: 'Vendor Contact ID',
name: 'vendorContactId',
type: 'string',
displayOptions: {
show: {
resource: ['vendor'],
operation: ['deleteContact'],
},
},
default: '',
description: 'The ID of the vendor contact to delete',
required: true,
},
];
export async function execute(
this: IExecuteFunctions,
itemIndex: number,
): Promise<INodeExecutionData> {
const vendorContactId = this.getNodeParameter('vendorContactId', itemIndex) as string;
const query = `
mutation DeleteVendorContact($input: DeleteVendorContactInput!) {
deleteVendorContact(input: $input) {
deletedVendorContactId
}
}
`;
const responseData = await proboApiRequest.call(this, query, { input: { vendorContactId } });
return {
json: responseData,
pairedItem: { item: itemIndex },
};
}

View File

@@ -0,0 +1,135 @@
import type { INodeProperties, IExecuteFunctions, INodeExecutionData, IDataObject } from 'n8n-workflow';
import { proboApiRequestAllItems } from '../../GenericFunctions';
export const description: INodeProperties[] = [
{
displayName: 'Vendor ID',
name: 'vendorId',
type: 'string',
displayOptions: {
show: {
resource: ['vendor'],
operation: ['getAllContacts'],
},
},
default: '',
description: 'The ID of the vendor',
required: true,
},
{
displayName: 'Return All',
name: 'returnAll',
type: 'boolean',
displayOptions: {
show: {
resource: ['vendor'],
operation: ['getAllContacts'],
},
},
default: false,
description: 'Whether to return all results or only up to a given limit',
},
{
displayName: 'Limit',
name: 'limit',
type: 'number',
displayOptions: {
show: {
resource: ['vendor'],
operation: ['getAllContacts'],
returnAll: [false],
},
},
typeOptions: {
minValue: 1,
},
default: 50,
description: 'Max number of results to return',
},
{
displayName: 'Options',
name: 'options',
type: 'collection',
placeholder: 'Add Option',
default: {},
displayOptions: {
show: {
resource: ['vendor'],
operation: ['getAllContacts'],
},
},
options: [
{
displayName: 'Include Vendor',
name: 'includeVendor',
type: 'boolean',
default: false,
description: 'Whether to include vendor in the response',
},
],
},
];
export async function execute(
this: IExecuteFunctions,
itemIndex: number,
): Promise<INodeExecutionData> {
const vendorId = this.getNodeParameter('vendorId', itemIndex) as string;
const returnAll = this.getNodeParameter('returnAll', itemIndex) as boolean;
const limit = this.getNodeParameter('limit', itemIndex, 50) as number;
const options = this.getNodeParameter('options', itemIndex, {}) as {
includeVendor?: boolean;
};
const vendorFragment = options.includeVendor
? `vendor {
id
name
}`
: '';
const query = `
query GetVendorContacts($vendorId: ID!, $first: Int, $after: CursorKey) {
node(id: $vendorId) {
... on Vendor {
contacts(first: $first, after: $after) {
edges {
node {
id
fullName
email
phone
role
${vendorFragment}
createdAt
updatedAt
}
}
pageInfo {
hasNextPage
endCursor
}
}
}
}
}
`;
const vendorContacts = await proboApiRequestAllItems.call(
this,
query,
{ vendorId },
(response) => {
const data = response?.data as IDataObject | undefined;
const node = data?.node as IDataObject | undefined;
return node?.contacts as IDataObject | undefined;
},
returnAll,
limit,
);
return {
json: { vendorContacts },
pairedItem: { item: itemIndex },
};
}

View File

@@ -0,0 +1,82 @@
import type { INodeProperties, IExecuteFunctions, INodeExecutionData } from 'n8n-workflow';
import { proboApiRequest } from '../../GenericFunctions';
export const description: INodeProperties[] = [
{
displayName: 'Vendor Contact ID',
name: 'vendorContactId',
type: 'string',
displayOptions: {
show: {
resource: ['vendor'],
operation: ['getContact'],
},
},
default: '',
description: 'The ID of the vendor contact',
required: true,
},
{
displayName: 'Options',
name: 'options',
type: 'collection',
placeholder: 'Add Option',
default: {},
displayOptions: {
show: {
resource: ['vendor'],
operation: ['getContact'],
},
},
options: [
{
displayName: 'Include Vendor',
name: 'includeVendor',
type: 'boolean',
default: false,
description: 'Whether to include vendor in the response',
},
],
},
];
export async function execute(
this: IExecuteFunctions,
itemIndex: number,
): Promise<INodeExecutionData> {
const vendorContactId = this.getNodeParameter('vendorContactId', itemIndex) as string;
const options = this.getNodeParameter('options', itemIndex, {}) as {
includeVendor?: boolean;
};
const vendorFragment = options.includeVendor
? `vendor {
id
name
}`
: '';
const query = `
query GetVendorContact($vendorContactId: ID!) {
node(id: $vendorContactId) {
... on VendorContact {
id
fullName
email
phone
role
${vendorFragment}
createdAt
updatedAt
}
}
}
`;
const responseData = await proboApiRequest.call(this, query, { vendorContactId });
return {
json: responseData,
pairedItem: { item: itemIndex },
};
}

View File

@@ -4,6 +4,11 @@ import * as updateOp from './update.operation';
import * as deleteOp from './delete.operation';
import * as getOp from './get.operation';
import * as getAllOp from './getAll.operation';
import * as createContactOp from './createContact.operation';
import * as updateContactOp from './updateContact.operation';
import * as deleteContactOp from './deleteContact.operation';
import * as getContactOp from './getContact.operation';
import * as getAllContactsOp from './getAllContacts.operation';
import * as createServiceOp from './createService.operation';
import * as updateServiceOp from './updateService.operation';
import * as deleteServiceOp from './deleteService.operation';
@@ -31,6 +36,12 @@ export const description: INodeProperties[] = [
description: 'Create a new vendor',
action: 'Create a vendor',
},
{
name: 'Create Contact',
value: 'createContact',
description: 'Create a new vendor contact',
action: 'Create a vendor contact',
},
{
name: 'Create Risk Assessment',
value: 'createRiskAssessment',
@@ -49,6 +60,12 @@ export const description: INodeProperties[] = [
description: 'Delete a vendor',
action: 'Delete a vendor',
},
{
name: 'Delete Contact',
value: 'deleteContact',
description: 'Delete a vendor contact',
action: 'Delete a vendor contact',
},
{
name: 'Delete Service',
value: 'deleteService',
@@ -61,12 +78,24 @@ export const description: INodeProperties[] = [
description: 'Get a vendor',
action: 'Get a vendor',
},
{
name: 'Get Contact',
value: 'getContact',
description: 'Get a vendor contact',
action: 'Get a vendor contact',
},
{
name: 'Get Many',
value: 'getAll',
description: 'Get many vendors',
action: 'Get many vendors',
},
{
name: 'Get Many Contacts',
value: 'getAllContacts',
description: 'Get many vendor contacts',
action: 'Get many vendor contacts',
},
{
name: 'Get Many Risk Assessments',
value: 'getAllRiskAssessments',
@@ -97,6 +126,12 @@ export const description: INodeProperties[] = [
description: 'Update an existing vendor',
action: 'Update a vendor',
},
{
name: 'Update Contact',
value: 'updateContact',
description: 'Update an existing vendor contact',
action: 'Update a vendor contact',
},
{
name: 'Update Service',
value: 'updateService',
@@ -111,6 +146,11 @@ export const description: INodeProperties[] = [
...deleteOp.description,
...getOp.description,
...getAllOp.description,
...createContactOp.description,
...updateContactOp.description,
...deleteContactOp.description,
...getContactOp.description,
...getAllContactsOp.description,
...createServiceOp.description,
...updateServiceOp.description,
...deleteServiceOp.description,
@@ -127,6 +167,11 @@ export {
deleteOp as delete,
getOp as get,
getAllOp as getAll,
createContactOp as createContact,
updateContactOp as updateContact,
deleteContactOp as deleteContact,
getContactOp as getContact,
getAllContactsOp as getAllContacts,
createServiceOp as createService,
updateServiceOp as updateService,
deleteServiceOp as deleteService,

View File

@@ -0,0 +1,105 @@
import type { INodeProperties, IExecuteFunctions, INodeExecutionData } from 'n8n-workflow';
import { proboApiRequest } from '../../GenericFunctions';
export const description: INodeProperties[] = [
{
displayName: 'Vendor Contact ID',
name: 'vendorContactId',
type: 'string',
displayOptions: {
show: {
resource: ['vendor'],
operation: ['updateContact'],
},
},
default: '',
description: 'The ID of the vendor contact to update',
required: true,
},
{
displayName: 'Additional Fields',
name: 'additionalFields',
type: 'collection',
placeholder: 'Add Field',
default: {},
displayOptions: {
show: {
resource: ['vendor'],
operation: ['updateContact'],
},
},
options: [
{
displayName: 'Email',
name: 'email',
type: 'string',
placeholder: 'name@email.com',
default: '',
description: 'The email address of the contact',
},
{
displayName: 'Full Name',
name: 'fullName',
type: 'string',
default: '',
description: 'The full name of the contact',
},
{
displayName: 'Phone',
name: 'phone',
type: 'string',
default: '',
description: 'The phone number of the contact',
},
{
displayName: 'Role',
name: 'role',
type: 'string',
default: '',
description: 'The role of the contact',
},
],
},
];
export async function execute(
this: IExecuteFunctions,
itemIndex: number,
): Promise<INodeExecutionData> {
const vendorContactId = this.getNodeParameter('vendorContactId', itemIndex) as string;
const additionalFields = this.getNodeParameter('additionalFields', itemIndex, {}) as {
fullName?: string;
email?: string;
phone?: string;
role?: string;
};
const query = `
mutation UpdateVendorContact($input: UpdateVendorContactInput!) {
updateVendorContact(input: $input) {
vendorContact {
id
fullName
email
phone
role
createdAt
updatedAt
}
}
}
`;
const input: Record<string, unknown> = { id: vendorContactId };
if (additionalFields.fullName !== undefined) input.fullName = additionalFields.fullName === '' ? null : additionalFields.fullName;
if (additionalFields.email !== undefined) input.email = additionalFields.email === '' ? null : additionalFields.email;
if (additionalFields.phone !== undefined) input.phone = additionalFields.phone === '' ? null : additionalFields.phone;
if (additionalFields.role !== undefined) input.role = additionalFields.role === '' ? null : additionalFields.role;
const responseData = await proboApiRequest.call(this, query, { input });
return {
json: responseData,
pairedItem: { item: itemIndex },
};
}