From 8374a23389e9309d9d3d0a24ef9bbbb12230eee4 Mon Sep 17 00:00:00 2001 From: trojanh Date: Fri, 31 Jan 2020 18:17:20 +0530 Subject: [PATCH 01/14] Add DELETE for Harvest APIs --- .../nodes/Harvest/ClientDescription.ts | 27 +++++ .../nodes/Harvest/ContactDescription.ts | 27 +++++ .../nodes/Harvest/EstimateDescription.ts | 27 +++++ .../nodes/Harvest/ExpenseDescription.ts | 27 +++++ .../nodes-base/nodes/Harvest/Harvest.node.ts | 98 ++++++++++++++++++- .../nodes/Harvest/InvoiceDescription.ts | 27 +++++ .../nodes/Harvest/ProjectDescription.ts | 27 +++++ .../nodes/Harvest/TaskDescription.ts | 30 +++++- .../nodes/Harvest/UserDescription.ts | 27 +++++ 9 files changed, 311 insertions(+), 6 deletions(-) diff --git a/packages/nodes-base/nodes/Harvest/ClientDescription.ts b/packages/nodes-base/nodes/Harvest/ClientDescription.ts index 3950b3525..fe769b5eb 100644 --- a/packages/nodes-base/nodes/Harvest/ClientDescription.ts +++ b/packages/nodes-base/nodes/Harvest/ClientDescription.ts @@ -23,6 +23,11 @@ export const clientOperations = [ value: 'getAll', description: 'Get data of all clients', }, + { + name: 'Delete', + value: 'delete', + description: `Delete a client`, + }, ], default: 'getAll', description: 'The operation to perform.', @@ -131,6 +136,28 @@ export const clientFields = [ }, }, description: 'The ID of the client you are retrieving.', +}, + +/* -------------------------------------------------------------------------- */ +/* client:delete */ +/* -------------------------------------------------------------------------- */ +{ + displayName: 'Client Id', + name: 'id', + type: 'string', + default: '', + required: true, + displayOptions: { + show: { + operation: [ + 'delete', + ], + resource: [ + 'client', + ], + }, + }, + description: 'The ID of the client you want to delete.', } ] as INodeProperties[]; diff --git a/packages/nodes-base/nodes/Harvest/ContactDescription.ts b/packages/nodes-base/nodes/Harvest/ContactDescription.ts index f4156eeb1..1c1d645fe 100644 --- a/packages/nodes-base/nodes/Harvest/ContactDescription.ts +++ b/packages/nodes-base/nodes/Harvest/ContactDescription.ts @@ -23,6 +23,11 @@ export const contactOperations = [ value: 'getAll', description: 'Get data of all contacts', }, + { + name: 'Delete', + value: 'delete', + description: `Delete a contact`, + }, ], default: 'getAll', description: 'The operation to perform.', @@ -131,6 +136,28 @@ export const contactFields = [ }, }, description: 'The ID of the contact you are retrieving.', +}, + +/* -------------------------------------------------------------------------- */ +/* contact:delete */ +/* -------------------------------------------------------------------------- */ +{ + displayName: 'Contact Id', + name: 'id', + type: 'string', + default: '', + required: true, + displayOptions: { + show: { + operation: [ + 'delete', + ], + resource: [ + 'contact', + ], + }, + }, + description: 'The ID of the contact you want to delete.', } ] as INodeProperties[]; diff --git a/packages/nodes-base/nodes/Harvest/EstimateDescription.ts b/packages/nodes-base/nodes/Harvest/EstimateDescription.ts index 60a24bdb8..cc0e3e02a 100644 --- a/packages/nodes-base/nodes/Harvest/EstimateDescription.ts +++ b/packages/nodes-base/nodes/Harvest/EstimateDescription.ts @@ -23,6 +23,11 @@ export const estimateOperations = [ value: 'getAll', description: 'Get data of all estimates', }, + { + name: 'Delete', + value: 'delete', + description: `Delete an estimate`, + }, ], default: 'getAll', description: 'The operation to perform.', @@ -162,6 +167,28 @@ export const estimateFields = [ }, }, description: 'The ID of the estimate you are retrieving.', +}, + +/* -------------------------------------------------------------------------- */ +/* estimate:delete */ +/* -------------------------------------------------------------------------- */ +{ + displayName: 'Estimate Id', + name: 'id', + type: 'string', + default: '', + required: true, + displayOptions: { + show: { + operation: [ + 'delete', + ], + resource: [ + 'estimate', + ], + }, + }, + description: 'The ID of the estimate want to delete.', } ] as INodeProperties[]; diff --git a/packages/nodes-base/nodes/Harvest/ExpenseDescription.ts b/packages/nodes-base/nodes/Harvest/ExpenseDescription.ts index 54659e4a3..96626056a 100644 --- a/packages/nodes-base/nodes/Harvest/ExpenseDescription.ts +++ b/packages/nodes-base/nodes/Harvest/ExpenseDescription.ts @@ -23,6 +23,11 @@ export const expenseOperations = [ value: 'getAll', description: 'Get data of all expenses', }, + { + name: 'Delete', + value: 'delete', + description: `Delete an expense`, + }, ], default: 'getAll', description: 'The operation to perform.', @@ -176,6 +181,28 @@ export const expenseFields = [ }, }, description: 'The ID of the expense you are retrieving.', +}, + +/* -------------------------------------------------------------------------- */ +/* expense:delete */ +/* -------------------------------------------------------------------------- */ +{ + displayName: 'Expense Id', + name: 'id', + type: 'string', + default: '', + required: true, + displayOptions: { + show: { + operation: [ + 'delete', + ], + resource: [ + 'expense', + ], + }, + }, + description: 'The ID of the expense you want to delete.', } ] as INodeProperties[]; diff --git a/packages/nodes-base/nodes/Harvest/Harvest.node.ts b/packages/nodes-base/nodes/Harvest/Harvest.node.ts index d8bef6ea1..dba51023a 100644 --- a/packages/nodes-base/nodes/Harvest/Harvest.node.ts +++ b/packages/nodes-base/nodes/Harvest/Harvest.node.ts @@ -306,6 +306,17 @@ export class Harvest implements INodeType { const responseData: IDataObject[] = await getAllResource.call(this, 'clients', i); returnData.push.apply(returnData, responseData); + } else if (operation === 'delete') { + // ---------------------------------- + // delete + // ---------------------------------- + + requestMethod = 'DELETE'; + const id = this.getNodeParameter('id', i) as string; + endpoint = `clients/${id}`; + + const responseData = await harvestApiRequest.call(this, requestMethod, qs, endpoint); + returnData.push(responseData); } else { throw new Error(`The resource "${resource}" is not known!`); } @@ -331,6 +342,17 @@ export class Harvest implements INodeType { const responseData: IDataObject[] = await getAllResource.call(this, 'projects', i); returnData.push.apply(returnData, responseData); + } else if (operation === 'delete') { + // ---------------------------------- + // delete + // ---------------------------------- + + requestMethod = 'DELETE'; + const id = this.getNodeParameter('id', i) as string; + endpoint = `projects/${id}`; + + const responseData = await harvestApiRequest.call(this, requestMethod, qs, endpoint); + returnData.push(responseData); } else { throw new Error(`The resource "${resource}" is not known!`); } @@ -368,7 +390,18 @@ export class Harvest implements INodeType { const responseData = await harvestApiRequest.call(this, requestMethod, qs, endpoint); returnData.push(responseData); - } else { + } else if (operation === 'delete') { + // ---------------------------------- + // delete + // ---------------------------------- + + requestMethod = 'DELETE'; + const id = this.getNodeParameter('id', i) as string; + endpoint = `users/${id}`; + + const responseData = await harvestApiRequest.call(this, requestMethod, qs, endpoint); + returnData.push(responseData); + } else { throw new Error(`The resource "${resource}" is not known!`); } } else if (resource === 'contact') { @@ -393,7 +426,18 @@ export class Harvest implements INodeType { const responseData: IDataObject[] = await getAllResource.call(this, 'contacts', i); returnData.push.apply(returnData, responseData); - } else { + } else if (operation === 'delete') { + // ---------------------------------- + // delete + // ---------------------------------- + + requestMethod = 'DELETE'; + const id = this.getNodeParameter('id', i) as string; + endpoint = `contacts/${id}`; + + const responseData = await harvestApiRequest.call(this, requestMethod, qs, endpoint); + returnData.push(responseData); + } else { throw new Error(`The resource "${resource}" is not known!`); } } else if (resource === 'company') { @@ -433,6 +477,17 @@ export class Harvest implements INodeType { const responseData: IDataObject[] = await getAllResource.call(this, 'tasks', i); returnData.push.apply(returnData, responseData); + } else if (operation === 'delete') { + // ---------------------------------- + // delete + // ---------------------------------- + + requestMethod = 'DELETE'; + const id = this.getNodeParameter('id', i) as string; + endpoint = `tasks/${id}`; + + const responseData = await harvestApiRequest.call(this, requestMethod, qs, endpoint); + returnData.push(responseData); } else { throw new Error(`The resource "${resource}" is not known!`); } @@ -458,7 +513,18 @@ export class Harvest implements INodeType { const responseData: IDataObject[] = await getAllResource.call(this, 'invoices', i); returnData.push.apply(returnData, responseData); - } else { + } else if (operation === 'delete') { + // ---------------------------------- + // delete + // ---------------------------------- + + requestMethod = 'DELETE'; + const id = this.getNodeParameter('id', i) as string; + endpoint = `invoices/${id}`; + + const responseData = await harvestApiRequest.call(this, requestMethod, qs, endpoint); + returnData.push(responseData); + } else { throw new Error(`The resource "${resource}" is not known!`); } } else if (resource === 'expense') { @@ -483,7 +549,18 @@ export class Harvest implements INodeType { const responseData: IDataObject[] = await getAllResource.call(this, 'expenses', i); returnData.push.apply(returnData, responseData); - } else { + } else if (operation === 'delete') { + // ---------------------------------- + // delete + // ---------------------------------- + + requestMethod = 'DELETE'; + const id = this.getNodeParameter('id', i) as string; + endpoint = `expenses/${id}`; + + const responseData = await harvestApiRequest.call(this, requestMethod, qs, endpoint); + returnData.push(responseData); + } else { throw new Error(`The resource "${resource}" is not known!`); } } else if (resource === 'estimate') { @@ -508,7 +585,18 @@ export class Harvest implements INodeType { const responseData: IDataObject[] = await getAllResource.call(this, 'estimates', i); returnData.push.apply(returnData, responseData); - } else { + } else if (operation === 'delete') { + // ---------------------------------- + // delete + // ---------------------------------- + + requestMethod = 'DELETE'; + const id = this.getNodeParameter('id', i) as string; + endpoint = `estimates/${id}`; + + const responseData = await harvestApiRequest.call(this, requestMethod, qs, endpoint); + returnData.push(responseData); + } else { throw new Error(`The resource "${resource}" is not known!`); } } else { diff --git a/packages/nodes-base/nodes/Harvest/InvoiceDescription.ts b/packages/nodes-base/nodes/Harvest/InvoiceDescription.ts index cb876f872..fe19a8463 100644 --- a/packages/nodes-base/nodes/Harvest/InvoiceDescription.ts +++ b/packages/nodes-base/nodes/Harvest/InvoiceDescription.ts @@ -23,6 +23,11 @@ export const invoiceOperations = [ value: 'getAll', description: 'Get data of all invoices', }, + { + name: 'Delete', + value: 'delete', + description: `Delete a invoice`, + }, ], default: 'getAll', description: 'The operation to perform.', @@ -187,6 +192,28 @@ export const invoiceFields = [ }, }, description: 'The ID of the invoice you are retrieving.', +}, + +/* -------------------------------------------------------------------------- */ +/* invoice:delete */ +/* -------------------------------------------------------------------------- */ +{ + displayName: 'Invoice Id', + name: 'id', + type: 'string', + default: '', + required: true, + displayOptions: { + show: { + operation: [ + 'delete', + ], + resource: [ + 'invoice', + ], + }, + }, + description: 'The ID of the invoice want to delete.', } ] as INodeProperties[]; diff --git a/packages/nodes-base/nodes/Harvest/ProjectDescription.ts b/packages/nodes-base/nodes/Harvest/ProjectDescription.ts index a0c04531a..7d039ccab 100644 --- a/packages/nodes-base/nodes/Harvest/ProjectDescription.ts +++ b/packages/nodes-base/nodes/Harvest/ProjectDescription.ts @@ -23,6 +23,11 @@ export const projectOperations = [ value: 'getAll', description: 'Get data of all projects', }, + { + name: 'Delete', + value: 'delete', + description: `Delete a project`, + }, ], default: 'getAll', description: 'The operation to perform.', @@ -149,6 +154,28 @@ export const projectFields = [ }, }, description: 'The ID of the project you are retrieving.', +}, + +/* -------------------------------------------------------------------------- */ +/* project:delete */ +/* -------------------------------------------------------------------------- */ +{ + displayName: 'Project Id', + name: 'id', + type: 'string', + default: '', + required: true, + displayOptions: { + show: { + operation: [ + 'delete', + ], + resource: [ + 'project', + ], + }, + }, + description: 'The ID of the project want to delete.', } ] as INodeProperties[]; diff --git a/packages/nodes-base/nodes/Harvest/TaskDescription.ts b/packages/nodes-base/nodes/Harvest/TaskDescription.ts index ac35fc207..b8aea2fcd 100644 --- a/packages/nodes-base/nodes/Harvest/TaskDescription.ts +++ b/packages/nodes-base/nodes/Harvest/TaskDescription.ts @@ -23,6 +23,11 @@ export const taskOperations = [ value: 'getAll', description: 'Get data of all tasks', }, + { + name: 'Delete', + value: 'delete', + description: `Delete a task`, + }, ], default: 'getAll', description: 'The operation to perform.', @@ -141,6 +146,29 @@ export const taskFields = [ }, }, description: 'The ID of the task you are retrieving.', -} +}, + +/* -------------------------------------------------------------------------- */ +/* task:delete */ +/* -------------------------------------------------------------------------- */ +{ + displayName: 'Task Id', + name: 'id', + type: 'string', + default: '', + required: true, + displayOptions: { + show: { + operation: [ + 'delete', + ], + resource: [ + 'task', + ], + }, + }, + description: 'The ID of the task you wan to delete.', +}, + ] as INodeProperties[]; diff --git a/packages/nodes-base/nodes/Harvest/UserDescription.ts b/packages/nodes-base/nodes/Harvest/UserDescription.ts index 4e1c563c7..0a69c8fc3 100644 --- a/packages/nodes-base/nodes/Harvest/UserDescription.ts +++ b/packages/nodes-base/nodes/Harvest/UserDescription.ts @@ -28,6 +28,11 @@ export const userOperations = [ value: 'getAll', description: 'Get data of all users', }, + { + name: 'Delete', + value: 'delete', + description: `Delete a user`, + }, ], default: 'me', description: 'The operation to perform.', @@ -146,6 +151,28 @@ export const userFields = [ }, }, description: 'The ID of the user you are retrieving.', +}, + +/* -------------------------------------------------------------------------- */ +/* user:delete */ +/* -------------------------------------------------------------------------- */ +{ + displayName: 'User Id', + name: 'id', + type: 'string', + default: '', + required: true, + displayOptions: { + show: { + operation: [ + 'delete', + ], + resource: [ + 'user', + ], + }, + }, + description: 'The ID of the user you want to delete.', } ] as INodeProperties[]; From adcc482703c3525f7e09b64c99823bf14f56774a Mon Sep 17 00:00:00 2001 From: trojanh Date: Fri, 31 Jan 2020 18:49:16 +0530 Subject: [PATCH 02/14] Add user Create API --- .../nodes-base/nodes/Harvest/Harvest.node.ts | 30 +- .../nodes/Harvest/UserDescription.ts | 405 ++++++++++++------ 2 files changed, 304 insertions(+), 131 deletions(-) diff --git a/packages/nodes-base/nodes/Harvest/Harvest.node.ts b/packages/nodes-base/nodes/Harvest/Harvest.node.ts index dba51023a..2e604ad4b 100644 --- a/packages/nodes-base/nodes/Harvest/Harvest.node.ts +++ b/packages/nodes-base/nodes/Harvest/Harvest.node.ts @@ -111,7 +111,7 @@ export class Harvest implements INodeType { }, { name: 'User', - value: 'user', + value: 'users', }, ], default: 'task', @@ -356,7 +356,7 @@ export class Harvest implements INodeType { } else { throw new Error(`The resource "${resource}" is not known!`); } - } else if (resource === 'user') { + } else if (resource === 'users') { if (operation === 'get') { // ---------------------------------- // get @@ -365,7 +365,7 @@ export class Harvest implements INodeType { requestMethod = 'GET'; const id = this.getNodeParameter('id', i) as string; - endpoint = `users/${id}`; + endpoint = `${resource}/${id}`; const responseData = await harvestApiRequest.call(this, requestMethod, qs, endpoint); returnData.push(responseData); @@ -375,7 +375,7 @@ export class Harvest implements INodeType { // getAll // ---------------------------------- - const responseData: IDataObject[] = await getAllResource.call(this, 'users', i); + const responseData: IDataObject[] = await getAllResource.call(this, resource, i); returnData.push.apply(returnData, responseData); } else if (operation === 'me') { @@ -385,12 +385,30 @@ export class Harvest implements INodeType { requestMethod = 'GET'; - endpoint = 'users/me'; + endpoint = `${resource}/me`; const responseData = await harvestApiRequest.call(this, requestMethod, qs, endpoint); returnData.push(responseData); - } else if (operation === 'delete') { + } else if (operation === 'create') { + // ---------------------------------- + // createByDuration + // ---------------------------------- + + requestMethod = 'POST'; + endpoint = resource; + ['first_name', 'last_name', 'email'].forEach(val => { + body[val] = this.getNodeParameter(val, i) as string; + }) + + + const additionalFields = this.getNodeParameter('additionalFields', i) as IDataObject; + Object.assign(body, additionalFields); + + const responseData = await harvestApiRequest.call(this, requestMethod, qs, endpoint, body); + returnData.push(responseData); + + } else if (operation === 'delete') { // ---------------------------------- // delete // ---------------------------------- diff --git a/packages/nodes-base/nodes/Harvest/UserDescription.ts b/packages/nodes-base/nodes/Harvest/UserDescription.ts index 0a69c8fc3..d4f445f2d 100644 --- a/packages/nodes-base/nodes/Harvest/UserDescription.ts +++ b/packages/nodes-base/nodes/Harvest/UserDescription.ts @@ -1,5 +1,7 @@ import { INodeProperties } from "n8n-workflow"; +const resource = ['users']; + export const userOperations = [ { displayName: 'Operation', @@ -7,9 +9,7 @@ export const userOperations = [ type: 'options', displayOptions: { show: { - resource: [ - 'user', - ], + resource, }, }, options: [ @@ -28,6 +28,11 @@ export const userOperations = [ value: 'getAll', description: 'Get data of all users', }, + { + name: 'Create', + value: 'create', + description: `Create a user`, + }, { name: 'Delete', value: 'delete', @@ -42,137 +47,287 @@ export const userOperations = [ export const userFields = [ -/* -------------------------------------------------------------------------- */ -/* user:getAll */ -/* -------------------------------------------------------------------------- */ + /* -------------------------------------------------------------------------- */ + /* user:getAll */ + /* -------------------------------------------------------------------------- */ -{ - displayName: 'Return All', - name: 'returnAll', - type: 'boolean', - displayOptions: { - show: { - resource: [ - 'user', - ], - operation: [ - 'getAll', - ], - }, - }, - default: false, - description: 'Returns a list of your users.', -}, -{ - displayName: 'Limit', - name: 'limit', - type: 'number', - displayOptions: { - show: { - resource: [ - 'user', - ], - operation: [ - 'getAll', - ], - returnAll: [ - false, - ], - }, - }, - typeOptions: { - minValue: 1, - maxValue: 100, - }, - default: 100, - description: 'How many results to return.', -}, -{ - displayName: 'Filters', - name: 'filters', - type: 'collection', - placeholder: 'Add Filter', - default: {}, - displayOptions: { - show: { - resource: [ - 'user', - ], - operation: [ - 'getAll', - ], - }, - }, - options: [ - { - displayName: 'Is Active', - name: 'is_active', - type: 'boolean', - default: true, - description: 'Pass true to only return active users and false to return inactive users.', - }, - { - displayName: 'Updated Since', - name: 'updated_since', - type: 'dateTime', - default: '', - description: 'Only return users belonging to the user with the given ID.', - }, - { - displayName: 'Page', - name: 'page', - type: 'number', - typeOptions: { - minValue: 1, + { + displayName: 'Return All', + name: 'returnAll', + type: 'boolean', + displayOptions: { + show: { + resource, + operation: [ + 'getAll', + ], }, - default: 1, - description: 'The page number to use in pagination..', - } - ] -}, + }, + default: false, + description: 'Returns a list of your users.', + }, + { + displayName: 'Limit', + name: 'limit', + type: 'number', + displayOptions: { + show: { + resource, + operation: [ + 'getAll', + ], + returnAll: [ + false, + ], + }, + }, + typeOptions: { + minValue: 1, + maxValue: 100, + }, + default: 100, + description: 'How many results to return.', + }, + { + displayName: 'Filters', + name: 'filters', + type: 'collection', + placeholder: 'Add Filter', + default: {}, + displayOptions: { + show: { + resource, + operation: [ + 'getAll', + ], + }, + }, + options: [ + { + displayName: 'Is Active', + name: 'is_active', + type: 'boolean', + default: true, + description: 'Pass true to only return active users and false to return inactive users.', + }, + { + displayName: 'Updated Since', + name: 'updated_since', + type: 'dateTime', + default: '', + description: 'Only return users belonging to the user with the given ID.', + }, + { + displayName: 'Page', + name: 'page', + type: 'number', + typeOptions: { + minValue: 1, + }, + default: 1, + description: 'The page number to use in pagination..', + } + ] + }, + + /* -------------------------------------------------------------------------- */ + /* user:get */ + /* -------------------------------------------------------------------------- */ + { + displayName: 'User Id', + name: 'id', + type: 'string', + default: '', + required: true, + displayOptions: { + show: { + operation: [ + 'get', + ], + resource, + }, + }, + description: 'The ID of the user you are retrieving.', + }, + + /* -------------------------------------------------------------------------- */ + /* user:delete */ + /* -------------------------------------------------------------------------- */ + { + displayName: 'User Id', + name: 'id', + type: 'string', + default: '', + required: true, + displayOptions: { + show: { + operation: [ + 'delete', + ], + resource, + }, + }, + description: 'The ID of the user you want to delete.', + }, /* -------------------------------------------------------------------------- */ -/* user:get */ +/* user:create */ /* -------------------------------------------------------------------------- */ { - displayName: 'User Id', - name: 'id', - type: 'string', - default: '', - required: true, - displayOptions: { - show: { - operation: [ - 'get', - ], - resource: [ - 'user', - ], + displayName: 'First Name', + name: 'first_name', + type: 'string', + displayOptions: { + show: { + operation: [ + 'create', + ], + resource, + }, }, + default: '', + required: true, + description: 'The first name of the user.', }, - description: 'The ID of the user you are retrieving.', -}, - -/* -------------------------------------------------------------------------- */ -/* user:delete */ -/* -------------------------------------------------------------------------- */ -{ - displayName: 'User Id', - name: 'id', - type: 'string', - default: '', - required: true, - displayOptions: { - show: { - operation: [ - 'delete', - ], - resource: [ - 'user', - ], + { + displayName: 'Last Name', + name: 'last_name', + type: 'string', + displayOptions: { + show: { + operation: [ + 'create', + ], + resource, + }, }, + default: '', + required: true, + description: 'The last name of the user.', + }, + { + displayName: 'Email', + name: 'email', + type: 'string', + displayOptions: { + show: { + operation: [ + 'create', + ], + resource, + }, + }, + default: '', + required: true, + description: 'The email of the user.', + }, + { + displayName: 'Additional Fields', + name: 'additionalFields', + type: 'collection', + placeholder: 'Add Field', + displayOptions: { + show: { + operation: [ + 'create', + ], + resource, + }, + }, + default: {}, + options: [ + { + displayName: 'Timezone', + name: 'timezone', + type: 'string', + default: '', + description: 'The user’s timezone. Defaults to the company’s timezone. See a list of supported time zones.' + }, + { + displayName: 'Has Access To All Future Projects', + name: 'has_access_to_all_future_projects', + type: 'string', + default: '', + description: 'Whether the user should be automatically added to future projects. Defaults to false.' + }, + { + displayName: 'Is Contractor', + name: 'is_contractor', + type: 'string', + default: '', + description: 'Whether the user is a contractor or an employee. Defaults to false.' + }, + { + displayName: 'Is Admin', + name: 'is_admin', + type: 'string', + default: '', + description: 'Whether the user has Admin permissions. Defaults to false.' + }, + { + displayName: 'Is Project Manager', + name: 'is_project_manager', + type: 'string', + default: '', + description: 'Whether the user has Project Manager permissions. Defaults to false.' + }, + { + displayName: 'Can See Rates', + name: 'can_see_rates', + type: 'string', + default: '', + description: 'Whether the user can see billable rates on projects. Only applicable to Project Managers. Defaults to false.' + }, + { + displayName: 'Can Create Projects', + name: 'can_create_projects', + type: 'string', + default: '', + description: 'Whether the user can create projects. Only applicable to Project Managers. Defaults to false.' + }, + { + displayName: 'Can Create Invoices', + name: 'can_create_invoices', + type: 'string', + default: '', + description: 'Whether the user can create invoices. Only applicable to Project Managers. Defaults to false.' + }, + { + displayName: 'Is Active', + name: 'is_active', + type: 'string', + default: '', + description: 'Whether the user is active or archived. Defaults to true.' + }, + { + displayName: 'Weekly Capacity', + name: 'weekly_capacity', + type: 'string', + default: '', + description: 'The number of hours per week this person is available to work in seconds. Defaults to 126000 seconds (35 hours).' + }, + { + displayName: 'Default Hourly Rate', + name: 'default_hourly_rate', + type: 'string', + default: '', + description: 'The billable rate to use for this user when they are added to a project. Defaults to 0.' + }, + { + displayName: 'Cost Rate', + name: 'cost_rate', + type: 'string', + default: '', + description: 'The cost rate to use for this user when calculating a project’s costs vs billable amount. Defaults to 0.' + }, + { + displayName: 'Roles', + name: 'roles', + type: 'string', + default: '', + description: 'The role names assigned to this person.' + }, + ], }, - description: 'The ID of the user you want to delete.', -} ] as INodeProperties[]; From b4394ec122bcbd47fb4b475f5b797ce8754e96f0 Mon Sep 17 00:00:00 2001 From: trojanh Date: Fri, 31 Jan 2020 18:54:42 +0530 Subject: [PATCH 03/14] Add User update API --- .../nodes-base/nodes/Harvest/Harvest.node.ts | 14 ++ .../nodes/Harvest/UserDescription.ts | 157 ++++++++++++++++++ 2 files changed, 171 insertions(+) diff --git a/packages/nodes-base/nodes/Harvest/Harvest.node.ts b/packages/nodes-base/nodes/Harvest/Harvest.node.ts index 2e604ad4b..fc9dc707d 100644 --- a/packages/nodes-base/nodes/Harvest/Harvest.node.ts +++ b/packages/nodes-base/nodes/Harvest/Harvest.node.ts @@ -408,6 +408,20 @@ export class Harvest implements INodeType { const responseData = await harvestApiRequest.call(this, requestMethod, qs, endpoint, body); returnData.push(responseData); + } else if (operation === 'update') { + // ---------------------------------- + // createByDuration + // ---------------------------------- + + requestMethod = 'POST'; + endpoint = resource; + + const additionalFields = this.getNodeParameter('updateFields', i) as IDataObject; + Object.assign(body, additionalFields); + + const responseData = await harvestApiRequest.call(this, requestMethod, qs, endpoint, body); + returnData.push(responseData); + } else if (operation === 'delete') { // ---------------------------------- // delete diff --git a/packages/nodes-base/nodes/Harvest/UserDescription.ts b/packages/nodes-base/nodes/Harvest/UserDescription.ts index d4f445f2d..86728f950 100644 --- a/packages/nodes-base/nodes/Harvest/UserDescription.ts +++ b/packages/nodes-base/nodes/Harvest/UserDescription.ts @@ -33,6 +33,11 @@ export const userOperations = [ value: 'create', description: `Create a user`, }, + { + name: 'Update', + value: 'update', + description: `Update a user`, + }, { name: 'Delete', value: 'delete', @@ -330,4 +335,156 @@ export const userFields = [ ], }, + +/* -------------------------------------------------------------------------- */ +/* user:update */ +/* -------------------------------------------------------------------------- */ +{ + displayName: 'Time Entry Id', + name: 'id', + type: 'string', + default: '', + required: true, + displayOptions: { + show: { + operation: [ + 'update', + ], + resource, + }, + }, + description: 'The ID of the time entry to update.', +}, +{ + displayName: 'Update Fields', + name: 'updateFields', + type: 'collection', + placeholder: 'Add Field', + displayOptions: { + show: { + operation: [ + 'update', + ], + resource: [ + 'timeEntry', + ], + }, + }, + default: {}, + options: [ + { + displayName: 'First Name', + name: 'first_name', + type: 'string', + default: '', + description: 'The user first name' + }, + { + displayName: 'Last Name', + name: 'last_name', + type: 'string', + default: '', + description: 'The user last name' + }, + { + displayName: 'Email', + name: 'email', + type: 'string', + default: '', + description: 'The user email' + }, + { + displayName: 'Timezone', + name: 'timezone', + type: 'string', + default: '', + description: 'The user’s timezone. Defaults to the company’s timezone. See a list of supported time zones.' + }, + { + displayName: 'Has Access To All Future Projects', + name: 'has_access_to_all_future_projects', + type: 'string', + default: '', + description: 'Whether the user should be automatically added to future projects. Defaults to false.' + }, + { + displayName: 'Is Contractor', + name: 'is_contractor', + type: 'string', + default: '', + description: 'Whether the user is a contractor or an employee. Defaults to false.' + }, + { + displayName: 'Is Admin', + name: 'is_admin', + type: 'string', + default: '', + description: 'Whether the user has Admin permissions. Defaults to false.' + }, + { + displayName: 'Is Project Manager', + name: 'is_project_manager', + type: 'string', + default: '', + description: 'Whether the user has Project Manager permissions. Defaults to false.' + }, + { + displayName: 'Can See Rates', + name: 'can_see_rates', + type: 'string', + default: '', + description: 'Whether the user can see billable rates on projects. Only applicable to Project Managers. Defaults to false.' + }, + { + displayName: 'Can Create Projects', + name: 'can_create_projects', + type: 'string', + default: '', + description: 'Whether the user can create projects. Only applicable to Project Managers. Defaults to false.' + }, + { + displayName: 'Can Create Invoices', + name: 'can_create_invoices', + type: 'string', + default: '', + description: 'Whether the user can create invoices. Only applicable to Project Managers. Defaults to false.' + }, + { + displayName: 'Is Active', + name: 'is_active', + type: 'string', + default: '', + description: 'Whether the user is active or archived. Defaults to true.' + }, + { + displayName: 'Weekly Capacity', + name: 'weekly_capacity', + type: 'string', + default: '', + description: 'The number of hours per week this person is available to work in seconds. Defaults to 126000 seconds (35 hours).' + }, + { + displayName: 'Default Hourly Rate', + name: 'default_hourly_rate', + type: 'string', + default: '', + description: 'The billable rate to use for this user when they are added to a project. Defaults to 0.' + }, + { + displayName: 'Cost Rate', + name: 'cost_rate', + type: 'string', + default: '', + description: 'The cost rate to use for this user when calculating a project’s costs vs billable amount. Defaults to 0.' + }, + { + displayName: 'Roles', + name: 'roles', + type: 'string', + default: '', + description: 'The role names assigned to this person.' + }, + ], +}, + ] as INodeProperties[]; From 9ff78410ef18e17eb4c079e816294619cd5bc0f0 Mon Sep 17 00:00:00 2001 From: trojanh Date: Fri, 31 Jan 2020 19:02:14 +0530 Subject: [PATCH 04/14] Refactor time entry and user --- .../nodes-base/nodes/Harvest/Harvest.node.ts | 33 ++++---- .../nodes/Harvest/TimeEntryDescription.ts | 78 +++++-------------- .../nodes/Harvest/UserDescription.ts | 4 +- 3 files changed, 38 insertions(+), 77 deletions(-) diff --git a/packages/nodes-base/nodes/Harvest/Harvest.node.ts b/packages/nodes-base/nodes/Harvest/Harvest.node.ts index fc9dc707d..260000e6f 100644 --- a/packages/nodes-base/nodes/Harvest/Harvest.node.ts +++ b/packages/nodes-base/nodes/Harvest/Harvest.node.ts @@ -107,7 +107,7 @@ export class Harvest implements INodeType { }, { name: 'Time Entries', - value: 'timeEntry', + value: 'time_entries', }, { name: 'User', @@ -161,7 +161,7 @@ export class Harvest implements INodeType { body = {}; qs = {}; - if (resource === 'timeEntry') { + if (resource === 'time_entries') { if (operation === 'get') { // ---------------------------------- // get @@ -170,7 +170,7 @@ export class Harvest implements INodeType { requestMethod = 'GET'; const id = this.getNodeParameter('id', i) as string; - endpoint = `time_entries/${id}`; + endpoint = `${resource}/${id}`; const responseData = await harvestApiRequest.call(this, requestMethod, qs, endpoint); returnData.push(responseData); @@ -179,7 +179,7 @@ export class Harvest implements INodeType { // ---------------------------------- // getAll // ---------------------------------- - const responseData: IDataObject[] = await getAllResource.call(this, 'time_entries', i); + const responseData: IDataObject[] = await getAllResource.call(this, resource, i); returnData.push.apply(returnData, responseData); } else if (operation === 'createByStartEnd') { @@ -188,7 +188,7 @@ export class Harvest implements INodeType { // ---------------------------------- requestMethod = 'POST'; - endpoint = 'time_entries'; + endpoint = resource; body.project_id = this.getNodeParameter('projectId', i) as string; body.task_id = this.getNodeParameter('taskId', i) as string; @@ -206,7 +206,7 @@ export class Harvest implements INodeType { // ---------------------------------- requestMethod = 'POST'; - endpoint = 'time_entries'; + endpoint = resource; body.project_id = this.getNodeParameter('projectId', i) as string; body.task_id = this.getNodeParameter('taskId', i) as string; @@ -225,7 +225,7 @@ export class Harvest implements INodeType { requestMethod = 'DELETE'; const id = this.getNodeParameter('id', i) as string; - endpoint = `time_entries/${id}`; + endpoint = `${resource}/${id}`; const responseData = await harvestApiRequest.call(this, requestMethod, qs, endpoint); returnData.push(responseData); @@ -236,7 +236,7 @@ export class Harvest implements INodeType { requestMethod = 'DELETE'; const id = this.getNodeParameter('id', i) as string; - endpoint = `time_entries/${id}/external_reference`; + endpoint = `${resource}/${id}/external_reference`; const responseData = await harvestApiRequest.call(this, requestMethod, qs, endpoint); returnData.push(responseData); @@ -248,7 +248,7 @@ export class Harvest implements INodeType { requestMethod = 'PATCH'; const id = this.getNodeParameter('id', i) as string; - endpoint = `time_entries/${id}/restart`; + endpoint = `${resource}/${id}/restart`; const responseData = await harvestApiRequest.call(this, requestMethod, qs, endpoint); returnData.push(responseData); @@ -260,7 +260,7 @@ export class Harvest implements INodeType { requestMethod = 'PATCH'; const id = this.getNodeParameter('id', i) as string; - endpoint = `time_entries/${id}/stop`; + endpoint = `${resource}/${id}/stop`; const responseData = await harvestApiRequest.call(this, requestMethod, qs, endpoint); returnData.push(responseData); @@ -272,7 +272,7 @@ export class Harvest implements INodeType { requestMethod = 'PATCH'; const id = this.getNodeParameter('id', i) as string; - endpoint = `time_entries/${id}`; + endpoint = `${resource}/${id}`; const updateFields = this.getNodeParameter('updateFields', i) as IDataObject; @@ -397,9 +397,10 @@ export class Harvest implements INodeType { requestMethod = 'POST'; endpoint = resource; - ['first_name', 'last_name', 'email'].forEach(val => { - body[val] = this.getNodeParameter(val, i) as string; - }) + + body.first_name = this.getNodeParameter('first_name', i) as string; + body.last_name = this.getNodeParameter('last_name', i) as string; + body.email = this.getNodeParameter('email', i) as string; const additionalFields = this.getNodeParameter('additionalFields', i) as IDataObject; @@ -416,8 +417,8 @@ export class Harvest implements INodeType { requestMethod = 'POST'; endpoint = resource; - const additionalFields = this.getNodeParameter('updateFields', i) as IDataObject; - Object.assign(body, additionalFields); + const updateFields = this.getNodeParameter('updateFields', i) as IDataObject; + Object.assign(qs, updateFields); const responseData = await harvestApiRequest.call(this, requestMethod, qs, endpoint, body); returnData.push(responseData); diff --git a/packages/nodes-base/nodes/Harvest/TimeEntryDescription.ts b/packages/nodes-base/nodes/Harvest/TimeEntryDescription.ts index a1ba83e2a..b16a810bc 100644 --- a/packages/nodes-base/nodes/Harvest/TimeEntryDescription.ts +++ b/packages/nodes-base/nodes/Harvest/TimeEntryDescription.ts @@ -1,5 +1,5 @@ import { INodeProperties } from "n8n-workflow"; - +export const resource = [ 'time_entries' ] export const timeEntryOperations = [ { displayName: 'Operation', @@ -7,9 +7,7 @@ export const timeEntryOperations = [ type: 'options', displayOptions: { show: { - resource: [ - 'timeEntry', - ], + resource, }, }, options: [ @@ -75,9 +73,7 @@ export const timeEntryFields = [ type: 'boolean', displayOptions: { show: { - resource: [ - 'timeEntry', - ], + resource, operation: [ 'getAll', ], @@ -92,9 +88,7 @@ export const timeEntryFields = [ type: 'number', displayOptions: { show: { - resource: [ - 'timeEntry', - ], + resource, operation: [ 'getAll', ], @@ -118,9 +112,7 @@ export const timeEntryFields = [ default: {}, displayOptions: { show: { - resource: [ - 'timeEntry', - ], + resource, operation: [ 'getAll', ], @@ -203,9 +195,7 @@ export const timeEntryFields = [ operation: [ 'get', ], - resource: [ - 'timeEntry', - ], + resource, }, }, description: 'The ID of the time entry you are retrieving.', @@ -225,9 +215,7 @@ export const timeEntryFields = [ operation: [ 'delete', ], - resource: [ - 'timeEntry', - ], + resource, }, }, description: 'The ID of the time entry you are deleting.', @@ -247,9 +235,7 @@ export const timeEntryFields = [ operation: [ 'deleteExternal', ], - resource: [ - 'timeEntry', - ], + resource, }, }, description: 'The ID of the time entry whose external reference you are deleting.', @@ -269,9 +255,7 @@ export const timeEntryFields = [ operation: [ 'stopTime', ], - resource: [ - 'timeEntry', - ], + resource, }, }, description: 'Stop a running time entry. Stopping a time entry is only possible if it’s currently running.', @@ -291,9 +275,7 @@ export const timeEntryFields = [ operation: [ 'restartTime', ], - resource: [ - 'timeEntry', - ], + resource, }, }, description: 'Restart a stopped time entry. Restarting a time entry is only possible if it isn’t currently running.', @@ -313,9 +295,7 @@ export const timeEntryFields = [ operation: [ 'update', ], - resource: [ - 'timeEntry', - ], + resource, }, }, description: 'The ID of the time entry to update.', @@ -330,9 +310,7 @@ export const timeEntryFields = [ operation: [ 'update', ], - resource: [ - 'timeEntry', - ], + resource, }, }, default: {}, @@ -385,9 +363,7 @@ export const timeEntryFields = [ operation: [ 'createByDuration', ], - resource: [ - 'timeEntry', - ], + resource, }, }, default: '', @@ -403,9 +379,7 @@ export const timeEntryFields = [ operation: [ 'createByDuration', ], - resource: [ - 'timeEntry', - ], + resource, }, }, default: '', @@ -421,9 +395,7 @@ export const timeEntryFields = [ operation: [ 'createByDuration', ], - resource: [ - 'timeEntry', - ], + resource, }, }, default: '', @@ -440,9 +412,7 @@ export const timeEntryFields = [ operation: [ 'createByDuration', ], - resource: [ - 'timeEntry', - ], + resource, }, }, default: {}, @@ -486,9 +456,7 @@ export const timeEntryFields = [ operation: [ 'createByStartEnd', ], - resource: [ - 'timeEntry', - ], + resource, }, }, default: '', @@ -504,9 +472,7 @@ export const timeEntryFields = [ operation: [ 'createByStartEnd', ], - resource: [ - 'timeEntry', - ], + resource, }, }, default: '', @@ -522,9 +488,7 @@ export const timeEntryFields = [ operation: [ 'createByStartEnd', ], - resource: [ - 'timeEntry', - ], + resource, }, }, default: '', @@ -541,9 +505,7 @@ export const timeEntryFields = [ operation: [ 'createByStartEnd', ], - resource: [ - 'timeEntry', - ], + resource, }, }, default: {}, diff --git a/packages/nodes-base/nodes/Harvest/UserDescription.ts b/packages/nodes-base/nodes/Harvest/UserDescription.ts index 86728f950..2c8023ac2 100644 --- a/packages/nodes-base/nodes/Harvest/UserDescription.ts +++ b/packages/nodes-base/nodes/Harvest/UserDescription.ts @@ -365,9 +365,7 @@ export const userFields = [ operation: [ 'update', ], - resource: [ - 'timeEntry', - ], + resource }, }, default: {}, From 1759f6ce981e09b36765b932ba99abefe682149d Mon Sep 17 00:00:00 2001 From: trojanh Date: Fri, 31 Jan 2020 19:13:40 +0530 Subject: [PATCH 05/14] Refactor reource names to match endpoint --- .../nodes/Harvest/ClientDescription.ts | 26 ++----- .../nodes/Harvest/CompanyDescription.ts | 6 +- .../nodes/Harvest/ContactDescription.ts | 26 ++----- .../nodes/Harvest/EstimateDescription.ts | 26 ++----- .../nodes/Harvest/ExpenseDescription.ts | 26 ++----- .../nodes-base/nodes/Harvest/Harvest.node.ts | 78 +++++++++---------- .../nodes/Harvest/InvoiceDescription.ts | 26 ++----- .../nodes/Harvest/ProjectDescription.ts | 26 ++----- .../nodes/Harvest/TaskDescription.ts | 26 ++----- 9 files changed, 97 insertions(+), 169 deletions(-) diff --git a/packages/nodes-base/nodes/Harvest/ClientDescription.ts b/packages/nodes-base/nodes/Harvest/ClientDescription.ts index fe769b5eb..565cbf063 100644 --- a/packages/nodes-base/nodes/Harvest/ClientDescription.ts +++ b/packages/nodes-base/nodes/Harvest/ClientDescription.ts @@ -1,5 +1,7 @@ import { INodeProperties } from "n8n-workflow"; +const resource = [ 'clients' ]; + export const clientOperations = [ { displayName: 'Operation', @@ -7,9 +9,7 @@ export const clientOperations = [ type: 'options', displayOptions: { show: { - resource: [ - 'client', - ], + resource }, }, options: [ @@ -47,9 +47,7 @@ export const clientFields = [ type: 'boolean', displayOptions: { show: { - resource: [ - 'client', - ], + resource operation: [ 'getAll', ], @@ -64,9 +62,7 @@ export const clientFields = [ type: 'number', displayOptions: { show: { - resource: [ - 'client', - ], + resource operation: [ 'getAll', ], @@ -90,9 +86,7 @@ export const clientFields = [ default: {}, displayOptions: { show: { - resource: [ - 'client', - ], + resource operation: [ 'getAll', ], @@ -130,9 +124,7 @@ export const clientFields = [ operation: [ 'get', ], - resource: [ - 'client', - ], + resource }, }, description: 'The ID of the client you are retrieving.', @@ -152,9 +144,7 @@ export const clientFields = [ operation: [ 'delete', ], - resource: [ - 'client', - ], + resource }, }, description: 'The ID of the client you want to delete.', diff --git a/packages/nodes-base/nodes/Harvest/CompanyDescription.ts b/packages/nodes-base/nodes/Harvest/CompanyDescription.ts index 26303b7eb..8de3c255c 100644 --- a/packages/nodes-base/nodes/Harvest/CompanyDescription.ts +++ b/packages/nodes-base/nodes/Harvest/CompanyDescription.ts @@ -1,5 +1,7 @@ import { INodeProperties } from "n8n-workflow"; +const resource = [ 'companies' ]; + export const companyOperations = [ { displayName: 'Operation', @@ -7,9 +9,7 @@ export const companyOperations = [ type: 'options', displayOptions: { show: { - resource: [ - 'company', - ], + resource, }, }, options: [ diff --git a/packages/nodes-base/nodes/Harvest/ContactDescription.ts b/packages/nodes-base/nodes/Harvest/ContactDescription.ts index 1c1d645fe..66dd0386e 100644 --- a/packages/nodes-base/nodes/Harvest/ContactDescription.ts +++ b/packages/nodes-base/nodes/Harvest/ContactDescription.ts @@ -1,5 +1,7 @@ import { INodeProperties } from "n8n-workflow"; +const resource = [ 'contacts' ]; + export const contactOperations = [ { displayName: 'Operation', @@ -7,9 +9,7 @@ export const contactOperations = [ type: 'options', displayOptions: { show: { - resource: [ - 'contact', - ], + resource, }, }, options: [ @@ -47,9 +47,7 @@ export const contactFields = [ type: 'boolean', displayOptions: { show: { - resource: [ - 'contact', - ], + resource, operation: [ 'getAll', ], @@ -64,9 +62,7 @@ export const contactFields = [ type: 'number', displayOptions: { show: { - resource: [ - 'contact', - ], + resource, operation: [ 'getAll', ], @@ -90,9 +86,7 @@ export const contactFields = [ default: {}, displayOptions: { show: { - resource: [ - 'contact', - ], + resource, operation: [ 'getAll', ], @@ -130,9 +124,7 @@ export const contactFields = [ operation: [ 'get', ], - resource: [ - 'contact', - ], + resource, }, }, description: 'The ID of the contact you are retrieving.', @@ -152,9 +144,7 @@ export const contactFields = [ operation: [ 'delete', ], - resource: [ - 'contact', - ], + resource, }, }, description: 'The ID of the contact you want to delete.', diff --git a/packages/nodes-base/nodes/Harvest/EstimateDescription.ts b/packages/nodes-base/nodes/Harvest/EstimateDescription.ts index cc0e3e02a..4216ab0db 100644 --- a/packages/nodes-base/nodes/Harvest/EstimateDescription.ts +++ b/packages/nodes-base/nodes/Harvest/EstimateDescription.ts @@ -1,5 +1,7 @@ import { INodeProperties } from "n8n-workflow"; +const resource = [ 'estimates' ]; + export const estimateOperations = [ { displayName: 'Operation', @@ -7,9 +9,7 @@ export const estimateOperations = [ type: 'options', displayOptions: { show: { - resource: [ - 'estimate', - ], + resource, }, }, options: [ @@ -47,9 +47,7 @@ export const estimateFields = [ type: 'boolean', displayOptions: { show: { - resource: [ - 'estimate', - ], + resource, operation: [ 'getAll', ], @@ -64,9 +62,7 @@ export const estimateFields = [ type: 'number', displayOptions: { show: { - resource: [ - 'estimate', - ], + resource, operation: [ 'getAll', ], @@ -90,9 +86,7 @@ export const estimateFields = [ default: {}, displayOptions: { show: { - resource: [ - 'estimate', - ], + resource, operation: [ 'getAll', ], @@ -161,9 +155,7 @@ export const estimateFields = [ operation: [ 'get', ], - resource: [ - 'estimate', - ], + resource, }, }, description: 'The ID of the estimate you are retrieving.', @@ -183,9 +175,7 @@ export const estimateFields = [ operation: [ 'delete', ], - resource: [ - 'estimate', - ], + resource, }, }, description: 'The ID of the estimate want to delete.', diff --git a/packages/nodes-base/nodes/Harvest/ExpenseDescription.ts b/packages/nodes-base/nodes/Harvest/ExpenseDescription.ts index 96626056a..ff1613d62 100644 --- a/packages/nodes-base/nodes/Harvest/ExpenseDescription.ts +++ b/packages/nodes-base/nodes/Harvest/ExpenseDescription.ts @@ -1,5 +1,7 @@ import { INodeProperties } from "n8n-workflow"; +const resource = [ 'invoices' ]; + export const expenseOperations = [ { displayName: 'Operation', @@ -7,9 +9,7 @@ export const expenseOperations = [ type: 'options', displayOptions: { show: { - resource: [ - 'expense', - ], + resource, }, }, options: [ @@ -47,9 +47,7 @@ export const expenseFields = [ type: 'boolean', displayOptions: { show: { - resource: [ - 'expense', - ], + resource, operation: [ 'getAll', ], @@ -64,9 +62,7 @@ export const expenseFields = [ type: 'number', displayOptions: { show: { - resource: [ - 'expense', - ], + resource, operation: [ 'getAll', ], @@ -90,9 +86,7 @@ export const expenseFields = [ default: {}, displayOptions: { show: { - resource: [ - 'expense', - ], + resource, operation: [ 'getAll', ], @@ -175,9 +169,7 @@ export const expenseFields = [ operation: [ 'get', ], - resource: [ - 'expense', - ], + resource, }, }, description: 'The ID of the expense you are retrieving.', @@ -197,9 +189,7 @@ export const expenseFields = [ operation: [ 'delete', ], - resource: [ - 'expense', - ], + resource, }, }, description: 'The ID of the expense you want to delete.', diff --git a/packages/nodes-base/nodes/Harvest/Harvest.node.ts b/packages/nodes-base/nodes/Harvest/Harvest.node.ts index 260000e6f..2cd1b0c6f 100644 --- a/packages/nodes-base/nodes/Harvest/Harvest.node.ts +++ b/packages/nodes-base/nodes/Harvest/Harvest.node.ts @@ -75,35 +75,35 @@ export class Harvest implements INodeType { { name: 'Client', - value: 'client', + value: 'clients', }, { name: 'Company', - value: 'company', + value: 'companies', }, { name: 'Contact', - value: 'contact', + value: 'contacts', }, { name: 'Estimates', - value: 'estimate', + value: 'estimates', }, { name: 'Expense', - value: 'expense', + value: 'expenses', }, { name: 'Invoice', - value: 'invoice', + value: 'invoices', }, { name: 'Project', - value: 'project', + value: 'projects', }, { name: 'Task', - value: 'task', + value: 'tasks', }, { name: 'Time Entries', @@ -114,7 +114,7 @@ export class Harvest implements INodeType { value: 'users', }, ], - default: 'task', + default: 'tasks', description: 'The resource to operate on.', }, @@ -284,7 +284,7 @@ export class Harvest implements INodeType { throw new Error(`The operation "${operation}" is not known!`); } - } else if (resource === 'client') { + } else if (resource === 'clients') { if (operation === 'get') { // ---------------------------------- // get @@ -293,7 +293,7 @@ export class Harvest implements INodeType { requestMethod = 'GET'; const id = this.getNodeParameter('id', i) as string; - endpoint = `clients/${id}`; + endpoint = `${resource}/${id}`; const responseData = await harvestApiRequest.call(this, requestMethod, qs, endpoint); returnData.push(responseData); @@ -303,7 +303,7 @@ export class Harvest implements INodeType { // getAll // ---------------------------------- - const responseData: IDataObject[] = await getAllResource.call(this, 'clients', i); + const responseData: IDataObject[] = await getAllResource.call(this, resource, i); returnData.push.apply(returnData, responseData); } else if (operation === 'delete') { @@ -313,14 +313,14 @@ export class Harvest implements INodeType { requestMethod = 'DELETE'; const id = this.getNodeParameter('id', i) as string; - endpoint = `clients/${id}`; + endpoint = `${resource}/${id}`; const responseData = await harvestApiRequest.call(this, requestMethod, qs, endpoint); returnData.push(responseData); } else { throw new Error(`The resource "${resource}" is not known!`); } - } else if (resource === 'project') { + } else if (resource === 'projects') { if (operation === 'get') { // ---------------------------------- // get @@ -329,7 +329,7 @@ export class Harvest implements INodeType { requestMethod = 'GET'; const id = this.getNodeParameter('id', i) as string; - endpoint = `projects/${id}`; + endpoint = `${resource}/${id}`; const responseData = await harvestApiRequest.call(this, requestMethod, qs, endpoint); returnData.push(responseData); @@ -339,7 +339,7 @@ export class Harvest implements INodeType { // getAll // ---------------------------------- - const responseData: IDataObject[] = await getAllResource.call(this, 'projects', i); + const responseData: IDataObject[] = await getAllResource.call(this, resource, i); returnData.push.apply(returnData, responseData); } else if (operation === 'delete') { @@ -349,7 +349,7 @@ export class Harvest implements INodeType { requestMethod = 'DELETE'; const id = this.getNodeParameter('id', i) as string; - endpoint = `projects/${id}`; + endpoint = `${resource}/${id}`; const responseData = await harvestApiRequest.call(this, requestMethod, qs, endpoint); returnData.push(responseData); @@ -430,14 +430,14 @@ export class Harvest implements INodeType { requestMethod = 'DELETE'; const id = this.getNodeParameter('id', i) as string; - endpoint = `users/${id}`; + endpoint = `${resource}/${id}`; const responseData = await harvestApiRequest.call(this, requestMethod, qs, endpoint); returnData.push(responseData); } else { throw new Error(`The resource "${resource}" is not known!`); } - } else if (resource === 'contact') { + } else if (resource === 'contacts') { if (operation === 'get') { // ---------------------------------- // get @@ -446,7 +446,7 @@ export class Harvest implements INodeType { requestMethod = 'GET'; const id = this.getNodeParameter('id', i) as string; - endpoint = `contacts/${id}`; + endpoint = `${resource}/${id}`; const responseData = await harvestApiRequest.call(this, requestMethod, qs, endpoint); returnData.push(responseData); @@ -456,7 +456,7 @@ export class Harvest implements INodeType { // getAll // ---------------------------------- - const responseData: IDataObject[] = await getAllResource.call(this, 'contacts', i); + const responseData: IDataObject[] = await getAllResource.call(this, resource, i); returnData.push.apply(returnData, responseData); } else if (operation === 'delete') { @@ -466,14 +466,14 @@ export class Harvest implements INodeType { requestMethod = 'DELETE'; const id = this.getNodeParameter('id', i) as string; - endpoint = `contacts/${id}`; + endpoint = `${resource}/${id}`; const responseData = await harvestApiRequest.call(this, requestMethod, qs, endpoint); returnData.push(responseData); } else { throw new Error(`The resource "${resource}" is not known!`); } - } else if (resource === 'company') { + } else if (resource === 'companies') { if (operation === 'get') { // ---------------------------------- // get @@ -488,7 +488,7 @@ export class Harvest implements INodeType { } else { throw new Error(`The resource "${resource}" is not known!`); } - } else if (resource === 'task') { + } else if (resource === 'tasks') { if (operation === 'get') { // ---------------------------------- // get @@ -497,7 +497,7 @@ export class Harvest implements INodeType { requestMethod = 'GET'; const id = this.getNodeParameter('id', i) as string; - endpoint = `tasks/${id}`; + endpoint = `${resource}/${id}`; const responseData = await harvestApiRequest.call(this, requestMethod, qs, endpoint); returnData.push(responseData); @@ -507,7 +507,7 @@ export class Harvest implements INodeType { // getAll // ---------------------------------- - const responseData: IDataObject[] = await getAllResource.call(this, 'tasks', i); + const responseData: IDataObject[] = await getAllResource.call(this, resource, i); returnData.push.apply(returnData, responseData); } else if (operation === 'delete') { @@ -517,14 +517,14 @@ export class Harvest implements INodeType { requestMethod = 'DELETE'; const id = this.getNodeParameter('id', i) as string; - endpoint = `tasks/${id}`; + endpoint = `${resource}/${id}`; const responseData = await harvestApiRequest.call(this, requestMethod, qs, endpoint); returnData.push(responseData); } else { throw new Error(`The resource "${resource}" is not known!`); } - } else if (resource === 'invoice') { + } else if (resource === 'invoices') { if (operation === 'get') { // ---------------------------------- // get @@ -533,7 +533,7 @@ export class Harvest implements INodeType { requestMethod = 'GET'; const id = this.getNodeParameter('id', i) as string; - endpoint = `invoices/${id}`; + endpoint = `${resource}/${id}`; const responseData = await harvestApiRequest.call(this, requestMethod, qs, endpoint); returnData.push(responseData); @@ -543,7 +543,7 @@ export class Harvest implements INodeType { // getAll // ---------------------------------- - const responseData: IDataObject[] = await getAllResource.call(this, 'invoices', i); + const responseData: IDataObject[] = await getAllResource.call(this, resource, i); returnData.push.apply(returnData, responseData); } else if (operation === 'delete') { @@ -553,14 +553,14 @@ export class Harvest implements INodeType { requestMethod = 'DELETE'; const id = this.getNodeParameter('id', i) as string; - endpoint = `invoices/${id}`; + endpoint = `${resource}/${id}`; const responseData = await harvestApiRequest.call(this, requestMethod, qs, endpoint); returnData.push(responseData); } else { throw new Error(`The resource "${resource}" is not known!`); } - } else if (resource === 'expense') { + } else if (resource === 'expenses') { if (operation === 'get') { // ---------------------------------- // get @@ -569,7 +569,7 @@ export class Harvest implements INodeType { requestMethod = 'GET'; const id = this.getNodeParameter('id', i) as string; - endpoint = `expenses/${id}`; + endpoint = `${resource}/${id}`; const responseData = await harvestApiRequest.call(this, requestMethod, qs, endpoint); returnData.push(responseData); @@ -579,7 +579,7 @@ export class Harvest implements INodeType { // getAll // ---------------------------------- - const responseData: IDataObject[] = await getAllResource.call(this, 'expenses', i); + const responseData: IDataObject[] = await getAllResource.call(this, resource, i); returnData.push.apply(returnData, responseData); } else if (operation === 'delete') { @@ -589,14 +589,14 @@ export class Harvest implements INodeType { requestMethod = 'DELETE'; const id = this.getNodeParameter('id', i) as string; - endpoint = `expenses/${id}`; + endpoint = `${resource}/${id}`; const responseData = await harvestApiRequest.call(this, requestMethod, qs, endpoint); returnData.push(responseData); } else { throw new Error(`The resource "${resource}" is not known!`); } - } else if (resource === 'estimate') { + } else if (resource === 'estimates') { if (operation === 'get') { // ---------------------------------- // get @@ -605,7 +605,7 @@ export class Harvest implements INodeType { requestMethod = 'GET'; const id = this.getNodeParameter('id', i) as string; - endpoint = `estimates/${id}`; + endpoint = `${resource}/${id}`; const responseData = await harvestApiRequest.call(this, requestMethod, qs, endpoint); returnData.push(responseData); @@ -615,7 +615,7 @@ export class Harvest implements INodeType { // getAll // ---------------------------------- - const responseData: IDataObject[] = await getAllResource.call(this, 'estimates', i); + const responseData: IDataObject[] = await getAllResource.call(this, resource, i); returnData.push.apply(returnData, responseData); } else if (operation === 'delete') { @@ -625,7 +625,7 @@ export class Harvest implements INodeType { requestMethod = 'DELETE'; const id = this.getNodeParameter('id', i) as string; - endpoint = `estimates/${id}`; + endpoint = `${resource}/${id}`; const responseData = await harvestApiRequest.call(this, requestMethod, qs, endpoint); returnData.push(responseData); diff --git a/packages/nodes-base/nodes/Harvest/InvoiceDescription.ts b/packages/nodes-base/nodes/Harvest/InvoiceDescription.ts index fe19a8463..8ec5814df 100644 --- a/packages/nodes-base/nodes/Harvest/InvoiceDescription.ts +++ b/packages/nodes-base/nodes/Harvest/InvoiceDescription.ts @@ -1,5 +1,7 @@ import { INodeProperties } from "n8n-workflow"; +const resource = [ 'invoices' ]; + export const invoiceOperations = [ { displayName: 'Operation', @@ -7,9 +9,7 @@ export const invoiceOperations = [ type: 'options', displayOptions: { show: { - resource: [ - 'invoice', - ], + resource, }, }, options: [ @@ -47,9 +47,7 @@ export const invoiceFields = [ type: 'boolean', displayOptions: { show: { - resource: [ - 'invoice', - ], + resource, operation: [ 'getAll', ], @@ -64,9 +62,7 @@ export const invoiceFields = [ type: 'number', displayOptions: { show: { - resource: [ - 'invoice', - ], + resource, operation: [ 'getAll', ], @@ -90,9 +86,7 @@ export const invoiceFields = [ default: {}, displayOptions: { show: { - resource: [ - 'invoice', - ], + resource, operation: [ 'getAll', ], @@ -186,9 +180,7 @@ export const invoiceFields = [ operation: [ 'get', ], - resource: [ - 'invoice', - ], + resource, }, }, description: 'The ID of the invoice you are retrieving.', @@ -208,9 +200,7 @@ export const invoiceFields = [ operation: [ 'delete', ], - resource: [ - 'invoice', - ], + resource, }, }, description: 'The ID of the invoice want to delete.', diff --git a/packages/nodes-base/nodes/Harvest/ProjectDescription.ts b/packages/nodes-base/nodes/Harvest/ProjectDescription.ts index 7d039ccab..c80c67724 100644 --- a/packages/nodes-base/nodes/Harvest/ProjectDescription.ts +++ b/packages/nodes-base/nodes/Harvest/ProjectDescription.ts @@ -1,5 +1,7 @@ import { INodeProperties } from "n8n-workflow"; +const resource = [ 'projects' ]; + export const projectOperations = [ { displayName: 'Operation', @@ -7,9 +9,7 @@ export const projectOperations = [ type: 'options', displayOptions: { show: { - resource: [ - 'project', - ], + resource, }, }, options: [ @@ -47,9 +47,7 @@ export const projectFields = [ type: 'boolean', displayOptions: { show: { - resource: [ - 'project', - ], + resource, operation: [ 'getAll', ], @@ -64,9 +62,7 @@ export const projectFields = [ type: 'number', displayOptions: { show: { - resource: [ - 'project', - ], + resource, operation: [ 'getAll', ], @@ -90,9 +86,7 @@ export const projectFields = [ default: {}, displayOptions: { show: { - resource: [ - 'project', - ], + resource, operation: [ 'getAll', ], @@ -148,9 +142,7 @@ export const projectFields = [ operation: [ 'get', ], - resource: [ - 'project', - ], + resource, }, }, description: 'The ID of the project you are retrieving.', @@ -170,9 +162,7 @@ export const projectFields = [ operation: [ 'delete', ], - resource: [ - 'project', - ], + resource, }, }, description: 'The ID of the project want to delete.', diff --git a/packages/nodes-base/nodes/Harvest/TaskDescription.ts b/packages/nodes-base/nodes/Harvest/TaskDescription.ts index b8aea2fcd..feb404d8b 100644 --- a/packages/nodes-base/nodes/Harvest/TaskDescription.ts +++ b/packages/nodes-base/nodes/Harvest/TaskDescription.ts @@ -1,5 +1,5 @@ import { INodeProperties } from "n8n-workflow"; - +const resource = [ 'tasks' ]; export const taskOperations = [ { displayName: 'Operation', @@ -7,9 +7,7 @@ export const taskOperations = [ type: 'options', displayOptions: { show: { - resource: [ - 'task', - ], + resource, }, }, options: [ @@ -47,9 +45,7 @@ export const taskFields = [ type: 'boolean', displayOptions: { show: { - resource: [ - 'task', - ], + resource, operation: [ 'getAll', ], @@ -64,9 +60,7 @@ export const taskFields = [ type: 'number', displayOptions: { show: { - resource: [ - 'task', - ], + resource, operation: [ 'getAll', ], @@ -90,9 +84,7 @@ export const taskFields = [ default: {}, displayOptions: { show: { - resource: [ - 'task', - ], + resource, operation: [ 'getAll', ], @@ -140,9 +132,7 @@ export const taskFields = [ operation: [ 'get', ], - resource: [ - 'task', - ], + resource, }, }, description: 'The ID of the task you are retrieving.', @@ -162,9 +152,7 @@ export const taskFields = [ operation: [ 'delete', ], - resource: [ - 'task', - ], + resource, }, }, description: 'The ID of the task you wan to delete.', From cc302b7508ab2e9431d9c3c7a0dd33928cdab251 Mon Sep 17 00:00:00 2001 From: trojanh Date: Fri, 31 Jan 2020 19:36:10 +0530 Subject: [PATCH 06/14] Add task create and update --- .../nodes/Harvest/ClientDescription.ts | 8 +- .../nodes-base/nodes/Harvest/Harvest.node.ts | 32 +- .../nodes/Harvest/TaskDescription.ts | 364 ++++++++++++------ .../nodes/Harvest/UserDescription.ts | 296 +++++++------- 4 files changed, 430 insertions(+), 270 deletions(-) diff --git a/packages/nodes-base/nodes/Harvest/ClientDescription.ts b/packages/nodes-base/nodes/Harvest/ClientDescription.ts index 565cbf063..532d3a67a 100644 --- a/packages/nodes-base/nodes/Harvest/ClientDescription.ts +++ b/packages/nodes-base/nodes/Harvest/ClientDescription.ts @@ -9,7 +9,7 @@ export const clientOperations = [ type: 'options', displayOptions: { show: { - resource + resource, }, }, options: [ @@ -47,7 +47,7 @@ export const clientFields = [ type: 'boolean', displayOptions: { show: { - resource + resource, operation: [ 'getAll', ], @@ -62,7 +62,7 @@ export const clientFields = [ type: 'number', displayOptions: { show: { - resource + resource, operation: [ 'getAll', ], @@ -86,7 +86,7 @@ export const clientFields = [ default: {}, displayOptions: { show: { - resource + resource, operation: [ 'getAll', ], diff --git a/packages/nodes-base/nodes/Harvest/Harvest.node.ts b/packages/nodes-base/nodes/Harvest/Harvest.node.ts index 2cd1b0c6f..b8a54c616 100644 --- a/packages/nodes-base/nodes/Harvest/Harvest.node.ts +++ b/packages/nodes-base/nodes/Harvest/Harvest.node.ts @@ -546,7 +546,37 @@ export class Harvest implements INodeType { const responseData: IDataObject[] = await getAllResource.call(this, resource, i); returnData.push.apply(returnData, responseData); - } else if (operation === 'delete') { + } else if (operation === 'create') { + // ---------------------------------- + // create + // ---------------------------------- + + requestMethod = 'POST'; + endpoint = resource; + + body.name = this.getNodeParameter('name', i) as string; + + const additionalFields = this.getNodeParameter('additionalFields', i) as IDataObject; + Object.assign(body, additionalFields); + + const responseData = await harvestApiRequest.call(this, requestMethod, qs, endpoint, body); + returnData.push(responseData); + + } else if (operation === 'update') { + // ---------------------------------- + // createByDuration + // ---------------------------------- + + requestMethod = 'POST'; + endpoint = resource; + + const updateFields = this.getNodeParameter('updateFields', i) as IDataObject; + Object.assign(qs, updateFields); + + const responseData = await harvestApiRequest.call(this, requestMethod, qs, endpoint, body); + returnData.push(responseData); + + } else if (operation === 'delete') { // ---------------------------------- // delete // ---------------------------------- diff --git a/packages/nodes-base/nodes/Harvest/TaskDescription.ts b/packages/nodes-base/nodes/Harvest/TaskDescription.ts index feb404d8b..2f3735364 100644 --- a/packages/nodes-base/nodes/Harvest/TaskDescription.ts +++ b/packages/nodes-base/nodes/Harvest/TaskDescription.ts @@ -1,5 +1,5 @@ import { INodeProperties } from "n8n-workflow"; -const resource = [ 'tasks' ]; +const resource = ['tasks']; export const taskOperations = [ { displayName: 'Operation', @@ -21,6 +21,16 @@ export const taskOperations = [ value: 'getAll', description: 'Get data of all tasks', }, + { + name: 'Create', + value: 'create', + description: `Create a task`, + }, + { + name: 'Update', + value: 'update', + description: `Update a task`, + }, { name: 'Delete', value: 'delete', @@ -35,128 +45,248 @@ export const taskOperations = [ export const taskFields = [ -/* -------------------------------------------------------------------------- */ -/* task:getAll */ -/* -------------------------------------------------------------------------- */ + /* -------------------------------------------------------------------------- */ + /* task:getAll */ + /* -------------------------------------------------------------------------- */ -{ - displayName: 'Return All', - name: 'returnAll', - type: 'boolean', - displayOptions: { - show: { - resource, - operation: [ - 'getAll', - ], - }, - }, - default: false, - description: 'Returns a list of your tasks.', -}, -{ - displayName: 'Limit', - name: 'limit', - type: 'number', - displayOptions: { - show: { - resource, - operation: [ - 'getAll', - ], - returnAll: [ - false, - ], - }, - }, - typeOptions: { - minValue: 1, - maxValue: 100, - }, - default: 100, - description: 'How many results to return.', -}, -{ - displayName: 'Filters', - name: 'filters', - type: 'collection', - placeholder: 'Add Filter', - default: {}, - displayOptions: { - show: { - resource, - operation: [ - 'getAll', - ], - }, - }, - options: [ - { - displayName: 'Is Active', - name: 'is_active', - type: 'boolean', - default: true, - description: 'Pass true to only return active tasks and false to return inactive tasks.', - }, - { - displayName: 'Updated Since', - name: 'updated_since', - type: 'dateTime', - default: '', - description: 'Only return tasks belonging to the task with the given ID.', - }, - { - displayName: 'Page', - name: 'page', - type: 'number', - typeOptions: { - minValue: 1, + { + displayName: 'Return All', + name: 'returnAll', + type: 'boolean', + displayOptions: { + show: { + resource, + operation: [ + 'getAll', + ], }, - default: 1, - description: 'The page number to use in pagination.', - } - ] -}, - -/* -------------------------------------------------------------------------- */ -/* task:get */ -/* -------------------------------------------------------------------------- */ -{ - displayName: 'Task Id', - name: 'id', - type: 'string', - default: '', - required: true, - displayOptions: { - show: { - operation: [ - 'get', - ], - resource, }, + default: false, + description: 'Returns a list of your tasks.', }, - description: 'The ID of the task you are retrieving.', -}, - -/* -------------------------------------------------------------------------- */ -/* task:delete */ -/* -------------------------------------------------------------------------- */ -{ - displayName: 'Task Id', - name: 'id', - type: 'string', - default: '', - required: true, - displayOptions: { - show: { - operation: [ - 'delete', - ], - resource, + { + displayName: 'Limit', + name: 'limit', + type: 'number', + displayOptions: { + show: { + resource, + operation: [ + 'getAll', + ], + returnAll: [ + false, + ], + }, }, + typeOptions: { + minValue: 1, + maxValue: 100, + }, + default: 100, + description: 'How many results to return.', + }, + { + displayName: 'Filters', + name: 'filters', + type: 'collection', + placeholder: 'Add Filter', + default: {}, + displayOptions: { + show: { + resource, + operation: [ + 'getAll', + ], + }, + }, + options: [ + { + displayName: 'Is Active', + name: 'is_active', + type: 'boolean', + default: true, + description: 'Pass true to only return active tasks and false to return inactive tasks.', + }, + { + displayName: 'Updated Since', + name: 'updated_since', + type: 'dateTime', + default: '', + description: 'Only return tasks belonging to the task with the given ID.', + }, + { + displayName: 'Page', + name: 'page', + type: 'number', + typeOptions: { + minValue: 1, + }, + default: 1, + description: 'The page number to use in pagination.', + } + ] + }, + + /* -------------------------------------------------------------------------- */ + /* task:get */ + /* -------------------------------------------------------------------------- */ + { + displayName: 'Task Id', + name: 'id', + type: 'string', + default: '', + required: true, + displayOptions: { + show: { + operation: [ + 'get', + ], + resource, + }, + }, + description: 'The ID of the task you are retrieving.', + }, + + /* -------------------------------------------------------------------------- */ + /* task:delete */ + /* -------------------------------------------------------------------------- */ + { + displayName: 'Task Id', + name: 'id', + type: 'string', + default: '', + required: true, + displayOptions: { + show: { + operation: [ + 'delete', + ], + resource, + }, + }, + description: 'The ID of the task you wan to delete.', + }, + + /* -------------------------------------------------------------------------- */ + /* task:create */ + /* -------------------------------------------------------------------------- */ + { + displayName: 'Name', + name: 'name', + type: 'string', + displayOptions: { + show: { + operation: [ + 'create', + ], + resource, + }, + }, + default: '', + required: true, + description: 'The name of the task.', + }, + { + displayName: 'Additional Fields', + name: 'additionalFields', + type: 'collection', + placeholder: 'Add Field', + displayOptions: { + show: { + operation: [ + 'create', + ], + resource, + }, + }, + default: {}, + options: [ + { + displayName: 'Billable By Default', + name: 'billable_by_default', + type: 'boolean', + default: '', + description: 'Used in determining whether default tasks should be marked billable when creating a new project. Defaults to true.' + }, + { + displayName: 'Default Hourly Rate', + name: 'default_hourly_rate', + type: 'string', + default: '0', + description: 'The default hourly rate to use for this task when it is added to a project. Defaults to 0.' + }, + { + displayName: 'Is Default', + name: 'is_default', + type: 'boolean', + default: false, + description: 'Whether this task should be automatically added to future projects. Defaults to false.' + }, + { + displayName: 'Is Active', + name: 'is_active', + type: 'boolean', + default: true, + description: 'Whether this task is active or archived. Defaults to true' + }, + ], + }, + /* -------------------------------------------------------------------------- */ + /* task:update */ + /* -------------------------------------------------------------------------- */ + { + displayName: 'Update Fields', + name: 'updateFields', + type: 'collection', + placeholder: 'Update Field', + displayOptions: { + show: { + operation: [ + 'update', + ], + resource, + }, + }, + default: {}, + options: [ + { + displayName: 'Name', + name: 'name', + type: 'string', + default: '', + description: 'Name of the task.' + }, + { + displayName: 'Billable By Default', + name: 'billable_by_default', + type: 'boolean', + default: '', + description: 'Used in determining whether default tasks should be marked billable when creating a new project. Defaults to true.' + }, + { + displayName: 'Default Hourly Rate', + name: 'default_hourly_rate', + type: 'string', + default: '0', + description: 'The default hourly rate to use for this task when it is added to a project. Defaults to 0.' + }, + { + displayName: 'Is Default', + name: 'is_default', + type: 'boolean', + default: false, + description: 'Whether this task should be automatically added to future projects. Defaults to false.' + }, + { + displayName: 'Is Active', + name: 'is_active', + type: 'boolean', + default: true, + description: 'Whether this task is active or archived. Defaults to true' + } + ], }, - description: 'The ID of the task you wan to delete.', -}, ] as INodeProperties[]; diff --git a/packages/nodes-base/nodes/Harvest/UserDescription.ts b/packages/nodes-base/nodes/Harvest/UserDescription.ts index 2c8023ac2..f0760daf4 100644 --- a/packages/nodes-base/nodes/Harvest/UserDescription.ts +++ b/packages/nodes-base/nodes/Harvest/UserDescription.ts @@ -175,10 +175,10 @@ export const userFields = [ description: 'The ID of the user you want to delete.', }, -/* -------------------------------------------------------------------------- */ -/* user:create */ -/* -------------------------------------------------------------------------- */ -{ + /* -------------------------------------------------------------------------- */ + /* user:create */ + /* -------------------------------------------------------------------------- */ + { displayName: 'First Name', name: 'first_name', type: 'string', @@ -336,153 +336,153 @@ export const userFields = [ }, -/* -------------------------------------------------------------------------- */ -/* user:update */ -/* -------------------------------------------------------------------------- */ -{ - displayName: 'Time Entry Id', - name: 'id', - type: 'string', - default: '', - required: true, - displayOptions: { - show: { - operation: [ - 'update', - ], - resource, + /* -------------------------------------------------------------------------- */ + /* user:update */ + /* -------------------------------------------------------------------------- */ + { + displayName: 'Time Entry Id', + name: 'id', + type: 'string', + default: '', + required: true, + displayOptions: { + show: { + operation: [ + 'update', + ], + resource, + }, }, + description: 'The ID of the time entry to update.', }, - description: 'The ID of the time entry to update.', -}, -{ - displayName: 'Update Fields', - name: 'updateFields', - type: 'collection', - placeholder: 'Add Field', - displayOptions: { - show: { - operation: [ - 'update', - ], - resource + { + displayName: 'Update Fields', + name: 'updateFields', + type: 'collection', + placeholder: 'Add Field', + displayOptions: { + show: { + operation: [ + 'update', + ], + resource + }, }, + default: {}, + options: [ + { + displayName: 'First Name', + name: 'first_name', + type: 'string', + default: '', + description: 'The user first name' + }, + { + displayName: 'Last Name', + name: 'last_name', + type: 'string', + default: '', + description: 'The user last name' + }, + { + displayName: 'Email', + name: 'email', + type: 'string', + default: '', + description: 'The user email' + }, + { + displayName: 'Timezone', + name: 'timezone', + type: 'string', + default: '', + description: 'The user’s timezone. Defaults to the company’s timezone. See a list of supported time zones.' + }, + { + displayName: 'Has Access To All Future Projects', + name: 'has_access_to_all_future_projects', + type: 'string', + default: '', + description: 'Whether the user should be automatically added to future projects. Defaults to false.' + }, + { + displayName: 'Is Contractor', + name: 'is_contractor', + type: 'string', + default: '', + description: 'Whether the user is a contractor or an employee. Defaults to false.' + }, + { + displayName: 'Is Admin', + name: 'is_admin', + type: 'string', + default: '', + description: 'Whether the user has Admin permissions. Defaults to false.' + }, + { + displayName: 'Is Project Manager', + name: 'is_project_manager', + type: 'string', + default: '', + description: 'Whether the user has Project Manager permissions. Defaults to false.' + }, + { + displayName: 'Can See Rates', + name: 'can_see_rates', + type: 'string', + default: '', + description: 'Whether the user can see billable rates on projects. Only applicable to Project Managers. Defaults to false.' + }, + { + displayName: 'Can Create Projects', + name: 'can_create_projects', + type: 'string', + default: '', + description: 'Whether the user can create projects. Only applicable to Project Managers. Defaults to false.' + }, + { + displayName: 'Can Create Invoices', + name: 'can_create_invoices', + type: 'string', + default: '', + description: 'Whether the user can create invoices. Only applicable to Project Managers. Defaults to false.' + }, + { + displayName: 'Is Active', + name: 'is_active', + type: 'string', + default: '', + description: 'Whether the user is active or archived. Defaults to true.' + }, + { + displayName: 'Weekly Capacity', + name: 'weekly_capacity', + type: 'string', + default: '', + description: 'The number of hours per week this person is available to work in seconds. Defaults to 126000 seconds (35 hours).' + }, + { + displayName: 'Default Hourly Rate', + name: 'default_hourly_rate', + type: 'string', + default: '', + description: 'The billable rate to use for this user when they are added to a project. Defaults to 0.' + }, + { + displayName: 'Cost Rate', + name: 'cost_rate', + type: 'string', + default: '', + description: 'The cost rate to use for this user when calculating a project’s costs vs billable amount. Defaults to 0.' + }, + { + displayName: 'Roles', + name: 'roles', + type: 'string', + default: '', + description: 'The role names assigned to this person.' + }, + ], }, - default: {}, - options: [ - { - displayName: 'First Name', - name: 'first_name', - type: 'string', - default: '', - description: 'The user first name' - }, - { - displayName: 'Last Name', - name: 'last_name', - type: 'string', - default: '', - description: 'The user last name' - }, - { - displayName: 'Email', - name: 'email', - type: 'string', - default: '', - description: 'The user email' - }, - { - displayName: 'Timezone', - name: 'timezone', - type: 'string', - default: '', - description: 'The user’s timezone. Defaults to the company’s timezone. See a list of supported time zones.' - }, - { - displayName: 'Has Access To All Future Projects', - name: 'has_access_to_all_future_projects', - type: 'string', - default: '', - description: 'Whether the user should be automatically added to future projects. Defaults to false.' - }, - { - displayName: 'Is Contractor', - name: 'is_contractor', - type: 'string', - default: '', - description: 'Whether the user is a contractor or an employee. Defaults to false.' - }, - { - displayName: 'Is Admin', - name: 'is_admin', - type: 'string', - default: '', - description: 'Whether the user has Admin permissions. Defaults to false.' - }, - { - displayName: 'Is Project Manager', - name: 'is_project_manager', - type: 'string', - default: '', - description: 'Whether the user has Project Manager permissions. Defaults to false.' - }, - { - displayName: 'Can See Rates', - name: 'can_see_rates', - type: 'string', - default: '', - description: 'Whether the user can see billable rates on projects. Only applicable to Project Managers. Defaults to false.' - }, - { - displayName: 'Can Create Projects', - name: 'can_create_projects', - type: 'string', - default: '', - description: 'Whether the user can create projects. Only applicable to Project Managers. Defaults to false.' - }, - { - displayName: 'Can Create Invoices', - name: 'can_create_invoices', - type: 'string', - default: '', - description: 'Whether the user can create invoices. Only applicable to Project Managers. Defaults to false.' - }, - { - displayName: 'Is Active', - name: 'is_active', - type: 'string', - default: '', - description: 'Whether the user is active or archived. Defaults to true.' - }, - { - displayName: 'Weekly Capacity', - name: 'weekly_capacity', - type: 'string', - default: '', - description: 'The number of hours per week this person is available to work in seconds. Defaults to 126000 seconds (35 hours).' - }, - { - displayName: 'Default Hourly Rate', - name: 'default_hourly_rate', - type: 'string', - default: '', - description: 'The billable rate to use for this user when they are added to a project. Defaults to 0.' - }, - { - displayName: 'Cost Rate', - name: 'cost_rate', - type: 'string', - default: '', - description: 'The cost rate to use for this user when calculating a project’s costs vs billable amount. Defaults to 0.' - }, - { - displayName: 'Roles', - name: 'roles', - type: 'string', - default: '', - description: 'The role names assigned to this person.' - }, - ], -}, ] as INodeProperties[]; From 2a57b15e1090701768b65912010cb5905c3b6c1b Mon Sep 17 00:00:00 2001 From: trojanh Date: Mon, 3 Feb 2020 14:09:22 +0530 Subject: [PATCH 07/14] Add Create and Update for Project API --- .../nodes-base/nodes/Harvest/Harvest.node.ts | 22 +- .../nodes/Harvest/ProjectDescription.ts | 616 ++++++++++++++---- 2 files changed, 512 insertions(+), 126 deletions(-) diff --git a/packages/nodes-base/nodes/Harvest/Harvest.node.ts b/packages/nodes-base/nodes/Harvest/Harvest.node.ts index b8a54c616..8ea4b6d33 100644 --- a/packages/nodes-base/nodes/Harvest/Harvest.node.ts +++ b/packages/nodes-base/nodes/Harvest/Harvest.node.ts @@ -342,7 +342,27 @@ export class Harvest implements INodeType { const responseData: IDataObject[] = await getAllResource.call(this, resource, i); returnData.push.apply(returnData, responseData); - } else if (operation === 'delete') { + } else if (operation === 'create') { + // ---------------------------------- + // create + // ---------------------------------- + + requestMethod = 'POST'; + endpoint = resource; + + body.client_id = this.getNodeParameter('client_id', i) as string; + body.name = this.getNodeParameter('name', i) as string; + body.is_billable = this.getNodeParameter('is_billable', i) as string; + body.bill_by = this.getNodeParameter('bill_by', i) as string; + body.budget_by = this.getNodeParameter('budget_by', i) as string; + + const additionalFields = this.getNodeParameter('additionalFields', i) as IDataObject; + Object.assign(body, additionalFields); + + const responseData = await harvestApiRequest.call(this, requestMethod, qs, endpoint, body); + returnData.push(responseData); + + } else if (operation === 'delete') { // ---------------------------------- // delete // ---------------------------------- diff --git a/packages/nodes-base/nodes/Harvest/ProjectDescription.ts b/packages/nodes-base/nodes/Harvest/ProjectDescription.ts index c80c67724..839c1aafd 100644 --- a/packages/nodes-base/nodes/Harvest/ProjectDescription.ts +++ b/packages/nodes-base/nodes/Harvest/ProjectDescription.ts @@ -1,6 +1,6 @@ import { INodeProperties } from "n8n-workflow"; -const resource = [ 'projects' ]; +const resource = ['projects']; export const projectOperations = [ { @@ -23,6 +23,16 @@ export const projectOperations = [ value: 'getAll', description: 'Get data of all projects', }, + { + name: 'Create', + value: 'create', + description: `Create a project`, + }, + { + name: 'Update', + value: 'update', + description: `Update a project`, + }, { name: 'Delete', value: 'delete', @@ -37,135 +47,491 @@ export const projectOperations = [ export const projectFields = [ -/* -------------------------------------------------------------------------- */ -/* projects:getAll */ -/* -------------------------------------------------------------------------- */ + /* -------------------------------------------------------------------------- */ + /* projects:getAll */ + /* -------------------------------------------------------------------------- */ -{ - displayName: 'Return All', - name: 'returnAll', - type: 'boolean', - displayOptions: { - show: { - resource, - operation: [ - 'getAll', - ], - }, - }, - default: false, - description: 'Returns a list of your projects.', -}, -{ - displayName: 'Limit', - name: 'limit', - type: 'number', - displayOptions: { - show: { - resource, - operation: [ - 'getAll', - ], - returnAll: [ - false, - ], - }, - }, - typeOptions: { - minValue: 1, - maxValue: 100, - }, - default: 100, - description: 'How many results to return.', -}, -{ - displayName: 'Filters', - name: 'filters', - type: 'collection', - placeholder: 'Add Filter', - default: {}, - displayOptions: { - show: { - resource, - operation: [ - 'getAll', - ], - }, - }, - options: [ - { - displayName: 'Is Active', - name: 'is_active', - type: 'boolean', - default: true, - description: 'Pass true to only return active projects and false to return inactive projects.', - }, - { - displayName: 'Client Id', - name: 'client_id', - type: 'string', - default: '', - description: 'Only return projects belonging to the client with the given ID.', - }, - { - displayName: 'Updated Since', - name: 'updated_since', - type: 'dateTime', - default: '', - description: 'Only return projects by updated_since.', - }, - { - displayName: 'Page', - name: 'page', - type: 'number', - typeOptions: { - minValue: 1, + { + displayName: 'Return All', + name: 'returnAll', + type: 'boolean', + displayOptions: { + show: { + resource, + operation: [ + 'getAll', + ], }, - default: 1, - description: 'The page number to use in pagination.', - }, - - ] -}, - -/* -------------------------------------------------------------------------- */ -/* project:get */ -/* -------------------------------------------------------------------------- */ -{ - displayName: 'Project Id', - name: 'id', - type: 'string', - default: '', - required: true, - displayOptions: { - show: { - operation: [ - 'get', - ], - resource, }, + default: false, + description: 'Returns a list of your projects.', }, - description: 'The ID of the project you are retrieving.', -}, - -/* -------------------------------------------------------------------------- */ -/* project:delete */ -/* -------------------------------------------------------------------------- */ -{ - displayName: 'Project Id', - name: 'id', - type: 'string', - default: '', - required: true, - displayOptions: { - show: { - operation: [ - 'delete', - ], - resource, + { + displayName: 'Limit', + name: 'limit', + type: 'number', + displayOptions: { + show: { + resource, + operation: [ + 'getAll', + ], + returnAll: [ + false, + ], + }, }, + typeOptions: { + minValue: 1, + maxValue: 100, + }, + default: 100, + description: 'How many results to return.', + }, + { + displayName: 'Filters', + name: 'filters', + type: 'collection', + placeholder: 'Add Filter', + default: {}, + displayOptions: { + show: { + resource, + operation: [ + 'getAll', + ], + }, + }, + options: [ + { + displayName: 'Is Active', + name: 'is_active', + type: 'boolean', + default: true, + description: 'Pass true to only return active projects and false to return inactive projects.', + }, + { + displayName: 'Client Id', + name: 'client_id', + type: 'string', + default: '', + description: 'Only return projects belonging to the client with the given ID.', + }, + { + displayName: 'Updated Since', + name: 'updated_since', + type: 'dateTime', + default: '', + description: 'Only return projects by updated_since.', + }, + { + displayName: 'Page', + name: 'page', + type: 'number', + typeOptions: { + minValue: 1, + }, + default: 1, + description: 'The page number to use in pagination.', + }, + + ] + }, + + /* -------------------------------------------------------------------------- */ + /* project:get */ + /* -------------------------------------------------------------------------- */ + { + displayName: 'Project Id', + name: 'id', + type: 'string', + default: '', + required: true, + displayOptions: { + show: { + operation: [ + 'get', + ], + resource, + }, + }, + description: 'The ID of the project you are retrieving.', + }, + + /* -------------------------------------------------------------------------- */ + /* project:delete */ + /* -------------------------------------------------------------------------- */ + { + displayName: 'Project Id', + name: 'id', + type: 'string', + default: '', + required: true, + displayOptions: { + show: { + operation: [ + 'delete', + ], + resource, + }, + }, + description: 'The ID of the project want to delete.', + }, + + /* -------------------------------------------------------------------------- */ + /* project:create */ + /* -------------------------------------------------------------------------- */ + { + displayName: 'Name', + name: 'name', + type: 'string', + displayOptions: { + show: { + operation: [ + 'create', + ], + resource, + }, + }, + default: '', + required: true, + description: 'The name of the project.', + }, + { + displayName: 'Client Id', + name: 'client_id', + type: 'string', + displayOptions: { + show: { + operation: [ + 'create', + ], + resource, + }, + }, + default: '', + required: true, + description: 'The ID of the client to associate this project with.', + }, + { + displayName: 'Is Billable', + name: 'is_billable', + type: 'string', + displayOptions: { + show: { + operation: [ + 'create', + ], + resource, + }, + }, + default: '', + required: true, + description: 'Whether the project is billable or not.', + }, + { + displayName: 'Bill By', + name: 'bill_by', + type: 'string', + displayOptions: { + show: { + operation: [ + 'create', + ], + resource, + }, + }, + default: '', + required: true, + description: 'The method by which the project is invoiced. Options: Project, Tasks, People, or none.', + }, + { + displayName: 'Budget By', + name: 'budget_by', + type: 'string', + displayOptions: { + show: { + operation: [ + 'create', + ], + resource, + }, + }, + default: '', + required: true, + description: 'The email of the user.', + }, + { + displayName: 'Additional Fields', + name: 'additionalFields', + type: 'collection', + placeholder: 'Add Field', + displayOptions: { + show: { + operation: [ + 'create', + ], + resource, + }, + }, + default: {}, + options: [ + { + displayName: 'Is Active', + name: 'is_active', + type: 'boolean', + default: true, + description: 'Whether the project is active or archived. Defaults to true' + }, + { + displayName: 'Is Fixed Fee', + name: 'is_fixed_fee', + type: 'string', + default: '', + description: 'Whether the project is a fixed-fee project or not.' + }, + { + displayName: 'Hourly Rate', + name: 'hourly_rate', + type: 'string', + default: '', + description: 'Rate for projects billed by Project Hourly Rate.' + }, + { + displayName: 'Budget', + name: 'budget', + type: 'string', + default: '', + description: 'The budget in hours for the project when budgeting by time.' + }, + { + displayName: 'Budget Is Monthly', + name: 'budget_is_monthly', + type: 'string', + default: '', + description: 'Option to have the budget reset every month. Defaults to false.' + }, + { + displayName: 'Notify When Over Budget', + name: 'notify_when_over_budget', + type: 'string', + default: '', + description: 'Whether project managers should be notified when the project goes over budget. Defaults to false.' + }, + { + displayName: 'Over Budget Notification Percentage', + name: 'over_budget_notification_percentage', + type: 'string', + default: '', + description: 'Percentage value used to trigger over budget email alerts. Example: use 10.0 for 10.0%.' + }, + { + displayName: 'Show Budget To All', + name: 'show_budget_to_all', + type: 'string', + default: '', + description: 'Option to show project budget to all employees. Does not apply to Total Project Fee projects. Defaults to false.' + }, + { + displayName: 'Cost Budget', + name: 'cost_budget', + type: 'string', + default: '', + description: 'The monetary budget for the project when budgeting by money.' + }, + { + displayName: 'Cost Budget Include Expenses', + name: 'cost_budget_include_expenses', + type: 'string', + default: '', + description: 'Option for budget of Total Project Fees projects to include tracked expenses. Defaults to false.' + }, + { + displayName: 'Fee', + name: 'fee', + type: 'string', + default: '', + description: 'The amount you plan to invoice for the project. Only used by fixed-fee projects.' + }, + { + displayName: 'Notes', + name: 'notes', + type: 'string', + default: '', + description: 'Notes about the project.' + }, + { + displayName: 'Starts On', + name: 'starts_on', + type: 'dateTime', + default: '', + description: 'Date the project was started.' + }, + { + displayName: 'Ends On', + name: 'ends_on', + type: 'dateTime', + default: '', + description: 'Date the project will end.' + }, + + ], + }, + + /* -------------------------------------------------------------------------- */ + /* project:update */ + /* -------------------------------------------------------------------------- */ + + { + displayName: 'Additional Fields', + name: 'additionalFields', + type: 'collection', + placeholder: 'Add Field', + displayOptions: { + show: { + operation: [ + 'create', + ], + resource, + }, + }, + default: {}, + options: [ + { + displayName: 'Name', + name: 'name', + type: 'string', + default: '', + description: 'The name of the project.', + }, + { + displayName: 'Client Id', + name: 'client_id', + type: 'string', + default: '', + description: 'The ID of the client to associate this project with.', + }, + { + displayName: 'Is Billable', + name: 'is_billable', + type: 'string', + default: '', + description: 'Whether the project is billable or not.', + }, + { + displayName: 'Bill By', + name: 'bill_by', + type: 'string', + default: '', + description: 'The method by which the project is invoiced. Options: Project, Tasks, People, or none.', + }, + { + displayName: 'Budget By', + name: 'budget_by', + type: 'string', + default: '', + description: 'The email of the user.', + }, + { + displayName: 'Is Active', + name: 'is_active', + type: 'boolean', + default: true, + description: 'Whether the project is active or archived. Defaults to true' + }, + { + displayName: 'Is Fixed Fee', + name: 'is_fixed_fee', + type: 'string', + default: '', + description: 'Whether the project is a fixed-fee project or not.' + }, + { + displayName: 'Hourly Rate', + name: 'hourly_rate', + type: 'string', + default: '', + description: 'Rate for projects billed by Project Hourly Rate.' + }, + { + displayName: 'Budget', + name: 'budget', + type: 'string', + default: '', + description: 'The budget in hours for the project when budgeting by time.' + }, + { + displayName: 'Budget Is Monthly', + name: 'budget_is_monthly', + type: 'string', + default: '', + description: 'Option to have the budget reset every month. Defaults to false.' + }, + { + displayName: 'Notify When Over Budget', + name: 'notify_when_over_budget', + type: 'string', + default: '', + description: 'Whether project managers should be notified when the project goes over budget. Defaults to false.' + }, + { + displayName: 'Over Budget Notification Percentage', + name: 'over_budget_notification_percentage', + type: 'string', + default: '', + description: 'Percentage value used to trigger over budget email alerts. Example: use 10.0 for 10.0%.' + }, + { + displayName: 'Show Budget To All', + name: 'show_budget_to_all', + type: 'string', + default: '', + description: 'Option to show project budget to all employees. Does not apply to Total Project Fee projects. Defaults to false.' + }, + { + displayName: 'Cost Budget', + name: 'cost_budget', + type: 'string', + default: '', + description: 'The monetary budget for the project when budgeting by money.' + }, + { + displayName: 'Cost Budget Include Expenses', + name: 'cost_budget_include_expenses', + type: 'string', + default: '', + description: 'Option for budget of Total Project Fees projects to include tracked expenses. Defaults to false.' + }, + { + displayName: 'Fee', + name: 'fee', + type: 'string', + default: '', + description: 'The amount you plan to invoice for the project. Only used by fixed-fee projects.' + }, + { + displayName: 'Notes', + name: 'notes', + type: 'string', + default: '', + description: 'Notes about the project.' + }, + { + displayName: 'Starts On', + name: 'starts_on', + type: 'dateTime', + default: '', + description: 'Date the project was started.' + }, + { + displayName: 'Ends On', + name: 'ends_on', + type: 'dateTime', + default: '', + description: 'Date the project will end.' + }, + + ], }, - description: 'The ID of the project want to delete.', -} ] as INodeProperties[]; From 0121e3b85cb26ea1ad232651a31d3e32ce9ee8fd Mon Sep 17 00:00:00 2001 From: trojanh Date: Mon, 3 Feb 2020 14:53:58 +0530 Subject: [PATCH 08/14] Add Create and Update for Invoice API --- .../nodes-base/nodes/Harvest/Harvest.node.ts | 17 +- .../nodes/Harvest/InvoiceDescription.ts | 250 +++++++++++++++++- .../nodes/Harvest/ProjectDescription.ts | 5 +- 3 files changed, 268 insertions(+), 4 deletions(-) diff --git a/packages/nodes-base/nodes/Harvest/Harvest.node.ts b/packages/nodes-base/nodes/Harvest/Harvest.node.ts index 8ea4b6d33..ebe61d38a 100644 --- a/packages/nodes-base/nodes/Harvest/Harvest.node.ts +++ b/packages/nodes-base/nodes/Harvest/Harvest.node.ts @@ -362,6 +362,21 @@ export class Harvest implements INodeType { const responseData = await harvestApiRequest.call(this, requestMethod, qs, endpoint, body); returnData.push(responseData); + } else if (operation === 'update') { + // ---------------------------------- + // update + // ---------------------------------- + + requestMethod = 'PATCH'; + const id = this.getNodeParameter('id', i) as string; + endpoint = `${resource}/${id}`; + + const updateFields = this.getNodeParameter('updateFields', i) as IDataObject; + + Object.assign(body, updateFields); + const responseData = await harvestApiRequest.call(this, requestMethod, qs, endpoint, body); + returnData.push(responseData); + } else if (operation === 'delete') { // ---------------------------------- // delete @@ -574,7 +589,7 @@ export class Harvest implements INodeType { requestMethod = 'POST'; endpoint = resource; - body.name = this.getNodeParameter('name', i) as string; + body.client_id = this.getNodeParameter('client_id', i) as string; const additionalFields = this.getNodeParameter('additionalFields', i) as IDataObject; Object.assign(body, additionalFields); diff --git a/packages/nodes-base/nodes/Harvest/InvoiceDescription.ts b/packages/nodes-base/nodes/Harvest/InvoiceDescription.ts index 8ec5814df..f294653fb 100644 --- a/packages/nodes-base/nodes/Harvest/InvoiceDescription.ts +++ b/packages/nodes-base/nodes/Harvest/InvoiceDescription.ts @@ -204,6 +204,254 @@ export const invoiceFields = [ }, }, description: 'The ID of the invoice want to delete.', -} +}, + /* -------------------------------------------------------------------------- */ + /* invoice:create */ + /* -------------------------------------------------------------------------- */ + { + displayName: 'client_id', + name: 'client_id', + type: 'string', + displayOptions: { + show: { + operation: [ + 'create', + ], + resource, + }, + }, + default: '', + required: true, + description: 'The ID of the retainer associated with this invoice..', + }, + { + displayName: 'Additional Fields', + name: 'additionalFields', + type: 'collection', + placeholder: 'Add Field', + displayOptions: { + show: { + operation: [ + 'create', + ], + resource, + }, + }, + default: {}, + options: [ + { + displayName: 'Retainer Id', + name: 'retainer_id', + type: 'boolean', + default: true, + description: 'The ID of the retainer associated with this invoice.' + }, + { + displayName: 'Estimate Id', + name: 'estimate_id', + type: 'string', + default: '', + description: 'The ID of the estimate associated with this invoice.' + }, + { + displayName: 'Number', + name: 'number', + type: 'string', + default: '', + description: 'If no value is set, the number will be automatically generated.' + }, + { + displayName: 'Purchase Order', + name: 'purchase_order', + type: 'string', + default: '', + description: 'The purchase order number.' + }, + { + displayName: 'Tax', + name: 'tax', + type: 'string', + default: '', + description: 'This percentage is applied to the subtotal, including line items and discounts. Example: use 10.0 for 10.0%.' + }, + { + displayName: 'Tax2', + name: 'tax2', + type: 'string', + default: '', + description: 'This percentage is applied to the subtotal, including line items and discounts. Example: use 10.0 for 10.0%.' + }, + { + displayName: 'Discount', + name: 'over_budget_notification_percentage', + type: 'string', + default: '', + description: 'This percentage is subtracted from the subtotal. Example: use 10.0 for 10.0%.' + }, + { + displayName: 'Subject', + name: 'subject', + type: 'string', + default: '', + description: 'The invoice subject.' + }, + { + displayName: 'Currency', + name: 'currency', + type: 'string', + default: '', + description: 'The currency used by the invoice. If not provided, the client’s currency will be used. See a list of supported currencies' + }, + { + displayName: 'Payment Term', + name: 'payment_term', + type: 'string', + default: '', + description: 'The timeframe in which the invoice should be paid. Defaults to custom. Options: upon receipt, net 15, net 30, net 45, or net 60.' + }, + { + displayName: 'Notes', + name: 'notes', + type: 'string', + default: '', + description: 'Notes about the project.' + }, + { + displayName: 'Issue Date', + name: 'issue_date', + type: 'dateTime', + default: '', + description: 'Date the invoice was issued. Defaults to today’s date.' + }, + { + displayName: 'Due Date', + name: 'ends_on', + type: 'dateTime', + default: '', + description: 'Date the invoice is due. Defaults to the issue_date if no payment_term is specified.' + }, + + ], + }, + + /* -------------------------------------------------------------------------- */ + /* invoice:update */ + /* -------------------------------------------------------------------------- */ + { + displayName: 'Update Fields', + name: 'updateFields', + type: 'collection', + placeholder: 'Add Field', + displayOptions: { + show: { + operation: [ + 'create', + ], + resource, + }, + }, + default: {}, + options: [ + { + displayName: 'client_id', + name: 'client_id', + type: 'string', + default: '', + description: 'The ID of the retainer associated with this invoice..', + }, + { + displayName: 'Retainer Id', + name: 'retainer_id', + type: 'boolean', + default: true, + description: 'The ID of the retainer associated with this invoice.' + }, + { + displayName: 'Estimate Id', + name: 'estimate_id', + type: 'string', + default: '', + description: 'The ID of the estimate associated with this invoice.' + }, + { + displayName: 'Number', + name: 'number', + type: 'string', + default: '', + description: 'If no value is set, the number will be automatically generated.' + }, + { + displayName: 'Purchase Order', + name: 'purchase_order', + type: 'string', + default: '', + description: 'The purchase order number.' + }, + { + displayName: 'Tax', + name: 'tax', + type: 'string', + default: '', + description: 'This percentage is applied to the subtotal, including line items and discounts. Example: use 10.0 for 10.0%.' + }, + { + displayName: 'Tax2', + name: 'tax2', + type: 'string', + default: '', + description: 'This percentage is applied to the subtotal, including line items and discounts. Example: use 10.0 for 10.0%.' + }, + { + displayName: 'Discount', + name: 'over_budget_notification_percentage', + type: 'string', + default: '', + description: 'This percentage is subtracted from the subtotal. Example: use 10.0 for 10.0%.' + }, + { + displayName: 'Subject', + name: 'subject', + type: 'string', + default: '', + description: 'The invoice subject.' + }, + { + displayName: 'Currency', + name: 'currency', + type: 'string', + default: '', + description: 'The currency used by the invoice. If not provided, the client’s currency will be used. See a list of supported currencies' + }, + { + displayName: 'Payment Term', + name: 'payment_term', + type: 'string', + default: '', + description: 'The timeframe in which the invoice should be paid. Defaults to custom. Options: upon receipt, net 15, net 30, net 45, or net 60.' + }, + { + displayName: 'Notes', + name: 'notes', + type: 'string', + default: '', + description: 'Notes about the project.' + }, + { + displayName: 'Issue Date', + name: 'issue_date', + type: 'dateTime', + default: '', + description: 'Date the invoice was issued. Defaults to today’s date.' + }, + { + displayName: 'Due Date', + name: 'ends_on', + type: 'dateTime', + default: '', + description: 'Date the invoice is due. Defaults to the issue_date if no payment_term is specified.' + }, + + ], + }, ] as INodeProperties[]; diff --git a/packages/nodes-base/nodes/Harvest/ProjectDescription.ts b/packages/nodes-base/nodes/Harvest/ProjectDescription.ts index 839c1aafd..d2092b427 100644 --- a/packages/nodes-base/nodes/Harvest/ProjectDescription.ts +++ b/packages/nodes-base/nodes/Harvest/ProjectDescription.ts @@ -383,8 +383,8 @@ export const projectFields = [ /* -------------------------------------------------------------------------- */ { - displayName: 'Additional Fields', - name: 'additionalFields', + displayName: 'Update Fields', + name: 'updateFields', type: 'collection', placeholder: 'Add Field', displayOptions: { @@ -535,3 +535,4 @@ export const projectFields = [ }, ] as INodeProperties[]; + From 41b12456104b2ce2ef81620d21cf287743e35ed0 Mon Sep 17 00:00:00 2001 From: trojanh Date: Mon, 3 Feb 2020 15:07:56 +0530 Subject: [PATCH 09/14] Fix update methods --- packages/nodes-base/nodes/Harvest/Harvest.node.ts | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/packages/nodes-base/nodes/Harvest/Harvest.node.ts b/packages/nodes-base/nodes/Harvest/Harvest.node.ts index ebe61d38a..a98921220 100644 --- a/packages/nodes-base/nodes/Harvest/Harvest.node.ts +++ b/packages/nodes-base/nodes/Harvest/Harvest.node.ts @@ -449,8 +449,9 @@ export class Harvest implements INodeType { // createByDuration // ---------------------------------- - requestMethod = 'POST'; - endpoint = resource; + requestMethod = 'PATCH'; + const id = this.getNodeParameter('id', i) as string; + endpoint = `${resource}/${id}`; const updateFields = this.getNodeParameter('updateFields', i) as IDataObject; Object.assign(qs, updateFields); @@ -602,8 +603,9 @@ export class Harvest implements INodeType { // createByDuration // ---------------------------------- - requestMethod = 'POST'; - endpoint = resource; + requestMethod = 'PATCH'; + const id = this.getNodeParameter('id', i) as string; + endpoint = `${resource}/${id}`; const updateFields = this.getNodeParameter('updateFields', i) as IDataObject; Object.assign(qs, updateFields); From aceccf01d3522cb7f53c56138e5744f4049fa9fb Mon Sep 17 00:00:00 2001 From: trojanh Date: Mon, 3 Feb 2020 15:24:21 +0530 Subject: [PATCH 10/14] Fix operation name for update --- .../nodes/Harvest/InvoiceDescription.ts | 18 +++++++++++++++++- .../nodes/Harvest/ProjectDescription.ts | 19 +++++++++++++++++-- 2 files changed, 34 insertions(+), 3 deletions(-) diff --git a/packages/nodes-base/nodes/Harvest/InvoiceDescription.ts b/packages/nodes-base/nodes/Harvest/InvoiceDescription.ts index f294653fb..b38e6a665 100644 --- a/packages/nodes-base/nodes/Harvest/InvoiceDescription.ts +++ b/packages/nodes-base/nodes/Harvest/InvoiceDescription.ts @@ -338,6 +338,22 @@ export const invoiceFields = [ /* -------------------------------------------------------------------------- */ /* invoice:update */ /* -------------------------------------------------------------------------- */ + { + displayName: 'Invoice Id', + name: 'id', + type: 'string', + default: '', + required: true, + displayOptions: { + show: { + operation: [ + 'update', + ], + resource, + }, + }, + description: 'The ID of the invoice want to update.', + }, { displayName: 'Update Fields', name: 'updateFields', @@ -346,7 +362,7 @@ export const invoiceFields = [ displayOptions: { show: { operation: [ - 'create', + 'update', ], resource, }, diff --git a/packages/nodes-base/nodes/Harvest/ProjectDescription.ts b/packages/nodes-base/nodes/Harvest/ProjectDescription.ts index d2092b427..607894bcd 100644 --- a/packages/nodes-base/nodes/Harvest/ProjectDescription.ts +++ b/packages/nodes-base/nodes/Harvest/ProjectDescription.ts @@ -381,7 +381,22 @@ export const projectFields = [ /* -------------------------------------------------------------------------- */ /* project:update */ /* -------------------------------------------------------------------------- */ - + { + displayName: 'Project Id', + name: 'id', + type: 'string', + default: '', + required: true, + displayOptions: { + show: { + operation: [ + 'update', + ], + resource, + }, + }, + description: 'The ID of the project want to update.', + }, { displayName: 'Update Fields', name: 'updateFields', @@ -390,7 +405,7 @@ export const projectFields = [ displayOptions: { show: { operation: [ - 'create', + 'update', ], resource, }, From 9e7ac3c13f6d82037de065632e7c07e517584f18 Mon Sep 17 00:00:00 2001 From: trojanh Date: Mon, 3 Feb 2020 17:27:39 +0530 Subject: [PATCH 11/14] Add Expense and Estimate API --- .../nodes/Harvest/ClientDescription.ts | 10 + .../nodes/Harvest/ContactDescription.ts | 10 + .../nodes/Harvest/EstimateDescription.ts | 221 +++++++++++++++++- .../nodes/Harvest/ExpenseDescription.ts | 213 ++++++++++++++++- .../nodes-base/nodes/Harvest/Harvest.node.ts | 69 +++++- .../nodes/Harvest/InvoiceDescription.ts | 10 + 6 files changed, 528 insertions(+), 5 deletions(-) diff --git a/packages/nodes-base/nodes/Harvest/ClientDescription.ts b/packages/nodes-base/nodes/Harvest/ClientDescription.ts index 532d3a67a..eccb91018 100644 --- a/packages/nodes-base/nodes/Harvest/ClientDescription.ts +++ b/packages/nodes-base/nodes/Harvest/ClientDescription.ts @@ -23,6 +23,16 @@ export const clientOperations = [ value: 'getAll', description: 'Get data of all clients', }, + { + name: 'Create', + value: 'create', + description: `Create a client`, + }, + { + name: 'Update', + value: 'update', + description: `Update a client`, + }, { name: 'Delete', value: 'delete', diff --git a/packages/nodes-base/nodes/Harvest/ContactDescription.ts b/packages/nodes-base/nodes/Harvest/ContactDescription.ts index 66dd0386e..0fda65bf6 100644 --- a/packages/nodes-base/nodes/Harvest/ContactDescription.ts +++ b/packages/nodes-base/nodes/Harvest/ContactDescription.ts @@ -23,6 +23,16 @@ export const contactOperations = [ value: 'getAll', description: 'Get data of all contacts', }, + { + name: 'Create', + value: 'create', + description: `Create a contact`, + }, + { + name: 'Update', + value: 'update', + description: `Update a contact`, + }, { name: 'Delete', value: 'delete', diff --git a/packages/nodes-base/nodes/Harvest/EstimateDescription.ts b/packages/nodes-base/nodes/Harvest/EstimateDescription.ts index 4216ab0db..1bb35601f 100644 --- a/packages/nodes-base/nodes/Harvest/EstimateDescription.ts +++ b/packages/nodes-base/nodes/Harvest/EstimateDescription.ts @@ -23,6 +23,16 @@ export const estimateOperations = [ value: 'getAll', description: 'Get data of all estimates', }, + { + name: 'Create', + value: 'create', + description: `Create a estimate`, + }, + { + name: 'Update', + value: 'update', + description: `Update a estimate`, + }, { name: 'Delete', value: 'delete', @@ -179,6 +189,215 @@ export const estimateFields = [ }, }, description: 'The ID of the estimate want to delete.', -} +}, + + /* -------------------------------------------------------------------------- */ + /* invoice:create */ + /* -------------------------------------------------------------------------- */ + { + displayName: 'client_id', + name: 'client_id', + type: 'string', + displayOptions: { + show: { + operation: [ + 'create', + ], + resource, + }, + }, + default: '', + required: true, + description: 'The ID of the client this estimate belongs to.', + }, + { + displayName: 'Additional Fields', + name: 'additionalFields', + type: 'collection', + placeholder: 'Add Field', + displayOptions: { + show: { + operation: [ + 'create', + ], + resource, + }, + }, + default: {}, + options: [ + { + displayName: 'Number', + name: 'number', + type: 'string', + default: '', + description: 'If no value is set, the number will be automatically generated.' + }, + { + displayName: 'Purchase Order', + name: 'purchase_order', + type: 'string', + default: '', + description: 'The purchase order number.' + }, + { + displayName: 'Tax', + name: 'tax', + type: 'string', + default: '', + description: 'This percentage is applied to the subtotal, including line items and discounts. Example: use 10.0 for 10.0%.' + }, + { + displayName: 'Tax2', + name: 'tax2', + type: 'string', + default: '', + description: 'This percentage is applied to the subtotal, including line items and discounts. Example: use 10.0 for 10.0%.' + }, + { + displayName: 'Discount', + name: 'over_budget_notification_percentage', + type: 'string', + default: '', + description: 'This percentage is subtracted from the subtotal. Example: use 10.0 for 10.0%.' + }, + { + displayName: 'Subject', + name: 'subject', + type: 'string', + default: '', + description: 'The estimate subject.' + }, + { + displayName: 'Currency', + name: 'currency', + type: 'string', + default: '', + description: 'The currency used by the estimate. If not provided, the client’s currency will be used. See a list of supported currencies' + }, + { + displayName: 'Notes', + name: 'notes', + type: 'string', + default: '', + description: 'Any additional notes to include on the estimate.' + }, + { + displayName: 'Issue Date', + name: 'issue_date', + type: 'dateTime', + default: '', + description: 'Date the invoice was issued. Defaults to today’s date.' + }, + + ], + }, + + /* -------------------------------------------------------------------------- */ + /* invoice:update */ + /* -------------------------------------------------------------------------- */ + { + displayName: 'Invoice Id', + name: 'id', + type: 'string', + default: '', + required: true, + displayOptions: { + show: { + operation: [ + 'update', + ], + resource, + }, + }, + description: 'The ID of the invoice want to update.', + }, + { + displayName: 'Update Fields', + name: 'updateFields', + type: 'collection', + placeholder: 'Add Field', + displayOptions: { + show: { + operation: [ + 'update', + ], + resource, + }, + }, + default: {}, + options: [ + { + displayName: 'client_id', + name: 'client_id', + type: 'string', + default: '', + description: 'The ID of the retainer associated with this invoice..', + }, + { + displayName: 'Number', + name: 'number', + type: 'string', + default: '', + description: 'If no value is set, the number will be automatically generated.' + }, + { + displayName: 'Purchase Order', + name: 'purchase_order', + type: 'string', + default: '', + description: 'The purchase order number.' + }, + { + displayName: 'Tax', + name: 'tax', + type: 'string', + default: '', + description: 'This percentage is applied to the subtotal, including line items and discounts. Example: use 10.0 for 10.0%.' + }, + { + displayName: 'Tax2', + name: 'tax2', + type: 'string', + default: '', + description: 'This percentage is applied to the subtotal, including line items and discounts. Example: use 10.0 for 10.0%.' + }, + { + displayName: 'Discount', + name: 'over_budget_notification_percentage', + type: 'string', + default: '', + description: 'This percentage is subtracted from the subtotal. Example: use 10.0 for 10.0%.' + }, + { + displayName: 'Subject', + name: 'subject', + type: 'string', + default: '', + description: 'The estimate subject.' + }, + { + displayName: 'Currency', + name: 'currency', + type: 'string', + default: '', + description: 'The currency used by the estimate. If not provided, the client’s currency will be used. See a list of supported currencies' + }, + { + displayName: 'Notes', + name: 'notes', + type: 'string', + default: '', + description: 'Any additional notes to include on the estimate.' + }, + { + displayName: 'Issue Date', + name: 'issue_date', + type: 'dateTime', + default: '', + description: 'Date the invoice was issued. Defaults to today’s date.' + }, + + ], + }, ] as INodeProperties[]; diff --git a/packages/nodes-base/nodes/Harvest/ExpenseDescription.ts b/packages/nodes-base/nodes/Harvest/ExpenseDescription.ts index ff1613d62..c2095b622 100644 --- a/packages/nodes-base/nodes/Harvest/ExpenseDescription.ts +++ b/packages/nodes-base/nodes/Harvest/ExpenseDescription.ts @@ -1,6 +1,6 @@ import { INodeProperties } from "n8n-workflow"; -const resource = [ 'invoices' ]; +const resource = [ 'expenses' ]; export const expenseOperations = [ { @@ -23,6 +23,16 @@ export const expenseOperations = [ value: 'getAll', description: 'Get data of all expenses', }, + { + name: 'Create', + value: 'create', + description: `Create a expense`, + }, + { + name: 'Update', + value: 'update', + description: `Update a expense`, + }, { name: 'Delete', value: 'delete', @@ -193,6 +203,205 @@ export const expenseFields = [ }, }, description: 'The ID of the expense you want to delete.', -} +}, + + /* -------------------------------------------------------------------------- */ + /* expense:create */ + /* -------------------------------------------------------------------------- */ + { + displayName: 'Project Id', + name: 'project_id', + type: 'string', + displayOptions: { + show: { + operation: [ + 'create', + ], + resource, + }, + }, + default: '', + required: true, + description: 'The ID of the project associated with this expense.', + }, + { + displayName: 'Expense Category Id', + name: 'expense_category_id', + type: 'string', + displayOptions: { + show: { + operation: [ + 'create', + ], + resource, + }, + }, + default: '', + required: true, + description: 'The ID of the expense category this expense is being tracked against.', + }, + { + displayName: 'Spent Date', + name: 'spent_date', + type: 'dateTime', + displayOptions: { + show: { + operation: [ + 'create', + ], + resource, + }, + }, + default: '', + required: true, + description: 'Date the expense occurred.', + }, + { + displayName: 'Additional Fields', + name: 'additionalFields', + type: 'collection', + placeholder: 'Add Field', + displayOptions: { + show: { + operation: [ + 'create', + ], + resource, + }, + }, + default: {}, + options: [ + { + displayName: 'User Id', + name: 'user_id', + type: 'boolean', + default: true, + description: 'The ID of the user associated with this expense. Defaults to the ID of the currently authenticated user.' + }, + { + displayName: 'Units', + name: 'units', + type: 'string', + default: '', + description: 'The quantity of units to use in calculating the total_cost of the expense.' + }, + { + displayName: 'Total Cost', + name: 'total_cost', + type: 'string', + default: '', + description: 'The total amount of the expense.' + }, + { + displayName: 'Billable', + name: 'billable', + type: 'string', + default: '', + description: 'Whether this expense is billable or not. Defaults to true.' + }, + { + displayName: 'Notes', + name: 'notes', + type: 'string', + default: '', + description: 'Notes about the expense.' + }, + + ], + }, + + /* -------------------------------------------------------------------------- */ + /* invoice:update */ + /* -------------------------------------------------------------------------- */ + { + displayName: 'Invoice Id', + name: 'id', + type: 'string', + default: '', + required: true, + displayOptions: { + show: { + operation: [ + 'update', + ], + resource, + }, + }, + description: 'The ID of the invoice want to update.', + }, + { + displayName: 'Update Fields', + name: 'updateFields', + type: 'collection', + placeholder: 'Add Field', + displayOptions: { + show: { + operation: [ + 'update', + ], + resource, + }, + }, + default: {}, + options: [ + { + displayName: 'Project Id', + name: 'project_id', + type: 'string', + default: '', + description: 'The ID of the project associated with this expense.', + }, + { + displayName: 'Expense Category Id', + name: 'expense_category_id', + type: 'string', + default: '', + description: 'The ID of the expense category this expense is being tracked against.', + }, + { + displayName: 'Spent Date', + name: 'spent_date', + type: 'dateTime', + default: '', + description: 'Date the expense occurred.', + }, + { + displayName: 'User Id', + name: 'user_id', + type: 'boolean', + default: true, + description: 'The ID of the user associated with this expense. Defaults to the ID of the currently authenticated user.' + }, + { + displayName: 'Units', + name: 'units', + type: 'string', + default: '', + description: 'The quantity of units to use in calculating the total_cost of the expense.' + }, + { + displayName: 'Total Cost', + name: 'total_cost', + type: 'string', + default: '', + description: 'The total amount of the expense.' + }, + { + displayName: 'Billable', + name: 'billable', + type: 'string', + default: '', + description: 'Whether this expense is billable or not. Defaults to true.' + }, + { + displayName: 'Notes', + name: 'notes', + type: 'string', + default: '', + description: 'Notes about the expense.' + }, + + ], + }, ] as INodeProperties[]; diff --git a/packages/nodes-base/nodes/Harvest/Harvest.node.ts b/packages/nodes-base/nodes/Harvest/Harvest.node.ts index a98921220..0584aeb31 100644 --- a/packages/nodes-base/nodes/Harvest/Harvest.node.ts +++ b/packages/nodes-base/nodes/Harvest/Harvest.node.ts @@ -649,7 +649,41 @@ export class Harvest implements INodeType { const responseData: IDataObject[] = await getAllResource.call(this, resource, i); returnData.push.apply(returnData, responseData); - } else if (operation === 'delete') { + } else if (operation === 'create') { + // ---------------------------------- + // create + // ---------------------------------- + + requestMethod = 'POST'; + endpoint = resource; + + body.project_id = this.getNodeParameter('project_id', i) as string; + body.expense_category_id = this.getNodeParameter('expense_category_id', i) as string; + body.spent_date = this.getNodeParameter('spent_date', i) as string; + + + const additionalFields = this.getNodeParameter('additionalFields', i) as IDataObject; + Object.assign(body, additionalFields); + + const responseData = await harvestApiRequest.call(this, requestMethod, qs, endpoint, body); + returnData.push(responseData); + + } else if (operation === 'update') { + // ---------------------------------- + // createByDuration + // ---------------------------------- + + requestMethod = 'PATCH'; + const id = this.getNodeParameter('id', i) as string; + endpoint = `${resource}/${id}`; + + const updateFields = this.getNodeParameter('updateFields', i) as IDataObject; + Object.assign(qs, updateFields); + + const responseData = await harvestApiRequest.call(this, requestMethod, qs, endpoint, body); + returnData.push(responseData); + + } else if (operation === 'delete') { // ---------------------------------- // delete // ---------------------------------- @@ -685,7 +719,38 @@ export class Harvest implements INodeType { const responseData: IDataObject[] = await getAllResource.call(this, resource, i); returnData.push.apply(returnData, responseData); - } else if (operation === 'delete') { + } else if (operation === 'create') { + // ---------------------------------- + // create + // ---------------------------------- + + requestMethod = 'POST'; + endpoint = resource; + + body.client_id = this.getNodeParameter('client_id', i) as string; + + const additionalFields = this.getNodeParameter('additionalFields', i) as IDataObject; + Object.assign(body, additionalFields); + + const responseData = await harvestApiRequest.call(this, requestMethod, qs, endpoint, body); + returnData.push(responseData); + + } else if (operation === 'update') { + // ---------------------------------- + // createByDuration + // ---------------------------------- + + requestMethod = 'PATCH'; + const id = this.getNodeParameter('id', i) as string; + endpoint = `${resource}/${id}`; + + const updateFields = this.getNodeParameter('updateFields', i) as IDataObject; + Object.assign(qs, updateFields); + + const responseData = await harvestApiRequest.call(this, requestMethod, qs, endpoint, body); + returnData.push(responseData); + + } else if (operation === 'delete') { // ---------------------------------- // delete // ---------------------------------- diff --git a/packages/nodes-base/nodes/Harvest/InvoiceDescription.ts b/packages/nodes-base/nodes/Harvest/InvoiceDescription.ts index b38e6a665..ebab65a53 100644 --- a/packages/nodes-base/nodes/Harvest/InvoiceDescription.ts +++ b/packages/nodes-base/nodes/Harvest/InvoiceDescription.ts @@ -23,6 +23,16 @@ export const invoiceOperations = [ value: 'getAll', description: 'Get data of all invoices', }, + { + name: 'Create', + value: 'create', + description: `Create a invoice`, + }, + { + name: 'Update', + value: 'update', + description: `Update a invoice`, + }, { name: 'Delete', value: 'delete', From 5d36ce0a1eb604fe346befae1bf5d5317824dd9c Mon Sep 17 00:00:00 2001 From: trojanh Date: Mon, 3 Feb 2020 18:06:51 +0530 Subject: [PATCH 12/14] Add Create and Update for Client Contact --- .../nodes/Harvest/ClientDescription.ts | 125 +++++- .../nodes/Harvest/ContactDescription.ts | 388 +++++++++++++----- .../nodes/Harvest/GenericFunctions.ts | 1 + .../nodes-base/nodes/Harvest/Harvest.node.ts | 113 +++-- 4 files changed, 501 insertions(+), 126 deletions(-) diff --git a/packages/nodes-base/nodes/Harvest/ClientDescription.ts b/packages/nodes-base/nodes/Harvest/ClientDescription.ts index eccb91018..0ee743018 100644 --- a/packages/nodes-base/nodes/Harvest/ClientDescription.ts +++ b/packages/nodes-base/nodes/Harvest/ClientDescription.ts @@ -158,6 +158,129 @@ export const clientFields = [ }, }, description: 'The ID of the client you want to delete.', -} +}, + + /* -------------------------------------------------------------------------- */ + /* client:create */ + /* -------------------------------------------------------------------------- */ + { + displayName: 'name', + name: 'name', + type: 'string', + displayOptions: { + show: { + operation: [ + 'create', + ], + resource, + }, + }, + default: '', + required: true, + description: 'The name of the client.', + }, + { + displayName: 'Additional Fields', + name: 'additionalFields', + type: 'collection', + placeholder: 'Add Field', + displayOptions: { + show: { + operation: [ + 'create', + ], + resource, + }, + }, + default: {}, + options: [ + { + displayName: 'is_active', + name: 'is_active', + type: 'string', + default: '', + description: 'Whether the client is active, or archived. Defaults to true.' + }, + { + displayName: 'address', + name: 'address', + type: 'string', + default: '', + description: ' A textual representation of the client’s physical address. May include new line characters.' + }, + { + displayName: 'Currency', + name: 'currency', + type: 'string', + default: '', + description: 'The currency used by the estimate. If not provided, the client’s currency will be used. See a list of supported currencies' + }, + ], + }, + + /* -------------------------------------------------------------------------- */ + /* client:update */ + /* -------------------------------------------------------------------------- */ + { + displayName: 'client Id', + name: 'id', + type: 'string', + default: '', + required: true, + displayOptions: { + show: { + operation: [ + 'update', + ], + resource, + }, + }, + description: 'The ID of the client want to update.', + }, + { + displayName: 'Update Fields', + name: 'updateFields', + type: 'collection', + placeholder: 'Add Field', + displayOptions: { + show: { + operation: [ + 'update', + ], + resource, + }, + }, + default: {}, + options: [ + { + displayName: 'name', + name: 'name', + type: 'string', + default: '', + description: 'Whether the client is active, or archived. Defaults to true.' + }, + { + displayName: 'is_active', + name: 'is_active', + type: 'string', + default: '', + description: 'Whether the client is active, or archived. Defaults to true.' + }, + { + displayName: 'address', + name: 'address', + type: 'string', + default: '', + description: ' A textual representation of the client’s physical address. May include new line characters.' + }, + { + displayName: 'Currency', + name: 'currency', + type: 'string', + default: '', + description: 'The currency used by the estimate. If not provided, the client’s currency will be used. See a list of supported currencies' + }, + ], + }, ] as INodeProperties[]; diff --git a/packages/nodes-base/nodes/Harvest/ContactDescription.ts b/packages/nodes-base/nodes/Harvest/ContactDescription.ts index 0fda65bf6..1532809f5 100644 --- a/packages/nodes-base/nodes/Harvest/ContactDescription.ts +++ b/packages/nodes-base/nodes/Harvest/ContactDescription.ts @@ -1,6 +1,6 @@ import { INodeProperties } from "n8n-workflow"; -const resource = [ 'contacts' ]; +const resource = ['contacts']; export const contactOperations = [ { @@ -47,117 +47,305 @@ export const contactOperations = [ export const contactFields = [ -/* -------------------------------------------------------------------------- */ -/* contact:getAll */ -/* -------------------------------------------------------------------------- */ + /* -------------------------------------------------------------------------- */ + /* contact:getAll */ + /* -------------------------------------------------------------------------- */ -{ - displayName: 'Return All', - name: 'returnAll', - type: 'boolean', - displayOptions: { - show: { - resource, - operation: [ - 'getAll', - ], + { + displayName: 'Return All', + name: 'returnAll', + type: 'boolean', + displayOptions: { + show: { + resource, + operation: [ + 'getAll', + ], + }, }, + default: false, + description: 'Returns a list of your user contacts.', }, - default: false, - description: 'Returns a list of your user contacts.', -}, -{ - displayName: 'Limit', - name: 'limit', - type: 'number', - displayOptions: { - show: { - resource, - operation: [ - 'getAll', - ], - returnAll: [ - false, - ], + { + displayName: 'Limit', + name: 'limit', + type: 'number', + displayOptions: { + show: { + resource, + operation: [ + 'getAll', + ], + returnAll: [ + false, + ], + }, }, - }, - typeOptions: { - minValue: 1, - maxValue: 100, - }, - default: 100, - description: 'How many results to return.', -}, -{ - displayName: 'Filters', - name: 'filters', - type: 'collection', - placeholder: 'Add Filter', - default: {}, - displayOptions: { - show: { - resource, - operation: [ - 'getAll', - ], + typeOptions: { + minValue: 1, + maxValue: 100, }, + default: 100, + description: 'How many results to return.', }, - options: [ - { - displayName: 'Is Active', - name: 'is_active', - type: 'boolean', - default: '', - description: 'Pass true to only return active clients and false to return inactive clients.', + { + displayName: 'Filters', + name: 'filters', + type: 'collection', + placeholder: 'Add Filter', + default: {}, + displayOptions: { + show: { + resource, + operation: [ + 'getAll', + ], + }, }, - { - displayName: 'Updated Since', - name: 'updated_since', - type: 'dateTime', - default: '', - description: 'Only return clients that have been updated since the given date and time.', - } - ] -}, + options: [ + { + displayName: 'Is Active', + name: 'is_active', + type: 'boolean', + default: '', + description: 'Pass true to only return active clients and false to return inactive clients.', + }, + { + displayName: 'Updated Since', + name: 'updated_since', + type: 'dateTime', + default: '', + description: 'Only return clients that have been updated since the given date and time.', + } + ] + }, -/* -------------------------------------------------------------------------- */ -/* contact:get */ -/* -------------------------------------------------------------------------- */ -{ - displayName: 'Contact Id', - name: 'id', - type: 'string', - default: '', - required: true, - displayOptions: { - show: { - operation: [ - 'get', - ], - resource, + /* -------------------------------------------------------------------------- */ + /* contact:get */ + /* -------------------------------------------------------------------------- */ + { + displayName: 'Contact Id', + name: 'id', + type: 'string', + default: '', + required: true, + displayOptions: { + show: { + operation: [ + 'get', + ], + resource, + }, }, + description: 'The ID of the contact you are retrieving.', }, - description: 'The ID of the contact you are retrieving.', -}, -/* -------------------------------------------------------------------------- */ -/* contact:delete */ -/* -------------------------------------------------------------------------- */ -{ - displayName: 'Contact Id', - name: 'id', - type: 'string', - default: '', - required: true, - displayOptions: { - show: { - operation: [ - 'delete', - ], - resource, + /* -------------------------------------------------------------------------- */ + /* contact:delete */ + /* -------------------------------------------------------------------------- */ + { + displayName: 'Contact Id', + name: 'id', + type: 'string', + default: '', + required: true, + displayOptions: { + show: { + operation: [ + 'delete', + ], + resource, + }, }, + description: 'The ID of the contact you want to delete.', + }, + + /* -------------------------------------------------------------------------- */ + /* contact:create */ + /* -------------------------------------------------------------------------- */ + { + displayName: 'First name', + name: 'first_name', + type: 'string', + displayOptions: { + show: { + operation: [ + 'create', + ], + resource, + }, + }, + default: '', + required: true, + description: 'The first name of the contact.', + }, + { + displayName: 'client_id', + name: 'client_id', + type: 'string', + displayOptions: { + show: { + operation: [ + 'create', + ], + resource, + }, + }, + default: '', + required: true, + description: 'The ID of the client associated with this contact.', + }, + { + displayName: 'Additional Fields', + name: 'additionalFields', + type: 'collection', + placeholder: 'Add Field', + displayOptions: { + show: { + operation: [ + 'create', + ], + resource, + }, + }, + default: {}, + options: [ + { + displayName: 'last_name', + name: 'last_name', + type: 'string', + default: '', + description: 'The last name of the contact.' + }, + { + displayName: 'title', + name: 'title', + type: 'string', + default: '', + description: 'The title of the contact.' + }, + { + displayName: 'email', + name: 'email', + type: 'string', + default: '', + description: 'The contact’s email address.' + }, + { + displayName: 'phone_office', + name: 'phone_office', + type: 'string', + default: '', + description: 'The contact’s office phone number.' + }, + { + displayName: 'phone_mobile', + name: 'phone_mobile', + type: 'string', + default: '', + description: 'The contact’s mobile phone number.' + }, + { + displayName: 'fax', + name: 'fax', + type: 'string', + default: '', + description: 'The contact’s fax number.' + }, + ], + }, + + /* -------------------------------------------------------------------------- */ + /* contact:update */ + /* -------------------------------------------------------------------------- */ + { + displayName: 'contact Id', + name: 'id', + type: 'string', + default: '', + required: true, + displayOptions: { + show: { + operation: [ + 'update', + ], + resource, + }, + }, + description: 'The ID of the contact want to update.', + }, + { + displayName: 'Update Fields', + name: 'updateFields', + type: 'collection', + placeholder: 'Add Field', + displayOptions: { + show: { + operation: [ + 'update', + ], + resource, + }, + }, + default: {}, + options: [ + { + displayName: 'client_id', + name: 'client_id', + type: 'string', + default: '', + description: 'The ID of the client associated with this contact.', + }, + { + displayName: 'First name', + name: 'first_name', + type: 'string', + default: '', + description: 'The first name of the contact.', + }, + { + displayName: 'last_name', + name: 'last_name', + type: 'string', + default: '', + description: 'The last name of the contact.' + }, + { + displayName: 'title', + name: 'title', + type: 'string', + default: '', + description: 'The title of the contact.' + }, + { + displayName: 'email', + name: 'email', + type: 'string', + default: '', + description: 'The contact’s email address.' + }, + { + displayName: 'phone_office', + name: 'phone_office', + type: 'string', + default: '', + description: 'The contact’s office phone number.' + }, + { + displayName: 'phone_mobile', + name: 'phone_mobile', + type: 'string', + default: '', + description: 'The contact’s mobile phone number.' + }, + { + displayName: 'fax', + name: 'fax', + type: 'string', + default: '', + description: 'The contact’s fax number.' + }, + ], }, - description: 'The ID of the contact you want to delete.', -} ] as INodeProperties[]; diff --git a/packages/nodes-base/nodes/Harvest/GenericFunctions.ts b/packages/nodes-base/nodes/Harvest/GenericFunctions.ts index 6adf097b3..c0eced039 100644 --- a/packages/nodes-base/nodes/Harvest/GenericFunctions.ts +++ b/packages/nodes-base/nodes/Harvest/GenericFunctions.ts @@ -50,6 +50,7 @@ export async function harvestApiRequest( if (Object.keys(options.body).length === 0) { delete options.body; } + console.log(options) try { const result = await this.helpers.request!(options); diff --git a/packages/nodes-base/nodes/Harvest/Harvest.node.ts b/packages/nodes-base/nodes/Harvest/Harvest.node.ts index 0584aeb31..2c0eac3e6 100644 --- a/packages/nodes-base/nodes/Harvest/Harvest.node.ts +++ b/packages/nodes-base/nodes/Harvest/Harvest.node.ts @@ -35,7 +35,7 @@ async function getAllResource(this: IExecuteFunctions, resource: string, i: numb Object.assign(qs, additionalFields); let responseData: IDataObject = {}; - if(returnAll) { + if (returnAll) { responseData[resource] = await harvestApiRequestAllItems.call(this, requestMethod, qs, endpoint, resource); } else { const limit = this.getNodeParameter('limit', i) as string; @@ -306,6 +306,37 @@ export class Harvest implements INodeType { const responseData: IDataObject[] = await getAllResource.call(this, resource, i); returnData.push.apply(returnData, responseData); + } else if (operation === 'create') { + // ---------------------------------- + // create + // ---------------------------------- + + requestMethod = 'POST'; + endpoint = resource; + + body.name = this.getNodeParameter('name', i) as string; + + const additionalFields = this.getNodeParameter('additionalFields', i) as IDataObject; + Object.assign(body, additionalFields); + + const responseData = await harvestApiRequest.call(this, requestMethod, qs, endpoint, body); + returnData.push(responseData); + + } else if (operation === 'update') { + // ---------------------------------- + // update + // ---------------------------------- + + requestMethod = 'PATCH'; + const id = this.getNodeParameter('id', i) as string; + endpoint = `${resource}/${id}`; + + const updateFields = this.getNodeParameter('updateFields', i) as IDataObject; + Object.assign(qs, updateFields); + + const responseData = await harvestApiRequest.call(this, requestMethod, qs, endpoint, body); + returnData.push(responseData); + } else if (operation === 'delete') { // ---------------------------------- // delete @@ -342,7 +373,7 @@ export class Harvest implements INodeType { const responseData: IDataObject[] = await getAllResource.call(this, resource, i); returnData.push.apply(returnData, responseData); - } else if (operation === 'create') { + } else if (operation === 'create') { // ---------------------------------- // create // ---------------------------------- @@ -362,7 +393,7 @@ export class Harvest implements INodeType { const responseData = await harvestApiRequest.call(this, requestMethod, qs, endpoint, body); returnData.push(responseData); - } else if (operation === 'update') { + } else if (operation === 'update') { // ---------------------------------- // update // ---------------------------------- @@ -377,7 +408,7 @@ export class Harvest implements INodeType { const responseData = await harvestApiRequest.call(this, requestMethod, qs, endpoint, body); returnData.push(responseData); - } else if (operation === 'delete') { + } else if (operation === 'delete') { // ---------------------------------- // delete // ---------------------------------- @@ -444,9 +475,9 @@ export class Harvest implements INodeType { const responseData = await harvestApiRequest.call(this, requestMethod, qs, endpoint, body); returnData.push(responseData); - } else if (operation === 'update') { + } else if (operation === 'update') { // ---------------------------------- - // createByDuration + // update // ---------------------------------- requestMethod = 'PATCH'; @@ -459,7 +490,7 @@ export class Harvest implements INodeType { const responseData = await harvestApiRequest.call(this, requestMethod, qs, endpoint, body); returnData.push(responseData); - } else if (operation === 'delete') { + } else if (operation === 'delete') { // ---------------------------------- // delete // ---------------------------------- @@ -470,7 +501,7 @@ export class Harvest implements INodeType { const responseData = await harvestApiRequest.call(this, requestMethod, qs, endpoint); returnData.push(responseData); - } else { + } else { throw new Error(`The resource "${resource}" is not known!`); } } else if (resource === 'contacts') { @@ -495,6 +526,38 @@ export class Harvest implements INodeType { const responseData: IDataObject[] = await getAllResource.call(this, resource, i); returnData.push.apply(returnData, responseData); + } else if (operation === 'create') { + // ---------------------------------- + // create + // ---------------------------------- + + requestMethod = 'POST'; + endpoint = resource; + + body.client_id = this.getNodeParameter('client_id', i) as string; + body.first_name = this.getNodeParameter('first_name', i) as string; + + const additionalFields = this.getNodeParameter('additionalFields', i) as IDataObject; + Object.assign(body, additionalFields); + + const responseData = await harvestApiRequest.call(this, requestMethod, qs, endpoint, body); + returnData.push(responseData); + + } else if (operation === 'update') { + // ---------------------------------- + // update + // ---------------------------------- + + requestMethod = 'PATCH'; + const id = this.getNodeParameter('id', i) as string; + endpoint = `${resource}/${id}`; + + const updateFields = this.getNodeParameter('updateFields', i) as IDataObject; + Object.assign(qs, updateFields); + + const responseData = await harvestApiRequest.call(this, requestMethod, qs, endpoint, body); + returnData.push(responseData); + } else if (operation === 'delete') { // ---------------------------------- // delete @@ -506,7 +569,7 @@ export class Harvest implements INodeType { const responseData = await harvestApiRequest.call(this, requestMethod, qs, endpoint); returnData.push(responseData); - } else { + } else { throw new Error(`The resource "${resource}" is not known!`); } } else if (resource === 'companies') { @@ -546,7 +609,7 @@ export class Harvest implements INodeType { const responseData: IDataObject[] = await getAllResource.call(this, resource, i); returnData.push.apply(returnData, responseData); - } else if (operation === 'delete') { + } else if (operation === 'delete') { // ---------------------------------- // delete // ---------------------------------- @@ -582,7 +645,7 @@ export class Harvest implements INodeType { const responseData: IDataObject[] = await getAllResource.call(this, resource, i); returnData.push.apply(returnData, responseData); - } else if (operation === 'create') { + } else if (operation === 'create') { // ---------------------------------- // create // ---------------------------------- @@ -598,9 +661,9 @@ export class Harvest implements INodeType { const responseData = await harvestApiRequest.call(this, requestMethod, qs, endpoint, body); returnData.push(responseData); - } else if (operation === 'update') { + } else if (operation === 'update') { // ---------------------------------- - // createByDuration + // update // ---------------------------------- requestMethod = 'PATCH'; @@ -613,7 +676,7 @@ export class Harvest implements INodeType { const responseData = await harvestApiRequest.call(this, requestMethod, qs, endpoint, body); returnData.push(responseData); - } else if (operation === 'delete') { + } else if (operation === 'delete') { // ---------------------------------- // delete // ---------------------------------- @@ -624,7 +687,7 @@ export class Harvest implements INodeType { const responseData = await harvestApiRequest.call(this, requestMethod, qs, endpoint); returnData.push(responseData); - } else { + } else { throw new Error(`The resource "${resource}" is not known!`); } } else if (resource === 'expenses') { @@ -649,7 +712,7 @@ export class Harvest implements INodeType { const responseData: IDataObject[] = await getAllResource.call(this, resource, i); returnData.push.apply(returnData, responseData); - } else if (operation === 'create') { + } else if (operation === 'create') { // ---------------------------------- // create // ---------------------------------- @@ -668,9 +731,9 @@ export class Harvest implements INodeType { const responseData = await harvestApiRequest.call(this, requestMethod, qs, endpoint, body); returnData.push(responseData); - } else if (operation === 'update') { + } else if (operation === 'update') { // ---------------------------------- - // createByDuration + // update // ---------------------------------- requestMethod = 'PATCH'; @@ -683,7 +746,7 @@ export class Harvest implements INodeType { const responseData = await harvestApiRequest.call(this, requestMethod, qs, endpoint, body); returnData.push(responseData); - } else if (operation === 'delete') { + } else if (operation === 'delete') { // ---------------------------------- // delete // ---------------------------------- @@ -694,7 +757,7 @@ export class Harvest implements INodeType { const responseData = await harvestApiRequest.call(this, requestMethod, qs, endpoint); returnData.push(responseData); - } else { + } else { throw new Error(`The resource "${resource}" is not known!`); } } else if (resource === 'estimates') { @@ -719,7 +782,7 @@ export class Harvest implements INodeType { const responseData: IDataObject[] = await getAllResource.call(this, resource, i); returnData.push.apply(returnData, responseData); - } else if (operation === 'create') { + } else if (operation === 'create') { // ---------------------------------- // create // ---------------------------------- @@ -735,9 +798,9 @@ export class Harvest implements INodeType { const responseData = await harvestApiRequest.call(this, requestMethod, qs, endpoint, body); returnData.push(responseData); - } else if (operation === 'update') { + } else if (operation === 'update') { // ---------------------------------- - // createByDuration + // update // ---------------------------------- requestMethod = 'PATCH'; @@ -750,7 +813,7 @@ export class Harvest implements INodeType { const responseData = await harvestApiRequest.call(this, requestMethod, qs, endpoint, body); returnData.push(responseData); - } else if (operation === 'delete') { + } else if (operation === 'delete') { // ---------------------------------- // delete // ---------------------------------- @@ -761,7 +824,7 @@ export class Harvest implements INodeType { const responseData = await harvestApiRequest.call(this, requestMethod, qs, endpoint); returnData.push(responseData); - } else { + } else { throw new Error(`The resource "${resource}" is not known!`); } } else { From d06b38c5ff15366530a9ba886579de98d55814fe Mon Sep 17 00:00:00 2001 From: trojanh Date: Mon, 3 Feb 2020 18:25:21 +0530 Subject: [PATCH 13/14] Capitalize display title --- .../nodes/Harvest/ClientDescription.ts | 216 +++++++++--------- .../nodes/Harvest/ContactDescription.ts | 30 +-- .../nodes/Harvest/EstimateDescription.ts | 8 +- .../nodes/Harvest/GenericFunctions.ts | 2 +- .../nodes/Harvest/InvoiceDescription.ts | 4 +- 5 files changed, 130 insertions(+), 130 deletions(-) diff --git a/packages/nodes-base/nodes/Harvest/ClientDescription.ts b/packages/nodes-base/nodes/Harvest/ClientDescription.ts index 0ee743018..5bc339ae6 100644 --- a/packages/nodes-base/nodes/Harvest/ClientDescription.ts +++ b/packages/nodes-base/nodes/Harvest/ClientDescription.ts @@ -1,6 +1,6 @@ import { INodeProperties } from "n8n-workflow"; -const resource = [ 'clients' ]; +const resource = ['clients']; export const clientOperations = [ { @@ -47,124 +47,124 @@ export const clientOperations = [ export const clientFields = [ -/* -------------------------------------------------------------------------- */ -/* client:getAll */ -/* -------------------------------------------------------------------------- */ + /* -------------------------------------------------------------------------- */ + /* client:getAll */ + /* -------------------------------------------------------------------------- */ -{ - displayName: 'Return All', - name: 'returnAll', - type: 'boolean', - displayOptions: { - show: { - resource, - operation: [ - 'getAll', - ], + { + displayName: 'Return All', + name: 'returnAll', + type: 'boolean', + displayOptions: { + show: { + resource, + operation: [ + 'getAll', + ], + }, }, + default: false, + description: 'Returns a list of your clients.', }, - default: false, - description: 'Returns a list of your clients.', -}, -{ - displayName: 'Limit', - name: 'limit', - type: 'number', - displayOptions: { - show: { - resource, - operation: [ - 'getAll', - ], - returnAll: [ - false, - ], + { + displayName: 'Limit', + name: 'limit', + type: 'number', + displayOptions: { + show: { + resource, + operation: [ + 'getAll', + ], + returnAll: [ + false, + ], + }, }, - }, - typeOptions: { - minValue: 1, - maxValue: 100, - }, - default: 100, - description: 'How many results to return.', -}, -{ - displayName: 'Filters', - name: 'filters', - type: 'collection', - placeholder: 'Add Filter', - default: {}, - displayOptions: { - show: { - resource, - operation: [ - 'getAll', - ], + typeOptions: { + minValue: 1, + maxValue: 100, }, + default: 100, + description: 'How many results to return.', }, - options: [ - { - displayName: 'Is Active', - name: 'is_active', - type: 'boolean', - default: true, - description: 'Pass true to only return active clients and false to return inactive clients.', + { + displayName: 'Filters', + name: 'filters', + type: 'collection', + placeholder: 'Add Filter', + default: {}, + displayOptions: { + show: { + resource, + operation: [ + 'getAll', + ], + }, }, - { - displayName: 'Updated Since', - name: 'updated_since', - type: 'dateTime', - default: '', - description: 'Only return clients that have been updated since the given date and time.', - } - ] -}, + options: [ + { + displayName: 'Is Active', + name: 'is_active', + type: 'boolean', + default: true, + description: 'Pass true to only return active clients and false to return inactive clients.', + }, + { + displayName: 'Updated Since', + name: 'updated_since', + type: 'dateTime', + default: '', + description: 'Only return clients that have been updated since the given date and time.', + } + ] + }, -/* -------------------------------------------------------------------------- */ -/* client:get */ -/* -------------------------------------------------------------------------- */ -{ - displayName: 'Client Id', - name: 'id', - type: 'string', - default: '', - required: true, - displayOptions: { - show: { - operation: [ - 'get', - ], - resource + /* -------------------------------------------------------------------------- */ + /* client:get */ + /* -------------------------------------------------------------------------- */ + { + displayName: 'Client Id', + name: 'id', + type: 'string', + default: '', + required: true, + displayOptions: { + show: { + operation: [ + 'get', + ], + resource + }, }, + description: 'The ID of the client you are retrieving.', }, - description: 'The ID of the client you are retrieving.', -}, -/* -------------------------------------------------------------------------- */ -/* client:delete */ -/* -------------------------------------------------------------------------- */ -{ - displayName: 'Client Id', - name: 'id', - type: 'string', - default: '', - required: true, - displayOptions: { - show: { - operation: [ - 'delete', - ], - resource + /* -------------------------------------------------------------------------- */ + /* client:delete */ + /* -------------------------------------------------------------------------- */ + { + displayName: 'Client Id', + name: 'id', + type: 'string', + default: '', + required: true, + displayOptions: { + show: { + operation: [ + 'delete', + ], + resource + }, }, + description: 'The ID of the client you want to delete.', }, - description: 'The ID of the client you want to delete.', -}, /* -------------------------------------------------------------------------- */ /* client:create */ /* -------------------------------------------------------------------------- */ { - displayName: 'name', + displayName: 'Name', name: 'name', type: 'string', displayOptions: { @@ -195,14 +195,14 @@ export const clientFields = [ default: {}, options: [ { - displayName: 'is_active', + displayName: 'Is Active', name: 'is_active', type: 'string', default: '', description: 'Whether the client is active, or archived. Defaults to true.' }, { - displayName: 'address', + displayName: 'Address', name: 'address', type: 'string', default: '', @@ -218,11 +218,11 @@ export const clientFields = [ ], }, - /* -------------------------------------------------------------------------- */ + /* -------------------------------------------------------------------------- */ /* client:update */ /* -------------------------------------------------------------------------- */ { - displayName: 'client Id', + displayName: 'Client Id', name: 'id', type: 'string', default: '', @@ -253,21 +253,21 @@ export const clientFields = [ default: {}, options: [ { - displayName: 'name', + displayName: 'Name', name: 'name', type: 'string', default: '', description: 'Whether the client is active, or archived. Defaults to true.' }, { - displayName: 'is_active', + displayName: 'Is Active', name: 'is_active', type: 'string', default: '', description: 'Whether the client is active, or archived. Defaults to true.' }, { - displayName: 'address', + displayName: 'Address', name: 'address', type: 'string', default: '', diff --git a/packages/nodes-base/nodes/Harvest/ContactDescription.ts b/packages/nodes-base/nodes/Harvest/ContactDescription.ts index 1532809f5..fa11943a6 100644 --- a/packages/nodes-base/nodes/Harvest/ContactDescription.ts +++ b/packages/nodes-base/nodes/Harvest/ContactDescription.ts @@ -180,7 +180,7 @@ export const contactFields = [ description: 'The first name of the contact.', }, { - displayName: 'client_id', + displayName: 'Client Id', name: 'client_id', type: 'string', displayOptions: { @@ -211,42 +211,42 @@ export const contactFields = [ default: {}, options: [ { - displayName: 'last_name', + displayName: 'Last Name', name: 'last_name', type: 'string', default: '', description: 'The last name of the contact.' }, { - displayName: 'title', + displayName: 'Title', name: 'title', type: 'string', default: '', description: 'The title of the contact.' }, { - displayName: 'email', + displayName: 'Email', name: 'email', type: 'string', default: '', description: 'The contact’s email address.' }, { - displayName: 'phone_office', + displayName: 'Phone Office', name: 'phone_office', type: 'string', default: '', description: 'The contact’s office phone number.' }, { - displayName: 'phone_mobile', + displayName: 'Phone Mobile', name: 'phone_mobile', type: 'string', default: '', description: 'The contact’s mobile phone number.' }, { - displayName: 'fax', + displayName: 'Fax', name: 'fax', type: 'string', default: '', @@ -259,7 +259,7 @@ export const contactFields = [ /* contact:update */ /* -------------------------------------------------------------------------- */ { - displayName: 'contact Id', + displayName: 'Contact Id', name: 'id', type: 'string', default: '', @@ -290,7 +290,7 @@ export const contactFields = [ default: {}, options: [ { - displayName: 'client_id', + displayName: 'Client Id', name: 'client_id', type: 'string', default: '', @@ -304,42 +304,42 @@ export const contactFields = [ description: 'The first name of the contact.', }, { - displayName: 'last_name', + displayName: 'Last Name', name: 'last_name', type: 'string', default: '', description: 'The last name of the contact.' }, { - displayName: 'title', + displayName: 'Title', name: 'title', type: 'string', default: '', description: 'The title of the contact.' }, { - displayName: 'email', + displayName: 'Email', name: 'email', type: 'string', default: '', description: 'The contact’s email address.' }, { - displayName: 'phone_office', + displayName: 'Phone Office', name: 'phone_office', type: 'string', default: '', description: 'The contact’s office phone number.' }, { - displayName: 'phone_mobile', + displayName: 'Phone Mobile', name: 'phone_mobile', type: 'string', default: '', description: 'The contact’s mobile phone number.' }, { - displayName: 'fax', + displayName: 'Fax', name: 'fax', type: 'string', default: '', diff --git a/packages/nodes-base/nodes/Harvest/EstimateDescription.ts b/packages/nodes-base/nodes/Harvest/EstimateDescription.ts index 1bb35601f..f9ea2297c 100644 --- a/packages/nodes-base/nodes/Harvest/EstimateDescription.ts +++ b/packages/nodes-base/nodes/Harvest/EstimateDescription.ts @@ -192,10 +192,10 @@ export const estimateFields = [ }, /* -------------------------------------------------------------------------- */ - /* invoice:create */ + /* estimate:create */ /* -------------------------------------------------------------------------- */ { - displayName: 'client_id', + displayName: 'Client Id', name: 'client_id', type: 'string', displayOptions: { @@ -293,7 +293,7 @@ export const estimateFields = [ }, /* -------------------------------------------------------------------------- */ - /* invoice:update */ + /* estimate:update */ /* -------------------------------------------------------------------------- */ { displayName: 'Invoice Id', @@ -327,7 +327,7 @@ export const estimateFields = [ default: {}, options: [ { - displayName: 'client_id', + displayName: 'Client Id', name: 'client_id', type: 'string', default: '', diff --git a/packages/nodes-base/nodes/Harvest/GenericFunctions.ts b/packages/nodes-base/nodes/Harvest/GenericFunctions.ts index c0eced039..276405df3 100644 --- a/packages/nodes-base/nodes/Harvest/GenericFunctions.ts +++ b/packages/nodes-base/nodes/Harvest/GenericFunctions.ts @@ -50,7 +50,7 @@ export async function harvestApiRequest( if (Object.keys(options.body).length === 0) { delete options.body; } - console.log(options) + try { const result = await this.helpers.request!(options); diff --git a/packages/nodes-base/nodes/Harvest/InvoiceDescription.ts b/packages/nodes-base/nodes/Harvest/InvoiceDescription.ts index ebab65a53..694a99ed9 100644 --- a/packages/nodes-base/nodes/Harvest/InvoiceDescription.ts +++ b/packages/nodes-base/nodes/Harvest/InvoiceDescription.ts @@ -220,7 +220,7 @@ export const invoiceFields = [ /* invoice:create */ /* -------------------------------------------------------------------------- */ { - displayName: 'client_id', + displayName: 'Client Id', name: 'client_id', type: 'string', displayOptions: { @@ -380,7 +380,7 @@ export const invoiceFields = [ default: {}, options: [ { - displayName: 'client_id', + displayName: 'Client Id', name: 'client_id', type: 'string', default: '', From 101df5882d6c7d4f08808d83c90b9653e8c35067 Mon Sep 17 00:00:00 2001 From: Jan Oberhauser Date: Fri, 7 Feb 2020 20:38:13 -0800 Subject: [PATCH 14/14] :zap: Fix and revert changes on Harvest-Node to not break for existing users --- .../nodes/Harvest/ClientDescription.ts | 53 +-- .../nodes/Harvest/CompanyDescription.ts | 4 +- .../nodes/Harvest/ContactDescription.ts | 34 +- .../nodes/Harvest/EstimateDescription.ts | 190 ++++---- .../nodes/Harvest/ExpenseDescription.ts | 180 ++++---- .../nodes-base/nodes/Harvest/Harvest.node.ts | 180 ++++---- .../nodes/Harvest/InvoiceDescription.ts | 224 +++++----- .../nodes/Harvest/ProjectDescription.ts | 411 ++++++++++-------- .../nodes/Harvest/TaskDescription.ts | 67 +-- .../nodes/Harvest/TimeEntryDescription.ts | 50 +-- .../nodes/Harvest/UserDescription.ts | 323 +++++++------- 11 files changed, 879 insertions(+), 837 deletions(-) diff --git a/packages/nodes-base/nodes/Harvest/ClientDescription.ts b/packages/nodes-base/nodes/Harvest/ClientDescription.ts index 5bc339ae6..7a98fe89c 100644 --- a/packages/nodes-base/nodes/Harvest/ClientDescription.ts +++ b/packages/nodes-base/nodes/Harvest/ClientDescription.ts @@ -1,6 +1,6 @@ -import { INodeProperties } from "n8n-workflow"; +import { INodeProperties } from 'n8n-workflow'; -const resource = ['clients']; +const resource = ['client']; export const clientOperations = [ { @@ -13,6 +13,16 @@ export const clientOperations = [ }, }, options: [ + { + name: 'Create', + value: 'create', + description: `Create a client`, + }, + { + name: 'Delete', + value: 'delete', + description: `Delete a client`, + }, { name: 'Get', value: 'get', @@ -23,21 +33,12 @@ export const clientOperations = [ value: 'getAll', description: 'Get data of all clients', }, - { - name: 'Create', - value: 'create', - description: `Create a client`, - }, + { name: 'Update', value: 'update', description: `Update a client`, }, - { - name: 'Delete', - value: 'delete', - description: `Delete a client`, - }, ], default: 'getAll', description: 'The operation to perform.', @@ -252,20 +253,6 @@ export const clientFields = [ }, default: {}, options: [ - { - displayName: 'Name', - name: 'name', - type: 'string', - default: '', - description: 'Whether the client is active, or archived. Defaults to true.' - }, - { - displayName: 'Is Active', - name: 'is_active', - type: 'string', - default: '', - description: 'Whether the client is active, or archived. Defaults to true.' - }, { displayName: 'Address', name: 'address', @@ -280,6 +267,20 @@ export const clientFields = [ default: '', description: 'The currency used by the estimate. If not provided, the client’s currency will be used. See a list of supported currencies' }, + { + displayName: 'Is Active', + name: 'is_active', + type: 'boolean', + default: true, + description: 'Whether the client is active, or archived. Defaults to true.' + }, + { + displayName: 'Name', + name: 'name', + type: 'string', + default: '', + description: 'Whether the client is active, or archived. Defaults to true.' + }, ], }, diff --git a/packages/nodes-base/nodes/Harvest/CompanyDescription.ts b/packages/nodes-base/nodes/Harvest/CompanyDescription.ts index 8de3c255c..d67939afa 100644 --- a/packages/nodes-base/nodes/Harvest/CompanyDescription.ts +++ b/packages/nodes-base/nodes/Harvest/CompanyDescription.ts @@ -1,6 +1,6 @@ -import { INodeProperties } from "n8n-workflow"; +import { INodeProperties } from 'n8n-workflow'; -const resource = [ 'companies' ]; +const resource = [ 'company' ]; export const companyOperations = [ { diff --git a/packages/nodes-base/nodes/Harvest/ContactDescription.ts b/packages/nodes-base/nodes/Harvest/ContactDescription.ts index fa11943a6..c4ecd257b 100644 --- a/packages/nodes-base/nodes/Harvest/ContactDescription.ts +++ b/packages/nodes-base/nodes/Harvest/ContactDescription.ts @@ -1,6 +1,6 @@ -import { INodeProperties } from "n8n-workflow"; +import { INodeProperties } from 'n8n-workflow'; -const resource = ['contacts']; +const resource = ['contact']; export const contactOperations = [ { @@ -13,6 +13,16 @@ export const contactOperations = [ }, }, options: [ + { + name: 'Create', + value: 'create', + description: `Create a contact`, + }, + { + name: 'Delete', + value: 'delete', + description: `Delete a contact`, + }, { name: 'Get', value: 'get', @@ -23,21 +33,11 @@ export const contactOperations = [ value: 'getAll', description: 'Get data of all contacts', }, - { - name: 'Create', - value: 'create', - description: `Create a contact`, - }, { name: 'Update', value: 'update', description: `Update a contact`, }, - { - name: 'Delete', - value: 'delete', - description: `Delete a contact`, - }, ], default: 'getAll', description: 'The operation to perform.', @@ -107,7 +107,7 @@ export const contactFields = [ displayName: 'Is Active', name: 'is_active', type: 'boolean', - default: '', + default: true, description: 'Pass true to only return active clients and false to return inactive clients.', }, { @@ -164,8 +164,8 @@ export const contactFields = [ /* contact:create */ /* -------------------------------------------------------------------------- */ { - displayName: 'First name', - name: 'first_name', + displayName: 'First Name', + name: 'firstName', type: 'string', displayOptions: { show: { @@ -181,7 +181,7 @@ export const contactFields = [ }, { displayName: 'Client Id', - name: 'client_id', + name: 'clientId', type: 'string', displayOptions: { show: { @@ -297,7 +297,7 @@ export const contactFields = [ description: 'The ID of the client associated with this contact.', }, { - displayName: 'First name', + displayName: 'First Name', name: 'first_name', type: 'string', default: '', diff --git a/packages/nodes-base/nodes/Harvest/EstimateDescription.ts b/packages/nodes-base/nodes/Harvest/EstimateDescription.ts index f9ea2297c..35a252be8 100644 --- a/packages/nodes-base/nodes/Harvest/EstimateDescription.ts +++ b/packages/nodes-base/nodes/Harvest/EstimateDescription.ts @@ -1,6 +1,6 @@ -import { INodeProperties } from "n8n-workflow"; +import { INodeProperties } from 'n8n-workflow'; -const resource = [ 'estimates' ]; +const resource = [ 'estimate' ]; export const estimateOperations = [ { @@ -13,6 +13,16 @@ export const estimateOperations = [ }, }, options: [ + { + name: 'Create', + value: 'create', + description: `Create a estimate`, + }, + { + name: 'Delete', + value: 'delete', + description: `Delete an estimate`, + }, { name: 'Get', value: 'get', @@ -23,21 +33,11 @@ export const estimateOperations = [ value: 'getAll', description: 'Get data of all estimates', }, - { - name: 'Create', - value: 'create', - description: `Create a estimate`, - }, { name: 'Update', value: 'update', description: `Update a estimate`, }, - { - name: 'Delete', - value: 'delete', - description: `Delete an estimate`, - }, ], default: 'getAll', description: 'The operation to perform.', @@ -110,13 +110,6 @@ export const estimateFields = [ default: '', description: 'Only return time entries belonging to the client with the given ID.', }, - { - displayName: 'Updated Since', - name: 'updated_since', - type: 'dateTime', - default: '', - description: 'Only return time entries that have been updated since the given date and time.', - }, { displayName: 'From', name: 'from', @@ -124,6 +117,13 @@ export const estimateFields = [ default: '', description: 'Only return time entries with a spent_date on or after the given date.', }, + { + displayName: 'State', + name: 'state', + type: 'string', + default: '', + description: 'Only return estimates with a state matching the value provided. Options: draft, sent, accepted, or declined.', + }, { displayName: 'To', name: 'to', @@ -132,11 +132,11 @@ export const estimateFields = [ description: 'Only return time entries with a spent_date on or before the given date.', }, { - displayName: 'State', - name: 'state', - type: 'string', + displayName: 'Updated Since', + name: 'updated_since', + type: 'dateTime', default: '', - description: 'Only return estimates with a state matching the value provided. Options: draft, sent, accepted, or declined.', + description: 'Only return time entries that have been updated since the given date and time.', }, { displayName: 'Page', @@ -196,7 +196,7 @@ export const estimateFields = [ /* -------------------------------------------------------------------------- */ { displayName: 'Client Id', - name: 'client_id', + name: 'clientId', type: 'string', displayOptions: { show: { @@ -225,6 +225,34 @@ export const estimateFields = [ }, default: {}, options: [ + { + displayName: 'Currency', + name: 'currency', + type: 'string', + default: '', + description: 'The currency used by the estimate. If not provided, the client’s currency will be used. See a list of supported currencies' + }, + { + displayName: 'Discount', + name: 'over_budget_notification_percentage', + type: 'string', + default: '', + description: 'This percentage is subtracted from the subtotal. Example: use 10.0 for 10.0%.' + }, + { + displayName: 'Issue Date', + name: 'issue_date', + type: 'dateTime', + default: '', + description: 'Date the invoice was issued. Defaults to today’s date.' + }, + { + displayName: 'Notes', + name: 'notes', + type: 'string', + default: '', + description: 'Any additional notes to include on the estimate.' + }, { displayName: 'Number', name: 'number', @@ -239,6 +267,13 @@ export const estimateFields = [ default: '', description: 'The purchase order number.' }, + { + displayName: 'Subject', + name: 'subject', + type: 'string', + default: '', + description: 'The estimate subject.' + }, { displayName: 'Tax', name: 'tax', @@ -253,42 +288,6 @@ export const estimateFields = [ default: '', description: 'This percentage is applied to the subtotal, including line items and discounts. Example: use 10.0 for 10.0%.' }, - { - displayName: 'Discount', - name: 'over_budget_notification_percentage', - type: 'string', - default: '', - description: 'This percentage is subtracted from the subtotal. Example: use 10.0 for 10.0%.' - }, - { - displayName: 'Subject', - name: 'subject', - type: 'string', - default: '', - description: 'The estimate subject.' - }, - { - displayName: 'Currency', - name: 'currency', - type: 'string', - default: '', - description: 'The currency used by the estimate. If not provided, the client’s currency will be used. See a list of supported currencies' - }, - { - displayName: 'Notes', - name: 'notes', - type: 'string', - default: '', - description: 'Any additional notes to include on the estimate.' - }, - { - displayName: 'Issue Date', - name: 'issue_date', - type: 'dateTime', - default: '', - description: 'Date the invoice was issued. Defaults to today’s date.' - }, - ], }, @@ -333,6 +332,27 @@ export const estimateFields = [ default: '', description: 'The ID of the retainer associated with this invoice..', }, + { + displayName: 'Currency', + name: 'currency', + type: 'string', + default: '', + description: 'The currency used by the estimate. If not provided, the client’s currency will be used. See a list of supported currencies' + }, + { + displayName: 'Discount', + name: 'over_budget_notification_percentage', + type: 'string', + default: '', + description: 'This percentage is subtracted from the subtotal. Example: use 10.0 for 10.0%.' + }, + { + displayName: 'Issue Date', + name: 'issue_date', + type: 'dateTime', + default: '', + description: 'Date the invoice was issued. Defaults to today’s date.' + }, { displayName: 'Number', name: 'number', @@ -340,6 +360,13 @@ export const estimateFields = [ default: '', description: 'If no value is set, the number will be automatically generated.' }, + { + displayName: 'Notes', + name: 'notes', + type: 'string', + default: '', + description: 'Any additional notes to include on the estimate.' + }, { displayName: 'Purchase Order', name: 'purchase_order', @@ -347,6 +374,13 @@ export const estimateFields = [ default: '', description: 'The purchase order number.' }, + { + displayName: 'Subject', + name: 'subject', + type: 'string', + default: '', + description: 'The estimate subject.' + }, { displayName: 'Tax', name: 'tax', @@ -361,42 +395,6 @@ export const estimateFields = [ default: '', description: 'This percentage is applied to the subtotal, including line items and discounts. Example: use 10.0 for 10.0%.' }, - { - displayName: 'Discount', - name: 'over_budget_notification_percentage', - type: 'string', - default: '', - description: 'This percentage is subtracted from the subtotal. Example: use 10.0 for 10.0%.' - }, - { - displayName: 'Subject', - name: 'subject', - type: 'string', - default: '', - description: 'The estimate subject.' - }, - { - displayName: 'Currency', - name: 'currency', - type: 'string', - default: '', - description: 'The currency used by the estimate. If not provided, the client’s currency will be used. See a list of supported currencies' - }, - { - displayName: 'Notes', - name: 'notes', - type: 'string', - default: '', - description: 'Any additional notes to include on the estimate.' - }, - { - displayName: 'Issue Date', - name: 'issue_date', - type: 'dateTime', - default: '', - description: 'Date the invoice was issued. Defaults to today’s date.' - }, - ], }, diff --git a/packages/nodes-base/nodes/Harvest/ExpenseDescription.ts b/packages/nodes-base/nodes/Harvest/ExpenseDescription.ts index c2095b622..3a1b006ee 100644 --- a/packages/nodes-base/nodes/Harvest/ExpenseDescription.ts +++ b/packages/nodes-base/nodes/Harvest/ExpenseDescription.ts @@ -1,6 +1,6 @@ -import { INodeProperties } from "n8n-workflow"; +import { INodeProperties } from 'n8n-workflow'; -const resource = [ 'expenses' ]; +const resource = [ 'expense' ]; export const expenseOperations = [ { @@ -103,13 +103,6 @@ export const expenseFields = [ }, }, options: [ - { - displayName: 'User ID', - name: 'user_id', - type: 'string', - default: '', - description: 'Only return time entries belonging to the user with the given ID.', - }, { displayName: 'Client ID', name: 'client_id', @@ -117,27 +110,6 @@ export const expenseFields = [ default: '', description: 'Only return time entries belonging to the client with the given ID.', }, - { - displayName: 'Project ID', - name: 'project_id', - type: 'string', - default: '', - description: 'Only return time entries belonging to the client with the given ID.', - }, - { - displayName: 'Is Billed', - name: 'is_billed', - type: 'boolean', - default: '', - description: 'Pass true to only return time entries that have been invoiced and false to return time entries that have not been invoiced.', - }, - { - displayName: 'Updated Since', - name: 'updated_since', - type: 'dateTime', - default: '', - description: 'Only return time entries that have been updated since the given date and time.', - }, { displayName: 'From', name: 'from', @@ -146,11 +118,11 @@ export const expenseFields = [ description: 'Only return time entries with a spent_date on or after the given date.', }, { - displayName: 'To', - name: 'to', - type: 'dateTime', - default: '', - description: 'Only return time entries with a spent_date on or before the given date.', + displayName: 'Is Billed', + name: 'is_billed', + type: 'boolean', + default: false, + description: 'Pass true to only return time entries that have been invoiced and false to return time entries that have not been invoiced.', }, { displayName: 'Page', @@ -161,7 +133,35 @@ export const expenseFields = [ }, default: 1, description: 'The page number to use in pagination. For instance, if you make a list request and receive 100 records, your subsequent call can include page=2 to retrieve the next page of the list. (Default: 1)', - } + }, + { + displayName: 'Project ID', + name: 'project_id', + type: 'string', + default: '', + description: 'Only return time entries belonging to the client with the given ID.', + }, + { + displayName: 'To', + name: 'to', + type: 'dateTime', + default: '', + description: 'Only return time entries with a spent_date on or before the given date.', + }, + { + displayName: 'Updated Since', + name: 'updated_since', + type: 'dateTime', + default: '', + description: 'Only return time entries that have been updated since the given date and time.', + }, + { + displayName: 'User ID', + name: 'user_id', + type: 'string', + default: '', + description: 'Only return time entries belonging to the user with the given ID.', + }, ] }, @@ -210,7 +210,7 @@ export const expenseFields = [ /* -------------------------------------------------------------------------- */ { displayName: 'Project Id', - name: 'project_id', + name: 'projectId', type: 'string', displayOptions: { show: { @@ -226,7 +226,7 @@ export const expenseFields = [ }, { displayName: 'Expense Category Id', - name: 'expense_category_id', + name: 'expenseCategoryId', type: 'string', displayOptions: { show: { @@ -242,7 +242,7 @@ export const expenseFields = [ }, { displayName: 'Spent Date', - name: 'spent_date', + name: 'spentDate', type: 'dateTime', displayOptions: { show: { @@ -271,32 +271,11 @@ export const expenseFields = [ }, default: {}, options: [ - { - displayName: 'User Id', - name: 'user_id', - type: 'boolean', - default: true, - description: 'The ID of the user associated with this expense. Defaults to the ID of the currently authenticated user.' - }, - { - displayName: 'Units', - name: 'units', - type: 'string', - default: '', - description: 'The quantity of units to use in calculating the total_cost of the expense.' - }, - { - displayName: 'Total Cost', - name: 'total_cost', - type: 'string', - default: '', - description: 'The total amount of the expense.' - }, { displayName: 'Billable', name: 'billable', - type: 'string', - default: '', + type: 'boolean', + default: true, description: 'Whether this expense is billable or not. Defaults to true.' }, { @@ -306,7 +285,27 @@ export const expenseFields = [ default: '', description: 'Notes about the expense.' }, - + { + displayName: 'Total Cost', + name: 'total_cost', + type: 'string', + default: '', + description: 'The total amount of the expense.' + }, + { + displayName: 'Units', + name: 'units', + type: 'string', + default: '', + description: 'The quantity of units to use in calculating the total_cost of the expense.' + }, + { + displayName: 'User Id', + name: 'user_id', + type: 'boolean', + default: true, + description: 'The ID of the user associated with this expense. Defaults to the ID of the currently authenticated user.' + }, ], }, @@ -345,11 +344,11 @@ export const expenseFields = [ default: {}, options: [ { - displayName: 'Project Id', - name: 'project_id', - type: 'string', - default: '', - description: 'The ID of the project associated with this expense.', + displayName: 'Billable', + name: 'billable', + type: 'boolean', + default: true, + description: 'Whether this expense is billable or not. Defaults to true.' }, { displayName: 'Expense Category Id', @@ -358,6 +357,20 @@ export const expenseFields = [ default: '', description: 'The ID of the expense category this expense is being tracked against.', }, + { + displayName: 'Notes', + name: 'notes', + type: 'string', + default: '', + description: 'Notes about the expense.' + }, + { + displayName: 'Project Id', + name: 'project_id', + type: 'string', + default: '', + description: 'The ID of the project associated with this expense.', + }, { displayName: 'Spent Date', name: 'spent_date', @@ -365,20 +378,6 @@ export const expenseFields = [ default: '', description: 'Date the expense occurred.', }, - { - displayName: 'User Id', - name: 'user_id', - type: 'boolean', - default: true, - description: 'The ID of the user associated with this expense. Defaults to the ID of the currently authenticated user.' - }, - { - displayName: 'Units', - name: 'units', - type: 'string', - default: '', - description: 'The quantity of units to use in calculating the total_cost of the expense.' - }, { displayName: 'Total Cost', name: 'total_cost', @@ -387,20 +386,19 @@ export const expenseFields = [ description: 'The total amount of the expense.' }, { - displayName: 'Billable', - name: 'billable', + displayName: 'Units', + name: 'units', type: 'string', default: '', - description: 'Whether this expense is billable or not. Defaults to true.' + description: 'The quantity of units to use in calculating the total_cost of the expense.' }, { - displayName: 'Notes', - name: 'notes', - type: 'string', - default: '', - description: 'Notes about the expense.' + displayName: 'User Id', + name: 'user_id', + type: 'boolean', + default: true, + description: 'The ID of the user associated with this expense. Defaults to the ID of the currently authenticated user.' }, - ], }, diff --git a/packages/nodes-base/nodes/Harvest/Harvest.node.ts b/packages/nodes-base/nodes/Harvest/Harvest.node.ts index 2c0eac3e6..336a7838a 100644 --- a/packages/nodes-base/nodes/Harvest/Harvest.node.ts +++ b/packages/nodes-base/nodes/Harvest/Harvest.node.ts @@ -8,17 +8,17 @@ import { INodeType, } from 'n8n-workflow'; -import { harvestApiRequest, harvestApiRequestAllItems } from './GenericFunctions'; -import { timeEntryOperations, timeEntryFields } from './TimeEntryDescription'; import { clientOperations, clientFields } from './ClientDescription'; -import { companyOperations } from './CompanyDescription'; import { contactOperations, contactFields } from './ContactDescription'; +import { companyOperations } from './CompanyDescription'; +import { estimateOperations, estimateFields } from './EstimateDescription'; import { expenseOperations, expenseFields } from './ExpenseDescription'; +import { harvestApiRequest, harvestApiRequestAllItems } from './GenericFunctions'; import { invoiceOperations, invoiceFields } from './InvoiceDescription'; import { projectOperations, projectFields } from './ProjectDescription'; import { taskOperations, taskFields } from './TaskDescription'; +import { timeEntryOperations, timeEntryFields } from './TimeEntryDescription'; import { userOperations, userFields } from './UserDescription'; -import { estimateOperations, estimateFields } from './EstimateDescription'; /** * fetch All resource using paginated calls @@ -75,46 +75,46 @@ export class Harvest implements INodeType { { name: 'Client', - value: 'clients', + value: 'client', }, { name: 'Company', - value: 'companies', + value: 'company', }, { name: 'Contact', - value: 'contacts', + value: 'contact', }, { - name: 'Estimates', - value: 'estimates', + name: 'Estimate', + value: 'estimate', }, { name: 'Expense', - value: 'expenses', + value: 'expense', }, { name: 'Invoice', - value: 'invoices', + value: 'invoice', }, { name: 'Project', - value: 'projects', + value: 'project', }, { name: 'Task', - value: 'tasks', + value: 'task', }, { name: 'Time Entries', - value: 'time_entries', + value: 'timeEntry', }, { name: 'User', - value: 'users', + value: 'user', }, ], - default: 'tasks', + default: 'task', description: 'The resource to operate on.', }, @@ -147,7 +147,6 @@ export class Harvest implements INodeType { const items = this.getInputData(); const returnData: IDataObject[] = []; - const resource = this.getNodeParameter('resource', 0) as string; const operation = this.getNodeParameter('operation', 0) as string; @@ -156,12 +155,11 @@ export class Harvest implements INodeType { let body: IDataObject | Buffer; let qs: IDataObject; - for (let i = 0; i < items.length; i++) { body = {}; qs = {}; - if (resource === 'time_entries') { + if (resource === 'timeEntry') { if (operation === 'get') { // ---------------------------------- // get @@ -170,7 +168,7 @@ export class Harvest implements INodeType { requestMethod = 'GET'; const id = this.getNodeParameter('id', i) as string; - endpoint = `${resource}/${id}`; + endpoint = `time_entries/${id}`; const responseData = await harvestApiRequest.call(this, requestMethod, qs, endpoint); returnData.push(responseData); @@ -179,7 +177,7 @@ export class Harvest implements INodeType { // ---------------------------------- // getAll // ---------------------------------- - const responseData: IDataObject[] = await getAllResource.call(this, resource, i); + const responseData: IDataObject[] = await getAllResource.call(this, 'time_entries', i); returnData.push.apply(returnData, responseData); } else if (operation === 'createByStartEnd') { @@ -188,7 +186,7 @@ export class Harvest implements INodeType { // ---------------------------------- requestMethod = 'POST'; - endpoint = resource; + endpoint = 'time_entries'; body.project_id = this.getNodeParameter('projectId', i) as string; body.task_id = this.getNodeParameter('taskId', i) as string; @@ -206,7 +204,7 @@ export class Harvest implements INodeType { // ---------------------------------- requestMethod = 'POST'; - endpoint = resource; + endpoint = 'time_entries'; body.project_id = this.getNodeParameter('projectId', i) as string; body.task_id = this.getNodeParameter('taskId', i) as string; @@ -225,7 +223,7 @@ export class Harvest implements INodeType { requestMethod = 'DELETE'; const id = this.getNodeParameter('id', i) as string; - endpoint = `${resource}/${id}`; + endpoint = `time_entries/${id}`; const responseData = await harvestApiRequest.call(this, requestMethod, qs, endpoint); returnData.push(responseData); @@ -236,7 +234,7 @@ export class Harvest implements INodeType { requestMethod = 'DELETE'; const id = this.getNodeParameter('id', i) as string; - endpoint = `${resource}/${id}/external_reference`; + endpoint = `time_entries/${id}/external_reference`; const responseData = await harvestApiRequest.call(this, requestMethod, qs, endpoint); returnData.push(responseData); @@ -248,7 +246,7 @@ export class Harvest implements INodeType { requestMethod = 'PATCH'; const id = this.getNodeParameter('id', i) as string; - endpoint = `${resource}/${id}/restart`; + endpoint = `time_entries/${id}/restart`; const responseData = await harvestApiRequest.call(this, requestMethod, qs, endpoint); returnData.push(responseData); @@ -260,7 +258,7 @@ export class Harvest implements INodeType { requestMethod = 'PATCH'; const id = this.getNodeParameter('id', i) as string; - endpoint = `${resource}/${id}/stop`; + endpoint = `time_entries/${id}/stop`; const responseData = await harvestApiRequest.call(this, requestMethod, qs, endpoint); returnData.push(responseData); @@ -272,7 +270,7 @@ export class Harvest implements INodeType { requestMethod = 'PATCH'; const id = this.getNodeParameter('id', i) as string; - endpoint = `${resource}/${id}`; + endpoint = `time_entries/${id}`; const updateFields = this.getNodeParameter('updateFields', i) as IDataObject; @@ -284,7 +282,7 @@ export class Harvest implements INodeType { throw new Error(`The operation "${operation}" is not known!`); } - } else if (resource === 'clients') { + } else if (resource === 'client') { if (operation === 'get') { // ---------------------------------- // get @@ -293,7 +291,7 @@ export class Harvest implements INodeType { requestMethod = 'GET'; const id = this.getNodeParameter('id', i) as string; - endpoint = `${resource}/${id}`; + endpoint = `clients/${id}`; const responseData = await harvestApiRequest.call(this, requestMethod, qs, endpoint); returnData.push(responseData); @@ -303,7 +301,7 @@ export class Harvest implements INodeType { // getAll // ---------------------------------- - const responseData: IDataObject[] = await getAllResource.call(this, resource, i); + const responseData: IDataObject[] = await getAllResource.call(this, 'clients', i); returnData.push.apply(returnData, responseData); } else if (operation === 'create') { @@ -312,7 +310,7 @@ export class Harvest implements INodeType { // ---------------------------------- requestMethod = 'POST'; - endpoint = resource; + endpoint = 'clients'; body.name = this.getNodeParameter('name', i) as string; @@ -329,7 +327,7 @@ export class Harvest implements INodeType { requestMethod = 'PATCH'; const id = this.getNodeParameter('id', i) as string; - endpoint = `${resource}/${id}`; + endpoint = `clients/${id}`; const updateFields = this.getNodeParameter('updateFields', i) as IDataObject; Object.assign(qs, updateFields); @@ -344,14 +342,14 @@ export class Harvest implements INodeType { requestMethod = 'DELETE'; const id = this.getNodeParameter('id', i) as string; - endpoint = `${resource}/${id}`; + endpoint = `clients/${id}`; const responseData = await harvestApiRequest.call(this, requestMethod, qs, endpoint); returnData.push(responseData); } else { throw new Error(`The resource "${resource}" is not known!`); } - } else if (resource === 'projects') { + } else if (resource === 'project') { if (operation === 'get') { // ---------------------------------- // get @@ -360,7 +358,7 @@ export class Harvest implements INodeType { requestMethod = 'GET'; const id = this.getNodeParameter('id', i) as string; - endpoint = `${resource}/${id}`; + endpoint = `projects/${id}`; const responseData = await harvestApiRequest.call(this, requestMethod, qs, endpoint); returnData.push(responseData); @@ -370,7 +368,7 @@ export class Harvest implements INodeType { // getAll // ---------------------------------- - const responseData: IDataObject[] = await getAllResource.call(this, resource, i); + const responseData: IDataObject[] = await getAllResource.call(this, 'projects', i); returnData.push.apply(returnData, responseData); } else if (operation === 'create') { @@ -379,13 +377,13 @@ export class Harvest implements INodeType { // ---------------------------------- requestMethod = 'POST'; - endpoint = resource; + endpoint = 'projects'; - body.client_id = this.getNodeParameter('client_id', i) as string; + body.client_id = this.getNodeParameter('clientId', i) as string; body.name = this.getNodeParameter('name', i) as string; - body.is_billable = this.getNodeParameter('is_billable', i) as string; - body.bill_by = this.getNodeParameter('bill_by', i) as string; - body.budget_by = this.getNodeParameter('budget_by', i) as string; + body.is_billable = this.getNodeParameter('isBillable', i) as string; + body.bill_by = this.getNodeParameter('billBy', i) as string; + body.budget_by = this.getNodeParameter('budgetBy', i) as string; const additionalFields = this.getNodeParameter('additionalFields', i) as IDataObject; Object.assign(body, additionalFields); @@ -400,7 +398,7 @@ export class Harvest implements INodeType { requestMethod = 'PATCH'; const id = this.getNodeParameter('id', i) as string; - endpoint = `${resource}/${id}`; + endpoint = `projects/${id}`; const updateFields = this.getNodeParameter('updateFields', i) as IDataObject; @@ -415,14 +413,14 @@ export class Harvest implements INodeType { requestMethod = 'DELETE'; const id = this.getNodeParameter('id', i) as string; - endpoint = `${resource}/${id}`; + endpoint = `projects/${id}`; const responseData = await harvestApiRequest.call(this, requestMethod, qs, endpoint); returnData.push(responseData); } else { throw new Error(`The resource "${resource}" is not known!`); } - } else if (resource === 'users') { + } else if (resource === 'user') { if (operation === 'get') { // ---------------------------------- // get @@ -431,7 +429,7 @@ export class Harvest implements INodeType { requestMethod = 'GET'; const id = this.getNodeParameter('id', i) as string; - endpoint = `${resource}/${id}`; + endpoint = `users/${id}`; const responseData = await harvestApiRequest.call(this, requestMethod, qs, endpoint); returnData.push(responseData); @@ -441,7 +439,7 @@ export class Harvest implements INodeType { // getAll // ---------------------------------- - const responseData: IDataObject[] = await getAllResource.call(this, resource, i); + const responseData: IDataObject[] = await getAllResource.call(this, 'users', i); returnData.push.apply(returnData, responseData); } else if (operation === 'me') { @@ -451,24 +449,23 @@ export class Harvest implements INodeType { requestMethod = 'GET'; - endpoint = `${resource}/me`; + endpoint = `users/me`; const responseData = await harvestApiRequest.call(this, requestMethod, qs, endpoint); returnData.push(responseData); } else if (operation === 'create') { // ---------------------------------- - // createByDuration + // create // ---------------------------------- requestMethod = 'POST'; - endpoint = resource; + endpoint = 'users'; - body.first_name = this.getNodeParameter('first_name', i) as string; - body.last_name = this.getNodeParameter('last_name', i) as string; + body.first_name = this.getNodeParameter('firstName', i) as string; + body.last_name = this.getNodeParameter('lastName', i) as string; body.email = this.getNodeParameter('email', i) as string; - const additionalFields = this.getNodeParameter('additionalFields', i) as IDataObject; Object.assign(body, additionalFields); @@ -482,7 +479,7 @@ export class Harvest implements INodeType { requestMethod = 'PATCH'; const id = this.getNodeParameter('id', i) as string; - endpoint = `${resource}/${id}`; + endpoint = `users/${id}`; const updateFields = this.getNodeParameter('updateFields', i) as IDataObject; Object.assign(qs, updateFields); @@ -497,14 +494,14 @@ export class Harvest implements INodeType { requestMethod = 'DELETE'; const id = this.getNodeParameter('id', i) as string; - endpoint = `${resource}/${id}`; + endpoint = `users/${id}`; const responseData = await harvestApiRequest.call(this, requestMethod, qs, endpoint); returnData.push(responseData); } else { throw new Error(`The resource "${resource}" is not known!`); } - } else if (resource === 'contacts') { + } else if (resource === 'contact') { if (operation === 'get') { // ---------------------------------- // get @@ -513,7 +510,7 @@ export class Harvest implements INodeType { requestMethod = 'GET'; const id = this.getNodeParameter('id', i) as string; - endpoint = `${resource}/${id}`; + endpoint = `contacts/${id}`; const responseData = await harvestApiRequest.call(this, requestMethod, qs, endpoint); returnData.push(responseData); @@ -523,7 +520,7 @@ export class Harvest implements INodeType { // getAll // ---------------------------------- - const responseData: IDataObject[] = await getAllResource.call(this, resource, i); + const responseData: IDataObject[] = await getAllResource.call(this, 'contacts', i); returnData.push.apply(returnData, responseData); } else if (operation === 'create') { @@ -532,10 +529,10 @@ export class Harvest implements INodeType { // ---------------------------------- requestMethod = 'POST'; - endpoint = resource; + endpoint = 'contacts'; - body.client_id = this.getNodeParameter('client_id', i) as string; - body.first_name = this.getNodeParameter('first_name', i) as string; + body.client_id = this.getNodeParameter('clientId', i) as string; + body.first_name = this.getNodeParameter('firstName', i) as string; const additionalFields = this.getNodeParameter('additionalFields', i) as IDataObject; Object.assign(body, additionalFields); @@ -550,7 +547,7 @@ export class Harvest implements INodeType { requestMethod = 'PATCH'; const id = this.getNodeParameter('id', i) as string; - endpoint = `${resource}/${id}`; + endpoint = `contacts/${id}`; const updateFields = this.getNodeParameter('updateFields', i) as IDataObject; Object.assign(qs, updateFields); @@ -565,14 +562,14 @@ export class Harvest implements INodeType { requestMethod = 'DELETE'; const id = this.getNodeParameter('id', i) as string; - endpoint = `${resource}/${id}`; + endpoint = `contacts/${id}`; const responseData = await harvestApiRequest.call(this, requestMethod, qs, endpoint); returnData.push(responseData); } else { throw new Error(`The resource "${resource}" is not known!`); } - } else if (resource === 'companies') { + } else if (resource === 'company') { if (operation === 'get') { // ---------------------------------- // get @@ -587,7 +584,7 @@ export class Harvest implements INodeType { } else { throw new Error(`The resource "${resource}" is not known!`); } - } else if (resource === 'tasks') { + } else if (resource === 'task') { if (operation === 'get') { // ---------------------------------- // get @@ -596,7 +593,7 @@ export class Harvest implements INodeType { requestMethod = 'GET'; const id = this.getNodeParameter('id', i) as string; - endpoint = `${resource}/${id}`; + endpoint = `tasks/${id}`; const responseData = await harvestApiRequest.call(this, requestMethod, qs, endpoint); returnData.push(responseData); @@ -606,7 +603,7 @@ export class Harvest implements INodeType { // getAll // ---------------------------------- - const responseData: IDataObject[] = await getAllResource.call(this, resource, i); + const responseData: IDataObject[] = await getAllResource.call(this, 'tasks', i); returnData.push.apply(returnData, responseData); } else if (operation === 'delete') { @@ -616,14 +613,14 @@ export class Harvest implements INodeType { requestMethod = 'DELETE'; const id = this.getNodeParameter('id', i) as string; - endpoint = `${resource}/${id}`; + endpoint = `tasks/${id}`; const responseData = await harvestApiRequest.call(this, requestMethod, qs, endpoint); returnData.push(responseData); } else { throw new Error(`The resource "${resource}" is not known!`); } - } else if (resource === 'invoices') { + } else if (resource === 'invoice') { if (operation === 'get') { // ---------------------------------- // get @@ -632,7 +629,7 @@ export class Harvest implements INodeType { requestMethod = 'GET'; const id = this.getNodeParameter('id', i) as string; - endpoint = `${resource}/${id}`; + endpoint = `invoices/${id}`; const responseData = await harvestApiRequest.call(this, requestMethod, qs, endpoint); returnData.push(responseData); @@ -642,7 +639,7 @@ export class Harvest implements INodeType { // getAll // ---------------------------------- - const responseData: IDataObject[] = await getAllResource.call(this, resource, i); + const responseData: IDataObject[] = await getAllResource.call(this, 'invoices', i); returnData.push.apply(returnData, responseData); } else if (operation === 'create') { @@ -651,9 +648,9 @@ export class Harvest implements INodeType { // ---------------------------------- requestMethod = 'POST'; - endpoint = resource; + endpoint = 'invoices'; - body.client_id = this.getNodeParameter('client_id', i) as string; + body.client_id = this.getNodeParameter('clientId', i) as string; const additionalFields = this.getNodeParameter('additionalFields', i) as IDataObject; Object.assign(body, additionalFields); @@ -668,7 +665,7 @@ export class Harvest implements INodeType { requestMethod = 'PATCH'; const id = this.getNodeParameter('id', i) as string; - endpoint = `${resource}/${id}`; + endpoint = `invoices/${id}`; const updateFields = this.getNodeParameter('updateFields', i) as IDataObject; Object.assign(qs, updateFields); @@ -683,14 +680,14 @@ export class Harvest implements INodeType { requestMethod = 'DELETE'; const id = this.getNodeParameter('id', i) as string; - endpoint = `${resource}/${id}`; + endpoint = `invoices/${id}`; const responseData = await harvestApiRequest.call(this, requestMethod, qs, endpoint); returnData.push(responseData); } else { throw new Error(`The resource "${resource}" is not known!`); } - } else if (resource === 'expenses') { + } else if (resource === 'expense') { if (operation === 'get') { // ---------------------------------- // get @@ -699,7 +696,7 @@ export class Harvest implements INodeType { requestMethod = 'GET'; const id = this.getNodeParameter('id', i) as string; - endpoint = `${resource}/${id}`; + endpoint = `expenses/${id}`; const responseData = await harvestApiRequest.call(this, requestMethod, qs, endpoint); returnData.push(responseData); @@ -709,7 +706,7 @@ export class Harvest implements INodeType { // getAll // ---------------------------------- - const responseData: IDataObject[] = await getAllResource.call(this, resource, i); + const responseData: IDataObject[] = await getAllResource.call(this, 'expenses', i); returnData.push.apply(returnData, responseData); } else if (operation === 'create') { @@ -718,12 +715,11 @@ export class Harvest implements INodeType { // ---------------------------------- requestMethod = 'POST'; - endpoint = resource; - - body.project_id = this.getNodeParameter('project_id', i) as string; - body.expense_category_id = this.getNodeParameter('expense_category_id', i) as string; - body.spent_date = this.getNodeParameter('spent_date', i) as string; + endpoint = 'expenses'; + body.project_id = this.getNodeParameter('projectId', i) as string; + body.expense_category_id = this.getNodeParameter('expenseCategoryId', i) as string; + body.spent_date = this.getNodeParameter('spentDate', i) as string; const additionalFields = this.getNodeParameter('additionalFields', i) as IDataObject; Object.assign(body, additionalFields); @@ -738,7 +734,7 @@ export class Harvest implements INodeType { requestMethod = 'PATCH'; const id = this.getNodeParameter('id', i) as string; - endpoint = `${resource}/${id}`; + endpoint = `expenses/${id}`; const updateFields = this.getNodeParameter('updateFields', i) as IDataObject; Object.assign(qs, updateFields); @@ -753,14 +749,14 @@ export class Harvest implements INodeType { requestMethod = 'DELETE'; const id = this.getNodeParameter('id', i) as string; - endpoint = `${resource}/${id}`; + endpoint = `expenses/${id}`; const responseData = await harvestApiRequest.call(this, requestMethod, qs, endpoint); returnData.push(responseData); } else { throw new Error(`The resource "${resource}" is not known!`); } - } else if (resource === 'estimates') { + } else if (resource === 'estimate') { if (operation === 'get') { // ---------------------------------- // get @@ -769,7 +765,7 @@ export class Harvest implements INodeType { requestMethod = 'GET'; const id = this.getNodeParameter('id', i) as string; - endpoint = `${resource}/${id}`; + endpoint = `estimates/${id}`; const responseData = await harvestApiRequest.call(this, requestMethod, qs, endpoint); returnData.push(responseData); @@ -779,7 +775,7 @@ export class Harvest implements INodeType { // getAll // ---------------------------------- - const responseData: IDataObject[] = await getAllResource.call(this, resource, i); + const responseData: IDataObject[] = await getAllResource.call(this, 'estimates', i); returnData.push.apply(returnData, responseData); } else if (operation === 'create') { @@ -788,9 +784,9 @@ export class Harvest implements INodeType { // ---------------------------------- requestMethod = 'POST'; - endpoint = resource; + endpoint = 'estimates'; - body.client_id = this.getNodeParameter('client_id', i) as string; + body.client_id = this.getNodeParameter('clientId', i) as string; const additionalFields = this.getNodeParameter('additionalFields', i) as IDataObject; Object.assign(body, additionalFields); @@ -805,7 +801,7 @@ export class Harvest implements INodeType { requestMethod = 'PATCH'; const id = this.getNodeParameter('id', i) as string; - endpoint = `${resource}/${id}`; + endpoint = `estimates/${id}`; const updateFields = this.getNodeParameter('updateFields', i) as IDataObject; Object.assign(qs, updateFields); @@ -820,7 +816,7 @@ export class Harvest implements INodeType { requestMethod = 'DELETE'; const id = this.getNodeParameter('id', i) as string; - endpoint = `${resource}/${id}`; + endpoint = `estimates/${id}`; const responseData = await harvestApiRequest.call(this, requestMethod, qs, endpoint); returnData.push(responseData); diff --git a/packages/nodes-base/nodes/Harvest/InvoiceDescription.ts b/packages/nodes-base/nodes/Harvest/InvoiceDescription.ts index 694a99ed9..5f2987ddc 100644 --- a/packages/nodes-base/nodes/Harvest/InvoiceDescription.ts +++ b/packages/nodes-base/nodes/Harvest/InvoiceDescription.ts @@ -1,6 +1,6 @@ -import { INodeProperties } from "n8n-workflow"; +import { INodeProperties } from 'n8n-workflow'; -const resource = [ 'invoices' ]; +const resource = [ 'invoice' ]; export const invoiceOperations = [ { @@ -221,7 +221,7 @@ export const invoiceFields = [ /* -------------------------------------------------------------------------- */ { displayName: 'Client Id', - name: 'client_id', + name: 'clientId', type: 'string', displayOptions: { show: { @@ -251,11 +251,25 @@ export const invoiceFields = [ default: {}, options: [ { - displayName: 'Retainer Id', - name: 'retainer_id', - type: 'boolean', - default: true, - description: 'The ID of the retainer associated with this invoice.' + displayName: 'Currency', + name: 'currency', + type: 'string', + default: '', + description: 'The currency used by the invoice. If not provided, the client’s currency will be used. See a list of supported currencies' + }, + { + displayName: 'Discount', + name: 'over_budget_notification_percentage', + type: 'string', + default: '', + description: 'This percentage is subtracted from the subtotal. Example: use 10.0 for 10.0%.' + }, + { + displayName: 'Due Date', + name: 'ends_on', + type: 'dateTime', + default: '', + description: 'Date the invoice is due. Defaults to the issue_date if no payment_term is specified.' }, { displayName: 'Estimate Id', @@ -264,6 +278,20 @@ export const invoiceFields = [ default: '', description: 'The ID of the estimate associated with this invoice.' }, + { + displayName: 'Issue Date', + name: 'issue_date', + type: 'dateTime', + default: '', + description: 'Date the invoice was issued. Defaults to today’s date.' + }, + { + displayName: 'Notes', + name: 'notes', + type: 'string', + default: '', + description: 'Notes about the project.' + }, { displayName: 'Number', name: 'number', @@ -271,6 +299,13 @@ export const invoiceFields = [ default: '', description: 'If no value is set, the number will be automatically generated.' }, + { + displayName: 'Payment Term', + name: 'payment_term', + type: 'string', + default: '', + description: 'The timeframe in which the invoice should be paid. Defaults to custom. Options: upon receipt, net 15, net 30, net 45, or net 60.' + }, { displayName: 'Purchase Order', name: 'purchase_order', @@ -278,6 +313,20 @@ export const invoiceFields = [ default: '', description: 'The purchase order number.' }, + { + displayName: 'Retainer Id', + name: 'retainer_id', + type: 'boolean', + default: true, + description: 'The ID of the retainer associated with this invoice.' + }, + { + displayName: 'Subject', + name: 'subject', + type: 'string', + default: '', + description: 'The invoice subject.' + }, { displayName: 'Tax', name: 'tax', @@ -292,56 +341,6 @@ export const invoiceFields = [ default: '', description: 'This percentage is applied to the subtotal, including line items and discounts. Example: use 10.0 for 10.0%.' }, - { - displayName: 'Discount', - name: 'over_budget_notification_percentage', - type: 'string', - default: '', - description: 'This percentage is subtracted from the subtotal. Example: use 10.0 for 10.0%.' - }, - { - displayName: 'Subject', - name: 'subject', - type: 'string', - default: '', - description: 'The invoice subject.' - }, - { - displayName: 'Currency', - name: 'currency', - type: 'string', - default: '', - description: 'The currency used by the invoice. If not provided, the client’s currency will be used. See a list of supported currencies' - }, - { - displayName: 'Payment Term', - name: 'payment_term', - type: 'string', - default: '', - description: 'The timeframe in which the invoice should be paid. Defaults to custom. Options: upon receipt, net 15, net 30, net 45, or net 60.' - }, - { - displayName: 'Notes', - name: 'notes', - type: 'string', - default: '', - description: 'Notes about the project.' - }, - { - displayName: 'Issue Date', - name: 'issue_date', - type: 'dateTime', - default: '', - description: 'Date the invoice was issued. Defaults to today’s date.' - }, - { - displayName: 'Due Date', - name: 'ends_on', - type: 'dateTime', - default: '', - description: 'Date the invoice is due. Defaults to the issue_date if no payment_term is specified.' - }, - ], }, @@ -387,11 +386,25 @@ export const invoiceFields = [ description: 'The ID of the retainer associated with this invoice..', }, { - displayName: 'Retainer Id', - name: 'retainer_id', - type: 'boolean', - default: true, - description: 'The ID of the retainer associated with this invoice.' + displayName: 'Currency', + name: 'currency', + type: 'string', + default: '', + description: 'The currency used by the invoice. If not provided, the client’s currency will be used. See a list of supported currencies' + }, + { + displayName: 'Discount', + name: 'over_budget_notification_percentage', + type: 'string', + default: '', + description: 'This percentage is subtracted from the subtotal. Example: use 10.0 for 10.0%.' + }, + { + displayName: 'Due Date', + name: 'ends_on', + type: 'dateTime', + default: '', + description: 'Date the invoice is due. Defaults to the issue_date if no payment_term is specified.' }, { displayName: 'Estimate Id', @@ -400,6 +413,20 @@ export const invoiceFields = [ default: '', description: 'The ID of the estimate associated with this invoice.' }, + { + displayName: 'Issue Date', + name: 'issue_date', + type: 'dateTime', + default: '', + description: 'Date the invoice was issued. Defaults to today’s date.' + }, + { + displayName: 'Notes', + name: 'notes', + type: 'string', + default: '', + description: 'Notes about the project.' + }, { displayName: 'Number', name: 'number', @@ -407,6 +434,13 @@ export const invoiceFields = [ default: '', description: 'If no value is set, the number will be automatically generated.' }, + { + displayName: 'Payment Term', + name: 'payment_term', + type: 'string', + default: '', + description: 'The timeframe in which the invoice should be paid. Defaults to custom. Options: upon receipt, net 15, net 30, net 45, or net 60.' + }, { displayName: 'Purchase Order', name: 'purchase_order', @@ -414,6 +448,20 @@ export const invoiceFields = [ default: '', description: 'The purchase order number.' }, + { + displayName: 'Retainer Id', + name: 'retainer_id', + type: 'boolean', + default: true, + description: 'The ID of the retainer associated with this invoice.' + }, + { + displayName: 'Subject', + name: 'subject', + type: 'string', + default: '', + description: 'The invoice subject.' + }, { displayName: 'Tax', name: 'tax', @@ -428,56 +476,6 @@ export const invoiceFields = [ default: '', description: 'This percentage is applied to the subtotal, including line items and discounts. Example: use 10.0 for 10.0%.' }, - { - displayName: 'Discount', - name: 'over_budget_notification_percentage', - type: 'string', - default: '', - description: 'This percentage is subtracted from the subtotal. Example: use 10.0 for 10.0%.' - }, - { - displayName: 'Subject', - name: 'subject', - type: 'string', - default: '', - description: 'The invoice subject.' - }, - { - displayName: 'Currency', - name: 'currency', - type: 'string', - default: '', - description: 'The currency used by the invoice. If not provided, the client’s currency will be used. See a list of supported currencies' - }, - { - displayName: 'Payment Term', - name: 'payment_term', - type: 'string', - default: '', - description: 'The timeframe in which the invoice should be paid. Defaults to custom. Options: upon receipt, net 15, net 30, net 45, or net 60.' - }, - { - displayName: 'Notes', - name: 'notes', - type: 'string', - default: '', - description: 'Notes about the project.' - }, - { - displayName: 'Issue Date', - name: 'issue_date', - type: 'dateTime', - default: '', - description: 'Date the invoice was issued. Defaults to today’s date.' - }, - { - displayName: 'Due Date', - name: 'ends_on', - type: 'dateTime', - default: '', - description: 'Date the invoice is due. Defaults to the issue_date if no payment_term is specified.' - }, - ], }, ] as INodeProperties[]; diff --git a/packages/nodes-base/nodes/Harvest/ProjectDescription.ts b/packages/nodes-base/nodes/Harvest/ProjectDescription.ts index 607894bcd..4910eaaf3 100644 --- a/packages/nodes-base/nodes/Harvest/ProjectDescription.ts +++ b/packages/nodes-base/nodes/Harvest/ProjectDescription.ts @@ -1,6 +1,6 @@ -import { INodeProperties } from "n8n-workflow"; +import { INodeProperties } from 'n8n-workflow'; -const resource = ['projects']; +const resource = ['project']; export const projectOperations = [ { @@ -13,6 +13,16 @@ export const projectOperations = [ }, }, options: [ + { + name: 'Create', + value: 'create', + description: `Create a project`, + }, + { + name: 'Delete', + value: 'delete', + description: `Delete a project`, + }, { name: 'Get', value: 'get', @@ -23,21 +33,11 @@ export const projectOperations = [ value: 'getAll', description: 'Get data of all projects', }, - { - name: 'Create', - value: 'create', - description: `Create a project`, - }, { name: 'Update', value: 'update', description: `Update a project`, }, - { - name: 'Delete', - value: 'delete', - description: `Delete a project`, - }, ], default: 'getAll', description: 'The operation to perform.', @@ -103,13 +103,6 @@ export const projectFields = [ }, }, options: [ - { - displayName: 'Is Active', - name: 'is_active', - type: 'boolean', - default: true, - description: 'Pass true to only return active projects and false to return inactive projects.', - }, { displayName: 'Client Id', name: 'client_id', @@ -118,11 +111,11 @@ export const projectFields = [ description: 'Only return projects belonging to the client with the given ID.', }, { - displayName: 'Updated Since', - name: 'updated_since', - type: 'dateTime', - default: '', - description: 'Only return projects by updated_since.', + displayName: 'Is Active', + name: 'is_active', + type: 'boolean', + default: true, + description: 'Pass true to only return active projects and false to return inactive projects.', }, { displayName: 'Page', @@ -134,7 +127,13 @@ export const projectFields = [ default: 1, description: 'The page number to use in pagination.', }, - + { + displayName: 'Updated Since', + name: 'updated_since', + type: 'dateTime', + default: '', + description: 'Only return projects by updated_since.', + }, ] }, @@ -199,7 +198,7 @@ export const projectFields = [ }, { displayName: 'Client Id', - name: 'client_id', + name: 'clientId', type: 'string', displayOptions: { show: { @@ -215,8 +214,8 @@ export const projectFields = [ }, { displayName: 'Is Billable', - name: 'is_billable', - type: 'string', + name: 'isBillable', + type: 'boolean', displayOptions: { show: { operation: [ @@ -225,14 +224,14 @@ export const projectFields = [ resource, }, }, - default: '', + default: true, required: true, description: 'Whether the project is billable or not.', }, { displayName: 'Bill By', - name: 'bill_by', - type: 'string', + name: 'billBy', + type: 'options', displayOptions: { show: { operation: [ @@ -241,13 +240,31 @@ export const projectFields = [ resource, }, }, - default: '', + options: [ + { + name: 'none', + value: 'none', + }, + { + name: 'People', + value: 'People', + }, + { + name: 'Project', + value: 'Project', + }, + { + name: 'Tasks', + value: 'Tasks', + }, + ], + default: 'none', required: true, - description: 'The method by which the project is invoiced. Options: Project, Tasks, People, or none.', + description: 'The method by which the project is invoiced.', }, { displayName: 'Budget By', - name: 'budget_by', + name: 'budgetBy', type: 'string', displayOptions: { show: { @@ -257,9 +274,10 @@ export const projectFields = [ resource, }, }, - default: '', + default: 'none', + placeholder: '', required: true, - description: 'The email of the user.', + description: 'The email of the user or "none".', }, { displayName: 'Additional Fields', @@ -277,18 +295,49 @@ export const projectFields = [ default: {}, options: [ { - displayName: 'Is Active', - name: 'is_active', - type: 'boolean', - default: true, - description: 'Whether the project is active or archived. Defaults to true' + displayName: 'Budget', + name: 'budget', + type: 'number', + typeOptions: { + minValue: 0, + }, + default: 0, + description: 'The budget in hours for the project when budgeting by time.' }, { - displayName: 'Is Fixed Fee', - name: 'is_fixed_fee', + displayName: 'Budget Is Monthly', + name: 'budget_is_monthly', + type: 'boolean', + default: false, + description: 'Option to have the budget reset every month. Defaults to false.' + }, + { + displayName: 'Cost Budget', + name: 'cost_budget', type: 'string', default: '', - description: 'Whether the project is a fixed-fee project or not.' + description: 'The monetary budget for the project when budgeting by money.' + }, + { + displayName: 'Cost Budget Include Expenses', + name: 'cost_budget_include_expenses', + type: 'boolean', + default: false, + description: 'Option for budget of Total Project Fees projects to include tracked expenses. Defaults to false.' + }, + { + displayName: 'Ends On', + name: 'ends_on', + type: 'dateTime', + default: '', + description: 'Date the project will end.' + }, + { + displayName: 'Fee', + name: 'fee', + type: 'string', + default: '', + description: 'The amount you plan to invoice for the project. Only used by fixed-fee projects.' }, { displayName: 'Hourly Rate', @@ -298,24 +347,31 @@ export const projectFields = [ description: 'Rate for projects billed by Project Hourly Rate.' }, { - displayName: 'Budget', - name: 'budget', - type: 'string', - default: '', - description: 'The budget in hours for the project when budgeting by time.' + displayName: 'Is Active', + name: 'is_active', + type: 'boolean', + default: true, + description: 'Whether the project is active or archived. Defaults to true' }, { - displayName: 'Budget Is Monthly', - name: 'budget_is_monthly', + displayName: 'Is Fixed Fee', + name: 'is_fixed_fee', + type: 'boolean', + default: false, + description: 'Whether the project is a fixed-fee project or not.' + }, + { + displayName: 'Notes', + name: 'notes', type: 'string', default: '', - description: 'Option to have the budget reset every month. Defaults to false.' + description: 'Notes about the project.' }, { displayName: 'Notify When Over Budget', name: 'notify_when_over_budget', - type: 'string', - default: '', + type: 'boolean', + default: false, description: 'Whether project managers should be notified when the project goes over budget. Defaults to false.' }, { @@ -328,38 +384,10 @@ export const projectFields = [ { displayName: 'Show Budget To All', name: 'show_budget_to_all', - type: 'string', - default: '', + type: 'boolean', + default: false, description: 'Option to show project budget to all employees. Does not apply to Total Project Fee projects. Defaults to false.' }, - { - displayName: 'Cost Budget', - name: 'cost_budget', - type: 'string', - default: '', - description: 'The monetary budget for the project when budgeting by money.' - }, - { - displayName: 'Cost Budget Include Expenses', - name: 'cost_budget_include_expenses', - type: 'string', - default: '', - description: 'Option for budget of Total Project Fees projects to include tracked expenses. Defaults to false.' - }, - { - displayName: 'Fee', - name: 'fee', - type: 'string', - default: '', - description: 'The amount you plan to invoice for the project. Only used by fixed-fee projects.' - }, - { - displayName: 'Notes', - name: 'notes', - type: 'string', - default: '', - description: 'Notes about the project.' - }, { displayName: 'Starts On', name: 'starts_on', @@ -367,14 +395,6 @@ export const projectFields = [ default: '', description: 'Date the project was started.' }, - { - displayName: 'Ends On', - name: 'ends_on', - type: 'dateTime', - default: '', - description: 'Date the project will end.' - }, - ], }, @@ -412,61 +432,30 @@ export const projectFields = [ }, default: {}, options: [ - { - displayName: 'Name', - name: 'name', - type: 'string', - default: '', - description: 'The name of the project.', - }, - { - displayName: 'Client Id', - name: 'client_id', - type: 'string', - default: '', - description: 'The ID of the client to associate this project with.', - }, - { - displayName: 'Is Billable', - name: 'is_billable', - type: 'string', - default: '', - description: 'Whether the project is billable or not.', - }, { displayName: 'Bill By', name: 'bill_by', - type: 'string', - default: '', - description: 'The method by which the project is invoiced. Options: Project, Tasks, People, or none.', - }, - { - displayName: 'Budget By', - name: 'budget_by', - type: 'string', - default: '', - description: 'The email of the user.', - }, - { - displayName: 'Is Active', - name: 'is_active', - type: 'boolean', - default: true, - description: 'Whether the project is active or archived. Defaults to true' - }, - { - displayName: 'Is Fixed Fee', - name: 'is_fixed_fee', - type: 'string', - default: '', - description: 'Whether the project is a fixed-fee project or not.' - }, - { - displayName: 'Hourly Rate', - name: 'hourly_rate', - type: 'string', - default: '', - description: 'Rate for projects billed by Project Hourly Rate.' + type: 'options', + options: [ + { + name: 'none', + value: 'none', + }, + { + name: 'People', + value: 'People', + }, + { + name: 'Project', + value: 'Project', + }, + { + name: 'Tasks', + value: 'Tasks', + }, + ], + default: 'none', + description: 'The method by which the project is invoiced.', }, { displayName: 'Budget', @@ -476,17 +465,101 @@ export const projectFields = [ description: 'The budget in hours for the project when budgeting by time.' }, { - displayName: 'Budget Is Monthly', - name: 'budget_is_monthly', + displayName: 'Budget By', + name: 'budget_by', type: 'string', default: '', + description: 'The email of the user or "none".', + }, + { + displayName: 'Budget Is Monthly', + name: 'budget_is_monthly', + type: 'boolean', + default: false, description: 'Option to have the budget reset every month. Defaults to false.' }, + { + displayName: 'Client Id', + name: 'client_id', + type: 'string', + default: '', + description: 'The ID of the client to associate this project with.', + }, + { + displayName: 'Cost Budget', + name: 'cost_budget', + type: 'string', + default: '', + description: 'The monetary budget for the project when budgeting by money.' + }, + { + displayName: 'Cost Budget Include Expenses', + name: 'cost_budget_include_expenses', + type: 'boolean', + default: false, + description: 'Option for budget of Total Project Fees projects to include tracked expenses. Defaults to false.' + }, + { + displayName: 'Ends On', + name: 'ends_on', + type: 'dateTime', + default: '', + description: 'Date the project will end.' + }, + { + displayName: 'Fee', + name: 'fee', + type: 'string', + default: '', + description: 'The amount you plan to invoice for the project. Only used by fixed-fee projects.' + }, + { + displayName: 'Hourly Rate', + name: 'hourly_rate', + type: 'string', + default: '', + description: 'Rate for projects billed by Project Hourly Rate.' + }, + { + displayName: 'Is Active', + name: 'is_active', + type: 'boolean', + default: true, + description: 'Whether the project is active or archived. Defaults to true' + }, + { + displayName: 'Is Billable', + name: 'is_billable', + type: 'boolean', + default: true, + description: 'Whether the project is billable or not.', + }, + { + displayName: 'Is Fixed Fee', + name: 'is_fixed_fee', + type: 'boolean', + default: false, + description: 'Whether the project is a fixed-fee project or not.' + }, + { + displayName: 'Name', + name: 'name', + type: 'string', + default: '', + description: 'The name of the project.', + }, + { + displayName: 'Notes', + name: 'notes', + type: 'string', + default: '', + description: 'Notes about the project.' + }, { displayName: 'Notify When Over Budget', name: 'notify_when_over_budget', - type: 'string', - default: '', + type: 'boolean', + default: false, description: 'Whether project managers should be notified when the project goes over budget. Defaults to false.' }, { @@ -499,38 +572,11 @@ export const projectFields = [ { displayName: 'Show Budget To All', name: 'show_budget_to_all', - type: 'string', - default: '', + type: 'boolean', + default: false, description: 'Option to show project budget to all employees. Does not apply to Total Project Fee projects. Defaults to false.' }, - { - displayName: 'Cost Budget', - name: 'cost_budget', - type: 'string', - default: '', - description: 'The monetary budget for the project when budgeting by money.' - }, - { - displayName: 'Cost Budget Include Expenses', - name: 'cost_budget_include_expenses', - type: 'string', - default: '', - description: 'Option for budget of Total Project Fees projects to include tracked expenses. Defaults to false.' - }, - { - displayName: 'Fee', - name: 'fee', - type: 'string', - default: '', - description: 'The amount you plan to invoice for the project. Only used by fixed-fee projects.' - }, - { - displayName: 'Notes', - name: 'notes', - type: 'string', - default: '', - description: 'Notes about the project.' - }, + { displayName: 'Starts On', name: 'starts_on', @@ -538,16 +584,7 @@ export const projectFields = [ default: '', description: 'Date the project was started.' }, - { - displayName: 'Ends On', - name: 'ends_on', - type: 'dateTime', - default: '', - description: 'Date the project will end.' - }, - ], }, ] as INodeProperties[]; - diff --git a/packages/nodes-base/nodes/Harvest/TaskDescription.ts b/packages/nodes-base/nodes/Harvest/TaskDescription.ts index 2f3735364..33ff7e918 100644 --- a/packages/nodes-base/nodes/Harvest/TaskDescription.ts +++ b/packages/nodes-base/nodes/Harvest/TaskDescription.ts @@ -1,5 +1,5 @@ -import { INodeProperties } from "n8n-workflow"; -const resource = ['tasks']; +import { INodeProperties } from 'n8n-workflow'; +const resource = ['task']; export const taskOperations = [ { displayName: 'Operation', @@ -11,6 +11,16 @@ export const taskOperations = [ }, }, options: [ + { + name: 'Create', + value: 'create', + description: `Create a task`, + }, + { + name: 'Delete', + value: 'delete', + description: `Delete a task`, + }, { name: 'Get', value: 'get', @@ -21,21 +31,11 @@ export const taskOperations = [ value: 'getAll', description: 'Get data of all tasks', }, - { - name: 'Create', - value: 'create', - description: `Create a task`, - }, { name: 'Update', value: 'update', description: `Update a task`, }, - { - name: 'Delete', - value: 'delete', - description: `Delete a task`, - }, ], default: 'getAll', description: 'The operation to perform.', @@ -108,13 +108,6 @@ export const taskFields = [ default: true, description: 'Pass true to only return active tasks and false to return inactive tasks.', }, - { - displayName: 'Updated Since', - name: 'updated_since', - type: 'dateTime', - default: '', - description: 'Only return tasks belonging to the task with the given ID.', - }, { displayName: 'Page', name: 'page', @@ -124,7 +117,14 @@ export const taskFields = [ }, default: 1, description: 'The page number to use in pagination.', - } + }, + { + displayName: 'Updated Since', + name: 'updated_since', + type: 'dateTime', + default: '', + description: 'Only return tasks belonging to the task with the given ID.', + }, ] }, @@ -250,13 +250,7 @@ export const taskFields = [ }, default: {}, options: [ - { - displayName: 'Name', - name: 'name', - type: 'string', - default: '', - description: 'Name of the task.' - }, + { displayName: 'Billable By Default', name: 'billable_by_default', @@ -271,6 +265,13 @@ export const taskFields = [ default: '0', description: 'The default hourly rate to use for this task when it is added to a project. Defaults to 0.' }, + { + displayName: 'Is Active', + name: 'is_active', + type: 'boolean', + default: true, + description: 'Whether this task is active or archived. Defaults to true' + }, { displayName: 'Is Default', name: 'is_default', @@ -279,12 +280,12 @@ export const taskFields = [ description: 'Whether this task should be automatically added to future projects. Defaults to false.' }, { - displayName: 'Is Active', - name: 'is_active', - type: 'boolean', - default: true, - description: 'Whether this task is active or archived. Defaults to true' - } + displayName: 'Name', + name: 'name', + type: 'string', + default: '', + description: 'Name of the task.' + }, ], }, diff --git a/packages/nodes-base/nodes/Harvest/TimeEntryDescription.ts b/packages/nodes-base/nodes/Harvest/TimeEntryDescription.ts index b16a810bc..be6d6d02b 100644 --- a/packages/nodes-base/nodes/Harvest/TimeEntryDescription.ts +++ b/packages/nodes-base/nodes/Harvest/TimeEntryDescription.ts @@ -1,5 +1,5 @@ -import { INodeProperties } from "n8n-workflow"; -export const resource = [ 'time_entries' ] +import { INodeProperties } from 'n8n-workflow'; +export const resource = [ 'timeEntry' ]; export const timeEntryOperations = [ { displayName: 'Operation', @@ -119,13 +119,6 @@ export const timeEntryFields = [ }, }, options: [ - { - displayName: 'User ID', - name: 'user_id', - type: 'string', - default: '', - description: 'Only return time entries belonging to the user with the given ID.', - }, { displayName: 'Client ID', name: 'client_id', @@ -133,6 +126,13 @@ export const timeEntryFields = [ default: '', description: 'Only return time entries belonging to the client with the given ID.', }, + { + displayName: 'From', + name: 'from', + type: 'dateTime', + default: '', + description: 'Only return time entries with a spent_date on or after the given date.', + }, { displayName: 'Is Billed', name: 'is_billed', @@ -147,20 +147,6 @@ export const timeEntryFields = [ default: true, description: 'Pass true to only return running time entries and false to return non-running time entries.', }, - { - displayName: 'Updated Since', - name: 'updated_since', - type: 'dateTime', - default: '', - description: 'Only return time entries that have been updated since the given date and time.', - }, - { - displayName: 'From', - name: 'from', - type: 'dateTime', - default: '', - description: 'Only return time entries with a spent_date on or after the given date.', - }, { displayName: 'To', name: 'to', @@ -168,6 +154,13 @@ export const timeEntryFields = [ default: '', description: 'Only return time entries with a spent_date on or before the given date.', }, + { + displayName: 'Updated Since', + name: 'updated_since', + type: 'dateTime', + default: '', + description: 'Only return time entries that have been updated since the given date and time.', + }, { displayName: 'Page', name: 'page', @@ -177,8 +170,15 @@ export const timeEntryFields = [ }, default: 1, description: 'The page number to use in pagination. For instance, if you make a list request and receive 100 records, your subsequent call can include page=2 to retrieve the next page of the list. (Default: 1)', - } - ] + }, + { + displayName: 'User ID', + name: 'user_id', + type: 'string', + default: '', + description: 'Only return time entries belonging to the user with the given ID.', + }, + ], }, /* -------------------------------------------------------------------------- */ diff --git a/packages/nodes-base/nodes/Harvest/UserDescription.ts b/packages/nodes-base/nodes/Harvest/UserDescription.ts index f0760daf4..ea434c3ca 100644 --- a/packages/nodes-base/nodes/Harvest/UserDescription.ts +++ b/packages/nodes-base/nodes/Harvest/UserDescription.ts @@ -1,6 +1,6 @@ -import { INodeProperties } from "n8n-workflow"; +import { INodeProperties } from 'n8n-workflow'; -const resource = ['users']; +const resource = ['user']; export const userOperations = [ { @@ -14,9 +14,14 @@ export const userOperations = [ }, options: [ { - name: 'Me', - value: 'me', - description: 'Get data of authenticated user', + name: 'Create', + value: 'create', + description: `Create a user`, + }, + { + name: 'Delete', + value: 'delete', + description: `Delete a user`, }, { name: 'Get', @@ -28,21 +33,17 @@ export const userOperations = [ value: 'getAll', description: 'Get data of all users', }, + { - name: 'Create', - value: 'create', - description: `Create a user`, + name: 'Me', + value: 'me', + description: 'Get data of authenticated user', }, { name: 'Update', value: 'update', description: `Update a user`, }, - { - name: 'Delete', - value: 'delete', - description: `Delete a user`, - }, ], default: 'me', description: 'The operation to perform.', @@ -180,7 +181,7 @@ export const userFields = [ /* -------------------------------------------------------------------------- */ { displayName: 'First Name', - name: 'first_name', + name: 'firstName', type: 'string', displayOptions: { show: { @@ -196,7 +197,7 @@ export const userFields = [ }, { displayName: 'Last Name', - name: 'last_name', + name: 'lastName', type: 'string', displayOptions: { show: { @@ -241,96 +242,102 @@ export const userFields = [ }, default: {}, options: [ - { - displayName: 'Timezone', - name: 'timezone', - type: 'string', - default: '', - description: 'The user’s timezone. Defaults to the company’s timezone. See a list of supported time zones.' - }, - { - displayName: 'Has Access To All Future Projects', - name: 'has_access_to_all_future_projects', - type: 'string', - default: '', - description: 'Whether the user should be automatically added to future projects. Defaults to false.' - }, - { - displayName: 'Is Contractor', - name: 'is_contractor', - type: 'string', - default: '', - description: 'Whether the user is a contractor or an employee. Defaults to false.' - }, - { - displayName: 'Is Admin', - name: 'is_admin', - type: 'string', - default: '', - description: 'Whether the user has Admin permissions. Defaults to false.' - }, - { - displayName: 'Is Project Manager', - name: 'is_project_manager', - type: 'string', - default: '', - description: 'Whether the user has Project Manager permissions. Defaults to false.' - }, - { - displayName: 'Can See Rates', - name: 'can_see_rates', - type: 'string', - default: '', - description: 'Whether the user can see billable rates on projects. Only applicable to Project Managers. Defaults to false.' - }, { displayName: 'Can Create Projects', name: 'can_create_projects', - type: 'string', - default: '', - description: 'Whether the user can create projects. Only applicable to Project Managers. Defaults to false.' + type: 'boolean', + default: false, + description: 'Whether the user can create projects. Only applicable to Project Managers.' }, { displayName: 'Can Create Invoices', name: 'can_create_invoices', - type: 'string', - default: '', - description: 'Whether the user can create invoices. Only applicable to Project Managers. Defaults to false.' + type: 'boolean', + default: false, + description: 'Whether the user can create invoices. Only applicable to Project Managers.' }, { - displayName: 'Is Active', - name: 'is_active', - type: 'string', - default: '', - description: 'Whether the user is active or archived. Defaults to true.' + displayName: 'Can See Rates', + name: 'can_see_rates', + type: 'boolean', + default: false, + description: 'Whether the user can see billable rates on projects. Only applicable to Project Managers.' }, { - displayName: 'Weekly Capacity', - name: 'weekly_capacity', - type: 'string', - default: '', - description: 'The number of hours per week this person is available to work in seconds. Defaults to 126000 seconds (35 hours).' + displayName: 'Cost Rate', + name: 'cost_rate', + type: 'number', + typeOptions: { + minValue: 0, + }, + default: 0, + description: 'The cost rate to use for this user when calculating a project’s costs vs billable amount.' }, { displayName: 'Default Hourly Rate', name: 'default_hourly_rate', type: 'string', - default: '', - description: 'The billable rate to use for this user when they are added to a project. Defaults to 0.' + default: '0', + description: 'The billable rate to use for this user when they are added to a project.' }, { - displayName: 'Cost Rate', - name: 'cost_rate', - type: 'string', - default: '', - description: 'The cost rate to use for this user when calculating a project’s costs vs billable amount. Defaults to 0.' + displayName: 'Has Access To All Future Projects', + name: 'has_access_to_all_future_projects', + type: 'boolean', + default: false, + description: 'Whether the user should be automatically added to future projects.' + }, + { + displayName: 'Is Active', + name: 'is_active', + type: 'boolean', + default: true, + description: 'Whether the user is active or archived.' + }, + { + displayName: 'Is Admin', + name: 'is_admin', + type: 'boolean', + default: false, + description: 'Whether the user has Admin permissions.' + }, + { + displayName: 'Is Contractor', + name: 'is_contractor', + type: 'boolean', + default: false, + description: 'Whether the user is a contractor or an employee.' + }, + { + displayName: 'Is Project Manager', + name: 'is_project_manager', + type: 'boolean', + default: false, + description: 'Whether the user has Project Manager permissions.' }, { displayName: 'Roles', name: 'roles', type: 'string', default: '', - description: 'The role names assigned to this person.' + description: 'The role names assigned to this person.' + }, + { + displayName: 'Timezone', + name: 'timezone', + type: 'string', + default: '', + description: 'The user’s timezone. Defaults to the company’s timezone. See a list of supported time zones.' + }, + { + displayName: 'Weekly Capacity', + name: 'weekly_capacity', + type: 'number', + typeOptions: { + minValue: 0, + }, + default: 126000, + description: 'The number of hours per week this person is available to work in seconds. Defaults to 126000 seconds (35 hours).' }, ], }, @@ -371,18 +378,42 @@ export const userFields = [ default: {}, options: [ { - displayName: 'First Name', - name: 'first_name', - type: 'string', - default: '', - description: 'The user first name' + displayName: 'Can Create Projects', + name: 'can_create_projects', + type: 'boolean', + default: false, + description: 'Whether the user can create projects. Only applicable to Project Managers.' }, { - displayName: 'Last Name', - name: 'last_name', + displayName: 'Can Create Invoices', + name: 'can_create_invoices', + type: 'boolean', + default: false, + description: 'Whether the user can create invoices. Only applicable to Project Managers.' + }, + { + displayName: 'Can See Rates', + name: 'can_see_rates', + type: 'boolean', + default: false, + description: 'Whether the user can see billable rates on projects. Only applicable to Project Managers.' + }, + { + displayName: 'Cost Rate', + name: 'cost_rate', + type: 'number', + typeOptions: { + minValue: 0, + }, + default: 0, + description: 'The cost rate to use for this user when calculating a project’s costs vs billable amount.' + }, + { + displayName: 'Default Hourly Rate', + name: 'default_hourly_rate', type: 'string', - default: '', - description: 'The user last name' + default: '0', + description: 'The billable rate to use for this user when they are added to a project.' }, { displayName: 'Email', @@ -392,95 +423,77 @@ export const userFields = [ description: 'The user email' }, { - displayName: 'Timezone', - name: 'timezone', + displayName: 'First Name', + name: 'first_name', type: 'string', default: '', - description: 'The user’s timezone. Defaults to the company’s timezone. See a list of supported time zones.' + description: 'The user first name' }, { displayName: 'Has Access To All Future Projects', name: 'has_access_to_all_future_projects', - type: 'string', - default: '', - description: 'Whether the user should be automatically added to future projects. Defaults to false.' - }, - { - displayName: 'Is Contractor', - name: 'is_contractor', - type: 'string', - default: '', - description: 'Whether the user is a contractor or an employee. Defaults to false.' - }, - { - displayName: 'Is Admin', - name: 'is_admin', - type: 'string', - default: '', - description: 'Whether the user has Admin permissions. Defaults to false.' - }, - { - displayName: 'Is Project Manager', - name: 'is_project_manager', - type: 'string', - default: '', - description: 'Whether the user has Project Manager permissions. Defaults to false.' - }, - { - displayName: 'Can See Rates', - name: 'can_see_rates', - type: 'string', - default: '', - description: 'Whether the user can see billable rates on projects. Only applicable to Project Managers. Defaults to false.' - }, - { - displayName: 'Can Create Projects', - name: 'can_create_projects', - type: 'string', - default: '', - description: 'Whether the user can create projects. Only applicable to Project Managers. Defaults to false.' - }, - { - displayName: 'Can Create Invoices', - name: 'can_create_invoices', - type: 'string', - default: '', - description: 'Whether the user can create invoices. Only applicable to Project Managers. Defaults to false.' + type: 'boolean', + default: false, + description: 'Whether the user should be automatically added to future projects.' }, { displayName: 'Is Active', name: 'is_active', - type: 'string', - default: '', - description: 'Whether the user is active or archived. Defaults to true.' + type: 'boolean', + default: true, + description: 'Whether the user is active or archived.' }, { - displayName: 'Weekly Capacity', - name: 'weekly_capacity', - type: 'string', - default: '', - description: 'The number of hours per week this person is available to work in seconds. Defaults to 126000 seconds (35 hours).' + displayName: 'Is Admin', + name: 'is_admin', + type: 'boolean', + default: false, + description: 'Whether the user has Admin permissions.' }, { - displayName: 'Default Hourly Rate', - name: 'default_hourly_rate', - type: 'string', - default: '', - description: 'The billable rate to use for this user when they are added to a project. Defaults to 0.' + displayName: 'Is Contractor', + name: 'is_contractor', + type: 'boolean', + default: false, + description: 'Whether the user is a contractor or an employee.' }, { - displayName: 'Cost Rate', - name: 'cost_rate', + displayName: 'Is Project Manager', + name: 'is_project_manager', + type: 'boolean', + default: false, + description: 'Whether the user has Project Manager permissions.' + }, + { + displayName: 'Last Name', + name: 'last_name', type: 'string', default: '', - description: 'The cost rate to use for this user when calculating a project’s costs vs billable amount. Defaults to 0.' + description: 'The user last name' }, { displayName: 'Roles', name: 'roles', type: 'string', default: '', - description: 'The role names assigned to this person.' + description: 'The role names assigned to this person.' + }, + { + displayName: 'Timezone', + name: 'timezone', + type: 'string', + default: '', + description: 'The user’s timezone. Defaults to the company’s timezone. See a list of supported time zones.' + }, + { + displayName: 'Weekly Capacity', + name: 'weekly_capacity', + type: 'number', + typeOptions: { + minValue: 0, + }, + default: 126000, + description: 'The number of hours per week this person is available to work in seconds. Defaults to 126000 seconds (35 hours).' }, ], },