diff --git a/packages/nodes-base/nodes/Harvest/ClientDescription.ts b/packages/nodes-base/nodes/Harvest/ClientDescription.ts index 3950b35255..5bc339ae62 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: [ @@ -23,6 +23,21 @@ 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.', @@ -32,105 +47,240 @@ export const clientOperations = [ export const clientFields = [ -/* -------------------------------------------------------------------------- */ -/* client:getAll */ -/* -------------------------------------------------------------------------- */ + /* -------------------------------------------------------------------------- */ + /* client:getAll */ + /* -------------------------------------------------------------------------- */ -{ - displayName: 'Return All', - name: 'returnAll', - type: 'boolean', - displayOptions: { - show: { - resource: [ - 'client', - ], - 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: [ - 'client', - ], - 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: [ - 'client', - ], - 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', - ], + /* -------------------------------------------------------------------------- */ + /* 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.', + }, + + /* -------------------------------------------------------------------------- */ + /* 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.', + }, + + /* -------------------------------------------------------------------------- */ + /* 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' + }, + ], }, - description: 'The ID of the client you are retrieving.', -} ] as INodeProperties[]; diff --git a/packages/nodes-base/nodes/Harvest/CompanyDescription.ts b/packages/nodes-base/nodes/Harvest/CompanyDescription.ts index 26303b7eb3..8de3c255cc 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 f4156eeb1c..fa11943a66 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: [ @@ -23,6 +23,21 @@ 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.', @@ -32,105 +47,305 @@ export const contactOperations = [ export const contactFields = [ -/* -------------------------------------------------------------------------- */ -/* contact:getAll */ -/* -------------------------------------------------------------------------- */ + /* -------------------------------------------------------------------------- */ + /* contact:getAll */ + /* -------------------------------------------------------------------------- */ -{ - displayName: 'Return All', - name: 'returnAll', - type: 'boolean', - displayOptions: { - show: { - resource: [ - 'contact', - ], - 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: [ - 'contact', - ], - 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: [ - 'contact', - ], - 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', - ], + /* -------------------------------------------------------------------------- */ + /* 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.', + }, + + /* -------------------------------------------------------------------------- */ + /* 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 are retrieving.', -} ] as INodeProperties[]; diff --git a/packages/nodes-base/nodes/Harvest/EstimateDescription.ts b/packages/nodes-base/nodes/Harvest/EstimateDescription.ts index 60a24bdb80..f9ea2297ca 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: [ @@ -23,6 +23,21 @@ 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.', @@ -42,9 +57,7 @@ export const estimateFields = [ type: 'boolean', displayOptions: { show: { - resource: [ - 'estimate', - ], + resource, operation: [ 'getAll', ], @@ -59,9 +72,7 @@ export const estimateFields = [ type: 'number', displayOptions: { show: { - resource: [ - 'estimate', - ], + resource, operation: [ 'getAll', ], @@ -85,9 +96,7 @@ export const estimateFields = [ default: {}, displayOptions: { show: { - resource: [ - 'estimate', - ], + resource, operation: [ 'getAll', ], @@ -156,12 +165,239 @@ export const estimateFields = [ operation: [ 'get', ], - resource: [ - 'estimate', - ], + resource, }, }, 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, + }, + }, + description: 'The ID of the estimate want to delete.', +}, + + /* -------------------------------------------------------------------------- */ + /* estimate: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.' + }, + + ], + }, + + /* -------------------------------------------------------------------------- */ + /* estimate: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 54659e4a3a..c2095b622f 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 = [ 'expenses' ]; + export const expenseOperations = [ { displayName: 'Operation', @@ -7,9 +9,7 @@ export const expenseOperations = [ type: 'options', displayOptions: { show: { - resource: [ - 'expense', - ], + resource, }, }, options: [ @@ -23,6 +23,21 @@ 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', + description: `Delete an expense`, + }, ], default: 'getAll', description: 'The operation to perform.', @@ -42,9 +57,7 @@ export const expenseFields = [ type: 'boolean', displayOptions: { show: { - resource: [ - 'expense', - ], + resource, operation: [ 'getAll', ], @@ -59,9 +72,7 @@ export const expenseFields = [ type: 'number', displayOptions: { show: { - resource: [ - 'expense', - ], + resource, operation: [ 'getAll', ], @@ -85,9 +96,7 @@ export const expenseFields = [ default: {}, displayOptions: { show: { - resource: [ - 'expense', - ], + resource, operation: [ 'getAll', ], @@ -170,12 +179,229 @@ export const expenseFields = [ operation: [ 'get', ], - resource: [ - 'expense', - ], + resource, }, }, 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, + }, + }, + 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/GenericFunctions.ts b/packages/nodes-base/nodes/Harvest/GenericFunctions.ts index 6adf097b30..276405df3b 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; } + 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 d8bef6ea13..2c0eac3e66 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; @@ -75,46 +75,46 @@ 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', - value: 'timeEntry', + value: 'time_entries', }, { name: 'User', - value: 'user', + value: 'users', }, ], - default: 'task', + default: 'tasks', description: 'The resource to operate on.', }, @@ -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; @@ -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,13 +303,55 @@ 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 === '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 + // ---------------------------------- + + requestMethod = 'DELETE'; + const id = this.getNodeParameter('id', i) as string; + 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 @@ -318,7 +360,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); @@ -328,13 +370,59 @@ 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 === '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 === '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 + // ---------------------------------- + + requestMethod = 'DELETE'; + const id = this.getNodeParameter('id', i) as string; + 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 === 'user') { + } else if (resource === 'users') { if (operation === 'get') { // ---------------------------------- // get @@ -343,7 +431,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); @@ -353,7 +441,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') { @@ -363,15 +451,60 @@ 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 === 'create') { + // ---------------------------------- + // createByDuration + // ---------------------------------- + + requestMethod = 'POST'; + endpoint = resource; + + 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; + 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 + // ---------------------------------- + + requestMethod = 'DELETE'; + const id = this.getNodeParameter('id', i) as string; + 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 @@ -380,7 +513,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); @@ -390,13 +523,56 @@ 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 === '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 + // ---------------------------------- + + requestMethod = 'DELETE'; + const id = this.getNodeParameter('id', i) as string; + 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 @@ -411,7 +587,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 @@ -420,7 +596,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); @@ -430,13 +606,24 @@ 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') { + // ---------------------------------- + // delete + // ---------------------------------- + + requestMethod = 'DELETE'; + const id = this.getNodeParameter('id', i) as string; + 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 @@ -445,7 +632,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); @@ -455,13 +642,55 @@ 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 === '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') { + // ---------------------------------- + // 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 + // ---------------------------------- + + requestMethod = 'DELETE'; + const id = this.getNodeParameter('id', i) as string; + 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 @@ -470,7 +699,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); @@ -480,13 +709,58 @@ 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 === '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') { + // ---------------------------------- + // 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 + // ---------------------------------- + + requestMethod = 'DELETE'; + const id = this.getNodeParameter('id', i) as string; + 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 @@ -495,7 +769,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); @@ -505,9 +779,51 @@ 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 === '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') { + // ---------------------------------- + // 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 + // ---------------------------------- + + requestMethod = 'DELETE'; + const id = this.getNodeParameter('id', i) as string; + 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!`); } diff --git a/packages/nodes-base/nodes/Harvest/InvoiceDescription.ts b/packages/nodes-base/nodes/Harvest/InvoiceDescription.ts index cb876f872a..694a99ed9e 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: [ @@ -23,6 +23,21 @@ 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', + description: `Delete a invoice`, + }, ], default: 'getAll', description: 'The operation to perform.', @@ -42,9 +57,7 @@ export const invoiceFields = [ type: 'boolean', displayOptions: { show: { - resource: [ - 'invoice', - ], + resource, operation: [ 'getAll', ], @@ -59,9 +72,7 @@ export const invoiceFields = [ type: 'number', displayOptions: { show: { - resource: [ - 'invoice', - ], + resource, operation: [ 'getAll', ], @@ -85,9 +96,7 @@ export const invoiceFields = [ default: {}, displayOptions: { show: { - resource: [ - 'invoice', - ], + resource, operation: [ 'getAll', ], @@ -181,12 +190,294 @@ export const invoiceFields = [ operation: [ 'get', ], - resource: [ - 'invoice', - ], + resource, }, }, 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, + }, + }, + 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: '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: '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 a0c04531a8..607894bcd5 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: [ @@ -23,6 +23,21 @@ 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.', @@ -32,123 +47,507 @@ export const projectOperations = [ export const projectFields = [ -/* -------------------------------------------------------------------------- */ -/* projects:getAll */ -/* -------------------------------------------------------------------------- */ + /* -------------------------------------------------------------------------- */ + /* projects:getAll */ + /* -------------------------------------------------------------------------- */ -{ - displayName: 'Return All', - name: 'returnAll', - type: 'boolean', - displayOptions: { - show: { - resource: [ - 'project', - ], - operation: [ - 'getAll', - ], - }, - }, - default: false, - description: 'Returns a list of your projects.', -}, -{ - displayName: 'Limit', - name: 'limit', - type: 'number', - displayOptions: { - show: { - resource: [ - 'project', - ], - 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: [ - 'project', - ], - 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: [ - 'project', - ], }, + 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, + }, + 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: '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', + type: 'collection', + placeholder: 'Add Field', + displayOptions: { + show: { + operation: [ + 'update', + ], + 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 you are retrieving.', -} ] as INodeProperties[]; + diff --git a/packages/nodes-base/nodes/Harvest/TaskDescription.ts b/packages/nodes-base/nodes/Harvest/TaskDescription.ts index ac35fc2076..2f37353647 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: [ @@ -23,6 +21,21 @@ 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.', @@ -32,115 +45,248 @@ export const taskOperations = [ export const taskFields = [ -/* -------------------------------------------------------------------------- */ -/* task:getAll */ -/* -------------------------------------------------------------------------- */ + /* -------------------------------------------------------------------------- */ + /* task:getAll */ + /* -------------------------------------------------------------------------- */ -{ - displayName: 'Return All', - name: 'returnAll', - type: 'boolean', - displayOptions: { - show: { - resource: [ - 'task', - ], - operation: [ - 'getAll', - ], - }, - }, - default: false, - description: 'Returns a list of your tasks.', -}, -{ - displayName: 'Limit', - name: 'limit', - type: 'number', - displayOptions: { - show: { - resource: [ - 'task', - ], - 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: [ - 'task', - ], - 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: [ - 'task', - ], }, + default: false, + description: 'Returns a list of your tasks.', }, - description: 'The ID of the task you are retrieving.', -} + { + 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' + } + ], + }, + ] as INodeProperties[]; diff --git a/packages/nodes-base/nodes/Harvest/TimeEntryDescription.ts b/packages/nodes-base/nodes/Harvest/TimeEntryDescription.ts index a1ba83e2a0..b16a810bc0 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 4e1c563c7d..f0760daf45 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,21 @@ export const userOperations = [ value: 'getAll', description: 'Get data of all users', }, + { + name: 'Create', + value: 'create', + description: `Create a user`, + }, + { + name: 'Update', + value: 'update', + description: `Update a user`, + }, + { + name: 'Delete', + value: 'delete', + description: `Delete a user`, + }, ], default: 'me', description: 'The operation to perform.', @@ -37,115 +52,437 @@ 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..', - } - ] -}, - -/* -------------------------------------------------------------------------- */ -/* user:get */ -/* -------------------------------------------------------------------------- */ -{ - displayName: 'User Id', - name: 'id', - type: 'string', - default: '', - required: true, - displayOptions: { - show: { - operation: [ - 'get', - ], - resource: [ - 'user', - ], }, + 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:create */ + /* -------------------------------------------------------------------------- */ + { + displayName: 'First Name', + name: 'first_name', + type: 'string', + displayOptions: { + show: { + operation: [ + 'create', + ], + resource, + }, + }, + default: '', + required: true, + description: 'The first name of the 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.' + }, + ], + }, + + + /* -------------------------------------------------------------------------- */ + /* 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 + }, + }, + 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.' + }, + ], }, - description: 'The ID of the user you are retrieving.', -} ] as INodeProperties[];