mirror of
https://github.com/n8n-io/n8n.git
synced 2025-01-12 05:17:28 -08:00
🔀 Merge branch 'feature/invoice-ninja-node' of https://github.com/RicardoE105/n8n into RicardoE105-feature/invoice-ninja-node
This commit is contained in:
commit
a5a2f4606c
|
@ -0,0 +1,17 @@
|
|||
import {
|
||||
ICredentialType,
|
||||
NodePropertyTypes,
|
||||
} from 'n8n-workflow';
|
||||
|
||||
export class InvoiceNinjaCloudApi implements ICredentialType {
|
||||
name = 'invoiceNinjaCloudApi';
|
||||
displayName = 'Invoice Ninja API';
|
||||
properties = [
|
||||
{
|
||||
displayName: 'API Token',
|
||||
name: 'apiToken',
|
||||
type: 'string' as NodePropertyTypes,
|
||||
default: '',
|
||||
},
|
||||
];
|
||||
}
|
|
@ -0,0 +1,23 @@
|
|||
import {
|
||||
ICredentialType,
|
||||
NodePropertyTypes,
|
||||
} from 'n8n-workflow';
|
||||
|
||||
export class InvoiceNinjaServerApi implements ICredentialType {
|
||||
name = 'invoiceNinjaServerApi';
|
||||
displayName = 'Invoice Ninja API';
|
||||
properties = [
|
||||
{
|
||||
displayName: 'Domain',
|
||||
name: 'domain',
|
||||
type: 'string' as NodePropertyTypes,
|
||||
default: '',
|
||||
},
|
||||
{
|
||||
displayName: 'API Token',
|
||||
name: 'apiToken',
|
||||
type: 'string' as NodePropertyTypes,
|
||||
default: '',
|
||||
},
|
||||
];
|
||||
}
|
434
packages/nodes-base/nodes/InvoiceNinja/ClientDescription.ts
Normal file
434
packages/nodes-base/nodes/InvoiceNinja/ClientDescription.ts
Normal file
|
@ -0,0 +1,434 @@
|
|||
import { INodeProperties } from "n8n-workflow";
|
||||
|
||||
export const clientOperations = [
|
||||
{
|
||||
displayName: 'Operation',
|
||||
name: 'operation',
|
||||
type: 'options',
|
||||
displayOptions: {
|
||||
show: {
|
||||
resource: [
|
||||
'client',
|
||||
],
|
||||
},
|
||||
},
|
||||
options: [
|
||||
{
|
||||
name: 'Create',
|
||||
value: 'create',
|
||||
description: 'Create a new client',
|
||||
},
|
||||
{
|
||||
name: 'Get',
|
||||
value: 'get',
|
||||
description: 'Get data of a client',
|
||||
},
|
||||
{
|
||||
name: 'Get All',
|
||||
value: 'getAll',
|
||||
description: 'Get data of all clients',
|
||||
},
|
||||
{
|
||||
name: 'Delete',
|
||||
value: 'delete',
|
||||
description: 'Delete a client',
|
||||
}
|
||||
],
|
||||
default: 'create',
|
||||
description: 'The operation to perform.',
|
||||
},
|
||||
] as INodeProperties[];
|
||||
|
||||
export const clientFields = [
|
||||
/* -------------------------------------------------------------------------- */
|
||||
/* client:create */
|
||||
/* -------------------------------------------------------------------------- */
|
||||
{
|
||||
displayName: 'Additional Fields',
|
||||
name: 'additionalFields',
|
||||
type: 'collection',
|
||||
placeholder: 'Add Field',
|
||||
default: {},
|
||||
displayOptions: {
|
||||
show: {
|
||||
operation: [
|
||||
'create',
|
||||
],
|
||||
resource: [
|
||||
'client',
|
||||
],
|
||||
},
|
||||
},
|
||||
options: [
|
||||
{
|
||||
displayName: 'Client Name',
|
||||
name: 'clientName',
|
||||
type: 'string',
|
||||
default: '',
|
||||
},
|
||||
{
|
||||
displayName: 'ID Number',
|
||||
name: 'idNumber',
|
||||
type: 'string',
|
||||
default: '',
|
||||
},
|
||||
{
|
||||
displayName: 'Private Notes',
|
||||
name: 'privateNotes',
|
||||
type: 'string',
|
||||
typeOptions: {
|
||||
alwaysOpenEditWindow: true,
|
||||
},
|
||||
default: '',
|
||||
},
|
||||
{
|
||||
displayName: 'VAT Number',
|
||||
name: 'vatNumber',
|
||||
type: 'string',
|
||||
default: '',
|
||||
},
|
||||
{
|
||||
displayName: 'Work Phone',
|
||||
name: 'workPhone',
|
||||
type: 'string',
|
||||
default: '',
|
||||
},
|
||||
{
|
||||
displayName: 'Website',
|
||||
name: 'website',
|
||||
type: 'string',
|
||||
default: '',
|
||||
},
|
||||
]
|
||||
},
|
||||
{
|
||||
displayName: 'Billing Address',
|
||||
name: 'billingAddressUi',
|
||||
placeholder: 'Add Billing Address',
|
||||
type: 'fixedCollection',
|
||||
typeOptions: {
|
||||
multipleValues: false,
|
||||
},
|
||||
displayOptions: {
|
||||
show: {
|
||||
resource: [
|
||||
'client',
|
||||
],
|
||||
operation: [
|
||||
'create',
|
||||
],
|
||||
},
|
||||
},
|
||||
default: {},
|
||||
options: [
|
||||
{
|
||||
name: 'billingAddressValue',
|
||||
displayName: 'Billing Address',
|
||||
values: [
|
||||
{
|
||||
displayName: 'Street Address',
|
||||
name: 'streetAddress',
|
||||
type: 'string',
|
||||
default: '',
|
||||
},
|
||||
{
|
||||
displayName: 'Apt/Suite',
|
||||
name: 'aptSuite',
|
||||
type: 'string',
|
||||
default: '',
|
||||
},
|
||||
{
|
||||
displayName: 'City',
|
||||
name: 'city',
|
||||
type: 'string',
|
||||
default: '',
|
||||
},
|
||||
{
|
||||
displayName: 'State',
|
||||
name: 'state',
|
||||
type: 'string',
|
||||
default: '',
|
||||
},
|
||||
{
|
||||
displayName: 'Postal Code',
|
||||
name: 'postalCode',
|
||||
type: 'string',
|
||||
default: '',
|
||||
},
|
||||
{
|
||||
displayName: 'Country Code',
|
||||
name: 'countryCode',
|
||||
type: 'options',
|
||||
typeOptions: {
|
||||
loadOptionsMethod: 'getCountryCodes',
|
||||
},
|
||||
default: '',
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
displayName: 'Contacts',
|
||||
name: 'contactsUi',
|
||||
placeholder: 'Add Contact',
|
||||
type: 'fixedCollection',
|
||||
typeOptions: {
|
||||
multipleValues: true,
|
||||
},
|
||||
displayOptions: {
|
||||
show: {
|
||||
resource: [
|
||||
'client',
|
||||
],
|
||||
operation: [
|
||||
'create',
|
||||
],
|
||||
},
|
||||
},
|
||||
default: {},
|
||||
options: [
|
||||
{
|
||||
name: 'contacstValues',
|
||||
displayName: 'Contact',
|
||||
values: [
|
||||
{
|
||||
displayName: 'First Name',
|
||||
name: 'firstName',
|
||||
type: 'string',
|
||||
default: '',
|
||||
},
|
||||
{
|
||||
displayName: 'Last Name',
|
||||
name: 'lastName',
|
||||
type: 'string',
|
||||
default: '',
|
||||
},
|
||||
{
|
||||
displayName: 'Email',
|
||||
name: 'email',
|
||||
type: 'string',
|
||||
default: '',
|
||||
},
|
||||
{
|
||||
displayName: 'Phone',
|
||||
name: 'phone',
|
||||
type: 'string',
|
||||
default: '',
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
displayName: 'Shipping Address',
|
||||
name: 'shippingAddressUi',
|
||||
placeholder: 'Add Shipping Address',
|
||||
type: 'fixedCollection',
|
||||
typeOptions: {
|
||||
multipleValues: false,
|
||||
},
|
||||
displayOptions: {
|
||||
show: {
|
||||
resource: [
|
||||
'client',
|
||||
],
|
||||
operation: [
|
||||
'create',
|
||||
],
|
||||
},
|
||||
},
|
||||
default: {},
|
||||
options: [
|
||||
{
|
||||
name: 'shippingAddressValue',
|
||||
displayName: 'Shipping Address',
|
||||
values: [
|
||||
{
|
||||
displayName: 'Street Address',
|
||||
name: 'streetAddress',
|
||||
type: 'string',
|
||||
default: '',
|
||||
},
|
||||
{
|
||||
displayName: 'Apt/Suite',
|
||||
name: 'aptSuite',
|
||||
type: 'string',
|
||||
default: '',
|
||||
},
|
||||
{
|
||||
displayName: 'City',
|
||||
name: 'city',
|
||||
type: 'string',
|
||||
default: '',
|
||||
},
|
||||
{
|
||||
displayName: 'State',
|
||||
name: 'state',
|
||||
type: 'string',
|
||||
default: '',
|
||||
},
|
||||
{
|
||||
displayName: 'Postal Code',
|
||||
name: 'postalCode',
|
||||
type: 'string',
|
||||
default: '',
|
||||
},
|
||||
{
|
||||
displayName: 'Country Code',
|
||||
name: 'countryCode',
|
||||
type: 'options',
|
||||
typeOptions: {
|
||||
loadOptionsMethod: 'getCountryCodes',
|
||||
},
|
||||
default: '',
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
/* -------------------------------------------------------------------------- */
|
||||
/* client:delete */
|
||||
/* -------------------------------------------------------------------------- */
|
||||
{
|
||||
displayName: 'Client ID',
|
||||
name: 'clientId',
|
||||
type: 'string',
|
||||
required: true,
|
||||
displayOptions: {
|
||||
show: {
|
||||
resource: [
|
||||
'client',
|
||||
],
|
||||
operation: [
|
||||
'delete',
|
||||
],
|
||||
},
|
||||
},
|
||||
},
|
||||
/* -------------------------------------------------------------------------- */
|
||||
/* client:get */
|
||||
/* -------------------------------------------------------------------------- */
|
||||
{
|
||||
displayName: 'Client ID',
|
||||
name: 'clientId',
|
||||
type: 'string',
|
||||
required: true,
|
||||
displayOptions: {
|
||||
show: {
|
||||
resource: [
|
||||
'client',
|
||||
],
|
||||
operation: [
|
||||
'get',
|
||||
],
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
displayName: 'Options',
|
||||
name: 'options',
|
||||
type: 'collection',
|
||||
placeholder: 'Add Field',
|
||||
default: {},
|
||||
displayOptions: {
|
||||
show: {
|
||||
operation: [
|
||||
'get',
|
||||
],
|
||||
resource: [
|
||||
'client',
|
||||
],
|
||||
},
|
||||
},
|
||||
options: [
|
||||
{
|
||||
displayName: 'Include',
|
||||
name: 'include',
|
||||
type: 'options',
|
||||
options: [
|
||||
{
|
||||
name: 'Invoices',
|
||||
value: 'invoices',
|
||||
},
|
||||
],
|
||||
default: 'invoices',
|
||||
},
|
||||
],
|
||||
},
|
||||
/* -------------------------------------------------------------------------- */
|
||||
/* client:getAll */
|
||||
/* -------------------------------------------------------------------------- */
|
||||
{
|
||||
displayName: 'Return All',
|
||||
name: 'returnAll',
|
||||
type: 'boolean',
|
||||
displayOptions: {
|
||||
show: {
|
||||
resource: [
|
||||
'client',
|
||||
],
|
||||
operation: [
|
||||
'getAll',
|
||||
],
|
||||
},
|
||||
},
|
||||
default: false,
|
||||
description: 'If all results should be returned or only up to a given limit.',
|
||||
},
|
||||
{
|
||||
displayName: 'Limit',
|
||||
name: 'limit',
|
||||
type: 'number',
|
||||
displayOptions: {
|
||||
show: {
|
||||
resource: [
|
||||
'client',
|
||||
],
|
||||
operation: [
|
||||
'getAll',
|
||||
],
|
||||
returnAll: [
|
||||
false,
|
||||
],
|
||||
},
|
||||
},
|
||||
typeOptions: {
|
||||
minValue: 1,
|
||||
maxValue: 60,
|
||||
},
|
||||
default: 50,
|
||||
description: 'How many results to return.',
|
||||
},
|
||||
{
|
||||
displayName: 'Options',
|
||||
name: 'options',
|
||||
type: 'collection',
|
||||
placeholder: 'Add Field',
|
||||
default: {},
|
||||
displayOptions: {
|
||||
show: {
|
||||
operation: [
|
||||
'getAll',
|
||||
],
|
||||
resource: [
|
||||
'client',
|
||||
],
|
||||
},
|
||||
},
|
||||
options: [
|
||||
{
|
||||
displayName: 'Include',
|
||||
name: 'include',
|
||||
type: 'options',
|
||||
options: [
|
||||
{
|
||||
name: 'Invoices',
|
||||
value: 'invoices',
|
||||
},
|
||||
],
|
||||
default: 'invoices',
|
||||
},
|
||||
],
|
||||
},
|
||||
] as INodeProperties[];
|
30
packages/nodes-base/nodes/InvoiceNinja/ClientInterface.ts
Normal file
30
packages/nodes-base/nodes/InvoiceNinja/ClientInterface.ts
Normal file
|
@ -0,0 +1,30 @@
|
|||
import { IDataObject } from "n8n-workflow";
|
||||
|
||||
export interface IContact {
|
||||
first_name?: string;
|
||||
last_name?: string;
|
||||
email?: string;
|
||||
phone?: string;
|
||||
}
|
||||
|
||||
export interface IClient {
|
||||
contacts?: IContact[],
|
||||
name?: string;
|
||||
address1?: string;
|
||||
address2?: string;
|
||||
city?: string;
|
||||
state?: string;
|
||||
postal_code?: string;
|
||||
country_id?: number;
|
||||
shipping_address1?: string;
|
||||
shipping_address2?: string;
|
||||
shipping_city?: string;
|
||||
shipping_state?: string;
|
||||
shipping_postal_code?: string;
|
||||
shipping_country_id?: number;
|
||||
work_phone?: string;
|
||||
private_notes?: string;
|
||||
website?: string;
|
||||
vat_number?: string;
|
||||
id_number?: string;
|
||||
}
|
396
packages/nodes-base/nodes/InvoiceNinja/ExpenseDescription.ts
Normal file
396
packages/nodes-base/nodes/InvoiceNinja/ExpenseDescription.ts
Normal file
|
@ -0,0 +1,396 @@
|
|||
import { INodeProperties } from "n8n-workflow";
|
||||
|
||||
export const expenseOperations = [
|
||||
{
|
||||
displayName: 'Operation',
|
||||
name: 'operation',
|
||||
type: 'options',
|
||||
displayOptions: {
|
||||
show: {
|
||||
resource: [
|
||||
'expense',
|
||||
],
|
||||
},
|
||||
},
|
||||
options: [
|
||||
{
|
||||
name: 'Create',
|
||||
value: 'create',
|
||||
description: 'Create a new expense',
|
||||
},
|
||||
{
|
||||
name: 'Get',
|
||||
value: 'get',
|
||||
description: 'Get data of a expense',
|
||||
},
|
||||
{
|
||||
name: 'Get All',
|
||||
value: 'getAll',
|
||||
description: 'Get data of all expenses',
|
||||
},
|
||||
{
|
||||
name: 'Delete',
|
||||
value: 'delete',
|
||||
description: 'Delete a expense',
|
||||
}
|
||||
],
|
||||
default: 'create',
|
||||
description: 'The operation to perform.',
|
||||
},
|
||||
] as INodeProperties[];
|
||||
|
||||
export const expenseFields = [
|
||||
/* -------------------------------------------------------------------------- */
|
||||
/* expense:create */
|
||||
/* -------------------------------------------------------------------------- */
|
||||
{
|
||||
displayName: 'Additional Fields',
|
||||
name: 'additionalFields',
|
||||
type: 'collection',
|
||||
placeholder: 'Add Field',
|
||||
default: {},
|
||||
displayOptions: {
|
||||
show: {
|
||||
operation: [
|
||||
'create',
|
||||
],
|
||||
resource: [
|
||||
'expense',
|
||||
],
|
||||
},
|
||||
},
|
||||
options: [
|
||||
{
|
||||
displayName: 'Billable',
|
||||
name: 'billable',
|
||||
type: 'boolean',
|
||||
default: false,
|
||||
},
|
||||
{
|
||||
displayName: 'Client',
|
||||
name: 'client',
|
||||
type: 'options',
|
||||
typeOptions: {
|
||||
loadOptionsMethod: 'getClients',
|
||||
},
|
||||
default: '',
|
||||
},
|
||||
{
|
||||
displayName: 'Custom Value 1',
|
||||
name: 'customValue1',
|
||||
type: 'string',
|
||||
default: '',
|
||||
},
|
||||
{
|
||||
displayName: 'Custom Value 2',
|
||||
name: 'customValue2',
|
||||
type: 'string',
|
||||
default: '',
|
||||
},
|
||||
{
|
||||
displayName: 'Category',
|
||||
name: 'category',
|
||||
type: 'options',
|
||||
typeOptions: {
|
||||
loadOptionsMethod: 'getExpenseCategories',
|
||||
},
|
||||
default: '',
|
||||
},
|
||||
{
|
||||
displayName: 'Expense Date',
|
||||
name: 'expenseDate',
|
||||
type: 'dateTime',
|
||||
default: '',
|
||||
},
|
||||
{
|
||||
displayName: 'Payment Date',
|
||||
name: 'paymentDate',
|
||||
type: 'dateTime',
|
||||
default: '',
|
||||
},
|
||||
{
|
||||
displayName: 'Payment Type',
|
||||
name: 'paymentType',
|
||||
type: 'options',
|
||||
options: [
|
||||
{
|
||||
name: 'Apply Credit',
|
||||
value: 1,
|
||||
},
|
||||
{
|
||||
name: 'Bank Transfer',
|
||||
value: 2,
|
||||
},
|
||||
{
|
||||
name: 'Cash',
|
||||
value: 3,
|
||||
},
|
||||
{
|
||||
name: 'Debit',
|
||||
value: 4,
|
||||
},
|
||||
{
|
||||
name: 'ACH',
|
||||
value: 5,
|
||||
},
|
||||
{
|
||||
name: 'Visa Card',
|
||||
value: 6,
|
||||
},
|
||||
{
|
||||
name: 'MasterCard',
|
||||
value: 7,
|
||||
},
|
||||
{
|
||||
name: 'American Express',
|
||||
value: 8,
|
||||
},
|
||||
{
|
||||
name: 'Discover Card',
|
||||
value: 9,
|
||||
},
|
||||
{
|
||||
name: 'Diners Card',
|
||||
value: 10,
|
||||
},
|
||||
{
|
||||
name: 'EuroCard',
|
||||
value: 11,
|
||||
},
|
||||
{
|
||||
name: 'Nova',
|
||||
value: 12,
|
||||
},
|
||||
{
|
||||
name: 'Credit Card Other',
|
||||
value: 13,
|
||||
},
|
||||
{
|
||||
name: 'Paypal',
|
||||
value: 14,
|
||||
},
|
||||
{
|
||||
name: 'Google Wallet',
|
||||
value: 15,
|
||||
},
|
||||
{
|
||||
name: 'Check',
|
||||
value: 16,
|
||||
},
|
||||
{
|
||||
name: 'Carte Blanche',
|
||||
value: 17,
|
||||
},
|
||||
{
|
||||
name: 'UnionPay',
|
||||
value: 18,
|
||||
},
|
||||
{
|
||||
name: 'JCB',
|
||||
value: 19,
|
||||
},
|
||||
{
|
||||
name: 'Laser',
|
||||
value: 20,
|
||||
},
|
||||
{
|
||||
name: 'Maestro',
|
||||
value: 21,
|
||||
},
|
||||
{
|
||||
name: 'Solo',
|
||||
value: 22,
|
||||
},
|
||||
{
|
||||
name: 'Solo',
|
||||
value: 22,
|
||||
},
|
||||
{
|
||||
name: 'Swich',
|
||||
value: 23,
|
||||
},
|
||||
{
|
||||
name: 'Swich',
|
||||
value: 23,
|
||||
},
|
||||
{
|
||||
name: 'iZettle',
|
||||
value: 24,
|
||||
},
|
||||
{
|
||||
name: 'Swish',
|
||||
value: 25,
|
||||
},
|
||||
{
|
||||
name: 'Venmo',
|
||||
value: 26,
|
||||
},
|
||||
{
|
||||
name: 'Money Order',
|
||||
value: 27,
|
||||
},
|
||||
{
|
||||
name: 'Alipay',
|
||||
value: 28,
|
||||
},
|
||||
{
|
||||
name: 'Sofort',
|
||||
value: 29,
|
||||
},
|
||||
{
|
||||
name: 'SEPA',
|
||||
value: 30,
|
||||
},
|
||||
{
|
||||
name: 'GoCardless',
|
||||
value: 31,
|
||||
},
|
||||
{
|
||||
name: 'Bitcoin',
|
||||
value: 32,
|
||||
},
|
||||
],
|
||||
default: 1,
|
||||
},
|
||||
{
|
||||
displayName: 'Private Notes',
|
||||
name: 'privateNotes',
|
||||
type: 'string',
|
||||
typeOptions: {
|
||||
alwaysOpenEditWindow: true,
|
||||
},
|
||||
default: '',
|
||||
},
|
||||
{
|
||||
displayName: 'Public Notes',
|
||||
name: 'publicNotes',
|
||||
type: 'string',
|
||||
typeOptions: {
|
||||
alwaysOpenEditWindow: true,
|
||||
},
|
||||
default: '',
|
||||
},
|
||||
{
|
||||
displayName: 'Tax Name 1',
|
||||
name: 'taxName1',
|
||||
type: 'string',
|
||||
default: '',
|
||||
},
|
||||
{
|
||||
displayName: 'Tax Name 2',
|
||||
name: 'taxName2',
|
||||
type: 'string',
|
||||
default: '',
|
||||
},
|
||||
{
|
||||
displayName: 'Tax Rate 1',
|
||||
name: 'taxRate1',
|
||||
type: 'number',
|
||||
default: 0,
|
||||
},
|
||||
{
|
||||
displayName: 'Tax Rate 2',
|
||||
name: 'taxRate2',
|
||||
type: 'number',
|
||||
default: 0,
|
||||
},
|
||||
{
|
||||
displayName: 'Transaction Reference',
|
||||
name: 'transactionReference',
|
||||
type: 'string',
|
||||
default: '',
|
||||
},
|
||||
{
|
||||
displayName: 'Vendor',
|
||||
name: 'vendor',
|
||||
type: 'options',
|
||||
typeOptions: {
|
||||
loadOptionsMethod: 'getVendors',
|
||||
},
|
||||
default: '',
|
||||
},
|
||||
]
|
||||
},
|
||||
/* -------------------------------------------------------------------------- */
|
||||
/* expense:delete */
|
||||
/* -------------------------------------------------------------------------- */
|
||||
{
|
||||
displayName: 'Expense ID',
|
||||
name: 'expenseId',
|
||||
type: 'string',
|
||||
required: true,
|
||||
displayOptions: {
|
||||
show: {
|
||||
resource: [
|
||||
'expense',
|
||||
],
|
||||
operation: [
|
||||
'delete',
|
||||
],
|
||||
},
|
||||
},
|
||||
},
|
||||
/* -------------------------------------------------------------------------- */
|
||||
/* expense:get */
|
||||
/* -------------------------------------------------------------------------- */
|
||||
{
|
||||
displayName: 'Expense ID',
|
||||
name: 'expenseId',
|
||||
type: 'string',
|
||||
required: true,
|
||||
displayOptions: {
|
||||
show: {
|
||||
resource: [
|
||||
'expense',
|
||||
],
|
||||
operation: [
|
||||
'get',
|
||||
],
|
||||
},
|
||||
},
|
||||
},
|
||||
/* -------------------------------------------------------------------------- */
|
||||
/* expense:getAll */
|
||||
/* -------------------------------------------------------------------------- */
|
||||
{
|
||||
displayName: 'Return All',
|
||||
name: 'returnAll',
|
||||
type: 'boolean',
|
||||
displayOptions: {
|
||||
show: {
|
||||
resource: [
|
||||
'expense',
|
||||
],
|
||||
operation: [
|
||||
'getAll',
|
||||
],
|
||||
},
|
||||
},
|
||||
default: false,
|
||||
description: 'If all results should be returned or only up to a given limit.',
|
||||
},
|
||||
{
|
||||
displayName: 'Limit',
|
||||
name: 'limit',
|
||||
type: 'number',
|
||||
displayOptions: {
|
||||
show: {
|
||||
resource: [
|
||||
'expense',
|
||||
],
|
||||
operation: [
|
||||
'getAll',
|
||||
],
|
||||
returnAll: [
|
||||
false,
|
||||
],
|
||||
},
|
||||
},
|
||||
typeOptions: {
|
||||
minValue: 1,
|
||||
maxValue: 60,
|
||||
},
|
||||
default: 50,
|
||||
description: 'How many results to return.',
|
||||
},
|
||||
] as INodeProperties[];
|
19
packages/nodes-base/nodes/InvoiceNinja/ExpenseInterface.ts
Normal file
19
packages/nodes-base/nodes/InvoiceNinja/ExpenseInterface.ts
Normal file
|
@ -0,0 +1,19 @@
|
|||
export interface IExpense {
|
||||
amount?: number;
|
||||
client_id?: number;
|
||||
custom_value1?: string;
|
||||
custom_value2?: string;
|
||||
expense_category_id?: number;
|
||||
expense_date?: string;
|
||||
payment_date?: string;
|
||||
payment_type_id?: number;
|
||||
private_notes?: string;
|
||||
public_notes?: string;
|
||||
should_be_invoiced?: boolean;
|
||||
tax_name1?: string;
|
||||
tax_name2?: string;
|
||||
tax_rate1?: number;
|
||||
tax_rate2?: number;
|
||||
transaction_reference?: string;
|
||||
vendor_id?: number;
|
||||
}
|
80
packages/nodes-base/nodes/InvoiceNinja/GenericFunctions.ts
Normal file
80
packages/nodes-base/nodes/InvoiceNinja/GenericFunctions.ts
Normal file
|
@ -0,0 +1,80 @@
|
|||
import { OptionsWithUri } from 'request';
|
||||
|
||||
import {
|
||||
IExecuteFunctions,
|
||||
IExecuteSingleFunctions,
|
||||
IHookFunctions,
|
||||
ILoadOptionsFunctions,
|
||||
} from 'n8n-core';
|
||||
|
||||
import {
|
||||
IDataObject,
|
||||
} from 'n8n-workflow';
|
||||
|
||||
import { get } from 'lodash';
|
||||
|
||||
export async function invoiceninjaApiRequest(this: IHookFunctions | IExecuteFunctions | IExecuteSingleFunctions | ILoadOptionsFunctions, method: string, resource: string, body: any = {}, query?: IDataObject, uri?: string): Promise<any> { // tslint:disable-line:no-any
|
||||
let token;
|
||||
let endpoint;
|
||||
const cloudCredentials = this.getCredentials('invoiceNinjaCloudApi');
|
||||
const serverCredentials = this.getCredentials('invoiceNinjaServerApi');
|
||||
if (cloudCredentials === undefined && serverCredentials === undefined) {
|
||||
throw new Error('No credentials got returned!');
|
||||
}
|
||||
if (cloudCredentials !== undefined) {
|
||||
endpoint = 'https://app.invoiceninja.com';
|
||||
token = cloudCredentials!.apiToken;
|
||||
} else {
|
||||
endpoint = serverCredentials!.domain;
|
||||
token = serverCredentials!.apiToken;
|
||||
}
|
||||
const options: OptionsWithUri = {
|
||||
headers: {
|
||||
Accept: 'application/json',
|
||||
'X-Ninja-Token': token,
|
||||
},
|
||||
method,
|
||||
qs: query,
|
||||
uri: uri || `${endpoint}/api/v1${resource}`,
|
||||
body,
|
||||
json: true
|
||||
};
|
||||
try {
|
||||
return await this.helpers.request!(options);
|
||||
} catch (error) {
|
||||
if (error.response && error.response.body && error.response.body.errors) {
|
||||
// Try to return the error prettier
|
||||
const errorMessages = Object.keys(error.response.body.errors).map(errorName => {
|
||||
return (error.response.body.errors[errorName] as [string]).join('');
|
||||
});
|
||||
throw new Error(`Invoice Ninja error response [${error.statusCode}]: ${errorMessages.join(' | ')}`);
|
||||
}
|
||||
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
|
||||
export async function invoiceninjaApiRequestAllItems(this: IExecuteFunctions | ILoadOptionsFunctions, propertyName: string, method: string, endpoint: string, body: any = {}, query: IDataObject = {}): Promise<any> { // tslint:disable-line:no-any
|
||||
|
||||
const returnData: IDataObject[] = [];
|
||||
|
||||
let responseData;
|
||||
let uri;
|
||||
query.per_page = 100;
|
||||
|
||||
do {
|
||||
responseData = await invoiceninjaApiRequest.call(this, method, endpoint, body, query, uri);
|
||||
let next = get(responseData, 'meta.pagination.links.next') as string | undefined;
|
||||
if (next) {
|
||||
uri = next;
|
||||
}
|
||||
returnData.push.apply(returnData, responseData[propertyName]);
|
||||
} while (
|
||||
responseData.meta !== undefined &&
|
||||
responseData.meta.pagination &&
|
||||
responseData.meta.pagination.links &&
|
||||
responseData.meta.pagination.links.next
|
||||
);
|
||||
|
||||
return returnData;
|
||||
}
|
1581
packages/nodes-base/nodes/InvoiceNinja/ISOCountryCodes.ts
Normal file
1581
packages/nodes-base/nodes/InvoiceNinja/ISOCountryCodes.ts
Normal file
File diff suppressed because it is too large
Load diff
481
packages/nodes-base/nodes/InvoiceNinja/InvoiceDescription.ts
Normal file
481
packages/nodes-base/nodes/InvoiceNinja/InvoiceDescription.ts
Normal file
|
@ -0,0 +1,481 @@
|
|||
import { INodeProperties } from "n8n-workflow";
|
||||
|
||||
export const invoiceOperations = [
|
||||
{
|
||||
displayName: 'Operation',
|
||||
name: 'operation',
|
||||
type: 'options',
|
||||
displayOptions: {
|
||||
show: {
|
||||
resource: [
|
||||
'invoice',
|
||||
],
|
||||
},
|
||||
},
|
||||
options: [
|
||||
{
|
||||
name: 'Create',
|
||||
value: 'create',
|
||||
description: 'Create a new invoice',
|
||||
},
|
||||
{
|
||||
name: 'Email',
|
||||
value: 'email',
|
||||
description: 'Email an invoice',
|
||||
},
|
||||
{
|
||||
name: 'Get',
|
||||
value: 'get',
|
||||
description: 'Get data of a invoice',
|
||||
},
|
||||
{
|
||||
name: 'Get All',
|
||||
value: 'getAll',
|
||||
description: 'Get data of all invoices',
|
||||
},
|
||||
{
|
||||
name: 'Delete',
|
||||
value: 'delete',
|
||||
description: 'Delete a invoice',
|
||||
}
|
||||
],
|
||||
default: 'create',
|
||||
description: 'The operation to perform.',
|
||||
},
|
||||
] as INodeProperties[];
|
||||
|
||||
export const invoiceFields = [
|
||||
/* -------------------------------------------------------------------------- */
|
||||
/* invoice:create */
|
||||
/* -------------------------------------------------------------------------- */
|
||||
{
|
||||
displayName: 'Additional Fields',
|
||||
name: 'additionalFields',
|
||||
type: 'collection',
|
||||
placeholder: 'Add Field',
|
||||
default: {},
|
||||
displayOptions: {
|
||||
show: {
|
||||
operation: [
|
||||
'create',
|
||||
],
|
||||
resource: [
|
||||
'invoice',
|
||||
],
|
||||
},
|
||||
},
|
||||
options: [
|
||||
{
|
||||
displayName: 'Client',
|
||||
name: 'client',
|
||||
type: 'options',
|
||||
typeOptions: {
|
||||
loadOptionsMethod: 'getClients',
|
||||
},
|
||||
default: '',
|
||||
},
|
||||
{
|
||||
displayName: 'Auto Bill',
|
||||
name: 'autoBill',
|
||||
type: 'boolean',
|
||||
default: false,
|
||||
},
|
||||
{
|
||||
displayName: 'Custom Value 1',
|
||||
name: 'customValue1',
|
||||
type: 'number',
|
||||
typeOptions: {
|
||||
minValue: 0,
|
||||
},
|
||||
default: 0,
|
||||
},
|
||||
{
|
||||
displayName: 'Custom Value 2',
|
||||
name: 'customValue2',
|
||||
type: 'number',
|
||||
typeOptions: {
|
||||
minValue: 0,
|
||||
},
|
||||
default: 0,
|
||||
},
|
||||
{
|
||||
displayName: 'Discount',
|
||||
name: 'discount',
|
||||
type: 'string',
|
||||
default: '',
|
||||
},
|
||||
{
|
||||
displayName: 'Due Date',
|
||||
name: 'dueDate',
|
||||
type: 'dateTime',
|
||||
default: '',
|
||||
},
|
||||
{
|
||||
displayName: 'Email',
|
||||
name: 'email',
|
||||
type: 'string',
|
||||
default: '',
|
||||
},
|
||||
{
|
||||
displayName: 'Email Invoice',
|
||||
name: 'emailInvoice',
|
||||
type: 'boolean',
|
||||
default: false,
|
||||
},
|
||||
{
|
||||
displayName: 'Invoice Date',
|
||||
name: 'invoiceDate',
|
||||
type: 'dateTime',
|
||||
default: '',
|
||||
},
|
||||
{
|
||||
displayName: 'Invoice Number',
|
||||
name: 'invoiceNumber',
|
||||
type: 'string',
|
||||
default: '',
|
||||
},
|
||||
{
|
||||
displayName: 'Invoice Status',
|
||||
name: 'invoiceStatus',
|
||||
type: 'options',
|
||||
options: [
|
||||
{
|
||||
name: 'Draft',
|
||||
value: 1,
|
||||
},
|
||||
{
|
||||
name: 'Sent',
|
||||
value: 2,
|
||||
},
|
||||
],
|
||||
default: 1,
|
||||
},
|
||||
{
|
||||
displayName: 'Is Amount Discount',
|
||||
name: 'isAmountDiscount',
|
||||
type: 'boolean',
|
||||
default: false,
|
||||
},
|
||||
{
|
||||
displayName: 'Paid',
|
||||
name: 'paid',
|
||||
type: 'number',
|
||||
default: 0,
|
||||
},
|
||||
{
|
||||
displayName: 'Partial',
|
||||
name: 'partial',
|
||||
type: 'number',
|
||||
default: 0,
|
||||
},
|
||||
{
|
||||
displayName: 'Partial Due Date',
|
||||
name: 'partialDueDate',
|
||||
type: 'dateTime',
|
||||
default: '',
|
||||
},
|
||||
{
|
||||
displayName: 'Po Number',
|
||||
name: 'poNumber',
|
||||
type: 'string',
|
||||
default: '',
|
||||
},
|
||||
{
|
||||
displayName: 'Private Notes',
|
||||
name: 'privateNotes',
|
||||
type: 'string',
|
||||
typeOptions: {
|
||||
alwaysOpenEditWindow: true,
|
||||
},
|
||||
default: '',
|
||||
},
|
||||
{
|
||||
displayName: 'Public Notes',
|
||||
name: 'publicNotes',
|
||||
type: 'string',
|
||||
typeOptions: {
|
||||
alwaysOpenEditWindow: true,
|
||||
},
|
||||
default: '',
|
||||
},
|
||||
{
|
||||
displayName: 'Tax Name 1',
|
||||
name: 'taxName1',
|
||||
type: 'string',
|
||||
default: '',
|
||||
},
|
||||
{
|
||||
displayName: 'Tax Name 2',
|
||||
name: 'taxName2',
|
||||
type: 'string',
|
||||
default: '',
|
||||
},
|
||||
{
|
||||
displayName: 'Tax Rate 1',
|
||||
name: 'taxRate1',
|
||||
type: 'number',
|
||||
default: 0,
|
||||
},
|
||||
{
|
||||
displayName: 'Tax Rate 2',
|
||||
name: 'taxRate2',
|
||||
type: 'number',
|
||||
default: 0,
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
displayName: 'Invoice Items',
|
||||
name: 'invoiceItemsUi',
|
||||
placeholder: 'Add Invoice Item',
|
||||
type: 'fixedCollection',
|
||||
typeOptions: {
|
||||
multipleValues: true,
|
||||
},
|
||||
displayOptions: {
|
||||
show: {
|
||||
resource: [
|
||||
'invoice',
|
||||
],
|
||||
operation: [
|
||||
'create',
|
||||
],
|
||||
},
|
||||
},
|
||||
default: {},
|
||||
options: [
|
||||
{
|
||||
name: 'invoiceItemsValues',
|
||||
displayName: 'Invoice Item',
|
||||
values: [
|
||||
{
|
||||
displayName: 'Cost',
|
||||
name: 'cost',
|
||||
type: 'number',
|
||||
default: 0,
|
||||
},
|
||||
{
|
||||
displayName: 'Description',
|
||||
name: 'description',
|
||||
type: 'string',
|
||||
typeOptions: {
|
||||
alwaysOpenEditWindow: true,
|
||||
},
|
||||
default: '',
|
||||
},
|
||||
{
|
||||
displayName: 'Service',
|
||||
name: 'service',
|
||||
typeOptions: {
|
||||
alwaysOpenEditWindow: true,
|
||||
},
|
||||
type: 'string',
|
||||
default: '',
|
||||
},
|
||||
{
|
||||
displayName: 'Hours',
|
||||
name: 'hours',
|
||||
type: 'number',
|
||||
typeOptions: {
|
||||
minValue: 0,
|
||||
},
|
||||
default: 0,
|
||||
},
|
||||
{
|
||||
displayName: 'Tax Name 1',
|
||||
name: 'taxName1',
|
||||
type: 'string',
|
||||
default: '',
|
||||
},
|
||||
{
|
||||
displayName: 'Tax Name 2',
|
||||
name: 'taxName2',
|
||||
type: 'string',
|
||||
default: '',
|
||||
},
|
||||
{
|
||||
displayName: 'Tax Rate 1',
|
||||
name: 'taxRate1',
|
||||
type: 'number',
|
||||
default: 0,
|
||||
},
|
||||
{
|
||||
displayName: 'Tax Rate 2',
|
||||
name: 'taxRate2',
|
||||
type: 'number',
|
||||
default: 0,
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
/* -------------------------------------------------------------------------- */
|
||||
/* invoice:delete */
|
||||
/* -------------------------------------------------------------------------- */
|
||||
{
|
||||
displayName: 'Invoice ID',
|
||||
name: 'invoiceId',
|
||||
type: 'string',
|
||||
required: true,
|
||||
displayOptions: {
|
||||
show: {
|
||||
resource: [
|
||||
'invoice',
|
||||
],
|
||||
operation: [
|
||||
'delete',
|
||||
],
|
||||
},
|
||||
},
|
||||
},
|
||||
/* -------------------------------------------------------------------------- */
|
||||
/* invoice:email */
|
||||
/* -------------------------------------------------------------------------- */
|
||||
{
|
||||
displayName: 'Invoice ID',
|
||||
name: 'invoiceId',
|
||||
type: 'string',
|
||||
required: true,
|
||||
displayOptions: {
|
||||
show: {
|
||||
resource: [
|
||||
'invoice',
|
||||
],
|
||||
operation: [
|
||||
'email',
|
||||
],
|
||||
},
|
||||
},
|
||||
},
|
||||
/* -------------------------------------------------------------------------- */
|
||||
/* invoice:get */
|
||||
/* -------------------------------------------------------------------------- */
|
||||
{
|
||||
displayName: 'Invoice ID',
|
||||
name: 'invoiceId',
|
||||
type: 'string',
|
||||
required: true,
|
||||
displayOptions: {
|
||||
show: {
|
||||
resource: [
|
||||
'invoice',
|
||||
],
|
||||
operation: [
|
||||
'get',
|
||||
],
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
displayName: 'Options',
|
||||
name: 'options',
|
||||
type: 'collection',
|
||||
placeholder: 'Add Field',
|
||||
default: {},
|
||||
displayOptions: {
|
||||
show: {
|
||||
operation: [
|
||||
'get',
|
||||
],
|
||||
resource: [
|
||||
'invoice',
|
||||
],
|
||||
},
|
||||
},
|
||||
options: [
|
||||
{
|
||||
displayName: 'Include',
|
||||
name: 'include',
|
||||
type: 'options',
|
||||
options: [
|
||||
{
|
||||
name: 'Client',
|
||||
value: 'client',
|
||||
},
|
||||
],
|
||||
default: 'client',
|
||||
},
|
||||
],
|
||||
},
|
||||
/* -------------------------------------------------------------------------- */
|
||||
/* invoice:getAll */
|
||||
/* -------------------------------------------------------------------------- */
|
||||
{
|
||||
displayName: 'Return All',
|
||||
name: 'returnAll',
|
||||
type: 'boolean',
|
||||
displayOptions: {
|
||||
show: {
|
||||
resource: [
|
||||
'invoice',
|
||||
],
|
||||
operation: [
|
||||
'getAll',
|
||||
],
|
||||
},
|
||||
},
|
||||
default: false,
|
||||
description: 'If all results should be returned or only up to a given limit.',
|
||||
},
|
||||
{
|
||||
displayName: 'Limit',
|
||||
name: 'limit',
|
||||
type: 'number',
|
||||
displayOptions: {
|
||||
show: {
|
||||
resource: [
|
||||
'invoice',
|
||||
],
|
||||
operation: [
|
||||
'getAll',
|
||||
],
|
||||
returnAll: [
|
||||
false,
|
||||
],
|
||||
},
|
||||
},
|
||||
typeOptions: {
|
||||
minValue: 1,
|
||||
maxValue: 60,
|
||||
},
|
||||
default: 50,
|
||||
description: 'How many results to return.',
|
||||
},
|
||||
{
|
||||
displayName: 'Options',
|
||||
name: 'options',
|
||||
type: 'collection',
|
||||
placeholder: 'Add Field',
|
||||
default: {},
|
||||
displayOptions: {
|
||||
show: {
|
||||
operation: [
|
||||
'getAll',
|
||||
],
|
||||
resource: [
|
||||
'invoice',
|
||||
],
|
||||
},
|
||||
},
|
||||
options: [
|
||||
{
|
||||
displayName: 'Invoice Number',
|
||||
name: 'invoiceNumber',
|
||||
type: 'string',
|
||||
default: '',
|
||||
},
|
||||
{
|
||||
displayName: 'Include',
|
||||
name: 'include',
|
||||
type: 'options',
|
||||
options: [
|
||||
{
|
||||
name: 'Client',
|
||||
value: 'client',
|
||||
},
|
||||
],
|
||||
default: 'client',
|
||||
},
|
||||
],
|
||||
},
|
||||
] as INodeProperties[];
|
823
packages/nodes-base/nodes/InvoiceNinja/InvoiceNinja.node.ts
Normal file
823
packages/nodes-base/nodes/InvoiceNinja/InvoiceNinja.node.ts
Normal file
|
@ -0,0 +1,823 @@
|
|||
import {
|
||||
IExecuteFunctions,
|
||||
} from 'n8n-core';
|
||||
import {
|
||||
IDataObject,
|
||||
INodeTypeDescription,
|
||||
INodeExecutionData,
|
||||
INodeType,
|
||||
ILoadOptionsFunctions,
|
||||
INodePropertyOptions,
|
||||
} from 'n8n-workflow';
|
||||
import {
|
||||
invoiceninjaApiRequest,
|
||||
invoiceninjaApiRequestAllItems,
|
||||
} from './GenericFunctions';
|
||||
import {
|
||||
clientOperations,
|
||||
clientFields
|
||||
} from './ClientDescription';
|
||||
import {
|
||||
invoiceOperations,
|
||||
invoiceFields
|
||||
} from './InvoiceDescription';
|
||||
import {
|
||||
IClient,
|
||||
IContact,
|
||||
} from './ClientInterface';
|
||||
import {
|
||||
countryCodes,
|
||||
} from './ISOCountryCodes';
|
||||
import {
|
||||
IInvoice,
|
||||
IItem,
|
||||
} from './invoiceInterface';
|
||||
import {
|
||||
taskOperations,
|
||||
taskFields
|
||||
} from './TaskDescription';
|
||||
import {
|
||||
ITask,
|
||||
} from './TaskInterface';
|
||||
import {
|
||||
paymentOperations,
|
||||
paymentFields
|
||||
} from './PaymentDescription';
|
||||
import {
|
||||
IPayment,
|
||||
} from './PaymentInterface';
|
||||
import {
|
||||
expenseOperations,
|
||||
expenseFields
|
||||
} from './ExpenseDescription';
|
||||
import {
|
||||
IExpense,
|
||||
} from './ExpenseInterface';
|
||||
import {
|
||||
quoteOperations,
|
||||
quoteFields
|
||||
} from './QuoteDescription';
|
||||
import {
|
||||
IQuote,
|
||||
} from './QuoteInterface';
|
||||
|
||||
export class InvoiceNinja implements INodeType {
|
||||
description: INodeTypeDescription = {
|
||||
displayName: 'Invoice Ninja',
|
||||
name: 'invoiceNinja',
|
||||
icon: 'file:invoiceNinja.png',
|
||||
group: ['output'],
|
||||
version: 1,
|
||||
subtitle: '={{$parameter["operation"] + ": " + $parameter["resource"]}}',
|
||||
description: 'Consume Invoice Ninja API',
|
||||
defaults: {
|
||||
name: 'Invoice Ninja',
|
||||
color: '#000000',
|
||||
},
|
||||
inputs: ['main'],
|
||||
outputs: ['main'],
|
||||
credentials: [
|
||||
{
|
||||
name: 'invoiceNinjaCloudApi',
|
||||
required: true,
|
||||
displayOptions: {
|
||||
show: {
|
||||
invoiceNinjaVersion: [
|
||||
'cloud',
|
||||
],
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: 'invoiceNinjaServerApi',
|
||||
required: true,
|
||||
displayOptions: {
|
||||
show: {
|
||||
invoiceNinjaVersion: [
|
||||
'server',
|
||||
],
|
||||
},
|
||||
},
|
||||
},
|
||||
],
|
||||
properties: [
|
||||
{
|
||||
displayName: 'Version',
|
||||
name: 'invoiceNinjaVersion',
|
||||
type: 'options',
|
||||
options: [
|
||||
{
|
||||
name: 'Cloud',
|
||||
value: 'cloud',
|
||||
},
|
||||
{
|
||||
name: 'Server (Self Hosted)',
|
||||
value: 'server',
|
||||
},
|
||||
],
|
||||
default: 'cloud',
|
||||
},
|
||||
{
|
||||
displayName: 'Resource',
|
||||
name: 'resource',
|
||||
type: 'options',
|
||||
options: [
|
||||
{
|
||||
name: 'Client',
|
||||
value: 'client',
|
||||
},
|
||||
{
|
||||
name: 'Expense',
|
||||
value: 'expense',
|
||||
},
|
||||
{
|
||||
name: 'Invoice',
|
||||
value: 'invoice',
|
||||
},
|
||||
{
|
||||
name: 'Payment',
|
||||
value: 'payment',
|
||||
},
|
||||
{
|
||||
name: 'Quote',
|
||||
value: 'quote',
|
||||
},
|
||||
{
|
||||
name: 'Task',
|
||||
value: 'task',
|
||||
},
|
||||
],
|
||||
default: 'client',
|
||||
description: 'Resource to consume.',
|
||||
},
|
||||
...clientOperations,
|
||||
...clientFields,
|
||||
...invoiceOperations,
|
||||
...invoiceFields,
|
||||
...taskOperations,
|
||||
...taskFields,
|
||||
...paymentOperations,
|
||||
...paymentFields,
|
||||
...expenseOperations,
|
||||
...expenseFields,
|
||||
...quoteOperations,
|
||||
...quoteFields,
|
||||
],
|
||||
};
|
||||
|
||||
methods = {
|
||||
loadOptions: {
|
||||
// Get all the available clients to display them to user so that he can
|
||||
// select them easily
|
||||
async getClients(this: ILoadOptionsFunctions): Promise<INodePropertyOptions[]> {
|
||||
const returnData: INodePropertyOptions[] = [];
|
||||
const clients = await invoiceninjaApiRequestAllItems.call(this, 'data', 'GET', '/clients');
|
||||
for (const client of clients) {
|
||||
const clientName = client.display_name;
|
||||
const clientId = client.id;
|
||||
returnData.push({
|
||||
name: clientName,
|
||||
value: clientId,
|
||||
});
|
||||
}
|
||||
return returnData;
|
||||
},
|
||||
// Get all the available projects to display them to user so that he can
|
||||
// select them easily
|
||||
async getProjects(this: ILoadOptionsFunctions): Promise<INodePropertyOptions[]> {
|
||||
const returnData: INodePropertyOptions[] = [];
|
||||
const projects = await invoiceninjaApiRequestAllItems.call(this, 'data', 'GET', '/projects');
|
||||
for (const project of projects) {
|
||||
const projectName = project.name;
|
||||
const projectId = project.id;
|
||||
returnData.push({
|
||||
name: projectName,
|
||||
value: projectId,
|
||||
});
|
||||
}
|
||||
return returnData;
|
||||
},
|
||||
// Get all the available invoices to display them to user so that he can
|
||||
// select them easily
|
||||
async getInvoices(this: ILoadOptionsFunctions): Promise<INodePropertyOptions[]> {
|
||||
const returnData: INodePropertyOptions[] = [];
|
||||
const invoices = await invoiceninjaApiRequestAllItems.call(this, 'data', 'GET', '/invoices');
|
||||
for (const invoice of invoices) {
|
||||
const invoiceName = invoice.invoice_number;
|
||||
const invoiceId = invoice.id;
|
||||
returnData.push({
|
||||
name: invoiceName,
|
||||
value: invoiceId,
|
||||
});
|
||||
}
|
||||
return returnData;
|
||||
},
|
||||
// Get all the available country codes to display them to user so that he can
|
||||
// select them easily
|
||||
async getCountryCodes(this: ILoadOptionsFunctions): Promise<INodePropertyOptions[]> {
|
||||
const returnData: INodePropertyOptions[] = [];
|
||||
for (let i = 0; i < countryCodes.length; i++) {
|
||||
const countryName = countryCodes[i].name as string;
|
||||
const countryId = countryCodes[i].numeric as string;
|
||||
returnData.push({
|
||||
name: countryName,
|
||||
value: countryId,
|
||||
});
|
||||
}
|
||||
return returnData;
|
||||
},
|
||||
// Get all the available vendors to display them to user so that he can
|
||||
// select them easily
|
||||
async getVendors(this: ILoadOptionsFunctions): Promise<INodePropertyOptions[]> {
|
||||
const returnData: INodePropertyOptions[] = [];
|
||||
const vendors = await invoiceninjaApiRequestAllItems.call(this, 'data', 'GET', '/vendors');
|
||||
for (const vendor of vendors) {
|
||||
const vendorName = vendor.name;
|
||||
const vendorId = vendor.id;
|
||||
returnData.push({
|
||||
name: vendorName,
|
||||
value: vendorId,
|
||||
});
|
||||
}
|
||||
return returnData;
|
||||
},
|
||||
// Get all the available expense categories to display them to user so that he can
|
||||
// select them easily
|
||||
async getExpenseCategories(this: ILoadOptionsFunctions): Promise<INodePropertyOptions[]> {
|
||||
const returnData: INodePropertyOptions[] = [];
|
||||
const categories = await invoiceninjaApiRequestAllItems.call(this, 'data', 'GET', '/expense_categories');
|
||||
for (const category of categories) {
|
||||
const categoryName = category.name;
|
||||
const categoryId = category.id;
|
||||
returnData.push({
|
||||
name: categoryName,
|
||||
value: categoryId,
|
||||
});
|
||||
}
|
||||
return returnData;
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
async execute(this: IExecuteFunctions): Promise<INodeExecutionData[][]> {
|
||||
const items = this.getInputData();
|
||||
const returnData: IDataObject[] = [];
|
||||
const length = items.length as unknown as number;
|
||||
let responseData;
|
||||
const qs: IDataObject = {};
|
||||
const resource = this.getNodeParameter('resource', 0) as string;
|
||||
const operation = this.getNodeParameter('operation', 0) as string;
|
||||
for (let i = 0; i < length; i++) {
|
||||
//Routes: https://github.com/invoiceninja/invoiceninja/blob/ff455c8ed9fd0c0326956175ecd509efa8bad263/routes/api.php
|
||||
if (resource === 'client') {
|
||||
if (operation === 'create') {
|
||||
const additionalFields = this.getNodeParameter('additionalFields', i) as IDataObject;
|
||||
const body: IClient = {};
|
||||
if (additionalFields.clientName) {
|
||||
body.name = additionalFields.clientName as string;
|
||||
}
|
||||
if (additionalFields.clientName) {
|
||||
body.name = additionalFields.clientName as string;
|
||||
}
|
||||
if (additionalFields.idNumber) {
|
||||
body.id_number = additionalFields.idNumber as string;
|
||||
}
|
||||
if (additionalFields.idNumber) {
|
||||
body.id_number = additionalFields.idNumber as string;
|
||||
}
|
||||
if (additionalFields.privateNotes) {
|
||||
body.private_notes = additionalFields.privateNotes as string;
|
||||
}
|
||||
if (additionalFields.vatNumber) {
|
||||
body.vat_number = additionalFields.vatNumber as string;
|
||||
}
|
||||
if (additionalFields.workPhone) {
|
||||
body.work_phone = additionalFields.workPhone as string;
|
||||
}
|
||||
if (additionalFields.website) {
|
||||
body.website = additionalFields.website as string;
|
||||
}
|
||||
const contactsValues = (this.getNodeParameter('contactsUi', i) as IDataObject).contacstValues as IDataObject[];
|
||||
if (contactsValues) {
|
||||
const contacts: IContact[] = [];
|
||||
for (const contactValue of contactsValues) {
|
||||
const contact: IContact = {
|
||||
first_name: contactValue.firstName as string,
|
||||
last_name: contactValue.lastName as string,
|
||||
email: contactValue.email as string,
|
||||
phone: contactValue.phone as string,
|
||||
}
|
||||
contacts.push(contact)
|
||||
}
|
||||
body.contacts = contacts;
|
||||
}
|
||||
const shippingAddressValue = (this.getNodeParameter('shippingAddressUi', i) as IDataObject).shippingAddressValue as IDataObject;
|
||||
if (shippingAddressValue) {
|
||||
body.shipping_address1 = shippingAddressValue.streetAddress as string;
|
||||
body.shipping_address2 = shippingAddressValue.aptSuite as string;
|
||||
body.shipping_city = shippingAddressValue.city as string;
|
||||
body.shipping_state = shippingAddressValue.state as string;
|
||||
body.shipping_postal_code = shippingAddressValue.postalCode as string;
|
||||
body.shipping_country_id = parseInt(shippingAddressValue.countryCode as string, 10);
|
||||
}
|
||||
const billingAddressValue = (this.getNodeParameter('billingAddressUi', i) as IDataObject).billingAddressValue as IDataObject;
|
||||
if (billingAddressValue) {
|
||||
body.address1 = billingAddressValue.streetAddress as string;
|
||||
body.address2 = billingAddressValue.aptSuite as string;
|
||||
body.city = billingAddressValue.city as string;
|
||||
body.state = billingAddressValue.state as string;
|
||||
body.postal_code = billingAddressValue.postalCode as string;
|
||||
body.country_id = parseInt(billingAddressValue.countryCode as string, 10);
|
||||
}
|
||||
responseData = await invoiceninjaApiRequest.call(this, 'POST', '/clients', body);
|
||||
responseData = responseData.data;
|
||||
}
|
||||
if (operation === 'get') {
|
||||
const clientId = this.getNodeParameter('clientId', i) as string;
|
||||
const options = this.getNodeParameter('options', i) as IDataObject;
|
||||
if (options.include) {
|
||||
qs.include = options.include as string;
|
||||
}
|
||||
responseData = await invoiceninjaApiRequest.call(this, 'GET', `/clients/${clientId}`, {}, qs);
|
||||
responseData = responseData.data;
|
||||
}
|
||||
if (operation === 'getAll') {
|
||||
const returnAll = this.getNodeParameter('returnAll', 0) as boolean;
|
||||
const options = this.getNodeParameter('options', i) as IDataObject;
|
||||
if (options.include) {
|
||||
qs.include = options.include as string;
|
||||
}
|
||||
if (returnAll === true) {
|
||||
responseData = await invoiceninjaApiRequestAllItems.call(this, 'data', 'GET', '/clients', {}, qs);
|
||||
} else {
|
||||
qs.per_page = this.getNodeParameter('limit', 0) as number;
|
||||
responseData = await invoiceninjaApiRequest.call(this, 'GET', '/clients', {}, qs);
|
||||
responseData = responseData.data;
|
||||
}
|
||||
}
|
||||
if (operation === 'delete') {
|
||||
const clientId = this.getNodeParameter('clientId', i) as string;
|
||||
responseData = await invoiceninjaApiRequest.call(this, 'DELETE', `/clients/${clientId}`);
|
||||
responseData = responseData.data;
|
||||
}
|
||||
}
|
||||
if (resource === 'invoice') {
|
||||
if (operation === 'create') {
|
||||
const additionalFields = this.getNodeParameter('additionalFields', i) as IDataObject;
|
||||
const body: IInvoice = {};
|
||||
if (additionalFields.email) {
|
||||
body.email = additionalFields.email as string;
|
||||
}
|
||||
if (additionalFields.client) {
|
||||
body.client_id = additionalFields.client as number;
|
||||
}
|
||||
if (additionalFields.autoBill) {
|
||||
body.auto_bill = additionalFields.autoBill as boolean;
|
||||
}
|
||||
if (additionalFields.customValue1) {
|
||||
body.custom_value1 = additionalFields.customValue1 as number;
|
||||
}
|
||||
if (additionalFields.customValue2) {
|
||||
body.custom_value2 = additionalFields.customValue2 as number;
|
||||
}
|
||||
if (additionalFields.dueDate) {
|
||||
body.due_date = additionalFields.dueDate as string;
|
||||
}
|
||||
if (additionalFields.invoiceDate) {
|
||||
body.invoice_date = additionalFields.invoiceDate as string;
|
||||
}
|
||||
if (additionalFields.invoiceNumber) {
|
||||
body.invoice_number = additionalFields.invoiceNumber as string;
|
||||
}
|
||||
if (additionalFields.invoiceStatus) {
|
||||
body.invoice_status_id = additionalFields.invoiceStatus as number;
|
||||
}
|
||||
if (additionalFields.isAmountDiscount) {
|
||||
body.is_amount_discount = additionalFields.isAmountDiscount as boolean;
|
||||
}
|
||||
if (additionalFields.partial) {
|
||||
body.partial = additionalFields.partial as number;
|
||||
}
|
||||
if (additionalFields.partialDueDate) {
|
||||
body.partial_due_date = additionalFields.partialDueDate as string;
|
||||
}
|
||||
if (additionalFields.poNumber) {
|
||||
body.po_number = additionalFields.poNumber as string;
|
||||
}
|
||||
if (additionalFields.privateNotes) {
|
||||
body.private_notes = additionalFields.privateNotes as string;
|
||||
}
|
||||
if (additionalFields.publicNotes) {
|
||||
body.public_notes = additionalFields.publicNotes as string;
|
||||
}
|
||||
if (additionalFields.taxName1) {
|
||||
body.tax_name1 = additionalFields.taxName1 as string;
|
||||
}
|
||||
if (additionalFields.taxName2) {
|
||||
body.tax_name2 = additionalFields.taxName2 as string;
|
||||
}
|
||||
if (additionalFields.taxtRate1) {
|
||||
body.tax_rate1 = additionalFields.taxtRate1 as number;
|
||||
}
|
||||
if (additionalFields.taxtRate2) {
|
||||
body.tax_rate2 = additionalFields.taxtRate2 as number;
|
||||
}
|
||||
if (additionalFields.discount) {
|
||||
body.discount = additionalFields.discount as number;
|
||||
}
|
||||
if (additionalFields.paid) {
|
||||
body.paid = additionalFields.paid as number;
|
||||
}
|
||||
if (additionalFields.emailInvoice) {
|
||||
body.email_invoice = additionalFields.emailInvoice as boolean;
|
||||
}
|
||||
const invoceItemsValues = (this.getNodeParameter('invoiceItemsUi', i) as IDataObject).invoiceItemsValues as IDataObject[];
|
||||
if (invoceItemsValues) {
|
||||
const items: IItem[] = [];
|
||||
for (const itemValue of invoceItemsValues) {
|
||||
const item: IItem = {
|
||||
cost: itemValue.cost as number,
|
||||
notes: itemValue.description as string,
|
||||
product_key: itemValue.service as string,
|
||||
qty: itemValue.hours as number,
|
||||
tax_rate1: itemValue.taxRate1 as number,
|
||||
tax_rate2: itemValue.taxRate2 as number,
|
||||
tax_name1: itemValue.taxName1 as string,
|
||||
tax_name2: itemValue.taxName2 as string,
|
||||
}
|
||||
items.push(item)
|
||||
}
|
||||
body.invoice_items = items;
|
||||
}
|
||||
responseData = await invoiceninjaApiRequest.call(this, 'POST', '/invoices', body);
|
||||
responseData = responseData.data;
|
||||
}
|
||||
if (operation === 'email') {
|
||||
const invoiceId = this.getNodeParameter('invoiceId', i) as string;
|
||||
responseData = await invoiceninjaApiRequest.call(this, 'POST', '/email_invoice', { id: invoiceId });
|
||||
}
|
||||
if (operation === 'get') {
|
||||
const invoiceId = this.getNodeParameter('invoiceId', i) as string;
|
||||
const options = this.getNodeParameter('options', i) as IDataObject;
|
||||
if (options.include) {
|
||||
qs.include = options.include as string;
|
||||
}
|
||||
responseData = await invoiceninjaApiRequest.call(this, 'GET', `/invoices/${invoiceId}`, {}, qs);
|
||||
responseData = responseData.data;
|
||||
}
|
||||
if (operation === 'getAll') {
|
||||
const returnAll = this.getNodeParameter('returnAll', 0) as boolean;
|
||||
const options = this.getNodeParameter('options', i) as IDataObject;
|
||||
if (options.include) {
|
||||
qs.include = options.include as string;
|
||||
}
|
||||
if (options.invoiceNumber) {
|
||||
qs.invoice_number = options.invoiceNumber as string;
|
||||
}
|
||||
if (returnAll === true) {
|
||||
responseData = await invoiceninjaApiRequestAllItems.call(this, 'data', 'GET', '/invoices', {}, qs);
|
||||
} else {
|
||||
qs.per_page = this.getNodeParameter('limit', 0) as number;
|
||||
responseData = await invoiceninjaApiRequest.call(this, 'GET', '/invoices', {}, qs);
|
||||
responseData = responseData.data;
|
||||
}
|
||||
}
|
||||
if (operation === 'delete') {
|
||||
const invoiceId = this.getNodeParameter('invoiceId', i) as string;
|
||||
responseData = await invoiceninjaApiRequest.call(this, 'DELETE', `/invoices/${invoiceId}`);
|
||||
responseData = responseData.data;
|
||||
}
|
||||
}
|
||||
if (resource === 'task') {
|
||||
if (operation === 'create') {
|
||||
const additionalFields = this.getNodeParameter('additionalFields', i) as IDataObject;
|
||||
const body: ITask = {};
|
||||
if (additionalFields.client) {
|
||||
body.client_id = additionalFields.client as number;
|
||||
}
|
||||
if (additionalFields.project) {
|
||||
body.project = additionalFields.project as number;
|
||||
}
|
||||
if (additionalFields.customValue1) {
|
||||
body.custom_value1 = additionalFields.customValue1 as string;
|
||||
}
|
||||
if (additionalFields.customValue2) {
|
||||
body.custom_value2 = additionalFields.customValue2 as string;
|
||||
}
|
||||
if (additionalFields.description) {
|
||||
body.description = additionalFields.description as string;
|
||||
}
|
||||
const timeLogsValues = (this.getNodeParameter('timeLogsUi', i) as IDataObject).timeLogsValues as IDataObject[];
|
||||
if (timeLogsValues) {
|
||||
const logs: number[][] = [];
|
||||
for (const logValue of timeLogsValues) {
|
||||
let from = 0, to;
|
||||
if (logValue.startDate) {
|
||||
from = new Date(logValue.startDate as string).getTime()/1000 as number;
|
||||
}
|
||||
if (logValue.endDate) {
|
||||
to = new Date(logValue.endDate as string).getTime()/1000 as number;
|
||||
}
|
||||
if (logValue.duration) {
|
||||
to = from + (logValue.duration as number * 3600)
|
||||
}
|
||||
logs.push([from as number, to as number]);
|
||||
}
|
||||
body.time_log = JSON.stringify(logs);
|
||||
}
|
||||
responseData = await invoiceninjaApiRequest.call(this, 'POST', '/tasks', body);
|
||||
responseData = responseData.data;
|
||||
}
|
||||
if (operation === 'get') {
|
||||
const taskId = this.getNodeParameter('taskId', i) as string;
|
||||
const options = this.getNodeParameter('options', i) as IDataObject;
|
||||
if (options.include) {
|
||||
qs.include = options.include as string;
|
||||
}
|
||||
responseData = await invoiceninjaApiRequest.call(this, 'GET', `/tasks/${taskId}`, {}, qs);
|
||||
responseData = responseData.data;
|
||||
}
|
||||
if (operation === 'getAll') {
|
||||
const returnAll = this.getNodeParameter('returnAll', 0) as boolean;
|
||||
const options = this.getNodeParameter('options', i) as IDataObject;
|
||||
if (options.include) {
|
||||
qs.include = options.include as string;
|
||||
}
|
||||
if (returnAll === true) {
|
||||
responseData = await invoiceninjaApiRequestAllItems.call(this, 'data', 'GET', '/tasks', {}, qs);
|
||||
} else {
|
||||
qs.per_page = this.getNodeParameter('limit', 0) as number;
|
||||
responseData = await invoiceninjaApiRequest.call(this, 'GET', '/tasks', {}, qs);
|
||||
responseData = responseData.data;
|
||||
}
|
||||
}
|
||||
if (operation === 'delete') {
|
||||
const taskId = this.getNodeParameter('taskId', i) as string;
|
||||
responseData = await invoiceninjaApiRequest.call(this, 'DELETE', `/tasks/${taskId}`);
|
||||
responseData = responseData.data;
|
||||
}
|
||||
}
|
||||
if (resource === 'payment') {
|
||||
if (operation === 'create') {
|
||||
const additionalFields = this.getNodeParameter('additionalFields', i) as IDataObject;
|
||||
const invoice = this.getNodeParameter('invoice', i) as number;
|
||||
const amount = this.getNodeParameter('amount', i) as number;
|
||||
const body: IPayment = {
|
||||
invoice_id: invoice,
|
||||
amount,
|
||||
};
|
||||
if (additionalFields.paymentType) {
|
||||
body.payment_type_id = additionalFields.paymentType as number;
|
||||
}
|
||||
if (additionalFields.transferReference) {
|
||||
body.transaction_reference = additionalFields.transferReference as string;
|
||||
}
|
||||
if (additionalFields.privateNotes) {
|
||||
body.private_notes = additionalFields.privateNotes as string;
|
||||
}
|
||||
responseData = await invoiceninjaApiRequest.call(this, 'POST', '/payments', body);
|
||||
responseData = responseData.data;
|
||||
}
|
||||
if (operation === 'get') {
|
||||
const paymentId = this.getNodeParameter('paymentId', i) as string;
|
||||
const options = this.getNodeParameter('options', i) as IDataObject;
|
||||
if (options.include) {
|
||||
qs.include = options.include as string;
|
||||
}
|
||||
responseData = await invoiceninjaApiRequest.call(this, 'GET', `/payments/${paymentId}`, {}, qs);
|
||||
responseData = responseData.data;
|
||||
}
|
||||
if (operation === 'getAll') {
|
||||
const returnAll = this.getNodeParameter('returnAll', 0) as boolean;
|
||||
const options = this.getNodeParameter('options', i) as IDataObject;
|
||||
if (options.include) {
|
||||
qs.include = options.include as string;
|
||||
}
|
||||
if (returnAll === true) {
|
||||
responseData = await invoiceninjaApiRequestAllItems.call(this, 'data', 'GET', '/payments', {}, qs);
|
||||
} else {
|
||||
qs.per_page = this.getNodeParameter('limit', 0) as number;
|
||||
responseData = await invoiceninjaApiRequest.call(this, 'GET', '/payments', {}, qs);
|
||||
responseData = responseData.data;
|
||||
}
|
||||
}
|
||||
if (operation === 'delete') {
|
||||
const paymentId = this.getNodeParameter('paymentId', i) as string;
|
||||
responseData = await invoiceninjaApiRequest.call(this, 'DELETE', `/payments/${paymentId}`);
|
||||
responseData = responseData.data;
|
||||
}
|
||||
}
|
||||
if (resource === 'expense') {
|
||||
if (operation === 'create') {
|
||||
const additionalFields = this.getNodeParameter('additionalFields', i) as IDataObject;
|
||||
const body: IExpense = {};
|
||||
if (additionalFields.billable) {
|
||||
body.should_be_invoiced = additionalFields.billable as boolean;
|
||||
}
|
||||
if (additionalFields.client) {
|
||||
body.client_id = additionalFields.client as number;
|
||||
}
|
||||
if (additionalFields.customValue1) {
|
||||
body.custom_value1 = additionalFields.customValue1 as string;
|
||||
}
|
||||
if (additionalFields.customValue2) {
|
||||
body.custom_value2 = additionalFields.customValue2 as string;
|
||||
}
|
||||
if (additionalFields.category) {
|
||||
body.expense_category_id = additionalFields.category as number;
|
||||
}
|
||||
if (additionalFields.expenseDate) {
|
||||
body.expense_date = additionalFields.expenseDate as string;
|
||||
}
|
||||
if (additionalFields.paymentDate) {
|
||||
body.payment_date = additionalFields.paymentDate as string;
|
||||
}
|
||||
if (additionalFields.paymentType) {
|
||||
body.payment_type_id = additionalFields.paymentType as number;
|
||||
}
|
||||
if (additionalFields.publicNotes) {
|
||||
body.public_notes = additionalFields.publicNotes as string;
|
||||
}
|
||||
if (additionalFields.privateNotes) {
|
||||
body.private_notes = additionalFields.privateNotes as string;
|
||||
}
|
||||
if (additionalFields.taxName1) {
|
||||
body.tax_name1 = additionalFields.taxName1 as string;
|
||||
}
|
||||
if (additionalFields.taxName2) {
|
||||
body.tax_name2 = additionalFields.taxName2 as string;
|
||||
}
|
||||
if (additionalFields.taxRate1) {
|
||||
body.tax_rate1 = additionalFields.taxRate1 as number;
|
||||
}
|
||||
if (additionalFields.taxRate2) {
|
||||
body.tax_rate2 = additionalFields.taxRate2 as number;
|
||||
}
|
||||
if (additionalFields.transactionReference) {
|
||||
body.transaction_reference = additionalFields.transactionReference as string;
|
||||
}
|
||||
if (additionalFields.vendor) {
|
||||
body.vendor_id = additionalFields.vendor as number;
|
||||
}
|
||||
responseData = await invoiceninjaApiRequest.call(this, 'POST', '/expenses', body);
|
||||
responseData = responseData.data;
|
||||
}
|
||||
if (operation === 'get') {
|
||||
const expenseId = this.getNodeParameter('expenseId', i) as string;
|
||||
responseData = await invoiceninjaApiRequest.call(this, 'GET', `/expenses/${expenseId}`, {}, qs);
|
||||
responseData = responseData.data;
|
||||
}
|
||||
if (operation === 'getAll') {
|
||||
const returnAll = this.getNodeParameter('returnAll', 0) as boolean;
|
||||
if (returnAll === true) {
|
||||
responseData = await invoiceninjaApiRequestAllItems.call(this, 'data', 'GET', '/payments', {}, qs);
|
||||
} else {
|
||||
qs.per_page = this.getNodeParameter('limit', 0) as number;
|
||||
responseData = await invoiceninjaApiRequest.call(this, 'GET', '/payments', {}, qs);
|
||||
responseData = responseData.data;
|
||||
}
|
||||
}
|
||||
if (operation === 'delete') {
|
||||
const expenseId = this.getNodeParameter('expenseId', i) as string;
|
||||
responseData = await invoiceninjaApiRequest.call(this, 'DELETE', `/expenses/${expenseId}`);
|
||||
responseData = responseData.data;
|
||||
}
|
||||
}
|
||||
if (resource === 'quote') {
|
||||
if (operation === 'create') {
|
||||
const additionalFields = this.getNodeParameter('additionalFields', i) as IDataObject;
|
||||
const body: IQuote = {
|
||||
is_quote: true,
|
||||
};
|
||||
if (additionalFields.client) {
|
||||
body.client_id = additionalFields.client as number;
|
||||
}
|
||||
if (additionalFields.email) {
|
||||
body.email = additionalFields.email as string;
|
||||
}
|
||||
if (additionalFields.autoBill) {
|
||||
body.auto_bill = additionalFields.autoBill as boolean;
|
||||
}
|
||||
if (additionalFields.customValue1) {
|
||||
body.custom_value1 = additionalFields.customValue1 as number;
|
||||
}
|
||||
if (additionalFields.customValue2) {
|
||||
body.custom_value2 = additionalFields.customValue2 as number;
|
||||
}
|
||||
if (additionalFields.dueDate) {
|
||||
body.due_date = additionalFields.dueDate as string;
|
||||
}
|
||||
if (additionalFields.quouteDate) {
|
||||
body.invoice_date = additionalFields.quouteDate as string;
|
||||
}
|
||||
if (additionalFields.quoteNumber) {
|
||||
body.invoice_number = additionalFields.quoteNumber as string;
|
||||
}
|
||||
if (additionalFields.invoiceStatus) {
|
||||
body.invoice_status_id = additionalFields.invoiceStatus as number;
|
||||
}
|
||||
if (additionalFields.isAmountDiscount) {
|
||||
body.is_amount_discount = additionalFields.isAmountDiscount as boolean;
|
||||
}
|
||||
if (additionalFields.partial) {
|
||||
body.partial = additionalFields.partial as number;
|
||||
}
|
||||
if (additionalFields.partialDueDate) {
|
||||
body.partial_due_date = additionalFields.partialDueDate as string;
|
||||
}
|
||||
if (additionalFields.poNumber) {
|
||||
body.po_number = additionalFields.poNumber as string;
|
||||
}
|
||||
if (additionalFields.privateNotes) {
|
||||
body.private_notes = additionalFields.privateNotes as string;
|
||||
}
|
||||
if (additionalFields.publicNotes) {
|
||||
body.public_notes = additionalFields.publicNotes as string;
|
||||
}
|
||||
if (additionalFields.taxName1) {
|
||||
body.tax_name1 = additionalFields.taxName1 as string;
|
||||
}
|
||||
if (additionalFields.taxName2) {
|
||||
body.tax_name2 = additionalFields.taxName2 as string;
|
||||
}
|
||||
if (additionalFields.taxtRate1) {
|
||||
body.tax_rate1 = additionalFields.taxtRate1 as number;
|
||||
}
|
||||
if (additionalFields.taxtRate2) {
|
||||
body.tax_rate2 = additionalFields.taxtRate2 as number;
|
||||
}
|
||||
if (additionalFields.discount) {
|
||||
body.discount = additionalFields.discount as number;
|
||||
}
|
||||
if (additionalFields.paid) {
|
||||
body.paid = additionalFields.paid as number;
|
||||
}
|
||||
if (additionalFields.emailQoute) {
|
||||
body.email_invoice = additionalFields.emailQoute as boolean;
|
||||
}
|
||||
const invoceItemsValues = (this.getNodeParameter('invoiceItemsUi', i) as IDataObject).invoiceItemsValues as IDataObject[];
|
||||
if (invoceItemsValues) {
|
||||
const items: IItem[] = [];
|
||||
for (const itemValue of invoceItemsValues) {
|
||||
const item: IItem = {
|
||||
cost: itemValue.cost as number,
|
||||
notes: itemValue.description as string,
|
||||
product_key: itemValue.service as string,
|
||||
qty: itemValue.hours as number,
|
||||
tax_rate1: itemValue.taxRate1 as number,
|
||||
tax_rate2: itemValue.taxRate2 as number,
|
||||
tax_name1: itemValue.taxName1 as string,
|
||||
tax_name2: itemValue.taxName2 as string,
|
||||
}
|
||||
items.push(item)
|
||||
}
|
||||
body.invoice_items = items;
|
||||
}
|
||||
responseData = await invoiceninjaApiRequest.call(this, 'POST', '/invoices', body);
|
||||
responseData = responseData.data;
|
||||
}
|
||||
if (operation === 'email') {
|
||||
const quoteId = this.getNodeParameter('quoteId', i) as string;
|
||||
responseData = await invoiceninjaApiRequest.call(this, 'POST', '/email_invoice', { id: quoteId });
|
||||
}
|
||||
if (operation === 'get') {
|
||||
const quoteId = this.getNodeParameter('quoteId', i) as string;
|
||||
const options = this.getNodeParameter('options', i) as IDataObject;
|
||||
if (options.include) {
|
||||
qs.include = options.include as string;
|
||||
}
|
||||
responseData = await invoiceninjaApiRequest.call(this, 'GET', `/invoices/${quoteId}`, {}, qs);
|
||||
responseData = responseData.data;
|
||||
}
|
||||
if (operation === 'getAll') {
|
||||
const returnAll = this.getNodeParameter('returnAll', 0) as boolean;
|
||||
const options = this.getNodeParameter('options', i) as IDataObject;
|
||||
if (options.include) {
|
||||
qs.include = options.include as string;
|
||||
}
|
||||
if (options.invoiceNumber) {
|
||||
qs.invoice_number = options.invoiceNumber as string;
|
||||
}
|
||||
if (returnAll === true) {
|
||||
responseData = await invoiceninjaApiRequestAllItems.call(this, 'data', 'GET', '/quotes', {}, qs);
|
||||
} else {
|
||||
qs.per_page = this.getNodeParameter('limit', 0) as number;
|
||||
responseData = await invoiceninjaApiRequest.call(this, 'GET', '/quotes', {}, qs);
|
||||
responseData = responseData.data;
|
||||
}
|
||||
}
|
||||
if (operation === 'delete') {
|
||||
const quoteId = this.getNodeParameter('quoteId', i) as string;
|
||||
responseData = await invoiceninjaApiRequest.call(this, 'DELETE', `/invoices/${quoteId}`);
|
||||
responseData = responseData.data;
|
||||
}
|
||||
}
|
||||
if (Array.isArray(responseData)) {
|
||||
returnData.push.apply(returnData, responseData as IDataObject[]);
|
||||
} else {
|
||||
returnData.push(responseData as IDataObject);
|
||||
}
|
||||
}
|
||||
return [this.helpers.returnJsonArray(returnData)];
|
||||
}
|
||||
}
|
BIN
packages/nodes-base/nodes/InvoiceNinja/InvoiceNinja.png
Normal file
BIN
packages/nodes-base/nodes/InvoiceNinja/InvoiceNinja.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 4.6 KiB |
|
@ -0,0 +1,171 @@
|
|||
import {
|
||||
IHookFunctions,
|
||||
IWebhookFunctions,
|
||||
} from 'n8n-core';
|
||||
|
||||
import {
|
||||
INodeTypeDescription,
|
||||
INodeType,
|
||||
IWebhookResponseData,
|
||||
} from 'n8n-workflow';
|
||||
|
||||
import {
|
||||
invoiceninjaApiRequest,
|
||||
} from './GenericFunctions';
|
||||
|
||||
export class InvoiceNinjaTrigger implements INodeType {
|
||||
description: INodeTypeDescription = {
|
||||
displayName: 'Invoice Ninja Trigger',
|
||||
name: 'invoiceNinjaTrigger',
|
||||
icon: 'file:invoiceNinja.png',
|
||||
group: ['trigger'],
|
||||
version: 1,
|
||||
description: 'Starts the workflow when Invoice Ninja events occure.',
|
||||
defaults: {
|
||||
name: 'Invoice Ninja Trigger',
|
||||
color: '#000000',
|
||||
},
|
||||
inputs: [],
|
||||
outputs: ['main'],
|
||||
credentials: [
|
||||
{
|
||||
name: 'invoiceNinjaCloudApi',
|
||||
required: true,
|
||||
displayOptions: {
|
||||
show: {
|
||||
invoiceNinjaVersion: [
|
||||
'cloud',
|
||||
],
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: 'invoiceNinjaServerApi',
|
||||
required: true,
|
||||
displayOptions: {
|
||||
show: {
|
||||
invoiceNinjaVersion: [
|
||||
'server',
|
||||
],
|
||||
},
|
||||
},
|
||||
},
|
||||
],
|
||||
webhooks: [
|
||||
{
|
||||
name: 'default',
|
||||
httpMethod: 'POST',
|
||||
responseMode: 'onReceived',
|
||||
path: 'webhook',
|
||||
},
|
||||
],
|
||||
properties: [
|
||||
{
|
||||
displayName: 'Version',
|
||||
name: 'invoiceNinjaVersion',
|
||||
type: 'options',
|
||||
options: [
|
||||
{
|
||||
name: 'Cloud',
|
||||
value: 'cloud',
|
||||
},
|
||||
{
|
||||
name: 'Server (Self Hosted)',
|
||||
value: 'server',
|
||||
},
|
||||
],
|
||||
default: 'cloud',
|
||||
},
|
||||
{
|
||||
displayName: 'Event',
|
||||
name: 'event',
|
||||
type: 'options',
|
||||
options: [
|
||||
{
|
||||
name: 'client.created',
|
||||
value: 'create_client',
|
||||
},
|
||||
{
|
||||
name: 'invoce.created',
|
||||
value: 'create_invoice',
|
||||
},
|
||||
{
|
||||
name: 'payment.created',
|
||||
value: 'create_payment',
|
||||
},
|
||||
{
|
||||
name: 'quote.created',
|
||||
value: 'create_quote',
|
||||
},
|
||||
{
|
||||
name: 'vendor.created',
|
||||
value: 'create_vendor',
|
||||
},
|
||||
],
|
||||
default: '',
|
||||
required: true,
|
||||
},
|
||||
],
|
||||
|
||||
};
|
||||
|
||||
// @ts-ignore (because of request)
|
||||
webhookMethods = {
|
||||
default: {
|
||||
async checkExists(this: IHookFunctions): Promise<boolean> {
|
||||
return false;
|
||||
},
|
||||
async create(this: IHookFunctions): Promise<boolean> {
|
||||
const webhookUrl = this.getNodeWebhookUrl('default');
|
||||
const event = this.getNodeParameter('event') as string;
|
||||
|
||||
const endpoint = '/hooks';
|
||||
|
||||
const body = {
|
||||
target_url: webhookUrl,
|
||||
event,
|
||||
};
|
||||
|
||||
const responseData = await invoiceninjaApiRequest.call(this, 'POST', endpoint, body);
|
||||
|
||||
if (responseData.id === undefined) {
|
||||
// Required data is missing so was not successful
|
||||
return false;
|
||||
}
|
||||
|
||||
const webhookData = this.getWorkflowStaticData('node');
|
||||
webhookData.webhookId = responseData.id as string;
|
||||
|
||||
return true;
|
||||
},
|
||||
async delete(this: IHookFunctions): Promise<boolean> {
|
||||
const webhookData = this.getWorkflowStaticData('node');
|
||||
if (webhookData.webhookId !== undefined) {
|
||||
|
||||
const endpoint = `/hooks/${webhookData.webhookId}`;
|
||||
|
||||
try {
|
||||
await invoiceninjaApiRequest.call(this, 'DELETE', endpoint);
|
||||
} catch (e) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Remove from the static workflow data so that it is clear
|
||||
// that no webhooks are registred anymore
|
||||
delete webhookData.webhookId;
|
||||
}
|
||||
|
||||
return true;
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
async webhook(this: IWebhookFunctions): Promise<IWebhookResponseData> {
|
||||
const bodyData = this.getBodyData();
|
||||
return {
|
||||
workflowData: [
|
||||
this.helpers.returnJsonArray(bodyData),
|
||||
],
|
||||
};
|
||||
}
|
||||
}
|
408
packages/nodes-base/nodes/InvoiceNinja/PaymentDescription.ts
Normal file
408
packages/nodes-base/nodes/InvoiceNinja/PaymentDescription.ts
Normal file
|
@ -0,0 +1,408 @@
|
|||
import { INodeProperties } from "n8n-workflow";
|
||||
|
||||
export const paymentOperations = [
|
||||
{
|
||||
displayName: 'Operation',
|
||||
name: 'operation',
|
||||
type: 'options',
|
||||
displayOptions: {
|
||||
show: {
|
||||
resource: [
|
||||
'payment',
|
||||
],
|
||||
},
|
||||
},
|
||||
options: [
|
||||
{
|
||||
name: 'Create',
|
||||
value: 'create',
|
||||
description: 'Create a new payment',
|
||||
},
|
||||
{
|
||||
name: 'Get',
|
||||
value: 'get',
|
||||
description: 'Get data of a payment',
|
||||
},
|
||||
{
|
||||
name: 'Get All',
|
||||
value: 'getAll',
|
||||
description: 'Get data of all payments',
|
||||
},
|
||||
{
|
||||
name: 'Delete',
|
||||
value: 'delete',
|
||||
description: 'Delete a payment',
|
||||
}
|
||||
],
|
||||
default: 'create',
|
||||
description: 'The operation to perform.',
|
||||
},
|
||||
] as INodeProperties[];
|
||||
|
||||
export const paymentFields = [
|
||||
/* -------------------------------------------------------------------------- */
|
||||
/* payment:create */
|
||||
/* -------------------------------------------------------------------------- */
|
||||
{
|
||||
displayName: 'Invoice',
|
||||
name: 'invoice',
|
||||
type: 'options',
|
||||
typeOptions: {
|
||||
loadOptionsMethod: 'getInvoices',
|
||||
},
|
||||
displayOptions: {
|
||||
show: {
|
||||
operation: [
|
||||
'create',
|
||||
],
|
||||
resource: [
|
||||
'payment',
|
||||
],
|
||||
},
|
||||
},
|
||||
default: '',
|
||||
},
|
||||
{
|
||||
displayName: 'Amount',
|
||||
name: 'amount',
|
||||
type: 'number',
|
||||
displayOptions: {
|
||||
show: {
|
||||
operation: [
|
||||
'create',
|
||||
],
|
||||
resource: [
|
||||
'payment',
|
||||
],
|
||||
},
|
||||
},
|
||||
typeOptions: {
|
||||
minValue: 0,
|
||||
},
|
||||
default: 0,
|
||||
},
|
||||
{
|
||||
displayName: 'Additional Fields',
|
||||
name: 'additionalFields',
|
||||
type: 'collection',
|
||||
placeholder: 'Add Field',
|
||||
default: {},
|
||||
displayOptions: {
|
||||
show: {
|
||||
operation: [
|
||||
'create',
|
||||
],
|
||||
resource: [
|
||||
'payment',
|
||||
],
|
||||
},
|
||||
},
|
||||
options: [
|
||||
{
|
||||
displayName: 'Payment Type',
|
||||
name: 'paymentType',
|
||||
type: 'options',
|
||||
options: [
|
||||
{
|
||||
name: 'Apply Credit',
|
||||
value: 1,
|
||||
},
|
||||
{
|
||||
name: 'Bank Transfer',
|
||||
value: 2,
|
||||
},
|
||||
{
|
||||
name: 'Cash',
|
||||
value: 3,
|
||||
},
|
||||
{
|
||||
name: 'Debit',
|
||||
value: 4,
|
||||
},
|
||||
{
|
||||
name: 'ACH',
|
||||
value: 5,
|
||||
},
|
||||
{
|
||||
name: 'Visa Card',
|
||||
value: 6,
|
||||
},
|
||||
{
|
||||
name: 'MasterCard',
|
||||
value: 7,
|
||||
},
|
||||
{
|
||||
name: 'American Express',
|
||||
value: 8,
|
||||
},
|
||||
{
|
||||
name: 'Discover Card',
|
||||
value: 9,
|
||||
},
|
||||
{
|
||||
name: 'Diners Card',
|
||||
value: 10,
|
||||
},
|
||||
{
|
||||
name: 'EuroCard',
|
||||
value: 11,
|
||||
},
|
||||
{
|
||||
name: 'Nova',
|
||||
value: 12,
|
||||
},
|
||||
{
|
||||
name: 'Credit Card Other',
|
||||
value: 13,
|
||||
},
|
||||
{
|
||||
name: 'Paypal',
|
||||
value: 14,
|
||||
},
|
||||
{
|
||||
name: 'Google Wallet',
|
||||
value: 15,
|
||||
},
|
||||
{
|
||||
name: 'Check',
|
||||
value: 16,
|
||||
},
|
||||
{
|
||||
name: 'Carte Blanche',
|
||||
value: 17,
|
||||
},
|
||||
{
|
||||
name: 'UnionPay',
|
||||
value: 18,
|
||||
},
|
||||
{
|
||||
name: 'JCB',
|
||||
value: 19,
|
||||
},
|
||||
{
|
||||
name: 'Laser',
|
||||
value: 20,
|
||||
},
|
||||
{
|
||||
name: 'Maestro',
|
||||
value: 21,
|
||||
},
|
||||
{
|
||||
name: 'Solo',
|
||||
value: 22,
|
||||
},
|
||||
{
|
||||
name: 'Solo',
|
||||
value: 22,
|
||||
},
|
||||
{
|
||||
name: 'Swich',
|
||||
value: 23,
|
||||
},
|
||||
{
|
||||
name: 'Swich',
|
||||
value: 23,
|
||||
},
|
||||
{
|
||||
name: 'iZettle',
|
||||
value: 24,
|
||||
},
|
||||
{
|
||||
name: 'Swish',
|
||||
value: 25,
|
||||
},
|
||||
{
|
||||
name: 'Venmo',
|
||||
value: 26,
|
||||
},
|
||||
{
|
||||
name: 'Money Order',
|
||||
value: 27,
|
||||
},
|
||||
{
|
||||
name: 'Alipay',
|
||||
value: 28,
|
||||
},
|
||||
{
|
||||
name: 'Sofort',
|
||||
value: 29,
|
||||
},
|
||||
{
|
||||
name: 'SEPA',
|
||||
value: 30,
|
||||
},
|
||||
{
|
||||
name: 'GoCardless',
|
||||
value: 31,
|
||||
},
|
||||
{
|
||||
name: 'Bitcoin',
|
||||
value: 32,
|
||||
},
|
||||
],
|
||||
default: 1,
|
||||
},
|
||||
{
|
||||
displayName: 'Transfer Reference',
|
||||
name: 'transferReference',
|
||||
type: 'string',
|
||||
default: '',
|
||||
},
|
||||
{
|
||||
displayName: 'Private Notes',
|
||||
name: 'privateNotes',
|
||||
typeOptions: {
|
||||
alwaysOpenEditWindow: true,
|
||||
},
|
||||
type: 'string',
|
||||
default: '',
|
||||
},
|
||||
],
|
||||
},
|
||||
|
||||
/* -------------------------------------------------------------------------- */
|
||||
/* payment:delete */
|
||||
/* -------------------------------------------------------------------------- */
|
||||
{
|
||||
displayName: 'Payment ID',
|
||||
name: 'paymentId',
|
||||
type: 'string',
|
||||
required: true,
|
||||
displayOptions: {
|
||||
show: {
|
||||
resource: [
|
||||
'payment',
|
||||
],
|
||||
operation: [
|
||||
'delete',
|
||||
],
|
||||
},
|
||||
},
|
||||
},
|
||||
/* -------------------------------------------------------------------------- */
|
||||
/* payment:get */
|
||||
/* -------------------------------------------------------------------------- */
|
||||
{
|
||||
displayName: 'Payment ID',
|
||||
name: 'paymentId',
|
||||
type: 'string',
|
||||
required: true,
|
||||
displayOptions: {
|
||||
show: {
|
||||
resource: [
|
||||
'payment',
|
||||
],
|
||||
operation: [
|
||||
'get',
|
||||
],
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
displayName: 'Options',
|
||||
name: 'options',
|
||||
type: 'collection',
|
||||
placeholder: 'Add Field',
|
||||
default: {},
|
||||
displayOptions: {
|
||||
show: {
|
||||
operation: [
|
||||
'get',
|
||||
],
|
||||
resource: [
|
||||
'payment',
|
||||
],
|
||||
},
|
||||
},
|
||||
options: [
|
||||
{
|
||||
displayName: 'Include',
|
||||
name: 'include',
|
||||
type: 'options',
|
||||
options: [
|
||||
{
|
||||
name: 'Client',
|
||||
value: 'client',
|
||||
},
|
||||
],
|
||||
default: 'client',
|
||||
},
|
||||
],
|
||||
},
|
||||
/* -------------------------------------------------------------------------- */
|
||||
/* payment:getAll */
|
||||
/* -------------------------------------------------------------------------- */
|
||||
{
|
||||
displayName: 'Return All',
|
||||
name: 'returnAll',
|
||||
type: 'boolean',
|
||||
displayOptions: {
|
||||
show: {
|
||||
resource: [
|
||||
'payment',
|
||||
],
|
||||
operation: [
|
||||
'getAll',
|
||||
],
|
||||
},
|
||||
},
|
||||
default: false,
|
||||
description: 'If all results should be returned or only up to a given limit.',
|
||||
},
|
||||
{
|
||||
displayName: 'Limit',
|
||||
name: 'limit',
|
||||
type: 'number',
|
||||
displayOptions: {
|
||||
show: {
|
||||
resource: [
|
||||
'payment',
|
||||
],
|
||||
operation: [
|
||||
'getAll',
|
||||
],
|
||||
returnAll: [
|
||||
false,
|
||||
],
|
||||
},
|
||||
},
|
||||
typeOptions: {
|
||||
minValue: 1,
|
||||
maxValue: 60,
|
||||
},
|
||||
default: 50,
|
||||
description: 'How many results to return.',
|
||||
},
|
||||
{
|
||||
displayName: 'Options',
|
||||
name: 'options',
|
||||
type: 'collection',
|
||||
placeholder: 'Add Field',
|
||||
default: {},
|
||||
displayOptions: {
|
||||
show: {
|
||||
operation: [
|
||||
'getAll',
|
||||
],
|
||||
resource: [
|
||||
'payment',
|
||||
],
|
||||
},
|
||||
},
|
||||
options: [
|
||||
{
|
||||
displayName: 'Include',
|
||||
name: 'include',
|
||||
type: 'options',
|
||||
options: [
|
||||
{
|
||||
name: 'Client',
|
||||
value: 'client',
|
||||
},
|
||||
],
|
||||
default: 'client',
|
||||
},
|
||||
],
|
||||
},
|
||||
|
||||
] as INodeProperties[];
|
|
@ -0,0 +1,7 @@
|
|||
export interface IPayment {
|
||||
invoice_id?: number;
|
||||
amount?: number;
|
||||
payment_type_id?: number;
|
||||
transaction_reference?: string;
|
||||
private_notes?: string;
|
||||
}
|
481
packages/nodes-base/nodes/InvoiceNinja/QuoteDescription.ts
Normal file
481
packages/nodes-base/nodes/InvoiceNinja/QuoteDescription.ts
Normal file
|
@ -0,0 +1,481 @@
|
|||
import { INodeProperties } from "n8n-workflow";
|
||||
|
||||
export const quoteOperations = [
|
||||
{
|
||||
displayName: 'Operation',
|
||||
name: 'operation',
|
||||
type: 'options',
|
||||
displayOptions: {
|
||||
show: {
|
||||
resource: [
|
||||
'quote',
|
||||
],
|
||||
},
|
||||
},
|
||||
options: [
|
||||
{
|
||||
name: 'Create',
|
||||
value: 'create',
|
||||
description: 'Create a new quote',
|
||||
},
|
||||
{
|
||||
name: 'Email',
|
||||
value: 'email',
|
||||
description: 'Email an quote',
|
||||
},
|
||||
{
|
||||
name: 'Get',
|
||||
value: 'get',
|
||||
description: 'Get data of a quote',
|
||||
},
|
||||
{
|
||||
name: 'Get All',
|
||||
value: 'getAll',
|
||||
description: 'Get data of all quotes',
|
||||
},
|
||||
{
|
||||
name: 'Delete',
|
||||
value: 'delete',
|
||||
description: 'Delete a quote',
|
||||
}
|
||||
],
|
||||
default: 'create',
|
||||
description: 'The operation to perform.',
|
||||
},
|
||||
] as INodeProperties[];
|
||||
|
||||
export const quoteFields = [
|
||||
/* -------------------------------------------------------------------------- */
|
||||
/* quote:create */
|
||||
/* -------------------------------------------------------------------------- */
|
||||
{
|
||||
displayName: 'Additional Fields',
|
||||
name: 'additionalFields',
|
||||
type: 'collection',
|
||||
placeholder: 'Add Field',
|
||||
default: {},
|
||||
displayOptions: {
|
||||
show: {
|
||||
operation: [
|
||||
'create',
|
||||
],
|
||||
resource: [
|
||||
'quote',
|
||||
],
|
||||
},
|
||||
},
|
||||
options: [
|
||||
{
|
||||
displayName: 'Client',
|
||||
name: 'client',
|
||||
type: 'options',
|
||||
typeOptions: {
|
||||
loadOptionsMethod: 'getClients',
|
||||
},
|
||||
default: '',
|
||||
},
|
||||
{
|
||||
displayName: 'Auto Bill',
|
||||
name: 'autoBill',
|
||||
type: 'boolean',
|
||||
default: false,
|
||||
},
|
||||
{
|
||||
displayName: 'Custom Value 1',
|
||||
name: 'customValue1',
|
||||
type: 'number',
|
||||
typeOptions: {
|
||||
minValue: 0,
|
||||
},
|
||||
default: 0,
|
||||
},
|
||||
{
|
||||
displayName: 'Custom Value 2',
|
||||
name: 'customValue2',
|
||||
type: 'number',
|
||||
typeOptions: {
|
||||
minValue: 0,
|
||||
},
|
||||
default: 0,
|
||||
},
|
||||
{
|
||||
displayName: 'Discount',
|
||||
name: 'discount',
|
||||
type: 'string',
|
||||
default: '',
|
||||
},
|
||||
{
|
||||
displayName: 'Due Date',
|
||||
name: 'dueDate',
|
||||
type: 'dateTime',
|
||||
default: '',
|
||||
},
|
||||
{
|
||||
displayName: 'Email',
|
||||
name: 'email',
|
||||
type: 'string',
|
||||
default: '',
|
||||
},
|
||||
{
|
||||
displayName: 'Email Qoute',
|
||||
name: 'emailQoute',
|
||||
type: 'boolean',
|
||||
default: false,
|
||||
},
|
||||
{
|
||||
displayName: 'Quote Date',
|
||||
name: 'quoteDate',
|
||||
type: 'dateTime',
|
||||
default: '',
|
||||
},
|
||||
{
|
||||
displayName: 'Quote Number',
|
||||
name: 'quoteNumber',
|
||||
type: 'string',
|
||||
default: '',
|
||||
},
|
||||
{
|
||||
displayName: 'Qoute Status',
|
||||
name: 'quoteStatus',
|
||||
type: 'options',
|
||||
options: [
|
||||
{
|
||||
name: 'Draft',
|
||||
value: 1,
|
||||
},
|
||||
{
|
||||
name: 'Sent',
|
||||
value: 2,
|
||||
},
|
||||
],
|
||||
default: 1,
|
||||
},
|
||||
{
|
||||
displayName: 'Is Amount Discount',
|
||||
name: 'isAmountDiscount',
|
||||
type: 'boolean',
|
||||
default: false,
|
||||
},
|
||||
{
|
||||
displayName: 'Paid',
|
||||
name: 'paid',
|
||||
type: 'number',
|
||||
default: 0,
|
||||
},
|
||||
{
|
||||
displayName: 'Partial',
|
||||
name: 'partial',
|
||||
type: 'number',
|
||||
default: 0,
|
||||
},
|
||||
{
|
||||
displayName: 'Partial Due Date',
|
||||
name: 'partialDueDate',
|
||||
type: 'dateTime',
|
||||
default: '',
|
||||
},
|
||||
{
|
||||
displayName: 'Po Number',
|
||||
name: 'poNumber',
|
||||
type: 'string',
|
||||
default: '',
|
||||
},
|
||||
{
|
||||
displayName: 'Private Notes',
|
||||
name: 'privateNotes',
|
||||
type: 'string',
|
||||
typeOptions: {
|
||||
alwaysOpenEditWindow: true,
|
||||
},
|
||||
default: '',
|
||||
},
|
||||
{
|
||||
displayName: 'Public Notes',
|
||||
name: 'publicNotes',
|
||||
type: 'string',
|
||||
typeOptions: {
|
||||
alwaysOpenEditWindow: true,
|
||||
},
|
||||
default: '',
|
||||
},
|
||||
{
|
||||
displayName: 'Tax Name 1',
|
||||
name: 'taxName1',
|
||||
type: 'string',
|
||||
default: '',
|
||||
},
|
||||
{
|
||||
displayName: 'Tax Name 2',
|
||||
name: 'taxName2',
|
||||
type: 'string',
|
||||
default: '',
|
||||
},
|
||||
{
|
||||
displayName: 'Tax Rate 1',
|
||||
name: 'taxRate1',
|
||||
type: 'number',
|
||||
default: 0,
|
||||
},
|
||||
{
|
||||
displayName: 'Tax Rate 2',
|
||||
name: 'taxRate2',
|
||||
type: 'number',
|
||||
default: 0,
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
displayName: 'Invoice Items',
|
||||
name: 'invoiceItemsUi',
|
||||
placeholder: 'Add Invoice Item',
|
||||
type: 'fixedCollection',
|
||||
typeOptions: {
|
||||
multipleValues: true,
|
||||
},
|
||||
displayOptions: {
|
||||
show: {
|
||||
resource: [
|
||||
'quote',
|
||||
],
|
||||
operation: [
|
||||
'create',
|
||||
],
|
||||
},
|
||||
},
|
||||
default: {},
|
||||
options: [
|
||||
{
|
||||
name: 'invoiceItemsValues',
|
||||
displayName: 'Invoice Item',
|
||||
values: [
|
||||
{
|
||||
displayName: 'Cost',
|
||||
name: 'cost',
|
||||
type: 'number',
|
||||
default: 0,
|
||||
},
|
||||
{
|
||||
displayName: 'Description',
|
||||
name: 'description',
|
||||
type: 'string',
|
||||
typeOptions: {
|
||||
alwaysOpenEditWindow: true,
|
||||
},
|
||||
default: '',
|
||||
},
|
||||
{
|
||||
displayName: 'Service',
|
||||
name: 'service',
|
||||
typeOptions: {
|
||||
alwaysOpenEditWindow: true,
|
||||
},
|
||||
type: 'string',
|
||||
default: '',
|
||||
},
|
||||
{
|
||||
displayName: 'Hours',
|
||||
name: 'hours',
|
||||
type: 'number',
|
||||
typeOptions: {
|
||||
minValue: 0,
|
||||
},
|
||||
default: 0,
|
||||
},
|
||||
{
|
||||
displayName: 'Tax Name 1',
|
||||
name: 'taxName1',
|
||||
type: 'string',
|
||||
default: '',
|
||||
},
|
||||
{
|
||||
displayName: 'Tax Name 2',
|
||||
name: 'taxName2',
|
||||
type: 'string',
|
||||
default: '',
|
||||
},
|
||||
{
|
||||
displayName: 'Tax Rate 1',
|
||||
name: 'taxRate1',
|
||||
type: 'number',
|
||||
default: 0,
|
||||
},
|
||||
{
|
||||
displayName: 'Tax Rate 2',
|
||||
name: 'taxRate2',
|
||||
type: 'number',
|
||||
default: 0,
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
/* -------------------------------------------------------------------------- */
|
||||
/* quote:delete */
|
||||
/* -------------------------------------------------------------------------- */
|
||||
{
|
||||
displayName: 'Quote ID',
|
||||
name: 'quoteId',
|
||||
type: 'string',
|
||||
required: true,
|
||||
displayOptions: {
|
||||
show: {
|
||||
resource: [
|
||||
'quote',
|
||||
],
|
||||
operation: [
|
||||
'delete',
|
||||
],
|
||||
},
|
||||
},
|
||||
},
|
||||
/* -------------------------------------------------------------------------- */
|
||||
/* quote:email */
|
||||
/* -------------------------------------------------------------------------- */
|
||||
{
|
||||
displayName: 'Quote ID',
|
||||
name: 'quoteId',
|
||||
type: 'string',
|
||||
required: true,
|
||||
displayOptions: {
|
||||
show: {
|
||||
resource: [
|
||||
'quote',
|
||||
],
|
||||
operation: [
|
||||
'email',
|
||||
],
|
||||
},
|
||||
},
|
||||
},
|
||||
/* -------------------------------------------------------------------------- */
|
||||
/* quote:get */
|
||||
/* -------------------------------------------------------------------------- */
|
||||
{
|
||||
displayName: 'Qoute ID',
|
||||
name: 'quoteId',
|
||||
type: 'string',
|
||||
required: true,
|
||||
displayOptions: {
|
||||
show: {
|
||||
resource: [
|
||||
'quote',
|
||||
],
|
||||
operation: [
|
||||
'get',
|
||||
],
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
displayName: 'Options',
|
||||
name: 'options',
|
||||
type: 'collection',
|
||||
placeholder: 'Add Field',
|
||||
default: {},
|
||||
displayOptions: {
|
||||
show: {
|
||||
operation: [
|
||||
'get',
|
||||
],
|
||||
resource: [
|
||||
'quote',
|
||||
],
|
||||
},
|
||||
},
|
||||
options: [
|
||||
{
|
||||
displayName: 'Include',
|
||||
name: 'include',
|
||||
type: 'options',
|
||||
options: [
|
||||
{
|
||||
name: 'Client',
|
||||
value: 'client',
|
||||
},
|
||||
],
|
||||
default: 'client',
|
||||
},
|
||||
],
|
||||
},
|
||||
/* -------------------------------------------------------------------------- */
|
||||
/* quote:getAll */
|
||||
/* -------------------------------------------------------------------------- */
|
||||
{
|
||||
displayName: 'Return All',
|
||||
name: 'returnAll',
|
||||
type: 'boolean',
|
||||
displayOptions: {
|
||||
show: {
|
||||
resource: [
|
||||
'quote',
|
||||
],
|
||||
operation: [
|
||||
'getAll',
|
||||
],
|
||||
},
|
||||
},
|
||||
default: false,
|
||||
description: 'If all results should be returned or only up to a given limit.',
|
||||
},
|
||||
{
|
||||
displayName: 'Limit',
|
||||
name: 'limit',
|
||||
type: 'number',
|
||||
displayOptions: {
|
||||
show: {
|
||||
resource: [
|
||||
'quote',
|
||||
],
|
||||
operation: [
|
||||
'getAll',
|
||||
],
|
||||
returnAll: [
|
||||
false,
|
||||
],
|
||||
},
|
||||
},
|
||||
typeOptions: {
|
||||
minValue: 1,
|
||||
maxValue: 60,
|
||||
},
|
||||
default: 50,
|
||||
description: 'How many results to return.',
|
||||
},
|
||||
{
|
||||
displayName: 'Options',
|
||||
name: 'options',
|
||||
type: 'collection',
|
||||
placeholder: 'Add Field',
|
||||
default: {},
|
||||
displayOptions: {
|
||||
show: {
|
||||
operation: [
|
||||
'getAll',
|
||||
],
|
||||
resource: [
|
||||
'quote',
|
||||
],
|
||||
},
|
||||
},
|
||||
options: [
|
||||
{
|
||||
displayName: 'Qoute Number',
|
||||
name: 'quoteNumber',
|
||||
type: 'string',
|
||||
default: '',
|
||||
},
|
||||
{
|
||||
displayName: 'Include',
|
||||
name: 'include',
|
||||
type: 'options',
|
||||
options: [
|
||||
{
|
||||
name: 'Client',
|
||||
value: 'client',
|
||||
},
|
||||
],
|
||||
default: 'client',
|
||||
},
|
||||
],
|
||||
},
|
||||
] as INodeProperties[];
|
37
packages/nodes-base/nodes/InvoiceNinja/QuoteInterface.ts
Normal file
37
packages/nodes-base/nodes/InvoiceNinja/QuoteInterface.ts
Normal file
|
@ -0,0 +1,37 @@
|
|||
export interface IItem {
|
||||
cost?: number;
|
||||
notes?: string;
|
||||
product_key?: string;
|
||||
qty?: number;
|
||||
tax_rate1?: number;
|
||||
tax_rate2?: number;
|
||||
tax_name1?: string;
|
||||
tax_name2?: string;
|
||||
}
|
||||
|
||||
export interface IQuote {
|
||||
auto_bill?: boolean;
|
||||
client_id?: number;
|
||||
custom_value1?: number;
|
||||
custom_value2?: number;
|
||||
email_invoice?: boolean;
|
||||
discount?: number;
|
||||
due_date?: string;
|
||||
email?: string;
|
||||
invoice_date?: string;
|
||||
invoice_items?: IItem[];
|
||||
invoice_number?: string;
|
||||
invoice_status_id?: number;
|
||||
is_amount_discount?: boolean;
|
||||
is_quote?: boolean;
|
||||
paid?: number;
|
||||
partial?: number;
|
||||
partial_due_date?: string;
|
||||
po_number?: string;
|
||||
private_notes?: string;
|
||||
public_notes?: string;
|
||||
tax_name1?: string;
|
||||
tax_name2?: string;
|
||||
tax_rate1?: number;
|
||||
tax_rate2?: number;
|
||||
}
|
298
packages/nodes-base/nodes/InvoiceNinja/TaskDescription.ts
Normal file
298
packages/nodes-base/nodes/InvoiceNinja/TaskDescription.ts
Normal file
|
@ -0,0 +1,298 @@
|
|||
import { INodeProperties } from "n8n-workflow";
|
||||
|
||||
export const taskOperations = [
|
||||
{
|
||||
displayName: 'Operation',
|
||||
name: 'operation',
|
||||
type: 'options',
|
||||
displayOptions: {
|
||||
show: {
|
||||
resource: [
|
||||
'task',
|
||||
],
|
||||
},
|
||||
},
|
||||
options: [
|
||||
{
|
||||
name: 'Create',
|
||||
value: 'create',
|
||||
description: 'Create a new task',
|
||||
},
|
||||
{
|
||||
name: 'Get',
|
||||
value: 'get',
|
||||
description: 'Get data of a task',
|
||||
},
|
||||
{
|
||||
name: 'Get All',
|
||||
value: 'getAll',
|
||||
description: 'Get data of all tasks',
|
||||
},
|
||||
{
|
||||
name: 'Delete',
|
||||
value: 'delete',
|
||||
description: 'Delete a task',
|
||||
}
|
||||
],
|
||||
default: 'create',
|
||||
description: 'The operation to perform.',
|
||||
},
|
||||
] as INodeProperties[];
|
||||
|
||||
export const taskFields = [
|
||||
/* -------------------------------------------------------------------------- */
|
||||
/* task:create */
|
||||
/* -------------------------------------------------------------------------- */
|
||||
{
|
||||
displayName: 'Additional Fields',
|
||||
name: 'additionalFields',
|
||||
type: 'collection',
|
||||
placeholder: 'Add Field',
|
||||
default: {},
|
||||
displayOptions: {
|
||||
show: {
|
||||
operation: [
|
||||
'create',
|
||||
],
|
||||
resource: [
|
||||
'task',
|
||||
],
|
||||
},
|
||||
},
|
||||
options: [
|
||||
{
|
||||
displayName: 'Client',
|
||||
name: 'client',
|
||||
type: 'options',
|
||||
typeOptions: {
|
||||
loadOptionsMethod: 'getClients',
|
||||
},
|
||||
default: '',
|
||||
},
|
||||
{
|
||||
displayName: 'Custom Value 1',
|
||||
name: 'customValue1',
|
||||
type: 'string',
|
||||
default: '',
|
||||
},
|
||||
{
|
||||
displayName: 'Custom Value 2',
|
||||
name: 'customValue2',
|
||||
type: 'string',
|
||||
default: '',
|
||||
},
|
||||
{
|
||||
displayName: 'Description',
|
||||
name: 'description',
|
||||
type: 'string',
|
||||
typeOptions: {
|
||||
alwaysOpenEditWindow: true,
|
||||
},
|
||||
default: '',
|
||||
},
|
||||
{
|
||||
displayName: 'Project',
|
||||
name: 'project',
|
||||
type: 'options',
|
||||
typeOptions: {
|
||||
loadOptionsMethod: 'getProjects',
|
||||
},
|
||||
default: '',
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
displayName: 'Time Logs',
|
||||
name: 'timeLogsUi',
|
||||
placeholder: 'Add Time Log',
|
||||
type: 'fixedCollection',
|
||||
typeOptions: {
|
||||
multipleValues: true,
|
||||
},
|
||||
displayOptions: {
|
||||
show: {
|
||||
resource: [
|
||||
'task',
|
||||
],
|
||||
operation: [
|
||||
'create',
|
||||
],
|
||||
},
|
||||
},
|
||||
default: {},
|
||||
options: [
|
||||
{
|
||||
name: 'timeLogsValues',
|
||||
displayName: 'Time Log',
|
||||
values: [
|
||||
{
|
||||
displayName: 'Start Date',
|
||||
name: 'startDate',
|
||||
type: 'dateTime',
|
||||
default: '',
|
||||
},
|
||||
{
|
||||
displayName: 'End Date',
|
||||
name: 'endDate',
|
||||
type: 'dateTime',
|
||||
default: '',
|
||||
},
|
||||
{
|
||||
displayName: 'Duration (Hours)',
|
||||
name: 'duration',
|
||||
type: 'number',
|
||||
typeOptions: {
|
||||
minValue: 0,
|
||||
},
|
||||
default: 0,
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
/* -------------------------------------------------------------------------- */
|
||||
/* task:delete */
|
||||
/* -------------------------------------------------------------------------- */
|
||||
{
|
||||
displayName: 'Task ID',
|
||||
name: 'taskId',
|
||||
type: 'string',
|
||||
required: true,
|
||||
displayOptions: {
|
||||
show: {
|
||||
resource: [
|
||||
'task',
|
||||
],
|
||||
operation: [
|
||||
'delete',
|
||||
],
|
||||
},
|
||||
},
|
||||
},
|
||||
/* -------------------------------------------------------------------------- */
|
||||
/* task:get */
|
||||
/* -------------------------------------------------------------------------- */
|
||||
{
|
||||
displayName: 'Task ID',
|
||||
name: 'taskId',
|
||||
type: 'string',
|
||||
required: true,
|
||||
displayOptions: {
|
||||
show: {
|
||||
resource: [
|
||||
'task',
|
||||
],
|
||||
operation: [
|
||||
'get',
|
||||
],
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
displayName: 'Options',
|
||||
name: 'options',
|
||||
type: 'collection',
|
||||
placeholder: 'Add Field',
|
||||
default: {},
|
||||
displayOptions: {
|
||||
show: {
|
||||
operation: [
|
||||
'get',
|
||||
],
|
||||
resource: [
|
||||
'task',
|
||||
],
|
||||
},
|
||||
},
|
||||
options: [
|
||||
{
|
||||
displayName: 'Include',
|
||||
name: 'include',
|
||||
type: 'options',
|
||||
options: [
|
||||
{
|
||||
name: 'Client',
|
||||
value: 'client',
|
||||
},
|
||||
],
|
||||
default: 'client',
|
||||
},
|
||||
],
|
||||
},
|
||||
/* -------------------------------------------------------------------------- */
|
||||
/* task:getAll */
|
||||
/* -------------------------------------------------------------------------- */
|
||||
{
|
||||
displayName: 'Return All',
|
||||
name: 'returnAll',
|
||||
type: 'boolean',
|
||||
displayOptions: {
|
||||
show: {
|
||||
resource: [
|
||||
'task',
|
||||
],
|
||||
operation: [
|
||||
'getAll',
|
||||
],
|
||||
},
|
||||
},
|
||||
default: false,
|
||||
description: 'If all results should be returned or only up to a given limit.',
|
||||
},
|
||||
{
|
||||
displayName: 'Limit',
|
||||
name: 'limit',
|
||||
type: 'number',
|
||||
displayOptions: {
|
||||
show: {
|
||||
resource: [
|
||||
'task',
|
||||
],
|
||||
operation: [
|
||||
'getAll',
|
||||
],
|
||||
returnAll: [
|
||||
false,
|
||||
],
|
||||
},
|
||||
},
|
||||
typeOptions: {
|
||||
minValue: 1,
|
||||
maxValue: 60,
|
||||
},
|
||||
default: 50,
|
||||
description: 'How many results to return.',
|
||||
},
|
||||
{
|
||||
displayName: 'Options',
|
||||
name: 'options',
|
||||
type: 'collection',
|
||||
placeholder: 'Add Field',
|
||||
default: {},
|
||||
displayOptions: {
|
||||
show: {
|
||||
operation: [
|
||||
'getAll',
|
||||
],
|
||||
resource: [
|
||||
'task',
|
||||
],
|
||||
},
|
||||
},
|
||||
options: [
|
||||
{
|
||||
displayName: 'Include',
|
||||
name: 'include',
|
||||
type: 'options',
|
||||
options: [
|
||||
{
|
||||
name: 'Client',
|
||||
value: 'client',
|
||||
},
|
||||
],
|
||||
default: 'client',
|
||||
},
|
||||
],
|
||||
},
|
||||
|
||||
] as INodeProperties[];
|
8
packages/nodes-base/nodes/InvoiceNinja/TaskInterface.ts
Normal file
8
packages/nodes-base/nodes/InvoiceNinja/TaskInterface.ts
Normal file
|
@ -0,0 +1,8 @@
|
|||
export interface ITask {
|
||||
client_id?: number;
|
||||
custom_value1?: string;
|
||||
custom_value2?: string;
|
||||
description?: string;
|
||||
project?: number;
|
||||
time_log?: string;
|
||||
}
|
36
packages/nodes-base/nodes/InvoiceNinja/invoiceInterface.ts
Normal file
36
packages/nodes-base/nodes/InvoiceNinja/invoiceInterface.ts
Normal file
|
@ -0,0 +1,36 @@
|
|||
export interface IItem {
|
||||
cost?: number;
|
||||
notes?: string;
|
||||
product_key?: string;
|
||||
qty?: number;
|
||||
tax_rate1?: number;
|
||||
tax_rate2?: number;
|
||||
tax_name1?: string;
|
||||
tax_name2?: string;
|
||||
}
|
||||
|
||||
export interface IInvoice {
|
||||
auto_bill?: boolean;
|
||||
client_id?: number;
|
||||
custom_value1?: number;
|
||||
custom_value2?: number;
|
||||
email_invoice?: boolean;
|
||||
email?: string;
|
||||
discount?: number;
|
||||
due_date?: string;
|
||||
invoice_date?: string;
|
||||
invoice_items?: IItem[];
|
||||
invoice_number?: string;
|
||||
invoice_status_id?: number;
|
||||
is_amount_discount?: boolean;
|
||||
paid?: number;
|
||||
partial?: number;
|
||||
partial_due_date?: string;
|
||||
po_number?: string;
|
||||
private_notes?: string;
|
||||
public_notes?: string;
|
||||
tax_name1?: string;
|
||||
tax_name2?: string;
|
||||
tax_rate1?: number;
|
||||
tax_rate2?: number;
|
||||
}
|
|
@ -62,6 +62,8 @@
|
|||
"dist/credentials/HunterApi.credentials.js",
|
||||
"dist/credentials/Imap.credentials.js",
|
||||
"dist/credentials/IntercomApi.credentials.js",
|
||||
"dist/credentials/InvoiceNinjaCloudApi.credentials.js",
|
||||
"dist/credentials/InvoiceNinjaServerApi.credentials.js",
|
||||
"dist/credentials/JiraSoftwareCloudApi.credentials.js",
|
||||
"dist/credentials/JiraSoftwareServerApi.credentials.js",
|
||||
"dist/credentials/JotFormApi.credentials.js",
|
||||
|
@ -167,6 +169,8 @@
|
|||
"dist/nodes/Hunter/Hunter.node.js",
|
||||
"dist/nodes/If.node.js",
|
||||
"dist/nodes/Intercom/Intercom.node.js",
|
||||
"dist/nodes/InvoiceNinja/InvoiceNinja.node.js",
|
||||
"dist/nodes/InvoiceNinja/InvoiceNinjaTrigger.node.js",
|
||||
"dist/nodes/Interval.node.js",
|
||||
"dist/nodes/Jira/JiraSoftwareCloud.node.js",
|
||||
"dist/nodes/JotForm/JotFormTrigger.node.js",
|
||||
|
|
Loading…
Reference in a new issue