first commit
Security: Sync from Public / sync-from-public (push) Has been cancelled
Test: Benchmark Nightly / build (push) Has been cancelled
Test: Benchmark Nightly / Notify Cats on failure (push) Has been cancelled
CI: Python / Checks (push) Has been cancelled
Test: Evals Python / Workflow Comparison Python (push) Has been cancelled
Util: Check Docs URLs / check-docs-urls (push) Has been cancelled
Test: Visual Storybook / Cloudflare Pages (push) Has been cancelled
Test: E2E Performance / build-and-test-performance (push) Has been cancelled
Test: Workflows Nightly / Run Workflow Tests (push) Has been cancelled
Util: Cleanup CI Docker Images / Delete stale CI images (push) Has been cancelled
Test: Benchmark Destroy Env / build (push) Has been cancelled
Util: Update Node Popularity / update-popularity (push) Has been cancelled
Test: E2E Coverage Weekly / Coverage Tests (push) Has been cancelled

This commit is contained in:
2026-03-17 16:22:57 +03:30
commit 3d5eaf9445
15349 changed files with 2847338 additions and 0 deletions
@@ -0,0 +1,224 @@
import type { INodeProperties } from 'n8n-workflow';
export const bankTransactionOperations: INodeProperties[] = [
{
displayName: 'Operation',
name: 'operation',
type: 'options',
noDataExpression: true,
displayOptions: {
show: {
resource: ['bank_transaction'],
},
},
options: [
{
name: 'Create',
value: 'create',
description: 'Create a new bank transaction',
action: 'Create a bank transaction',
},
{
name: 'Delete',
value: 'delete',
description: 'Delete a bank transaction',
action: 'Delete a bank transaction',
},
{
name: 'Get',
value: 'get',
description: 'Get data of a bank transaction',
action: 'Get a bank transaction',
},
{
name: 'Get Many',
value: 'getAll',
description: 'Get data of many bank transactions',
action: 'Get many bank transactions',
},
{
name: 'Match Payment',
value: 'matchPayment',
description: 'Match payment to a bank transaction',
action: 'Match payment to a bank transaction',
},
],
default: 'create',
},
];
export const bankTransactionFields: INodeProperties[] = [
/* -------------------------------------------------------------------------- */
/* bankTransaction:create */
/* -------------------------------------------------------------------------- */
{
displayName: 'Additional Fields',
name: 'additionalFields',
type: 'collection',
placeholder: 'Add Field',
default: {},
displayOptions: {
show: {
operation: ['create'],
resource: ['bank_transaction'],
},
},
options: [
{
displayName: 'Amount',
name: 'amount',
type: 'number',
default: 0,
},
{
displayName: 'Bank Integration Name or ID',
name: 'bankIntegrationId',
type: 'options',
description:
'Choose from the list, or specify an ID using an <a href="https://docs.n8n.io/code/expressions/">expression</a>',
typeOptions: {
loadOptionsMethod: 'getBankIntegrations',
},
default: '',
},
{
displayName: 'Base Type',
name: 'baseType',
type: 'options',
options: [
{
name: 'Deposit',
value: 'CREDIT',
},
{
name: 'Withdrawal',
value: 'DEBIT',
},
],
default: '',
},
{
displayName: 'Currency Name or ID',
name: 'currencyId',
type: 'options',
description:
'Choose from the list, or specify an ID using an <a href="https://docs.n8n.io/code/expressions/">expression</a>',
typeOptions: {
loadOptionsMethod: 'getCurrencies',
},
default: '',
},
{
displayName: 'Date',
name: 'date',
type: 'dateTime',
default: '',
},
{
displayName: 'Description',
name: 'description',
type: 'string',
default: '',
},
],
},
/* -------------------------------------------------------------------------- */
/* bankTransaction:delete */
/* -------------------------------------------------------------------------- */
{
displayName: 'Bank Transaction ID',
name: 'bankTransactionId',
type: 'string',
default: '',
required: true,
displayOptions: {
show: {
resource: ['bank_transaction'],
operation: ['delete'],
},
},
},
/* -------------------------------------------------------------------------- */
/* bankTransaction:get */
/* -------------------------------------------------------------------------- */
{
displayName: 'Bank Transaction ID',
name: 'bankTransactionId',
type: 'string',
default: '',
required: true,
displayOptions: {
show: {
resource: ['bank_transaction'],
operation: ['get'],
},
},
},
/* -------------------------------------------------------------------------- */
/* bankTransaction:getAll */
/* -------------------------------------------------------------------------- */
{
displayName: 'Return All',
name: 'returnAll',
type: 'boolean',
displayOptions: {
show: {
resource: ['bank_transaction'],
operation: ['getAll'],
},
},
default: false,
description: 'Whether to return all results or only up to a given limit',
},
{
displayName: 'Limit',
name: 'limit',
type: 'number',
displayOptions: {
show: {
resource: ['bank_transaction'],
operation: ['getAll'],
returnAll: [false],
},
},
typeOptions: {
minValue: 1,
maxValue: 60,
},
default: 50,
description: 'Max number of results to return',
},
/* -------------------------------------------------------------------------- */
/* bankTransaction:matchPayment */
/* -------------------------------------------------------------------------- */
{
displayName: 'Bank Transaction ID',
name: 'bankTransactionId',
type: 'string',
default: '',
required: true,
displayOptions: {
show: {
resource: ['bank_transaction'],
operation: ['matchPayment'],
},
},
},
{
displayName: 'Payment Name or ID',
name: 'paymentId',
type: 'options',
description:
'Choose from the list, or specify an ID using an <a href="https://docs.n8n.io/code/expressions/">expression</a>',
typeOptions: {
loadOptionsMethod: 'getPayments',
},
default: '',
displayOptions: {
show: {
resource: ['bank_transaction'],
operation: ['matchPayment'],
},
},
},
];
@@ -0,0 +1,14 @@
export interface IBankTransaction {
amount?: number;
bank_integration_id?: number;
base_type?: string;
currency_id?: number;
date?: string;
description?: string;
id?: string;
payment_id?: string;
}
export interface IBankTransactions {
transactions: IBankTransaction[];
}
@@ -0,0 +1,437 @@
import type { INodeProperties } from 'n8n-workflow';
export const clientOperations: INodeProperties[] = [
{
displayName: 'Operation',
name: 'operation',
type: 'options',
noDataExpression: true,
displayOptions: {
show: {
resource: ['client'],
},
},
options: [
{
name: 'Create',
value: 'create',
description: 'Create a new client',
action: 'Create a client',
},
{
name: 'Delete',
value: 'delete',
description: 'Delete a client',
action: 'Delete a client',
},
{
name: 'Get',
value: 'get',
description: 'Get data of a client',
action: 'Get a client',
},
{
name: 'Get Many',
value: 'getAll',
description: 'Get data of many clients',
action: 'Get many clients',
},
],
default: 'create',
},
];
export const clientFields: INodeProperties[] = [
/* -------------------------------------------------------------------------- */
/* 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',
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 or ID',
name: 'countryCode',
type: 'options',
description:
'Choose from the list, or specify an ID using an <a href="https://docs.n8n.io/code/expressions/">expression</a>',
typeOptions: {
loadOptionsMethod: 'getCountryCodes',
},
default: '',
},
],
},
],
},
{
displayName: 'Contacts',
name: 'contactsUi',
placeholder: 'Add Contact',
type: 'fixedCollection',
typeOptions: {
multipleValues: true,
},
displayOptions: {
show: {
resource: ['client'],
operation: ['create'],
},
},
default: {},
options: [
{
// TODO: in v2.0, rename to contactsValue
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',
placeholder: 'name@email.com',
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 or ID',
name: 'countryCode',
type: 'options',
description:
'Choose from the list, or specify an ID using an <a href="https://docs.n8n.io/code/expressions/">expression</a>',
typeOptions: {
loadOptionsMethod: 'getCountryCodes',
},
default: '',
},
],
},
],
},
/* -------------------------------------------------------------------------- */
/* client:delete */
/* -------------------------------------------------------------------------- */
{
displayName: 'Client ID',
name: 'clientId',
type: 'string',
default: '',
required: true,
displayOptions: {
show: {
resource: ['client'],
operation: ['delete'],
},
},
},
/* -------------------------------------------------------------------------- */
/* client:get */
/* -------------------------------------------------------------------------- */
{
displayName: 'Client ID',
name: 'clientId',
type: 'string',
default: '',
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: 'Whether to return all results 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: 'Max number of 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',
},
{
displayName: 'Status',
name: 'status',
type: 'options',
options: [
{
name: 'Active',
value: 'active',
},
{
name: 'Archived',
value: 'archived',
},
{
name: 'Deleted',
value: 'deleted',
},
],
default: 'active',
},
{
displayName: 'Created At',
name: 'createdAt',
type: 'dateTime',
default: '',
},
{
displayName: 'Updated At',
name: 'updatedAt',
type: 'dateTime',
default: '',
},
{
displayName: 'Is Deleted',
name: 'isDeleted',
type: 'boolean',
default: false,
},
],
},
];
@@ -0,0 +1,28 @@
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;
}
@@ -0,0 +1,700 @@
import type { INodeProperties } from 'n8n-workflow';
export const expenseOperations: INodeProperties[] = [
{
displayName: 'Operation',
name: 'operation',
type: 'options',
noDataExpression: true,
displayOptions: {
show: {
resource: ['expense'],
},
},
options: [
{
name: 'Create',
value: 'create',
description: 'Create a new expense',
action: 'Create an expense',
},
{
name: 'Delete',
value: 'delete',
description: 'Delete an expense',
action: 'Delete an expense',
},
{
name: 'Get',
value: 'get',
description: 'Get data of an expense',
action: 'Get an expense',
},
{
name: 'Get Many',
value: 'getAll',
description: 'Get data of many expenses',
action: 'Get many expenses',
},
],
default: 'create',
},
];
export const expenseFields: INodeProperties[] = [
/* -------------------------------------------------------------------------- */
/* expense:create */
/* -------------------------------------------------------------------------- */
{
displayName: 'Additional Fields',
name: 'additionalFields',
type: 'collection',
placeholder: 'Add Field',
default: {},
displayOptions: {
show: {
apiVersion: ['v4'],
operation: ['create'],
resource: ['expense'],
},
},
options: [
{
displayName: 'Amount',
name: 'amount',
type: 'number',
default: 0,
},
{
displayName: 'Billable',
name: 'billable',
type: 'boolean',
default: false,
},
{
displayName: 'Client Name or ID',
name: 'client',
type: 'options',
description:
'Choose from the list, or specify an ID using an <a href="https://docs.n8n.io/code/expressions/">expression</a>',
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 or ID',
name: 'category',
type: 'options',
description:
'Choose from the list, or specify an ID using an <a href="https://docs.n8n.io/code/expressions/">expression</a>',
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: 'ACH',
value: 5,
},
{
name: 'Alipay',
value: 28,
},
{
name: 'American Express',
value: 8,
},
{
name: 'Apply Credit',
value: 1,
},
{
name: 'Bank Transfer',
value: 2,
},
{
name: 'Bitcoin',
value: 32,
},
{
name: 'Carte Blanche',
value: 17,
},
{
name: 'Cash',
value: 3,
},
{
name: 'Check',
value: 16,
},
{
name: 'Credit Card Other',
value: 13,
},
{
name: 'Debit',
value: 4,
},
{
name: 'Diners Card',
value: 10,
},
{
name: 'Discover Card',
value: 9,
},
{
name: 'EuroCard',
value: 11,
},
{
name: 'GoCardless',
value: 31,
},
{
name: 'Google Wallet',
value: 15,
},
{
name: 'iZettle',
value: 24,
},
{
name: 'JCB',
value: 19,
},
{
name: 'Laser',
value: 20,
},
{
name: 'Maestro',
value: 21,
},
{
name: 'MasterCard',
value: 7,
},
{
name: 'Money Order',
value: 27,
},
{
name: 'Nova',
value: 12,
},
{
name: 'Paypal',
value: 14,
},
{
name: 'SEPA',
value: 30,
},
{
name: 'Sofort',
value: 29,
},
{
name: 'Solo',
value: 22,
},
{
name: 'Swich',
value: 23,
},
{
name: 'Swish',
value: 25,
},
{
name: 'UnionPay',
value: 18,
},
{
name: 'Venmo',
value: 26,
},
{
name: 'Visa Card',
value: 6,
},
],
default: 1,
},
{
displayName: 'Private Notes',
name: 'privateNotes',
type: 'string',
default: '',
},
{
displayName: 'Public Notes',
name: 'publicNotes',
type: 'string',
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 or ID',
name: 'vendor',
type: 'options',
description:
'Choose from the list, or specify an ID using an <a href="https://docs.n8n.io/code/expressions/">expression</a>',
typeOptions: {
loadOptionsMethod: 'getVendors',
},
default: '',
},
],
},
{
displayName: 'Additional Fields',
name: 'additionalFields',
type: 'collection',
placeholder: 'Add Field',
default: {},
displayOptions: {
show: {
apiVersion: ['v5'],
operation: ['create'],
resource: ['expense'],
},
},
options: [
{
displayName: 'Amount',
name: 'amount',
type: 'number',
default: 0,
},
{
displayName: 'Billable',
name: 'billable',
type: 'boolean',
default: false,
},
{
displayName: 'Client Name or ID',
name: 'client',
type: 'options',
description:
'Choose from the list, or specify an ID using an <a href="https://docs.n8n.io/code/expressions/">expression</a>',
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 or ID',
name: 'category',
type: 'options',
description:
'Choose from the list, or specify an ID using an <a href="https://docs.n8n.io/code/expressions/">expression</a>',
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: 'Bank Transfer',
value: 1,
},
{
name: 'Cash',
value: 2,
},
{
name: 'ACH',
value: 4,
},
{
name: 'Visa',
value: 5,
},
{
name: 'Mastercard',
value: 6,
},
{
name: 'American Express',
value: 7,
},
{
name: 'Discover',
value: 8,
},
{
name: 'Diners',
value: 9,
},
{
name: 'Eurocard',
value: 10,
},
{
name: 'Nova',
value: 11,
},
{
name: 'Credit Card Other',
value: 12,
},
{
name: 'PayPal',
value: 13,
},
{
name: 'Check',
value: 15,
},
{
name: 'Carte Blanche',
value: 16,
},
{
name: 'UnionPay',
value: 17,
},
{
name: 'JCB',
value: 18,
},
{
name: 'Laser',
value: 19,
},
{
name: 'Maestro',
value: 20,
},
{
name: 'Solo',
value: 21,
},
{
name: 'Switch',
value: 22,
},
{
name: 'Venmo',
value: 24,
},
{
name: 'Alipay',
value: 27,
},
{
name: 'Sofort',
value: 28,
},
{
name: 'SEPA',
value: 29,
},
{
name: 'GoCardless',
value: 30,
},
{
name: 'Crypto',
value: 31,
},
{
name: 'Credit',
value: 32,
},
{
name: 'Zelle',
value: 33,
},
{
name: 'Mollie Bank Transfer',
value: 34,
},
{
name: 'KBC',
value: 35,
},
{
name: 'Bancontact',
value: 36,
},
{
name: 'iDEAL',
value: 37,
},
{
name: 'Hosted Page',
value: 38,
},
{
name: 'Giropay',
value: 39,
},
{
name: 'Przelewy24',
value: 40,
},
{
name: 'EPS',
value: 41,
},
{
name: 'Direct Debit',
value: 42,
},
{
name: 'BECS',
value: 43,
},
{
name: 'ACSS',
value: 44,
},
{
name: 'Instant Bank Pay',
value: 45,
},
{
name: 'FPX',
value: 46,
},
{
name: 'Klarna',
value: 47,
},
{
name: 'Interac E-Transfer',
value: 48,
},
{
name: 'BACS',
value: 49,
},
{
name: 'Stripe Bank Transfer',
value: 50,
},
{
name: 'Cash App',
value: 51,
},
{
name: 'Pay Later',
value: 52,
},
],
default: 1,
},
{
displayName: 'Private Notes',
name: 'privateNotes',
type: 'string',
default: '',
},
{
displayName: 'Public Notes',
name: 'publicNotes',
type: 'string',
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 or ID',
name: 'vendor',
type: 'options',
description:
'Choose from the list, or specify an ID using an <a href="https://docs.n8n.io/code/expressions/">expression</a>',
typeOptions: {
loadOptionsMethod: 'getVendors',
},
default: '',
},
],
},
/* -------------------------------------------------------------------------- */
/* expense:delete */
/* -------------------------------------------------------------------------- */
{
displayName: 'Expense ID',
name: 'expenseId',
type: 'string',
default: '',
required: true,
displayOptions: {
show: {
resource: ['expense'],
operation: ['delete'],
},
},
},
/* -------------------------------------------------------------------------- */
/* expense:get */
/* -------------------------------------------------------------------------- */
{
displayName: 'Expense ID',
name: 'expenseId',
type: 'string',
default: '',
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: 'Whether to return all results 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: 'Max number of results to return',
},
];
@@ -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;
}
@@ -0,0 +1,79 @@
import get from 'lodash/get';
import type {
IDataObject,
IExecuteFunctions,
IHookFunctions,
ILoadOptionsFunctions,
JsonObject,
IRequestOptions,
IHttpRequestMethods,
} from 'n8n-workflow';
import { NodeApiError, NodeOperationError } from 'n8n-workflow';
export const eventID: { [key: string]: string } = {
create_client: '1',
create_invoice: '2',
create_quote: '3',
create_payment: '4',
create_vendor: '5',
};
export async function invoiceNinjaApiRequest(
this: IHookFunctions | IExecuteFunctions | ILoadOptionsFunctions,
method: IHttpRequestMethods,
endpoint: string,
body: IDataObject = {},
query?: IDataObject,
uri?: string,
) {
const credentials = await this.getCredentials('invoiceNinjaApi');
if (credentials === undefined) {
throw new NodeOperationError(this.getNode(), 'No credentials got returned!');
}
const version = this.getNodeParameter('apiVersion', 0) as string;
const defaultUrl = version === 'v4' ? 'https://app.invoiceninja.com' : 'https://invoicing.co';
const baseUrl = credentials.url || defaultUrl;
const options: IRequestOptions = {
method,
qs: query,
uri: uri || `${baseUrl}/api/v1${endpoint}`,
body,
json: true,
};
try {
return await this.helpers.requestWithAuthentication.call(this, 'invoiceNinjaApi', options);
} catch (error) {
throw new NodeApiError(this.getNode(), error as JsonObject);
}
}
export async function invoiceNinjaApiRequestAllItems(
this: IExecuteFunctions | ILoadOptionsFunctions | IHookFunctions,
propertyName: string,
method: IHttpRequestMethods,
endpoint: string,
body: IDataObject = {},
query: IDataObject = {},
) {
const returnData: IDataObject[] = [];
let responseData;
let uri;
query.per_page = 100;
do {
responseData = await invoiceNinjaApiRequest.call(this, method, endpoint, body, query, uri);
const next = get(responseData, 'meta.pagination.links.next') as string | undefined;
if (next) {
uri = next;
}
returnData.push.apply(returnData, responseData[propertyName] as IDataObject[]);
} while (responseData.meta?.pagination?.links?.next);
return returnData;
}
@@ -0,0 +1,508 @@
import type { INodeProperties } from 'n8n-workflow';
export const invoiceOperations: INodeProperties[] = [
{
displayName: 'Operation',
name: 'operation',
type: 'options',
noDataExpression: true,
displayOptions: {
show: {
resource: ['invoice'],
},
},
options: [
{
name: 'Create',
value: 'create',
description: 'Create a new invoice',
action: 'Create an invoice',
},
{
name: 'Delete',
value: 'delete',
description: 'Delete a invoice',
action: 'Delete an invoice',
},
{
name: 'Email',
value: 'email',
description: 'Email an invoice',
action: 'Email an invoice',
},
{
name: 'Get',
value: 'get',
description: 'Get data of a invoice',
action: 'Get an invoice',
},
{
name: 'Get Many',
value: 'getAll',
description: 'Get data of many invoices',
action: 'Get many invoices',
},
],
default: 'create',
},
];
export const invoiceFields: INodeProperties[] = [
/* -------------------------------------------------------------------------- */
/* invoice:create */
/* -------------------------------------------------------------------------- */
{
displayName: 'Additional Fields',
name: 'additionalFields',
type: 'collection',
placeholder: 'Add Field',
default: {},
displayOptions: {
show: {
operation: ['create'],
resource: ['invoice'],
},
},
options: [
{
displayName: 'Client Name or ID',
name: 'client',
type: 'options',
description:
'Choose from the list, or specify an ID using an <a href="https://docs.n8n.io/code/expressions/">expression</a>',
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',
placeholder: 'name@email.com',
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: 'Mark Sent',
name: 'markSent',
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',
default: '',
},
{
displayName: 'Public Notes',
name: 'publicNotes',
type: 'string',
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',
default: '',
},
{
displayName: 'Service',
name: 'service',
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',
default: '',
required: true,
displayOptions: {
show: {
resource: ['invoice'],
operation: ['delete'],
},
},
},
/* -------------------------------------------------------------------------- */
/* invoice:email */
/* -------------------------------------------------------------------------- */
{
displayName: 'Invoice ID',
name: 'invoiceId',
type: 'string',
default: '',
required: true,
displayOptions: {
show: {
resource: ['invoice'],
operation: ['email'],
},
},
},
/* -------------------------------------------------------------------------- */
/* invoice:get */
/* -------------------------------------------------------------------------- */
{
displayName: 'Invoice ID',
name: 'invoiceId',
type: 'string',
default: '',
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: 'Whether to return all results 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: 'Max number of 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',
},
{
displayName: 'Status',
name: 'status',
type: 'options',
options: [
{
name: 'Active',
value: 'active',
},
{
name: 'Archived',
value: 'archived',
},
{
name: 'Deleted',
value: 'deleted',
},
],
default: 'active',
},
{
displayName: 'Created At',
name: 'createdAt',
type: 'dateTime',
default: '',
},
{
displayName: 'Updated At',
name: 'updatedAt',
type: 'dateTime',
default: '',
},
{
displayName: 'Is Deleted',
name: 'isDeleted',
type: 'boolean',
default: false,
},
{
displayName: 'Client Status',
name: 'clientStatus',
type: 'options',
options: [
{
name: 'All',
value: 'all',
},
{
name: 'Paid',
value: 'paid',
},
{
name: 'Unpaid',
value: 'unpaid',
},
{
name: 'Overdue',
value: 'overdue',
},
],
default: 'all',
},
],
},
];
@@ -0,0 +1,18 @@
{
"node": "n8n-nodes-base.invoiceNinja",
"nodeVersion": "1.0",
"codexVersion": "1.0",
"categories": ["Finance & Accounting"],
"resources": {
"credentialDocumentation": [
{
"url": "https://docs.n8n.io/integrations/builtin/credentials/invoiceninja/"
}
],
"primaryDocumentation": [
{
"url": "https://docs.n8n.io/integrations/builtin/app-nodes/n8n-nodes-base.invoiceninja/"
}
]
}
}
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,18 @@
{
"node": "n8n-nodes-base.invoiceNinjaTrigger",
"nodeVersion": "1.0",
"codexVersion": "1.0",
"categories": ["Finance & Accounting"],
"resources": {
"credentialDocumentation": [
{
"url": "https://docs.n8n.io/integrations/builtin/credentials/invoiceninja/"
}
],
"primaryDocumentation": [
{
"url": "https://docs.n8n.io/integrations/builtin/trigger-nodes/n8n-nodes-base.invoiceninjatrigger/"
}
]
}
}
@@ -0,0 +1,224 @@
import {
type IHookFunctions,
type IWebhookFunctions,
type INodeType,
type INodeTypeDescription,
type IWebhookResponseData,
NodeConnectionTypes,
} from 'n8n-workflow';
import {
eventID,
invoiceNinjaApiRequest,
invoiceNinjaApiRequestAllItems,
} from './GenericFunctions';
export class InvoiceNinjaTrigger implements INodeType {
description: INodeTypeDescription = {
displayName: 'Invoice Ninja Trigger',
name: 'invoiceNinjaTrigger',
icon: 'file:invoiceNinja.svg',
group: ['trigger'],
version: [1, 2],
description: 'Starts the workflow when Invoice Ninja events occur',
defaults: {
name: 'Invoice Ninja Trigger',
},
inputs: [],
outputs: [NodeConnectionTypes.Main],
credentials: [
{
name: 'invoiceNinjaApi',
required: true,
},
],
webhooks: [
{
name: 'default',
httpMethod: 'POST',
responseMode: 'onReceived',
path: 'webhook',
},
],
properties: [
{
displayName: 'API Version',
name: 'apiVersion',
type: 'options',
isNodeSetting: true,
displayOptions: {
show: {
'@version': [1],
},
},
options: [
{
name: 'Version 4',
value: 'v4',
},
{
name: 'Version 5',
value: 'v5',
},
],
default: 'v4',
},
{
displayName: 'API Version',
name: 'apiVersion',
type: 'options',
isNodeSetting: true,
displayOptions: {
show: {
'@version': [2],
},
},
options: [
{
name: 'Version 4',
value: 'v4',
},
{
name: 'Version 5',
value: 'v5',
},
],
default: 'v5',
},
{
displayName: 'Event',
name: 'event',
type: 'options',
options: [
{
name: 'Client Created',
value: 'create_client',
},
{
name: 'Invoice 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,
},
],
};
webhookMethods = {
default: {
async checkExists(this: IHookFunctions): Promise<boolean> {
const webhookData = this.getWorkflowStaticData('node');
const webhookUrl = this.getNodeWebhookUrl('default') as string;
const event = this.getNodeParameter('event') as string;
const apiVersion = this.getNodeParameter('apiVersion', 0) as string;
if (webhookData.webhookId === undefined) {
return false;
}
if (apiVersion === 'v5') {
const registeredWebhooks = await invoiceNinjaApiRequestAllItems.call(
this,
'data',
'GET',
'/webhooks',
);
for (const webhook of registeredWebhooks) {
if (
webhook.target_url === webhookUrl &&
webhook.is_deleted === false &&
webhook.event_id === eventID[event]
) {
webhookData.webhookId = webhook.id;
return true;
}
}
}
return false;
},
async create(this: IHookFunctions): Promise<boolean> {
const webhookUrl = this.getNodeWebhookUrl('default');
const webhookData = this.getWorkflowStaticData('node');
const event = this.getNodeParameter('event') as string;
const apiVersion = this.getNodeParameter('apiVersion', 0) as string;
let responseData;
if (apiVersion === 'v4') {
const endpoint = '/hooks';
const body = {
target_url: webhookUrl,
event,
};
responseData = await invoiceNinjaApiRequest.call(this, 'POST', endpoint, body);
webhookData.webhookId = responseData.id as string;
}
if (apiVersion === 'v5') {
const endpoint = '/webhooks';
const body = {
target_url: webhookUrl,
event_id: eventID[event],
};
responseData = await invoiceNinjaApiRequest.call(this, 'POST', endpoint, body);
webhookData.webhookId = responseData.data.id as string;
}
if (webhookData.webhookId === undefined) {
// Required data is missing so was not successful
return false;
}
return true;
},
async delete(this: IHookFunctions): Promise<boolean> {
const webhookData = this.getWorkflowStaticData('node');
const apiVersion = this.getNodeParameter('apiVersion', 0) as string;
const hooksEndpoint = apiVersion === 'v4' ? '/hooks' : '/webhooks';
if (webhookData.webhookId !== undefined) {
const endpoint = `${hooksEndpoint}/${webhookData.webhookId}`;
try {
await invoiceNinjaApiRequest.call(this, 'DELETE', endpoint);
} catch (error) {
return false;
}
// Remove from the static workflow data so that it is clear
// that no webhooks are registered anymore
delete webhookData.webhookId;
}
return true;
},
},
};
async webhook(this: IWebhookFunctions): Promise<IWebhookResponseData> {
const bodyData = this.getBodyData();
return {
workflowData: [this.helpers.returnJsonArray(bodyData)],
};
}
}
@@ -0,0 +1,627 @@
import type { INodeProperties } from 'n8n-workflow';
export const paymentOperations: INodeProperties[] = [
{
displayName: 'Operation',
name: 'operation',
type: 'options',
noDataExpression: true,
displayOptions: {
show: {
resource: ['payment'],
},
},
options: [
{
name: 'Create',
value: 'create',
description: 'Create a new payment',
action: 'Create a payment',
},
{
name: 'Delete',
value: 'delete',
description: 'Delete a payment',
action: 'Delete a payment',
},
{
name: 'Get',
value: 'get',
description: 'Get data of a payment',
action: 'Get a payment',
},
{
name: 'Get Many',
value: 'getAll',
description: 'Get data of many payments',
action: 'Get many payments',
},
],
default: 'create',
},
];
export const paymentFields: INodeProperties[] = [
/* -------------------------------------------------------------------------- */
/* payment:create */
/* -------------------------------------------------------------------------- */
{
displayName: 'Invoice Name or ID',
name: 'invoice',
type: 'options',
description:
'Choose from the list, or specify an ID using an <a href="https://docs.n8n.io/code/expressions/">expression</a>',
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: {
apiVersion: ['v4'],
operation: ['create'],
resource: ['payment'],
},
},
options: [
{
displayName: 'Payment Type',
name: 'paymentType',
type: 'options',
options: [
{
name: 'ACH',
value: 5,
},
{
name: 'Alipay',
value: 28,
},
{
name: 'American Express',
value: 8,
},
{
name: 'Apply Credit',
value: 1,
},
{
name: 'Bank Transfer',
value: 2,
},
{
name: 'Bitcoin',
value: 32,
},
{
name: 'Carte Blanche',
value: 17,
},
{
name: 'Cash',
value: 3,
},
{
name: 'Check',
value: 16,
},
{
name: 'Credit Card Other',
value: 13,
},
{
name: 'Debit',
value: 4,
},
{
name: 'Diners Card',
value: 10,
},
{
name: 'Discover Card',
value: 9,
},
{
name: 'EuroCard',
value: 11,
},
{
name: 'GoCardless',
value: 31,
},
{
name: 'Google Wallet',
value: 15,
},
{
name: 'iZettle',
value: 24,
},
{
name: 'JCB',
value: 19,
},
{
name: 'Laser',
value: 20,
},
{
name: 'Maestro',
value: 21,
},
{
name: 'MasterCard',
value: 7,
},
{
name: 'Money Order',
value: 27,
},
{
name: 'Nova',
value: 12,
},
{
name: 'Paypal',
value: 14,
},
{
name: 'SEPA',
value: 30,
},
{
name: 'Sofort',
value: 29,
},
{
name: 'Solo',
value: 22,
},
{
name: 'Swich',
value: 23,
},
{
name: 'Swish',
value: 25,
},
{
name: 'UnionPay',
value: 18,
},
{
name: 'Venmo',
value: 26,
},
{
name: 'Visa Card',
value: 6,
},
],
default: 1,
},
{
displayName: 'Transfer Reference',
name: 'transferReference',
type: 'string',
default: '',
},
{
displayName: 'Private Notes',
name: 'privateNotes',
type: 'string',
default: '',
},
],
},
{
displayName: 'Additional Fields',
name: 'additionalFields',
type: 'collection',
placeholder: 'Add Field',
default: {},
displayOptions: {
show: {
apiVersion: ['v5'],
operation: ['create'],
resource: ['payment'],
},
},
options: [
{
displayName: 'Payment Type',
name: 'paymentType',
type: 'options',
options: [
{
name: 'Bank Transfer',
value: 1,
},
{
name: 'Cash',
value: 2,
},
{
name: 'ACH',
value: 4,
},
{
name: 'Visa',
value: 5,
},
{
name: 'Mastercard',
value: 6,
},
{
name: 'American Express',
value: 7,
},
{
name: 'Discover',
value: 8,
},
{
name: 'Diners',
value: 9,
},
{
name: 'Eurocard',
value: 10,
},
{
name: 'Nova',
value: 11,
},
{
name: 'Credit Card Other',
value: 12,
},
{
name: 'PayPal',
value: 13,
},
{
name: 'Check',
value: 15,
},
{
name: 'Carte Blanche',
value: 16,
},
{
name: 'UnionPay',
value: 17,
},
{
name: 'JCB',
value: 18,
},
{
name: 'Laser',
value: 19,
},
{
name: 'Maestro',
value: 20,
},
{
name: 'Solo',
value: 21,
},
{
name: 'Switch',
value: 22,
},
{
name: 'Venmo',
value: 24,
},
{
name: 'Alipay',
value: 27,
},
{
name: 'Sofort',
value: 28,
},
{
name: 'SEPA',
value: 29,
},
{
name: 'GoCardless',
value: 30,
},
{
name: 'Crypto',
value: 31,
},
{
name: 'Credit',
value: 32,
},
{
name: 'Zelle',
value: 33,
},
{
name: 'Mollie Bank Transfer',
value: 34,
},
{
name: 'KBC',
value: 35,
},
{
name: 'Bancontact',
value: 36,
},
{
name: 'iDEAL',
value: 37,
},
{
name: 'Hosted Page',
value: 38,
},
{
name: 'Giropay',
value: 39,
},
{
name: 'Przelewy24',
value: 40,
},
{
name: 'EPS',
value: 41,
},
{
name: 'Direct Debit',
value: 42,
},
{
name: 'BECS',
value: 43,
},
{
name: 'ACSS',
value: 44,
},
{
name: 'Instant Bank Pay',
value: 45,
},
{
name: 'FPX',
value: 46,
},
{
name: 'Klarna',
value: 47,
},
{
name: 'Interac E-Transfer',
value: 48,
},
{
name: 'BACS',
value: 49,
},
{
name: 'Stripe Bank Transfer',
value: 50,
},
{
name: 'Cash App',
value: 51,
},
{
name: 'Pay Later',
value: 52,
},
],
default: 1,
},
{
displayName: 'Transfer Reference',
name: 'transferReference',
type: 'string',
default: '',
},
{
displayName: 'Private Notes',
name: 'privateNotes',
type: 'string',
default: '',
},
],
},
/* -------------------------------------------------------------------------- */
/* payment:delete */
/* -------------------------------------------------------------------------- */
{
displayName: 'Payment ID',
name: 'paymentId',
type: 'string',
default: '',
required: true,
displayOptions: {
show: {
resource: ['payment'],
operation: ['delete'],
},
},
},
/* -------------------------------------------------------------------------- */
/* payment:get */
/* -------------------------------------------------------------------------- */
{
displayName: 'Payment ID',
name: 'paymentId',
type: 'string',
default: '',
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: 'Whether to return all results 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: 'Max number of 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',
},
{
displayName: 'Status',
name: 'status',
type: 'options',
options: [
{
name: 'Active',
value: 'active',
},
{
name: 'Archived',
value: 'archived',
},
{
name: 'Deleted',
value: 'deleted',
},
],
default: 'active',
},
{
displayName: 'Created At',
name: 'createdAt',
type: 'dateTime',
default: '',
},
{
displayName: 'Updated At',
name: 'updatedAt',
type: 'dateTime',
default: '',
},
{
displayName: 'Is Deleted',
name: 'isDeleted',
type: 'boolean',
default: false,
},
],
},
];
@@ -0,0 +1,15 @@
export interface IPayment {
invoice_id?: number;
amount?: number;
payment_type_id?: number;
type_id?: number;
transaction_reference?: string;
private_notes?: string;
client_id?: string;
invoices?: IInvoice[];
}
export interface IInvoice {
invoice_id: string;
amount: number;
}
@@ -0,0 +1,478 @@
import type { INodeProperties } from 'n8n-workflow';
export const quoteOperations: INodeProperties[] = [
{
displayName: 'Operation',
name: 'operation',
type: 'options',
noDataExpression: true,
displayOptions: {
show: {
resource: ['quote'],
},
},
options: [
{
name: 'Create',
value: 'create',
description: 'Create a new quote',
action: 'Create a quote',
},
{
name: 'Delete',
value: 'delete',
description: 'Delete a quote',
action: 'Delete a quote',
},
{
name: 'Email',
value: 'email',
description: 'Email a quote',
action: 'Email a quote',
},
{
name: 'Get',
value: 'get',
description: 'Get data of a quote',
action: 'Get a quote',
},
{
name: 'Get Many',
value: 'getAll',
description: 'Get data of many quotes',
action: 'Get many quotes',
},
],
default: 'create',
},
];
export const quoteFields: INodeProperties[] = [
/* -------------------------------------------------------------------------- */
/* quote:create */
/* -------------------------------------------------------------------------- */
{
displayName: 'Additional Fields',
name: 'additionalFields',
type: 'collection',
placeholder: 'Add Field',
default: {},
displayOptions: {
show: {
operation: ['create'],
resource: ['quote'],
},
},
options: [
{
displayName: 'Client Name or ID',
name: 'client',
type: 'options',
description:
'Choose from the list, or specify an ID using an <a href="https://docs.n8n.io/code/expressions/">expression</a>',
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',
placeholder: 'name@email.com',
default: '',
},
{
displayName: 'Email Quote',
name: 'emailQuote',
type: 'boolean',
default: false,
},
{
displayName: 'Quote Date',
name: 'quoteDate',
type: 'dateTime',
default: '',
},
{
displayName: 'Quote Number',
name: 'quoteNumber',
type: 'string',
default: '',
},
{
displayName: 'Quote 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',
default: '',
},
{
displayName: 'Public Notes',
name: 'publicNotes',
type: 'string',
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',
default: '',
},
{
displayName: 'Service',
name: 'service',
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',
default: '',
required: true,
displayOptions: {
show: {
resource: ['quote'],
operation: ['delete'],
},
},
},
/* -------------------------------------------------------------------------- */
/* quote:email */
/* -------------------------------------------------------------------------- */
{
displayName: 'Quote ID',
name: 'quoteId',
type: 'string',
default: '',
required: true,
displayOptions: {
show: {
resource: ['quote'],
operation: ['email'],
},
},
},
/* -------------------------------------------------------------------------- */
/* quote:get */
/* -------------------------------------------------------------------------- */
{
displayName: 'Quote ID',
name: 'quoteId',
type: 'string',
default: '',
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: 'Whether to return all results 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: 'Max number of results to return',
},
{
displayName: 'Options',
name: 'options',
type: 'collection',
placeholder: 'Add Field',
default: {},
displayOptions: {
show: {
operation: ['getAll'],
resource: ['quote'],
},
},
options: [
{
displayName: 'Quote Number',
name: 'quoteNumber',
type: 'string',
default: '',
},
{
displayName: 'Include',
name: 'include',
type: 'options',
options: [
{
name: 'Client',
value: 'client',
},
],
default: 'client',
},
{
displayName: 'Status',
name: 'status',
type: 'options',
options: [
{
name: 'Active',
value: 'active',
},
{
name: 'Archived',
value: 'archived',
},
{
name: 'Deleted',
value: 'deleted',
},
],
default: 'active',
},
{
displayName: 'Created At',
name: 'createdAt',
type: 'dateTime',
default: '',
},
{
displayName: 'Updated At',
name: 'updatedAt',
type: 'dateTime',
default: '',
},
{
displayName: 'Is Deleted',
name: 'isDeleted',
type: 'boolean',
default: false,
},
],
},
];
@@ -0,0 +1,41 @@
export interface IItem {
cost?: number;
notes?: string;
product_key?: string;
qty?: number;
quantity?: 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[];
line_items?: IItem[];
invoice_number?: string;
// eslint-disable-next-line id-denylist
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;
}
@@ -0,0 +1,268 @@
import type { INodeProperties } from 'n8n-workflow';
export const taskOperations: INodeProperties[] = [
{
displayName: 'Operation',
name: 'operation',
type: 'options',
noDataExpression: true,
displayOptions: {
show: {
resource: ['task'],
},
},
options: [
{
name: 'Create',
value: 'create',
description: 'Create a new task',
action: 'Create a task',
},
{
name: 'Delete',
value: 'delete',
description: 'Delete a task',
action: 'Delete a task',
},
{
name: 'Get',
value: 'get',
description: 'Get data of a task',
action: 'Get a task',
},
{
name: 'Get Many',
value: 'getAll',
description: 'Get data of many tasks',
action: 'Get many tasks',
},
],
default: 'create',
},
];
export const taskFields: INodeProperties[] = [
/* -------------------------------------------------------------------------- */
/* task:create */
/* -------------------------------------------------------------------------- */
{
displayName: 'Additional Fields',
name: 'additionalFields',
type: 'collection',
placeholder: 'Add Field',
default: {},
displayOptions: {
show: {
operation: ['create'],
resource: ['task'],
},
},
options: [
{
displayName: 'Client Name or ID',
name: 'client',
type: 'options',
description:
'Choose from the list, or specify an ID using an <a href="https://docs.n8n.io/code/expressions/">expression</a>',
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',
default: '',
},
{
displayName: 'Project Name or ID',
name: 'project',
type: 'options',
description:
'Choose from the list, or specify an ID using an <a href="https://docs.n8n.io/code/expressions/">expression</a>',
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',
default: '',
required: true,
displayOptions: {
show: {
resource: ['task'],
operation: ['delete'],
},
},
},
/* -------------------------------------------------------------------------- */
/* task:get */
/* -------------------------------------------------------------------------- */
{
displayName: 'Task ID',
name: 'taskId',
type: 'string',
default: '',
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: 'Whether to return all results 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: 'Max number of 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',
},
],
},
];
@@ -0,0 +1,8 @@
export interface ITask {
client_id?: number;
custom_value1?: string;
custom_value2?: string;
description?: string;
project_id?: number;
time_log?: string;
}
@@ -0,0 +1,301 @@
{
"type": "object",
"properties": {
"archived_at": {
"type": "integer"
},
"assigned_user_id": {
"type": "string"
},
"auto_bill_enabled": {
"type": "boolean"
},
"balance": {
"type": "integer"
},
"client_id": {
"type": "string"
},
"created_at": {
"type": "integer"
},
"custom_surcharge_tax1": {
"type": "boolean"
},
"custom_surcharge_tax2": {
"type": "boolean"
},
"custom_surcharge_tax3": {
"type": "boolean"
},
"custom_surcharge_tax4": {
"type": "boolean"
},
"custom_surcharge1": {
"type": "integer"
},
"custom_surcharge2": {
"type": "integer"
},
"custom_surcharge3": {
"type": "integer"
},
"custom_surcharge4": {
"type": "integer"
},
"custom_value1": {
"type": "string"
},
"custom_value2": {
"type": "string"
},
"custom_value3": {
"type": "string"
},
"custom_value4": {
"type": "string"
},
"date": {
"type": "string"
},
"design_id": {
"type": "string"
},
"discount": {
"type": "integer"
},
"due_date": {
"type": "string"
},
"entity_type": {
"type": "string"
},
"exchange_rate": {
"type": "integer"
},
"footer": {
"type": "string"
},
"has_expenses": {
"type": "boolean"
},
"has_tasks": {
"type": "boolean"
},
"id": {
"type": "string"
},
"invitations": {
"type": "array",
"items": {
"type": "object",
"properties": {
"archived_at": {
"type": "integer"
},
"client_contact_id": {
"type": "string"
},
"created_at": {
"type": "integer"
},
"email_error": {
"type": "string"
},
"email_status": {
"type": "string"
},
"id": {
"type": "string"
},
"key": {
"type": "string"
},
"link": {
"type": "string"
},
"message_id": {
"type": "string"
},
"opened_date": {
"type": "string"
},
"sent_date": {
"type": "string"
},
"updated_at": {
"type": "integer"
},
"viewed_date": {
"type": "string"
}
}
}
},
"is_amount_discount": {
"type": "boolean"
},
"is_deleted": {
"type": "boolean"
},
"last_sent_date": {
"type": "string"
},
"line_items": {
"type": "array",
"items": {
"type": "object",
"properties": {
"_id": {
"type": "string"
},
"custom_value1": {
"type": "string"
},
"custom_value2": {
"type": "string"
},
"custom_value3": {
"type": "string"
},
"custom_value4": {
"type": "string"
},
"date": {
"type": "string"
},
"discount": {
"type": "integer"
},
"expense_id": {
"type": "string"
},
"is_amount_discount": {
"type": "boolean"
},
"notes": {
"type": "string"
},
"product_cost": {
"type": "integer"
},
"product_key": {
"type": "string"
},
"sort_id": {
"type": "string"
},
"task_id": {
"type": "string"
},
"tax_amount": {
"type": "integer"
},
"tax_id": {
"type": "string"
},
"tax_name1": {
"type": "string"
},
"tax_name2": {
"type": "string"
},
"tax_name3": {
"type": "string"
},
"tax_rate1": {
"type": "integer"
},
"tax_rate2": {
"type": "integer"
},
"tax_rate3": {
"type": "integer"
},
"type_id": {
"type": "string"
},
"unit_code": {
"type": "string"
}
}
}
},
"next_send_date": {
"type": "string"
},
"number": {
"type": "string"
},
"partial": {
"type": "integer"
},
"partial_due_date": {
"type": "string"
},
"po_number": {
"type": "string"
},
"private_notes": {
"type": "string"
},
"project_id": {
"type": "string"
},
"public_notes": {
"type": "string"
},
"recurring_id": {
"type": "string"
},
"reminder_last_sent": {
"type": "string"
},
"reminder1_sent": {
"type": "string"
},
"reminder2_sent": {
"type": "string"
},
"reminder3_sent": {
"type": "string"
},
"status_id": {
"type": "string"
},
"subscription_id": {
"type": "string"
},
"tax_name1": {
"type": "string"
},
"tax_name2": {
"type": "string"
},
"tax_name3": {
"type": "string"
},
"tax_rate2": {
"type": "integer"
},
"tax_rate3": {
"type": "integer"
},
"terms": {
"type": "string"
},
"updated_at": {
"type": "integer"
},
"user_id": {
"type": "string"
},
"uses_inclusive_taxes": {
"type": "boolean"
},
"vendor_id": {
"type": "string"
}
},
"version": 1
}
@@ -0,0 +1,40 @@
export interface IItem {
cost?: number;
notes?: string;
product_key?: string;
qty?: number;
quantity?: 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;
discount?: number;
due_date?: string;
email_invoice?: boolean;
email?: string;
invoice_date?: string;
invoice_items?: IItem[];
line_items?: IItem[];
invoice_number?: string;
// eslint-disable-next-line id-denylist
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;
}
@@ -0,0 +1,4 @@
<svg width="40" height="40" viewBox="0 0 40 40" fill="none" xmlns="http://www.w3.org/2000/svg">
<circle cx="19.9896" cy="19.9749" r="18.7752" fill="white"/>
<path d="M27.0432 17.2098C27.0432 17.7243 26.8388 18.2177 26.475 18.5816C26.1112 18.9454 25.6177 19.1498 25.1032 19.1498C24.5887 19.1498 24.0952 18.9454 23.7314 18.5816C23.3676 18.2177 23.1632 17.7243 23.1632 17.2098C23.1632 16.6952 23.3676 16.2018 23.7314 15.838C24.0952 15.4741 24.5887 15.2697 25.1032 15.2697C25.6177 15.2697 26.1112 15.4741 26.475 15.838C26.8388 16.2018 27.0432 16.6952 27.0432 17.2098ZM16.5631 17.2098C16.5631 17.4646 16.5129 17.717 16.4154 17.9525C16.3178 18.188 16.1749 18.4019 15.9946 18.5822C15.8144 18.7624 15.6004 18.9053 15.365 19.0029C15.1295 19.1004 14.8771 19.1506 14.6222 19.1506C14.3674 19.1506 14.115 19.1004 13.8795 19.0029C13.644 18.9053 13.4301 18.7624 13.2498 18.5822C13.0696 18.4019 12.9267 18.188 12.8291 17.9525C12.7316 17.717 12.6814 17.4646 12.6814 17.2098C12.6814 16.695 12.8859 16.2014 13.2498 15.8374C13.6138 15.4734 14.1075 15.2689 14.6222 15.2689C15.137 15.2689 15.6306 15.4734 15.9946 15.8374C16.3586 16.2014 16.5631 16.695 16.5631 17.2098ZM16.3298 39.7433C8.47634 38.11 2.61794 32.6483 0.526256 25.0065C-0.175419 22.4448 -0.175419 17.5231 0.526256 14.9614C2.47461 7.848 7.848 2.47461 14.9597 0.526256C17.5231 -0.175419 22.4432 -0.175419 25.0065 0.526256C32.1183 2.47461 37.4933 7.848 39.44 14.9597C39.84 16.4164 39.93 17.3431 39.93 19.9831C39.93 22.6232 39.84 23.5498 39.4417 25.0065C37.4917 32.1249 32.0433 37.5666 25.0065 39.4233C22.6882 40.035 18.4798 40.19 16.3298 39.7433ZM27.3965 24.2182C22.3182 21.9715 20.6398 21.3231 19.8965 21.3231C19.1531 21.3231 17.5081 21.9565 12.5964 24.1298C9.11135 25.6732 6.21632 27.0632 6.16298 27.1132H33.9349L27.3965 24.2182ZM10.9414 23.6165C13.6431 22.4015 16.0414 21.3048 16.2681 21.1765C16.6981 20.9348 16.8298 21.0265 7.45966 15.0397C6.52632 14.4431 5.75464 13.8764 5.75131 13.9564V25.9399C7.483 25.1691 9.21302 24.3947 10.9414 23.6165ZM34.4049 19.9598V14.0281C34.4049 13.8447 31.6116 15.6831 28.5782 17.5614C23.5782 20.6515 23.1098 20.9948 23.5715 21.2031C25.8132 22.2215 34.2716 25.9732 34.4049 25.9899V19.9598ZM20.7898 20.1431C21.6981 20.3515 21.8615 20.3165 22.8332 19.7048C23.4148 19.3381 23.9248 19.0065 23.9682 18.9681C24.0115 18.9281 23.8848 18.6664 23.6898 18.3848C23.4932 18.1048 23.3315 17.5514 23.3315 17.1531V16.4331L22.3832 16.7831C21.1731 17.2281 18.5831 17.2331 17.3831 16.7914L16.4564 16.4498L16.4781 17.2031C16.4898 17.6364 16.3314 18.1414 16.1031 18.3948C15.7164 18.8214 15.7364 18.8548 16.8531 19.6048C17.9198 20.3248 18.0614 20.3631 18.9031 20.1498C19.5223 19.9949 20.17 19.9938 20.7898 20.1465V20.1431ZM13.7397 15.7264C13.5647 15.5381 8.78968 14.1364 8.68468 14.2414C8.63467 14.2914 9.52469 14.9314 10.6614 15.6647L12.7281 16.9981L13.2947 16.4248C13.6047 16.1114 13.8064 15.7964 13.7414 15.7248L13.7397 15.7264ZM30.0066 15.1047C30.7949 14.5947 31.3399 14.1797 31.2199 14.1797C30.9616 14.1797 26.4249 15.5197 26.1749 15.6697C26.0799 15.7264 26.2299 16.0514 26.5082 16.3914L27.0149 17.0081L27.7982 16.5198C28.2266 16.2498 29.2216 15.6131 30.0082 15.1031L30.0066 15.1047ZM27.2799 14.1797C30.7966 13.1964 33.7249 12.343 33.7866 12.2814H5.94798C6.25965 12.593 18.9131 15.9398 19.8198 15.9514C20.5031 15.9598 23.1765 15.3247 27.2799 14.1797Z" fill="black"/>
</svg>

After

Width:  |  Height:  |  Size: 3.3 KiB