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
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:
@@ -0,0 +1,798 @@
|
||||
import type { INodeProperties } from 'n8n-workflow';
|
||||
|
||||
export const contactOperations: INodeProperties[] = [
|
||||
{
|
||||
displayName: 'Operation',
|
||||
name: 'operation',
|
||||
type: 'options',
|
||||
noDataExpression: true,
|
||||
displayOptions: {
|
||||
show: {
|
||||
resource: ['contact'],
|
||||
},
|
||||
},
|
||||
options: [
|
||||
{
|
||||
name: 'Create',
|
||||
value: 'create',
|
||||
description: 'Create a contact',
|
||||
action: 'Create a contact',
|
||||
},
|
||||
{
|
||||
name: 'Get',
|
||||
value: 'get',
|
||||
description: 'Get a contact',
|
||||
action: 'Get a contact',
|
||||
},
|
||||
{
|
||||
name: 'Get Many',
|
||||
value: 'getAll',
|
||||
description: 'Get many contacts',
|
||||
action: 'Get many contacts',
|
||||
},
|
||||
{
|
||||
name: 'Update',
|
||||
value: 'update',
|
||||
description: 'Update a contact',
|
||||
action: 'Update a contact',
|
||||
},
|
||||
],
|
||||
default: 'create',
|
||||
},
|
||||
];
|
||||
|
||||
export const contactFields: INodeProperties[] = [
|
||||
/* -------------------------------------------------------------------------- */
|
||||
/* contact:create */
|
||||
/* -------------------------------------------------------------------------- */
|
||||
{
|
||||
displayName: 'Organization Name or ID',
|
||||
name: 'organizationId',
|
||||
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: 'getTenants',
|
||||
},
|
||||
default: '',
|
||||
displayOptions: {
|
||||
show: {
|
||||
resource: ['contact'],
|
||||
operation: ['create'],
|
||||
},
|
||||
},
|
||||
required: true,
|
||||
},
|
||||
{
|
||||
displayName: 'Name',
|
||||
name: 'name',
|
||||
type: 'string',
|
||||
default: '',
|
||||
displayOptions: {
|
||||
show: {
|
||||
resource: ['contact'],
|
||||
operation: ['create'],
|
||||
},
|
||||
},
|
||||
description: 'Full name of contact/organisation',
|
||||
required: true,
|
||||
},
|
||||
{
|
||||
displayName: 'Additional Fields',
|
||||
name: 'additionalFields',
|
||||
type: 'collection',
|
||||
placeholder: 'Add Field',
|
||||
default: {},
|
||||
displayOptions: {
|
||||
show: {
|
||||
resource: ['contact'],
|
||||
operation: ['create'],
|
||||
},
|
||||
},
|
||||
options: [
|
||||
{
|
||||
displayName: 'Account Number',
|
||||
name: 'accountNumber',
|
||||
type: 'string',
|
||||
default: '',
|
||||
description: 'A user defined account number',
|
||||
},
|
||||
{
|
||||
displayName: 'Addresses',
|
||||
name: 'addressesUi',
|
||||
type: 'fixedCollection',
|
||||
typeOptions: {
|
||||
multipleValues: true,
|
||||
},
|
||||
default: {},
|
||||
placeholder: 'Add Address',
|
||||
options: [
|
||||
{
|
||||
name: 'addressesValues',
|
||||
displayName: 'Address',
|
||||
values: [
|
||||
{
|
||||
displayName: 'Type',
|
||||
name: 'type',
|
||||
type: 'options',
|
||||
options: [
|
||||
{
|
||||
name: 'PO Box',
|
||||
value: 'POBOX',
|
||||
},
|
||||
{
|
||||
name: 'Street',
|
||||
value: 'STREET',
|
||||
},
|
||||
],
|
||||
default: '',
|
||||
},
|
||||
{
|
||||
displayName: 'Line 1',
|
||||
name: 'line1',
|
||||
type: 'string',
|
||||
default: '',
|
||||
},
|
||||
{
|
||||
displayName: 'Line 2',
|
||||
name: 'line2',
|
||||
type: 'string',
|
||||
default: '',
|
||||
},
|
||||
{
|
||||
displayName: 'City',
|
||||
name: 'city',
|
||||
type: 'string',
|
||||
default: '',
|
||||
},
|
||||
{
|
||||
displayName: 'Region',
|
||||
name: 'region',
|
||||
type: 'string',
|
||||
default: '',
|
||||
},
|
||||
{
|
||||
displayName: 'Postal Code',
|
||||
name: 'postalCode',
|
||||
type: 'string',
|
||||
default: '',
|
||||
},
|
||||
{
|
||||
displayName: 'Country',
|
||||
name: 'country',
|
||||
type: 'string',
|
||||
default: '',
|
||||
},
|
||||
{
|
||||
displayName: 'Attention To',
|
||||
name: 'attentionTo',
|
||||
type: 'string',
|
||||
default: '',
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
displayName: 'Bank Account Details',
|
||||
name: 'bankAccountDetails',
|
||||
type: 'string',
|
||||
default: '',
|
||||
description: 'Bank account number of contact',
|
||||
},
|
||||
{
|
||||
displayName: 'Contact Number',
|
||||
name: 'contactNumber',
|
||||
type: 'string',
|
||||
default: '',
|
||||
description:
|
||||
'This field is read only on the Xero contact screen, used to identify contacts in external systems',
|
||||
},
|
||||
{
|
||||
displayName: 'Contact Status',
|
||||
name: 'contactStatus',
|
||||
type: 'options',
|
||||
options: [
|
||||
{
|
||||
name: 'Active',
|
||||
value: 'ACTIVE',
|
||||
description: 'The Contact is active and can be used in transactions',
|
||||
},
|
||||
{
|
||||
name: 'Archived',
|
||||
value: 'ARCHIVED',
|
||||
description: 'The Contact is archived and can no longer be used in transactions',
|
||||
},
|
||||
{
|
||||
name: 'GDPR Request',
|
||||
value: 'GDPRREQUEST',
|
||||
description: 'The Contact is the subject of a GDPR erasure request',
|
||||
},
|
||||
],
|
||||
default: '',
|
||||
description: 'Current status of a contact - see contact status types',
|
||||
},
|
||||
{
|
||||
displayName: 'Default Currency',
|
||||
name: 'defaultCurrency',
|
||||
type: 'string',
|
||||
default: '',
|
||||
description: 'Default currency for raising invoices against contact',
|
||||
},
|
||||
{
|
||||
displayName: 'Email',
|
||||
name: 'emailAddress',
|
||||
type: 'string',
|
||||
default: '',
|
||||
description: 'Email address of contact person (umlauts not supported) (max length = 255)',
|
||||
},
|
||||
{
|
||||
displayName: 'First Name',
|
||||
name: 'firstName',
|
||||
type: 'string',
|
||||
default: '',
|
||||
description: 'First name of contact person (max length = 255)',
|
||||
},
|
||||
{
|
||||
displayName: 'Last Name',
|
||||
name: 'lastName',
|
||||
type: 'string',
|
||||
default: '',
|
||||
description: 'Last name of contact person (max length = 255)',
|
||||
},
|
||||
{
|
||||
displayName: 'Phones',
|
||||
name: 'phonesUi',
|
||||
type: 'fixedCollection',
|
||||
typeOptions: {
|
||||
multipleValues: true,
|
||||
},
|
||||
default: {},
|
||||
placeholder: 'Add Phone',
|
||||
options: [
|
||||
{
|
||||
name: 'phonesValues',
|
||||
displayName: 'Phones',
|
||||
values: [
|
||||
{
|
||||
displayName: 'Type',
|
||||
name: 'phoneType',
|
||||
type: 'options',
|
||||
options: [
|
||||
{
|
||||
name: 'Default',
|
||||
value: 'DEFAULT',
|
||||
},
|
||||
{
|
||||
name: 'DDI',
|
||||
value: 'DDI',
|
||||
},
|
||||
{
|
||||
name: 'Mobile',
|
||||
value: 'MOBILE',
|
||||
},
|
||||
{
|
||||
name: 'Fax',
|
||||
value: 'FAX',
|
||||
},
|
||||
],
|
||||
default: '',
|
||||
},
|
||||
{
|
||||
displayName: 'Number',
|
||||
name: 'phoneNumber',
|
||||
type: 'string',
|
||||
default: '',
|
||||
},
|
||||
{
|
||||
displayName: 'Area Code',
|
||||
name: 'phoneAreaCode',
|
||||
type: 'string',
|
||||
default: '',
|
||||
},
|
||||
{
|
||||
displayName: 'Country Code',
|
||||
name: 'phoneCountryCode',
|
||||
type: 'string',
|
||||
default: '',
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
displayName: 'Purchase Default Account Code Name or ID',
|
||||
name: 'purchasesDefaultAccountCode',
|
||||
type: 'options',
|
||||
typeOptions: {
|
||||
loadOptionsMethod: 'getAccountCodes',
|
||||
},
|
||||
default: '',
|
||||
description:
|
||||
'The default purchases account code for contacts. Choose from the list, or specify an ID using an <a href="https://docs.n8n.io/code/expressions/">expression</a>.',
|
||||
},
|
||||
{
|
||||
displayName: 'Sales Default Account Code Name or ID',
|
||||
name: 'salesDefaultAccountCode',
|
||||
type: 'options',
|
||||
typeOptions: {
|
||||
loadOptionsMethod: 'getAccountCodes',
|
||||
},
|
||||
default: '',
|
||||
description:
|
||||
'The default sales account code for contacts. Choose from the list, or specify an ID using an <a href="https://docs.n8n.io/code/expressions/">expression</a>.',
|
||||
},
|
||||
{
|
||||
displayName: 'Skype',
|
||||
name: 'skypeUserName',
|
||||
type: 'string',
|
||||
default: '',
|
||||
description: 'Skype user name of contact',
|
||||
},
|
||||
{
|
||||
displayName: 'Tax Number',
|
||||
name: 'taxNumber',
|
||||
type: 'string',
|
||||
default: '',
|
||||
description: 'Tax number of contact',
|
||||
},
|
||||
{
|
||||
displayName: 'Xero Network Key',
|
||||
name: 'xeroNetworkKey',
|
||||
type: 'string',
|
||||
default: '',
|
||||
description: 'Store XeroNetworkKey for contacts',
|
||||
},
|
||||
],
|
||||
},
|
||||
/* -------------------------------------------------------------------------- */
|
||||
/* contact:get */
|
||||
/* -------------------------------------------------------------------------- */
|
||||
{
|
||||
displayName: 'Organization Name or ID',
|
||||
name: 'organizationId',
|
||||
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: 'getTenants',
|
||||
},
|
||||
default: '',
|
||||
displayOptions: {
|
||||
show: {
|
||||
resource: ['contact'],
|
||||
operation: ['get'],
|
||||
},
|
||||
},
|
||||
required: true,
|
||||
},
|
||||
{
|
||||
displayName: 'Contact ID',
|
||||
name: 'contactId',
|
||||
type: 'string',
|
||||
default: '',
|
||||
displayOptions: {
|
||||
show: {
|
||||
resource: ['contact'],
|
||||
operation: ['get'],
|
||||
},
|
||||
},
|
||||
required: true,
|
||||
},
|
||||
/* -------------------------------------------------------------------------- */
|
||||
/* contact:getAll */
|
||||
/* -------------------------------------------------------------------------- */
|
||||
{
|
||||
displayName: 'Organization Name or ID',
|
||||
name: 'organizationId',
|
||||
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: 'getTenants',
|
||||
},
|
||||
default: '',
|
||||
displayOptions: {
|
||||
show: {
|
||||
resource: ['contact'],
|
||||
operation: ['getAll'],
|
||||
},
|
||||
},
|
||||
required: true,
|
||||
},
|
||||
{
|
||||
displayName: 'Return All',
|
||||
name: 'returnAll',
|
||||
type: 'boolean',
|
||||
displayOptions: {
|
||||
show: {
|
||||
resource: ['contact'],
|
||||
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: ['contact'],
|
||||
operation: ['getAll'],
|
||||
returnAll: [false],
|
||||
},
|
||||
},
|
||||
typeOptions: {
|
||||
minValue: 1,
|
||||
maxValue: 100,
|
||||
},
|
||||
default: 100,
|
||||
description: 'Max number of results to return',
|
||||
},
|
||||
{
|
||||
displayName: 'Options',
|
||||
name: 'options',
|
||||
type: 'collection',
|
||||
placeholder: 'Add option',
|
||||
default: {},
|
||||
displayOptions: {
|
||||
show: {
|
||||
resource: ['contact'],
|
||||
operation: ['getAll'],
|
||||
},
|
||||
},
|
||||
options: [
|
||||
{
|
||||
displayName: 'Include Archived',
|
||||
name: 'includeArchived',
|
||||
type: 'boolean',
|
||||
default: false,
|
||||
description: 'Whether contacts with a status of ARCHIVED will be included in the response',
|
||||
},
|
||||
{
|
||||
displayName: 'Order By',
|
||||
name: 'orderBy',
|
||||
type: 'string',
|
||||
placeholder: 'contactID',
|
||||
default: '',
|
||||
description: 'Order by any element returned',
|
||||
},
|
||||
{
|
||||
displayName: 'Sort Order',
|
||||
name: 'sortOrder',
|
||||
type: 'options',
|
||||
options: [
|
||||
{
|
||||
name: 'Asc',
|
||||
value: 'ASC',
|
||||
},
|
||||
{
|
||||
name: 'Desc',
|
||||
value: 'DESC',
|
||||
},
|
||||
],
|
||||
default: '',
|
||||
},
|
||||
{
|
||||
displayName: 'Where',
|
||||
name: 'where',
|
||||
type: 'string',
|
||||
placeholder: 'EmailAddress!=null&&EmailAddress.StartsWith("boom")',
|
||||
default: '',
|
||||
description:
|
||||
'The where parameter allows you to filter on endpoints and elements that don\'t have explicit parameters. <a href="https://developer.xero.com/documentation/api/requests-and-responses#get-modified">Examples Here</a>.',
|
||||
},
|
||||
],
|
||||
},
|
||||
/* -------------------------------------------------------------------------- */
|
||||
/* contact:update */
|
||||
/* -------------------------------------------------------------------------- */
|
||||
{
|
||||
displayName: 'Organization Name or ID',
|
||||
name: 'organizationId',
|
||||
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: 'getTenants',
|
||||
},
|
||||
default: '',
|
||||
displayOptions: {
|
||||
show: {
|
||||
resource: ['contact'],
|
||||
operation: ['update'],
|
||||
},
|
||||
},
|
||||
required: true,
|
||||
},
|
||||
{
|
||||
displayName: 'Contact ID',
|
||||
name: 'contactId',
|
||||
type: 'string',
|
||||
default: '',
|
||||
displayOptions: {
|
||||
show: {
|
||||
resource: ['contact'],
|
||||
operation: ['update'],
|
||||
},
|
||||
},
|
||||
required: true,
|
||||
},
|
||||
{
|
||||
displayName: 'Update Fields',
|
||||
name: 'updateFields',
|
||||
type: 'collection',
|
||||
placeholder: 'Add Field',
|
||||
default: {},
|
||||
displayOptions: {
|
||||
show: {
|
||||
resource: ['contact'],
|
||||
operation: ['update'],
|
||||
},
|
||||
},
|
||||
options: [
|
||||
{
|
||||
displayName: 'Account Number',
|
||||
name: 'accountNumber',
|
||||
type: 'string',
|
||||
default: '',
|
||||
description: 'A user defined account number',
|
||||
},
|
||||
{
|
||||
displayName: 'Addresses',
|
||||
name: 'addressesUi',
|
||||
type: 'fixedCollection',
|
||||
typeOptions: {
|
||||
multipleValues: true,
|
||||
},
|
||||
default: {},
|
||||
placeholder: 'Add Address',
|
||||
options: [
|
||||
{
|
||||
name: 'addressesValues',
|
||||
displayName: 'Address',
|
||||
values: [
|
||||
{
|
||||
displayName: 'Type',
|
||||
name: 'type',
|
||||
type: 'options',
|
||||
options: [
|
||||
{
|
||||
name: 'PO Box',
|
||||
value: 'POBOX',
|
||||
},
|
||||
{
|
||||
name: 'Street',
|
||||
value: 'STREET',
|
||||
},
|
||||
],
|
||||
default: '',
|
||||
},
|
||||
{
|
||||
displayName: 'Line 1',
|
||||
name: 'line1',
|
||||
type: 'string',
|
||||
default: '',
|
||||
},
|
||||
{
|
||||
displayName: 'Line 2',
|
||||
name: 'line2',
|
||||
type: 'string',
|
||||
default: '',
|
||||
},
|
||||
{
|
||||
displayName: 'City',
|
||||
name: 'city',
|
||||
type: 'string',
|
||||
default: '',
|
||||
},
|
||||
{
|
||||
displayName: 'Region',
|
||||
name: 'region',
|
||||
type: 'string',
|
||||
default: '',
|
||||
},
|
||||
{
|
||||
displayName: 'Postal Code',
|
||||
name: 'postalCode',
|
||||
type: 'string',
|
||||
default: '',
|
||||
},
|
||||
{
|
||||
displayName: 'Country',
|
||||
name: 'country',
|
||||
type: 'string',
|
||||
default: '',
|
||||
},
|
||||
{
|
||||
displayName: 'Attention To',
|
||||
name: 'attentionTo',
|
||||
type: 'string',
|
||||
default: '',
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
displayName: 'Bank Account Details',
|
||||
name: 'bankAccountDetails',
|
||||
type: 'string',
|
||||
default: '',
|
||||
description: 'Bank account number of contact',
|
||||
},
|
||||
{
|
||||
displayName: 'Contact Number',
|
||||
name: 'contactNumber',
|
||||
type: 'string',
|
||||
default: '',
|
||||
description:
|
||||
'This field is read only on the Xero contact screen, used to identify contacts in external systems',
|
||||
},
|
||||
{
|
||||
displayName: 'Contact Status',
|
||||
name: 'contactStatus',
|
||||
type: 'options',
|
||||
options: [
|
||||
{
|
||||
name: 'Active',
|
||||
value: 'ACTIVE',
|
||||
description: 'The Contact is active and can be used in transactions',
|
||||
},
|
||||
{
|
||||
name: 'Archived',
|
||||
value: 'ARCHIVED',
|
||||
description: 'The Contact is archived and can no longer be used in transactions',
|
||||
},
|
||||
{
|
||||
name: 'GDPR Request',
|
||||
value: 'GDPRREQUEST',
|
||||
description: 'The Contact is the subject of a GDPR erasure request',
|
||||
},
|
||||
],
|
||||
default: '',
|
||||
description: 'Current status of a contact - see contact status types',
|
||||
},
|
||||
{
|
||||
displayName: 'Default Currency',
|
||||
name: 'defaultCurrency',
|
||||
type: 'string',
|
||||
default: '',
|
||||
description: 'Default currency for raising invoices against contact',
|
||||
},
|
||||
{
|
||||
displayName: 'Email',
|
||||
name: 'emailAddress',
|
||||
type: 'string',
|
||||
default: '',
|
||||
description: 'Email address of contact person (umlauts not supported) (max length = 255)',
|
||||
},
|
||||
{
|
||||
displayName: 'First Name',
|
||||
name: 'firstName',
|
||||
type: 'string',
|
||||
default: '',
|
||||
description: 'First name of contact person (max length = 255)',
|
||||
},
|
||||
{
|
||||
displayName: 'Last Name',
|
||||
name: 'lastName',
|
||||
type: 'string',
|
||||
default: '',
|
||||
description: 'Last name of contact person (max length = 255)',
|
||||
},
|
||||
{
|
||||
displayName: 'Name',
|
||||
name: 'name',
|
||||
type: 'string',
|
||||
default: '',
|
||||
description: 'Full name of contact/organisation',
|
||||
},
|
||||
{
|
||||
displayName: 'Phones',
|
||||
name: 'phonesUi',
|
||||
type: 'fixedCollection',
|
||||
typeOptions: {
|
||||
multipleValues: true,
|
||||
},
|
||||
default: {},
|
||||
placeholder: 'Add Phone',
|
||||
options: [
|
||||
{
|
||||
name: 'phonesValues',
|
||||
displayName: 'Phones',
|
||||
values: [
|
||||
{
|
||||
displayName: 'Type',
|
||||
name: 'phoneType',
|
||||
type: 'options',
|
||||
options: [
|
||||
{
|
||||
name: 'Default',
|
||||
value: 'DEFAULT',
|
||||
},
|
||||
{
|
||||
name: 'DDI',
|
||||
value: 'DDI',
|
||||
},
|
||||
{
|
||||
name: 'Mobile',
|
||||
value: 'MOBILE',
|
||||
},
|
||||
{
|
||||
name: 'Fax',
|
||||
value: 'FAX',
|
||||
},
|
||||
],
|
||||
default: '',
|
||||
},
|
||||
{
|
||||
displayName: 'Number',
|
||||
name: 'phoneNumber',
|
||||
type: 'string',
|
||||
default: '',
|
||||
},
|
||||
{
|
||||
displayName: 'Area Code',
|
||||
name: 'phoneAreaCode',
|
||||
type: 'string',
|
||||
default: '',
|
||||
},
|
||||
{
|
||||
displayName: 'Country Code',
|
||||
name: 'phoneCountryCode',
|
||||
type: 'string',
|
||||
default: '',
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
displayName: 'Purchase Default Account Code Name or ID',
|
||||
name: 'purchasesDefaultAccountCode',
|
||||
type: 'options',
|
||||
typeOptions: {
|
||||
loadOptionsMethod: 'getAccountCodes',
|
||||
},
|
||||
default: '',
|
||||
description:
|
||||
'The default purchases account code for contacts. Choose from the list, or specify an ID using an <a href="https://docs.n8n.io/code/expressions/">expression</a>.',
|
||||
},
|
||||
{
|
||||
displayName: 'Sales Default Account Code Name or ID',
|
||||
name: 'salesDefaultAccountCode',
|
||||
type: 'options',
|
||||
typeOptions: {
|
||||
loadOptionsMethod: 'getAccountCodes',
|
||||
},
|
||||
default: '',
|
||||
description:
|
||||
'The default sales account code for contacts. Choose from the list, or specify an ID using an <a href="https://docs.n8n.io/code/expressions/">expression</a>.',
|
||||
},
|
||||
{
|
||||
displayName: 'Skype',
|
||||
name: 'skypeUserName',
|
||||
type: 'string',
|
||||
default: '',
|
||||
description: 'Skype user name of contact',
|
||||
},
|
||||
{
|
||||
displayName: 'Tax Number',
|
||||
name: 'taxNumber',
|
||||
type: 'string',
|
||||
default: '',
|
||||
description: 'Tax number of contact',
|
||||
},
|
||||
{
|
||||
displayName: 'Xero Network Key',
|
||||
name: 'xeroNetworkKey',
|
||||
type: 'string',
|
||||
default: '',
|
||||
description: 'Store XeroNetworkKey for contacts',
|
||||
},
|
||||
],
|
||||
},
|
||||
];
|
||||
@@ -0,0 +1,69 @@
|
||||
import type {
|
||||
IExecuteFunctions,
|
||||
ILoadOptionsFunctions,
|
||||
IDataObject,
|
||||
JsonObject,
|
||||
IHttpRequestMethods,
|
||||
IRequestOptions,
|
||||
} from 'n8n-workflow';
|
||||
import { NodeApiError } from 'n8n-workflow';
|
||||
|
||||
export async function xeroApiRequest(
|
||||
this: IExecuteFunctions | ILoadOptionsFunctions,
|
||||
method: IHttpRequestMethods,
|
||||
resource: string,
|
||||
|
||||
body: any = {},
|
||||
qs: IDataObject = {},
|
||||
uri?: string,
|
||||
headers: IDataObject = {},
|
||||
): Promise<any> {
|
||||
const options: IRequestOptions = {
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
method,
|
||||
body,
|
||||
qs,
|
||||
uri: uri || `https://api.xero.com/api.xro/2.0${resource}`,
|
||||
json: true,
|
||||
};
|
||||
try {
|
||||
if (body.organizationId) {
|
||||
options.headers = { ...options.headers, 'Xero-tenant-id': body.organizationId };
|
||||
delete body.organizationId;
|
||||
}
|
||||
if (Object.keys(headers).length !== 0) {
|
||||
options.headers = Object.assign({}, options.headers, headers);
|
||||
}
|
||||
if (Object.keys(body as IDataObject).length === 0) {
|
||||
delete options.body;
|
||||
}
|
||||
return await this.helpers.requestOAuth2.call(this, 'xeroOAuth2Api', options);
|
||||
} catch (error) {
|
||||
throw new NodeApiError(this.getNode(), error as JsonObject);
|
||||
}
|
||||
}
|
||||
|
||||
export async function xeroApiRequestAllItems(
|
||||
this: IExecuteFunctions | ILoadOptionsFunctions,
|
||||
propertyName: string,
|
||||
method: IHttpRequestMethods,
|
||||
endpoint: string,
|
||||
|
||||
body: any = {},
|
||||
query: IDataObject = {},
|
||||
): Promise<any> {
|
||||
const returnData: IDataObject[] = [];
|
||||
|
||||
let responseData;
|
||||
query.page = 1;
|
||||
|
||||
do {
|
||||
responseData = await xeroApiRequest.call(this, method, endpoint, body, query);
|
||||
query.page++;
|
||||
returnData.push.apply(returnData, responseData[propertyName] as IDataObject[]);
|
||||
} while (responseData[propertyName].length !== 0);
|
||||
|
||||
return returnData;
|
||||
}
|
||||
@@ -0,0 +1,43 @@
|
||||
export interface IAddress {
|
||||
AddressType?: string;
|
||||
AddressLine1?: string;
|
||||
AddressLine2?: string;
|
||||
City?: string;
|
||||
Region?: string;
|
||||
PostalCode?: string;
|
||||
Country?: string;
|
||||
AttentionTo?: string;
|
||||
}
|
||||
|
||||
export interface IPhone {
|
||||
PhoneType?: string;
|
||||
PhoneNumber?: string;
|
||||
PhoneAreaCode?: string;
|
||||
PhoneCountryCode?: string;
|
||||
}
|
||||
|
||||
export interface IContact extends ITenantId {
|
||||
AccountNumber?: string;
|
||||
Addresses?: IAddress[];
|
||||
BankAccountDetails?: string;
|
||||
ContactId?: string;
|
||||
ContactNumber?: string;
|
||||
ContactStatus?: string;
|
||||
DefaultCurrency?: string;
|
||||
EmailAddress?: string;
|
||||
FirstName?: string;
|
||||
LastName?: string;
|
||||
Name?: string;
|
||||
Phones?: IPhone[];
|
||||
PurchaseTrackingCategory?: string;
|
||||
PurchasesDefaultAccountCode?: string;
|
||||
SalesDefaultAccountCode?: string;
|
||||
SalesTrackingCategory?: string;
|
||||
SkypeUserName?: string;
|
||||
taxNumber?: string;
|
||||
xeroNetworkKey?: string;
|
||||
}
|
||||
|
||||
export interface ITenantId {
|
||||
organizationId?: string;
|
||||
}
|
||||
@@ -0,0 +1,937 @@
|
||||
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 invoice',
|
||||
action: 'Create an invoice',
|
||||
},
|
||||
{
|
||||
name: 'Get',
|
||||
value: 'get',
|
||||
description: 'Get a invoice',
|
||||
action: 'Get an invoice',
|
||||
},
|
||||
{
|
||||
name: 'Get Many',
|
||||
value: 'getAll',
|
||||
description: 'Get many invoices',
|
||||
action: 'Get many invoices',
|
||||
},
|
||||
{
|
||||
name: 'Update',
|
||||
value: 'update',
|
||||
description: 'Update a invoice',
|
||||
action: 'Update an invoice',
|
||||
},
|
||||
],
|
||||
default: 'create',
|
||||
},
|
||||
];
|
||||
|
||||
export const invoiceFields: INodeProperties[] = [
|
||||
/* -------------------------------------------------------------------------- */
|
||||
/* invoice:create */
|
||||
/* -------------------------------------------------------------------------- */
|
||||
{
|
||||
displayName: 'Organization Name or ID',
|
||||
name: 'organizationId',
|
||||
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: 'getTenants',
|
||||
},
|
||||
default: '',
|
||||
displayOptions: {
|
||||
show: {
|
||||
resource: ['invoice'],
|
||||
operation: ['create'],
|
||||
},
|
||||
},
|
||||
required: true,
|
||||
},
|
||||
{
|
||||
displayName: 'Type',
|
||||
name: 'type',
|
||||
type: 'options',
|
||||
options: [
|
||||
{
|
||||
name: 'Bill',
|
||||
value: 'ACCPAY',
|
||||
description: 'Accounts Payable or supplier invoice',
|
||||
},
|
||||
{
|
||||
name: 'Sales Invoice',
|
||||
value: 'ACCREC',
|
||||
description: 'Accounts Receivable or customer invoice',
|
||||
},
|
||||
],
|
||||
default: '',
|
||||
displayOptions: {
|
||||
show: {
|
||||
resource: ['invoice'],
|
||||
operation: ['create'],
|
||||
},
|
||||
},
|
||||
required: true,
|
||||
description: 'Invoice Type',
|
||||
},
|
||||
{
|
||||
displayName: 'Contact ID',
|
||||
name: 'contactId',
|
||||
type: 'string',
|
||||
default: '',
|
||||
displayOptions: {
|
||||
show: {
|
||||
resource: ['invoice'],
|
||||
operation: ['create'],
|
||||
},
|
||||
},
|
||||
required: true,
|
||||
},
|
||||
{
|
||||
displayName: 'Line Items',
|
||||
name: 'lineItemsUi',
|
||||
placeholder: 'Add Line Item',
|
||||
type: 'fixedCollection',
|
||||
default: {},
|
||||
typeOptions: {
|
||||
multipleValues: true,
|
||||
},
|
||||
displayOptions: {
|
||||
show: {
|
||||
resource: ['invoice'],
|
||||
operation: ['create'],
|
||||
},
|
||||
},
|
||||
description: 'Line item data',
|
||||
options: [
|
||||
{
|
||||
name: 'lineItemsValues',
|
||||
displayName: 'Line Item',
|
||||
values: [
|
||||
{
|
||||
displayName: 'Description',
|
||||
name: 'description',
|
||||
type: 'string',
|
||||
default: '',
|
||||
description: 'A line item with just a description',
|
||||
},
|
||||
{
|
||||
displayName: 'Quantity',
|
||||
name: 'quantity',
|
||||
type: 'number',
|
||||
default: 1,
|
||||
typeOptions: {
|
||||
minValue: 1,
|
||||
},
|
||||
description: 'LineItem Quantity',
|
||||
},
|
||||
{
|
||||
displayName: 'Unit Amount',
|
||||
name: 'unitAmount',
|
||||
type: 'string',
|
||||
default: '',
|
||||
description:
|
||||
'Lineitem unit amount. By default, unit amount will be rounded to two decimal places.',
|
||||
},
|
||||
{
|
||||
displayName: 'Item Code Name or ID',
|
||||
name: 'itemCode',
|
||||
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: 'getItemCodes',
|
||||
loadOptionsDependsOn: ['organizationId'],
|
||||
},
|
||||
default: '',
|
||||
},
|
||||
{
|
||||
displayName: 'Account Code Name or ID',
|
||||
name: 'accountCode',
|
||||
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: 'getAccountCodes',
|
||||
loadOptionsDependsOn: ['organizationId'],
|
||||
},
|
||||
default: '',
|
||||
},
|
||||
{
|
||||
displayName: 'Tax Type',
|
||||
name: 'taxType',
|
||||
type: 'options',
|
||||
options: [
|
||||
{
|
||||
name: 'Tax on Purchases',
|
||||
value: 'INPUT',
|
||||
},
|
||||
{
|
||||
name: 'Tax Exempt',
|
||||
value: 'NONE',
|
||||
},
|
||||
{
|
||||
name: 'Tax on Sales',
|
||||
value: 'OUTPUT',
|
||||
},
|
||||
{
|
||||
name: 'Sales Tax on Imports',
|
||||
value: 'GSTONIMPORTS',
|
||||
},
|
||||
],
|
||||
default: '',
|
||||
required: true,
|
||||
},
|
||||
{
|
||||
displayName: 'Tax Amount',
|
||||
name: 'taxAmount',
|
||||
type: 'string',
|
||||
default: '',
|
||||
description:
|
||||
'The tax amount is auto calculated as a percentage of the line amount based on the tax rate',
|
||||
},
|
||||
{
|
||||
displayName: 'Line Amount',
|
||||
name: 'lineAmount',
|
||||
type: 'string',
|
||||
default: '',
|
||||
description:
|
||||
'The line amount reflects the discounted price if a DiscountRate has been used',
|
||||
},
|
||||
{
|
||||
displayName: 'Discount Rate',
|
||||
name: 'discountRate',
|
||||
type: 'string',
|
||||
default: '',
|
||||
description:
|
||||
'Percentage discount or discount amount being applied to a line item. Only supported on ACCREC invoices - ACCPAY invoices and credit notes in Xero do not support discounts.',
|
||||
},
|
||||
// {
|
||||
// displayName: 'Tracking',
|
||||
// name: 'trackingUi',
|
||||
// placeholder: 'Add Tracking',
|
||||
// description: 'Any LineItem can have a maximum of 2 TrackingCategory elements.',
|
||||
// type: 'fixedCollection',
|
||||
// typeOptions: {
|
||||
// multipleValues: true,
|
||||
// },
|
||||
// default: {},
|
||||
// options: [
|
||||
// {
|
||||
// name: 'trackingValues',
|
||||
// displayName: 'Tracking',
|
||||
// values: [
|
||||
// {
|
||||
// displayName: 'Name',
|
||||
// name: 'name',
|
||||
// type: 'options',
|
||||
// typeOptions: {
|
||||
// loadOptionsMethod: 'getTrakingCategories',
|
||||
// loadOptionsDependsOn: [
|
||||
// 'organizationId',
|
||||
// ],
|
||||
// },
|
||||
// default: '',
|
||||
// description: 'Name of the tracking category',
|
||||
// },
|
||||
// {
|
||||
// displayName: 'Option',
|
||||
// name: 'option',
|
||||
// type: 'options',
|
||||
// typeOptions: {
|
||||
// loadOptionsMethod: 'getTrakingOptions',
|
||||
// loadOptionsDependsOn: [
|
||||
// '/name',
|
||||
// ],
|
||||
// },
|
||||
// default: '',
|
||||
// description: 'Name of the option',
|
||||
// },
|
||||
// ],
|
||||
// },
|
||||
// ],
|
||||
// },
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
displayName: 'Additional Fields',
|
||||
name: 'additionalFields',
|
||||
type: 'collection',
|
||||
placeholder: 'Add Field',
|
||||
default: {},
|
||||
displayOptions: {
|
||||
show: {
|
||||
resource: ['invoice'],
|
||||
operation: ['create'],
|
||||
},
|
||||
},
|
||||
options: [
|
||||
{
|
||||
displayName: 'Branding Theme Name or ID',
|
||||
name: 'brandingThemeId',
|
||||
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: 'getBrandingThemes',
|
||||
loadOptionsDependsOn: ['organizationId'],
|
||||
},
|
||||
default: '',
|
||||
},
|
||||
{
|
||||
displayName: 'Currency Name or ID',
|
||||
name: 'currency',
|
||||
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',
|
||||
loadOptionsDependsOn: ['organizationId'],
|
||||
},
|
||||
default: '',
|
||||
},
|
||||
{
|
||||
displayName: 'Currency Rate',
|
||||
name: 'currencyRate',
|
||||
type: 'string',
|
||||
default: '',
|
||||
description:
|
||||
'The currency rate for a multicurrency invoice. If no rate is specified, the XE.com day rate is used.',
|
||||
},
|
||||
{
|
||||
displayName: 'Date',
|
||||
name: 'date',
|
||||
type: 'dateTime',
|
||||
default: '',
|
||||
description:
|
||||
'Date invoice was issued - YYYY-MM-DD. If the Date element is not specified it will default to the current date based on the timezone setting of the organisation.',
|
||||
},
|
||||
{
|
||||
displayName: 'Due Date',
|
||||
name: 'dueDate',
|
||||
type: 'dateTime',
|
||||
default: '',
|
||||
description: 'Date invoice is due - YYYY-MM-DD',
|
||||
},
|
||||
{
|
||||
displayName: 'Expected Payment Date',
|
||||
name: 'expectedPaymentDate',
|
||||
type: 'dateTime',
|
||||
default: '',
|
||||
description: 'Shown on sales invoices (Accounts Receivable) when this has been set',
|
||||
},
|
||||
{
|
||||
displayName: 'Invoice Number',
|
||||
name: 'invoiceNumber',
|
||||
type: 'string',
|
||||
default: '',
|
||||
},
|
||||
{
|
||||
displayName: 'Line Amount Type',
|
||||
name: 'lineAmountType',
|
||||
type: 'options',
|
||||
options: [
|
||||
{
|
||||
name: 'Exclusive',
|
||||
value: 'Exclusive',
|
||||
description: 'Line items are exclusive of tax',
|
||||
},
|
||||
{
|
||||
name: 'Inclusive',
|
||||
value: 'Inclusive',
|
||||
description: 'Line items are inclusive tax',
|
||||
},
|
||||
{
|
||||
name: 'NoTax',
|
||||
value: 'NoTax',
|
||||
description: 'Line have no tax',
|
||||
},
|
||||
],
|
||||
default: 'Exclusive',
|
||||
},
|
||||
{
|
||||
displayName: 'Planned Payment Date',
|
||||
name: 'plannedPaymentDate',
|
||||
type: 'dateTime',
|
||||
default: '',
|
||||
description: 'Shown on bills (Accounts Payable) when this has been set',
|
||||
},
|
||||
{
|
||||
displayName: 'Reference',
|
||||
name: 'reference',
|
||||
type: 'string',
|
||||
default: '',
|
||||
description: 'ACCREC only - additional reference number (max length = 255)',
|
||||
},
|
||||
{
|
||||
displayName: 'Send To Contact',
|
||||
name: 'sendToContact',
|
||||
type: 'boolean',
|
||||
default: false,
|
||||
description:
|
||||
'Whether the invoice in the Xero app should be marked as "sent". This can be set only on invoices that have been approved.',
|
||||
},
|
||||
{
|
||||
displayName: 'Status',
|
||||
name: 'status',
|
||||
type: 'options',
|
||||
options: [
|
||||
{
|
||||
name: 'Draft',
|
||||
value: 'DRAFT',
|
||||
},
|
||||
{
|
||||
name: 'Submitted',
|
||||
value: 'SUBMITTED',
|
||||
},
|
||||
{
|
||||
name: 'Authorised',
|
||||
value: 'AUTHORISED',
|
||||
},
|
||||
],
|
||||
default: 'DRAFT',
|
||||
},
|
||||
{
|
||||
displayName: 'URL',
|
||||
name: 'url',
|
||||
type: 'string',
|
||||
default: '',
|
||||
description: 'URL link to a source document - shown as "Go to [appName]" in the Xero app',
|
||||
},
|
||||
],
|
||||
},
|
||||
/* -------------------------------------------------------------------------- */
|
||||
/* invoice:update */
|
||||
/* -------------------------------------------------------------------------- */
|
||||
{
|
||||
displayName: 'Organization Name or ID',
|
||||
name: 'organizationId',
|
||||
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: 'getTenants',
|
||||
},
|
||||
default: '',
|
||||
displayOptions: {
|
||||
show: {
|
||||
resource: ['invoice'],
|
||||
operation: ['update'],
|
||||
},
|
||||
},
|
||||
required: true,
|
||||
},
|
||||
{
|
||||
displayName: 'Invoice ID',
|
||||
name: 'invoiceId',
|
||||
type: 'string',
|
||||
default: '',
|
||||
required: true,
|
||||
displayOptions: {
|
||||
show: {
|
||||
resource: ['invoice'],
|
||||
operation: ['update'],
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
displayName: 'Update Fields',
|
||||
name: 'updateFields',
|
||||
type: 'collection',
|
||||
placeholder: 'Add Field',
|
||||
default: {},
|
||||
displayOptions: {
|
||||
show: {
|
||||
resource: ['invoice'],
|
||||
operation: ['update'],
|
||||
},
|
||||
},
|
||||
options: [
|
||||
{
|
||||
displayName: 'Branding Theme Name or ID',
|
||||
name: 'brandingThemeId',
|
||||
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: 'getBrandingThemes',
|
||||
loadOptionsDependsOn: ['organizationId'],
|
||||
},
|
||||
default: '',
|
||||
},
|
||||
{
|
||||
displayName: 'Contact ID',
|
||||
name: 'contactId',
|
||||
type: 'string',
|
||||
default: '',
|
||||
},
|
||||
{
|
||||
displayName: 'Currency Name or ID',
|
||||
name: 'currency',
|
||||
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',
|
||||
loadOptionsDependsOn: ['organizationId'],
|
||||
},
|
||||
default: '',
|
||||
},
|
||||
{
|
||||
displayName: 'Currency Rate',
|
||||
name: 'currencyRate',
|
||||
type: 'string',
|
||||
default: '',
|
||||
description:
|
||||
'The currency rate for a multicurrency invoice. If no rate is specified, the XE.com day rate is used.',
|
||||
},
|
||||
{
|
||||
displayName: 'Date',
|
||||
name: 'date',
|
||||
type: 'dateTime',
|
||||
default: '',
|
||||
description:
|
||||
'Date invoice was issued - YYYY-MM-DD. If the Date element is not specified it will default to the current date based on the timezone setting of the organisation.',
|
||||
},
|
||||
{
|
||||
displayName: 'Due Date',
|
||||
name: 'dueDate',
|
||||
type: 'dateTime',
|
||||
default: '',
|
||||
description: 'Date invoice is due - YYYY-MM-DD',
|
||||
},
|
||||
{
|
||||
displayName: 'Expected Payment Date',
|
||||
name: 'expectedPaymentDate',
|
||||
type: 'dateTime',
|
||||
default: '',
|
||||
description: 'Shown on sales invoices (Accounts Receivable) when this has been set',
|
||||
},
|
||||
{
|
||||
displayName: 'Invoice Number',
|
||||
name: 'invoiceNumber',
|
||||
type: 'string',
|
||||
default: '',
|
||||
},
|
||||
{
|
||||
displayName: 'Line Amount Type',
|
||||
name: 'lineAmountType',
|
||||
type: 'options',
|
||||
options: [
|
||||
{
|
||||
name: 'Exclusive',
|
||||
value: 'Exclusive',
|
||||
description: 'Line items are exclusive of tax',
|
||||
},
|
||||
{
|
||||
name: 'Inclusive',
|
||||
value: 'Inclusive',
|
||||
description: 'Line items are inclusive tax',
|
||||
},
|
||||
{
|
||||
name: 'NoTax',
|
||||
value: 'NoTax',
|
||||
description: 'Line have no tax',
|
||||
},
|
||||
],
|
||||
default: 'Exclusive',
|
||||
},
|
||||
{
|
||||
displayName: 'Line Items',
|
||||
name: 'lineItemsUi',
|
||||
placeholder: 'Add Line Item',
|
||||
type: 'fixedCollection',
|
||||
default: {},
|
||||
typeOptions: {
|
||||
multipleValues: true,
|
||||
},
|
||||
description: 'Line item data',
|
||||
options: [
|
||||
{
|
||||
name: 'lineItemsValues',
|
||||
displayName: 'Line Item',
|
||||
values: [
|
||||
{
|
||||
displayName: 'Line Item ID',
|
||||
name: 'lineItemId',
|
||||
type: 'string',
|
||||
default: '',
|
||||
description: 'The Xero generated identifier for a LineItem',
|
||||
},
|
||||
{
|
||||
displayName: 'Description',
|
||||
name: 'description',
|
||||
type: 'string',
|
||||
default: '',
|
||||
description: 'A line item with just a description',
|
||||
},
|
||||
{
|
||||
displayName: 'Quantity',
|
||||
name: 'quantity',
|
||||
type: 'number',
|
||||
default: 1,
|
||||
typeOptions: {
|
||||
minValue: 1,
|
||||
},
|
||||
description: 'LineItem Quantity',
|
||||
},
|
||||
{
|
||||
displayName: 'Unit Amount',
|
||||
name: 'unitAmount',
|
||||
type: 'string',
|
||||
default: '',
|
||||
description:
|
||||
'Lineitem unit amount. By default, unit amount will be rounded to two decimal places.',
|
||||
},
|
||||
{
|
||||
displayName: 'Item Code Name or ID',
|
||||
name: 'itemCode',
|
||||
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: 'getItemCodes',
|
||||
loadOptionsDependsOn: ['organizationId'],
|
||||
},
|
||||
default: '',
|
||||
},
|
||||
{
|
||||
displayName: 'Account Code Name or ID',
|
||||
name: 'accountCode',
|
||||
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: 'getAccountCodes',
|
||||
loadOptionsDependsOn: ['organizationId'],
|
||||
},
|
||||
default: '',
|
||||
},
|
||||
{
|
||||
displayName: 'Tax Type',
|
||||
name: 'taxType',
|
||||
type: 'options',
|
||||
options: [
|
||||
{
|
||||
name: 'Tax on Purchases',
|
||||
value: 'INPUT',
|
||||
},
|
||||
{
|
||||
name: 'Tax Exempt',
|
||||
value: 'NONE',
|
||||
},
|
||||
{
|
||||
name: 'Tax on Sales',
|
||||
value: 'OUTPUT',
|
||||
},
|
||||
{
|
||||
name: 'Sales Tax on Imports',
|
||||
value: 'GSTONIMPORTS',
|
||||
},
|
||||
],
|
||||
default: '',
|
||||
required: true,
|
||||
},
|
||||
{
|
||||
displayName: 'Tax Amount',
|
||||
name: 'taxAmount',
|
||||
type: 'string',
|
||||
default: '',
|
||||
description:
|
||||
'The tax amount is auto calculated as a percentage of the line amount based on the tax rate',
|
||||
},
|
||||
{
|
||||
displayName: 'Line Amount',
|
||||
name: 'lineAmount',
|
||||
type: 'string',
|
||||
default: '',
|
||||
description:
|
||||
'The line amount reflects the discounted price if a DiscountRate has been used',
|
||||
},
|
||||
{
|
||||
displayName: 'Discount Rate',
|
||||
name: 'discountRate',
|
||||
type: 'string',
|
||||
default: '',
|
||||
description:
|
||||
'Percentage discount or discount amount being applied to a line item. Only supported on ACCREC invoices - ACCPAY invoices and credit notes in Xero do not support discounts.',
|
||||
},
|
||||
// {
|
||||
// displayName: 'Tracking',
|
||||
// name: 'trackingUi',
|
||||
// placeholder: 'Add Tracking',
|
||||
// description: 'Any LineItem can have a maximum of 2 TrackingCategory elements.',
|
||||
// type: 'fixedCollection',
|
||||
// typeOptions: {
|
||||
// multipleValues: true,
|
||||
// },
|
||||
// default: {},
|
||||
// options: [
|
||||
// {
|
||||
// name: 'trackingValues',
|
||||
// displayName: 'Tracking',
|
||||
// values: [
|
||||
// {
|
||||
// displayName: 'Name',
|
||||
// name: 'name',
|
||||
// type: 'options',
|
||||
// typeOptions: {
|
||||
// loadOptionsMethod: 'getTrakingCategories',
|
||||
// loadOptionsDependsOn: [
|
||||
// 'organizationId',
|
||||
// ],
|
||||
// },
|
||||
// default: '',
|
||||
// description: 'Name of the tracking category',
|
||||
// },
|
||||
// {
|
||||
// displayName: 'Option',
|
||||
// name: 'option',
|
||||
// type: 'options',
|
||||
// typeOptions: {
|
||||
// loadOptionsMethod: 'getTrakingOptions',
|
||||
// loadOptionsDependsOn: [
|
||||
// '/name',
|
||||
// ],
|
||||
// },
|
||||
// default: '',
|
||||
// description: 'Name of the option',
|
||||
// },
|
||||
// ],
|
||||
// },
|
||||
// ],
|
||||
// },
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
displayName: 'Planned Payment Date',
|
||||
name: 'plannedPaymentDate',
|
||||
type: 'dateTime',
|
||||
default: '',
|
||||
description: 'Shown on bills (Accounts Payable) when this has been set',
|
||||
},
|
||||
{
|
||||
displayName: 'Reference',
|
||||
name: 'reference',
|
||||
type: 'string',
|
||||
default: '',
|
||||
description: 'ACCREC only - additional reference number (max length = 255)',
|
||||
},
|
||||
{
|
||||
displayName: 'Send To Contact',
|
||||
name: 'sendToContact',
|
||||
type: 'boolean',
|
||||
default: false,
|
||||
description:
|
||||
'Whether the invoice in the Xero app should be marked as "sent". This can be set only on invoices that have been approved.',
|
||||
},
|
||||
{
|
||||
displayName: 'Status',
|
||||
name: 'status',
|
||||
type: 'options',
|
||||
options: [
|
||||
{
|
||||
name: 'Draft',
|
||||
value: 'DRAFT',
|
||||
},
|
||||
{
|
||||
name: 'Submitted',
|
||||
value: 'SUBMITTED',
|
||||
},
|
||||
{
|
||||
name: 'Authorised',
|
||||
value: 'AUTHORISED',
|
||||
},
|
||||
],
|
||||
default: 'DRAFT',
|
||||
},
|
||||
{
|
||||
displayName: 'URL',
|
||||
name: 'url',
|
||||
type: 'string',
|
||||
default: '',
|
||||
description: 'URL link to a source document - shown as "Go to [appName]" in the Xero app',
|
||||
},
|
||||
],
|
||||
},
|
||||
/* -------------------------------------------------------------------------- */
|
||||
/* invoice:get */
|
||||
/* -------------------------------------------------------------------------- */
|
||||
{
|
||||
displayName: 'Organization Name or ID',
|
||||
name: 'organizationId',
|
||||
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: 'getTenants',
|
||||
},
|
||||
default: '',
|
||||
displayOptions: {
|
||||
show: {
|
||||
resource: ['invoice'],
|
||||
operation: ['get'],
|
||||
},
|
||||
},
|
||||
required: true,
|
||||
},
|
||||
{
|
||||
displayName: 'Invoice ID',
|
||||
name: 'invoiceId',
|
||||
type: 'string',
|
||||
default: '',
|
||||
required: true,
|
||||
displayOptions: {
|
||||
show: {
|
||||
resource: ['invoice'],
|
||||
operation: ['get'],
|
||||
},
|
||||
},
|
||||
},
|
||||
/* -------------------------------------------------------------------------- */
|
||||
/* invoice:getAll */
|
||||
/* -------------------------------------------------------------------------- */
|
||||
{
|
||||
displayName: 'Organization Name or ID',
|
||||
name: 'organizationId',
|
||||
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: 'getTenants',
|
||||
},
|
||||
default: '',
|
||||
displayOptions: {
|
||||
show: {
|
||||
resource: ['invoice'],
|
||||
operation: ['getAll'],
|
||||
},
|
||||
},
|
||||
required: true,
|
||||
},
|
||||
{
|
||||
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: 100,
|
||||
},
|
||||
default: 100,
|
||||
description: 'Max number of results to return',
|
||||
},
|
||||
{
|
||||
displayName: 'Options',
|
||||
name: 'options',
|
||||
type: 'collection',
|
||||
placeholder: 'Add option',
|
||||
default: {},
|
||||
displayOptions: {
|
||||
show: {
|
||||
resource: ['invoice'],
|
||||
operation: ['getAll'],
|
||||
},
|
||||
},
|
||||
options: [
|
||||
{
|
||||
displayName: 'Created By My App',
|
||||
name: 'createdByMyApp',
|
||||
type: 'boolean',
|
||||
default: false,
|
||||
description: "Whether you'll only retrieve Invoices created by your app",
|
||||
},
|
||||
{
|
||||
displayName: 'Order By',
|
||||
name: 'orderBy',
|
||||
type: 'string',
|
||||
placeholder: 'InvoiceID',
|
||||
default: '',
|
||||
description: 'Order by any element returned',
|
||||
},
|
||||
{
|
||||
displayName: 'Sort Order',
|
||||
name: 'sortOrder',
|
||||
type: 'options',
|
||||
options: [
|
||||
{
|
||||
name: 'Asc',
|
||||
value: 'ASC',
|
||||
},
|
||||
{
|
||||
name: 'Desc',
|
||||
value: 'DESC',
|
||||
},
|
||||
],
|
||||
default: '',
|
||||
},
|
||||
{
|
||||
displayName: 'Statuses',
|
||||
name: 'statuses',
|
||||
type: 'multiOptions',
|
||||
options: [
|
||||
{
|
||||
name: 'Draft',
|
||||
value: 'DRAFT',
|
||||
},
|
||||
{
|
||||
name: 'Submitted',
|
||||
value: 'SUBMITTED',
|
||||
},
|
||||
{
|
||||
name: 'Authorised',
|
||||
value: 'AUTHORISED',
|
||||
},
|
||||
],
|
||||
default: [],
|
||||
},
|
||||
{
|
||||
displayName: 'Where',
|
||||
name: 'where',
|
||||
type: 'string',
|
||||
placeholder: 'EmailAddress!=null&&EmailAddress.StartsWith("boom")',
|
||||
default: '',
|
||||
description:
|
||||
'The where parameter allows you to filter on endpoints and elements that don\'t have explicit parameters. <a href="https://developer.xero.com/documentation/api/requests-and-responses#get-modified">Examples Here</a>.',
|
||||
},
|
||||
],
|
||||
},
|
||||
];
|
||||
@@ -0,0 +1,38 @@
|
||||
import type { IDataObject } from 'n8n-workflow';
|
||||
|
||||
export interface ILineItem {
|
||||
Description?: string;
|
||||
Quantity?: string;
|
||||
UnitAmount?: string;
|
||||
ItemCode?: string;
|
||||
AccountCode?: string;
|
||||
LineItemID?: string;
|
||||
TaxType?: string;
|
||||
TaxAmount?: string;
|
||||
LineAmount?: string;
|
||||
DiscountRate?: string;
|
||||
Tracking?: IDataObject[];
|
||||
}
|
||||
|
||||
export interface IInvoice extends ITenantId {
|
||||
Type?: string;
|
||||
LineItems?: ILineItem[];
|
||||
Contact?: IDataObject;
|
||||
Date?: string;
|
||||
DueDate?: string;
|
||||
LineAmountTypes?: string;
|
||||
InvoiceNumber?: string;
|
||||
Reference?: string;
|
||||
BrandingThemeID?: string;
|
||||
Url?: string;
|
||||
CurrencyCode?: string;
|
||||
CurrencyRate?: string;
|
||||
Status?: string;
|
||||
SentToContact?: boolean;
|
||||
ExpectedPaymentDate?: string;
|
||||
PlannedPaymentDate?: string;
|
||||
}
|
||||
|
||||
export interface ITenantId {
|
||||
organizationId?: string;
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
{
|
||||
"node": "n8n-nodes-base.xero",
|
||||
"nodeVersion": "1.0",
|
||||
"codexVersion": "1.0",
|
||||
"categories": ["Finance & Accounting"],
|
||||
"resources": {
|
||||
"credentialDocumentation": [
|
||||
{
|
||||
"url": "https://docs.n8n.io/integrations/builtin/credentials/xero/"
|
||||
}
|
||||
],
|
||||
"primaryDocumentation": [
|
||||
{
|
||||
"url": "https://docs.n8n.io/integrations/builtin/app-nodes/n8n-nodes-base.xero/"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,731 @@
|
||||
import {
|
||||
type IExecuteFunctions,
|
||||
type IDataObject,
|
||||
type ILoadOptionsFunctions,
|
||||
type INodeExecutionData,
|
||||
type INodePropertyOptions,
|
||||
type INodeType,
|
||||
type INodeTypeDescription,
|
||||
type JsonObject,
|
||||
NodeConnectionTypes,
|
||||
} from 'n8n-workflow';
|
||||
|
||||
import { contactFields, contactOperations } from './ContactDescription';
|
||||
import { xeroApiRequest, xeroApiRequestAllItems } from './GenericFunctions';
|
||||
import type { IAddress, IContact, IPhone } from './IContactInterface';
|
||||
import { invoiceFields, invoiceOperations } from './InvoiceDescription';
|
||||
import type { IInvoice, ILineItem } from './InvoiceInterface';
|
||||
|
||||
export class Xero implements INodeType {
|
||||
description: INodeTypeDescription = {
|
||||
displayName: 'Xero',
|
||||
name: 'xero',
|
||||
icon: 'file:xero.svg',
|
||||
group: ['output'],
|
||||
version: 1,
|
||||
subtitle: '={{$parameter["operation"] + ": " + $parameter["resource"]}}',
|
||||
description: 'Consume Xero API',
|
||||
defaults: {
|
||||
name: 'Xero',
|
||||
},
|
||||
usableAsTool: true,
|
||||
inputs: [NodeConnectionTypes.Main],
|
||||
outputs: [NodeConnectionTypes.Main],
|
||||
credentials: [
|
||||
{
|
||||
name: 'xeroOAuth2Api',
|
||||
required: true,
|
||||
},
|
||||
],
|
||||
properties: [
|
||||
{
|
||||
displayName: 'Resource',
|
||||
name: 'resource',
|
||||
type: 'options',
|
||||
noDataExpression: true,
|
||||
options: [
|
||||
{
|
||||
name: 'Contact',
|
||||
value: 'contact',
|
||||
},
|
||||
{
|
||||
name: 'Invoice',
|
||||
value: 'invoice',
|
||||
},
|
||||
],
|
||||
default: 'invoice',
|
||||
},
|
||||
// CONTACT
|
||||
...contactOperations,
|
||||
...contactFields,
|
||||
// INVOICE
|
||||
...invoiceOperations,
|
||||
...invoiceFields,
|
||||
],
|
||||
};
|
||||
|
||||
methods = {
|
||||
loadOptions: {
|
||||
// Get all the item codes to display them to user so that they can
|
||||
// select them easily
|
||||
async getItemCodes(this: ILoadOptionsFunctions): Promise<INodePropertyOptions[]> {
|
||||
const organizationId = this.getCurrentNodeParameter('organizationId');
|
||||
const returnData: INodePropertyOptions[] = [];
|
||||
const { Items: items } = await xeroApiRequest.call(this, 'GET', '/items', {
|
||||
organizationId,
|
||||
});
|
||||
for (const item of items) {
|
||||
const itemName = item.Description;
|
||||
const itemId = item.Code;
|
||||
returnData.push({
|
||||
name: itemName,
|
||||
value: itemId,
|
||||
});
|
||||
}
|
||||
return returnData;
|
||||
},
|
||||
// Get all the account codes to display them to user so that they can
|
||||
// select them easily
|
||||
async getAccountCodes(this: ILoadOptionsFunctions): Promise<INodePropertyOptions[]> {
|
||||
const organizationId = this.getCurrentNodeParameter('organizationId');
|
||||
const returnData: INodePropertyOptions[] = [];
|
||||
const { Accounts: accounts } = await xeroApiRequest.call(this, 'GET', '/Accounts', {
|
||||
organizationId,
|
||||
});
|
||||
for (const account of accounts) {
|
||||
const accountName = account.Name;
|
||||
const accountId = account.Code;
|
||||
returnData.push({
|
||||
name: accountName,
|
||||
value: accountId,
|
||||
});
|
||||
}
|
||||
return returnData;
|
||||
},
|
||||
// Get all the tenants to display them to user so that they can
|
||||
// select them easily
|
||||
async getTenants(this: ILoadOptionsFunctions): Promise<INodePropertyOptions[]> {
|
||||
const returnData: INodePropertyOptions[] = [];
|
||||
const tenants = await xeroApiRequest.call(
|
||||
this,
|
||||
'GET',
|
||||
'',
|
||||
{},
|
||||
{},
|
||||
'https://api.xero.com/connections',
|
||||
);
|
||||
for (const tenant of tenants) {
|
||||
const tenantName = tenant.tenantName;
|
||||
const tenantId = tenant.tenantId;
|
||||
returnData.push({
|
||||
name: tenantName,
|
||||
value: tenantId,
|
||||
});
|
||||
}
|
||||
return returnData;
|
||||
},
|
||||
// Get all the brading themes to display them to user so that they can
|
||||
// select them easily
|
||||
async getBrandingThemes(this: ILoadOptionsFunctions): Promise<INodePropertyOptions[]> {
|
||||
const organizationId = this.getCurrentNodeParameter('organizationId');
|
||||
const returnData: INodePropertyOptions[] = [];
|
||||
const { BrandingThemes: themes } = await xeroApiRequest.call(
|
||||
this,
|
||||
'GET',
|
||||
'/BrandingThemes',
|
||||
{ organizationId },
|
||||
);
|
||||
for (const theme of themes) {
|
||||
const themeName = theme.Name;
|
||||
const themeId = theme.BrandingThemeID;
|
||||
returnData.push({
|
||||
name: themeName,
|
||||
value: themeId,
|
||||
});
|
||||
}
|
||||
return returnData;
|
||||
},
|
||||
// Get all the currencies to display them to user so that they can
|
||||
// select them easily
|
||||
async getCurrencies(this: ILoadOptionsFunctions): Promise<INodePropertyOptions[]> {
|
||||
const organizationId = this.getCurrentNodeParameter('organizationId');
|
||||
const returnData: INodePropertyOptions[] = [];
|
||||
const { Currencies: currencies } = await xeroApiRequest.call(this, 'GET', '/Currencies', {
|
||||
organizationId,
|
||||
});
|
||||
for (const currency of currencies) {
|
||||
returnData.push({
|
||||
name: currency.Description, // e.g. "Euro"
|
||||
value: currency.Code, // e.g. "EUR"
|
||||
});
|
||||
}
|
||||
return returnData;
|
||||
},
|
||||
// Get all the tracking categories to display them to user so that they can
|
||||
// select them easily
|
||||
async getTrakingCategories(this: ILoadOptionsFunctions): Promise<INodePropertyOptions[]> {
|
||||
const organizationId = this.getCurrentNodeParameter('organizationId');
|
||||
const returnData: INodePropertyOptions[] = [];
|
||||
const { TrackingCategories: categories } = await xeroApiRequest.call(
|
||||
this,
|
||||
'GET',
|
||||
'/TrackingCategories',
|
||||
{ organizationId },
|
||||
);
|
||||
for (const category of categories) {
|
||||
const categoryName = category.Name;
|
||||
const categoryId = category.TrackingCategoryID;
|
||||
returnData.push({
|
||||
name: categoryName,
|
||||
value: categoryId,
|
||||
});
|
||||
}
|
||||
return returnData;
|
||||
},
|
||||
// // Get all the tracking categories to display them to user so that they can
|
||||
// // select them easily
|
||||
// async getTrakingOptions(this: ILoadOptionsFunctions): Promise<INodePropertyOptions[]> {
|
||||
// const organizationId = this.getCurrentNodeParameter('organizationId');
|
||||
// const name = this.getCurrentNodeParameter('name');
|
||||
// const returnData: INodePropertyOptions[] = [];
|
||||
// const { TrackingCategories: categories } = await xeroApiRequest.call(this, 'GET', '/TrackingCategories', { organizationId });
|
||||
// const { Options: options } = categories.filter((category: IDataObject) => category.Name === name)[0];
|
||||
// for (const option of options) {
|
||||
// const optionName = option.Name;
|
||||
// const optionId = option.TrackingOptionID;
|
||||
// returnData.push({
|
||||
// name: optionName,
|
||||
// value: optionId,
|
||||
// });
|
||||
// }
|
||||
// return returnData;
|
||||
// },
|
||||
},
|
||||
};
|
||||
|
||||
async execute(this: IExecuteFunctions): Promise<INodeExecutionData[][]> {
|
||||
const items = this.getInputData();
|
||||
const returnData: INodeExecutionData[] = [];
|
||||
const length = items.length;
|
||||
const qs: IDataObject = {};
|
||||
let responseData;
|
||||
for (let i = 0; i < length; i++) {
|
||||
try {
|
||||
const resource = this.getNodeParameter('resource', 0);
|
||||
const operation = this.getNodeParameter('operation', 0);
|
||||
//https://developer.xero.com/documentation/api/invoices
|
||||
if (resource === 'invoice') {
|
||||
if (operation === 'create') {
|
||||
const organizationId = this.getNodeParameter('organizationId', i) as string;
|
||||
const type = this.getNodeParameter('type', i) as string;
|
||||
const additionalFields = this.getNodeParameter('additionalFields', i);
|
||||
const contactId = this.getNodeParameter('contactId', i) as string;
|
||||
const lineItemsValues = (this.getNodeParameter('lineItemsUi', i) as IDataObject)
|
||||
.lineItemsValues as IDataObject[];
|
||||
|
||||
const body: IInvoice = {
|
||||
organizationId,
|
||||
Type: type,
|
||||
Contact: { ContactID: contactId },
|
||||
};
|
||||
|
||||
if (lineItemsValues) {
|
||||
const lineItems: ILineItem[] = [];
|
||||
for (const lineItemValue of lineItemsValues) {
|
||||
const lineItem: ILineItem = {
|
||||
Tracking: [],
|
||||
};
|
||||
lineItem.AccountCode = lineItemValue.accountCode as string;
|
||||
lineItem.Description = lineItemValue.description as string;
|
||||
lineItem.DiscountRate = lineItemValue.discountRate as string;
|
||||
lineItem.ItemCode = lineItemValue.itemCode as string;
|
||||
lineItem.LineAmount = lineItemValue.lineAmount as string;
|
||||
lineItem.Quantity = (lineItemValue.quantity as number).toString();
|
||||
lineItem.TaxAmount = lineItemValue.taxAmount as string;
|
||||
lineItem.TaxType = lineItemValue.taxType as string;
|
||||
lineItem.UnitAmount = lineItemValue.unitAmount as string;
|
||||
// if (lineItemValue.trackingUi) {
|
||||
// //@ts-ignore
|
||||
// const { trackingValues } = lineItemValue.trackingUi as IDataObject[];
|
||||
// if (trackingValues) {
|
||||
// for (const trackingValue of trackingValues) {
|
||||
// const tracking: IDataObject = {};
|
||||
// tracking.Name = trackingValue.name as string;
|
||||
// tracking.Option = trackingValue.option as string;
|
||||
// lineItem.Tracking!.push(tracking);
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
lineItems.push(lineItem);
|
||||
}
|
||||
body.LineItems = lineItems;
|
||||
}
|
||||
|
||||
if (additionalFields.brandingThemeId) {
|
||||
body.BrandingThemeID = additionalFields.brandingThemeId as string;
|
||||
}
|
||||
if (additionalFields.currency) {
|
||||
body.CurrencyCode = additionalFields.currency as string;
|
||||
}
|
||||
if (additionalFields.currencyRate) {
|
||||
body.CurrencyRate = additionalFields.currencyRate as string;
|
||||
}
|
||||
if (additionalFields.date) {
|
||||
body.Date = additionalFields.date as string;
|
||||
}
|
||||
if (additionalFields.dueDate) {
|
||||
body.DueDate = additionalFields.dueDate as string;
|
||||
}
|
||||
if (additionalFields.dueDate) {
|
||||
body.DueDate = additionalFields.dueDate as string;
|
||||
}
|
||||
if (additionalFields.expectedPaymentDate) {
|
||||
body.ExpectedPaymentDate = additionalFields.expectedPaymentDate as string;
|
||||
}
|
||||
if (additionalFields.invoiceNumber) {
|
||||
body.InvoiceNumber = additionalFields.invoiceNumber as string;
|
||||
}
|
||||
if (additionalFields.lineAmountType) {
|
||||
body.LineAmountTypes = additionalFields.lineAmountType as string;
|
||||
}
|
||||
if (additionalFields.plannedPaymentDate) {
|
||||
body.PlannedPaymentDate = additionalFields.plannedPaymentDate as string;
|
||||
}
|
||||
if (additionalFields.reference) {
|
||||
body.Reference = additionalFields.reference as string;
|
||||
}
|
||||
if (additionalFields.sendToContact) {
|
||||
body.SentToContact = additionalFields.sendToContact as boolean;
|
||||
}
|
||||
if (additionalFields.status) {
|
||||
body.Status = additionalFields.status as string;
|
||||
}
|
||||
if (additionalFields.url) {
|
||||
body.Url = additionalFields.url as string;
|
||||
}
|
||||
|
||||
responseData = await xeroApiRequest.call(this, 'POST', '/Invoices', body);
|
||||
responseData = responseData.Invoices;
|
||||
}
|
||||
if (operation === 'update') {
|
||||
const invoiceId = this.getNodeParameter('invoiceId', i) as string;
|
||||
const organizationId = this.getNodeParameter('organizationId', i) as string;
|
||||
const updateFields = this.getNodeParameter('updateFields', i);
|
||||
|
||||
const body: IInvoice = {
|
||||
organizationId,
|
||||
};
|
||||
|
||||
if (updateFields.lineItemsUi) {
|
||||
const lineItemsValues = (updateFields.lineItemsUi as IDataObject)
|
||||
.lineItemsValues as IDataObject[];
|
||||
if (lineItemsValues) {
|
||||
const lineItems: ILineItem[] = [];
|
||||
for (const lineItemValue of lineItemsValues) {
|
||||
const lineItem: ILineItem = {
|
||||
Tracking: [],
|
||||
};
|
||||
lineItem.AccountCode = lineItemValue.accountCode as string;
|
||||
lineItem.Description = lineItemValue.description as string;
|
||||
lineItem.DiscountRate = lineItemValue.discountRate as string;
|
||||
lineItem.ItemCode = lineItemValue.itemCode as string;
|
||||
lineItem.LineAmount = lineItemValue.lineAmount as string;
|
||||
lineItem.Quantity = (lineItemValue.quantity as number).toString();
|
||||
lineItem.TaxAmount = lineItemValue.taxAmount as string;
|
||||
lineItem.TaxType = lineItemValue.taxType as string;
|
||||
lineItem.UnitAmount = lineItemValue.unitAmount as string;
|
||||
// if (lineItemValue.trackingUi) {
|
||||
// //@ts-ignore
|
||||
// const { trackingValues } = lineItemValue.trackingUi as IDataObject[];
|
||||
// if (trackingValues) {
|
||||
// for (const trackingValue of trackingValues) {
|
||||
// const tracking: IDataObject = {};
|
||||
// tracking.Name = trackingValue.name as string;
|
||||
// tracking.Option = trackingValue.option as string;
|
||||
// lineItem.Tracking!.push(tracking);
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
lineItems.push(lineItem);
|
||||
}
|
||||
body.LineItems = lineItems;
|
||||
}
|
||||
}
|
||||
|
||||
if (updateFields.type) {
|
||||
body.Type = updateFields.type as string;
|
||||
}
|
||||
if (updateFields.Contact) {
|
||||
body.Contact = { ContactID: updateFields.contactId as string };
|
||||
}
|
||||
if (updateFields.brandingThemeId) {
|
||||
body.BrandingThemeID = updateFields.brandingThemeId as string;
|
||||
}
|
||||
if (updateFields.currency) {
|
||||
body.CurrencyCode = updateFields.currency as string;
|
||||
}
|
||||
if (updateFields.currencyRate) {
|
||||
body.CurrencyRate = updateFields.currencyRate as string;
|
||||
}
|
||||
if (updateFields.date) {
|
||||
body.Date = updateFields.date as string;
|
||||
}
|
||||
if (updateFields.dueDate) {
|
||||
body.DueDate = updateFields.dueDate as string;
|
||||
}
|
||||
if (updateFields.dueDate) {
|
||||
body.DueDate = updateFields.dueDate as string;
|
||||
}
|
||||
if (updateFields.expectedPaymentDate) {
|
||||
body.ExpectedPaymentDate = updateFields.expectedPaymentDate as string;
|
||||
}
|
||||
if (updateFields.invoiceNumber) {
|
||||
body.InvoiceNumber = updateFields.invoiceNumber as string;
|
||||
}
|
||||
if (updateFields.lineAmountType) {
|
||||
body.LineAmountTypes = updateFields.lineAmountType as string;
|
||||
}
|
||||
if (updateFields.plannedPaymentDate) {
|
||||
body.PlannedPaymentDate = updateFields.plannedPaymentDate as string;
|
||||
}
|
||||
if (updateFields.reference) {
|
||||
body.Reference = updateFields.reference as string;
|
||||
}
|
||||
if (updateFields.sendToContact) {
|
||||
body.SentToContact = updateFields.sendToContact as boolean;
|
||||
}
|
||||
if (updateFields.status) {
|
||||
body.Status = updateFields.status as string;
|
||||
}
|
||||
if (updateFields.url) {
|
||||
body.Url = updateFields.url as string;
|
||||
}
|
||||
|
||||
responseData = await xeroApiRequest.call(this, 'POST', `/Invoices/${invoiceId}`, body);
|
||||
responseData = responseData.Invoices;
|
||||
}
|
||||
if (operation === 'get') {
|
||||
const organizationId = this.getNodeParameter('organizationId', i) as string;
|
||||
const invoiceId = this.getNodeParameter('invoiceId', i) as string;
|
||||
responseData = await xeroApiRequest.call(this, 'GET', `/Invoices/${invoiceId}`, {
|
||||
organizationId,
|
||||
});
|
||||
responseData = responseData.Invoices;
|
||||
}
|
||||
if (operation === 'getAll') {
|
||||
const organizationId = this.getNodeParameter('organizationId', i) as string;
|
||||
const returnAll = this.getNodeParameter('returnAll', i);
|
||||
const options = this.getNodeParameter('options', i);
|
||||
if (options.statuses) {
|
||||
qs.statuses = (options.statuses as string[]).join(',');
|
||||
}
|
||||
if (options.orderBy) {
|
||||
qs.order = `${options.orderBy} ${
|
||||
options.sortOrder === undefined ? 'DESC' : options.sortOrder
|
||||
}`;
|
||||
}
|
||||
if (options.where) {
|
||||
qs.where = options.where;
|
||||
}
|
||||
if (options.createdByMyApp) {
|
||||
qs.createdByMyApp = options.createdByMyApp as boolean;
|
||||
}
|
||||
if (returnAll) {
|
||||
responseData = await xeroApiRequestAllItems.call(
|
||||
this,
|
||||
'Invoices',
|
||||
'GET',
|
||||
'/Invoices',
|
||||
{ organizationId },
|
||||
qs,
|
||||
);
|
||||
} else {
|
||||
const limit = this.getNodeParameter('limit', i);
|
||||
responseData = await xeroApiRequest.call(
|
||||
this,
|
||||
'GET',
|
||||
'/Invoices',
|
||||
{ organizationId },
|
||||
qs,
|
||||
);
|
||||
responseData = responseData.Invoices;
|
||||
responseData = responseData.splice(0, limit);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (resource === 'contact') {
|
||||
if (operation === 'create') {
|
||||
const organizationId = this.getNodeParameter('organizationId', i) as string;
|
||||
const name = this.getNodeParameter('name', i) as string;
|
||||
const additionalFields = this.getNodeParameter('additionalFields', i);
|
||||
const addressesUi = additionalFields.addressesUi as IDataObject;
|
||||
const phonesUi = additionalFields.phonesUi as IDataObject;
|
||||
|
||||
const body: IContact = {
|
||||
Name: name,
|
||||
};
|
||||
|
||||
if (additionalFields.accountNumber) {
|
||||
body.AccountNumber = additionalFields.accountNumber as string;
|
||||
}
|
||||
|
||||
if (additionalFields.bankAccountDetails) {
|
||||
body.BankAccountDetails = additionalFields.bankAccountDetails as string;
|
||||
}
|
||||
|
||||
if (additionalFields.contactNumber) {
|
||||
body.ContactNumber = additionalFields.contactNumber as string;
|
||||
}
|
||||
|
||||
if (additionalFields.contactStatus) {
|
||||
body.ContactStatus = additionalFields.contactStatus as string;
|
||||
}
|
||||
|
||||
if (additionalFields.defaultCurrency) {
|
||||
body.DefaultCurrency = additionalFields.defaultCurrency as string;
|
||||
}
|
||||
|
||||
if (additionalFields.emailAddress) {
|
||||
body.EmailAddress = additionalFields.emailAddress as string;
|
||||
}
|
||||
|
||||
if (additionalFields.firstName) {
|
||||
body.FirstName = additionalFields.firstName as string;
|
||||
}
|
||||
|
||||
if (additionalFields.lastName) {
|
||||
body.LastName = additionalFields.lastName as string;
|
||||
}
|
||||
|
||||
if (additionalFields.purchasesDefaultAccountCode) {
|
||||
body.PurchasesDefaultAccountCode =
|
||||
additionalFields.purchasesDefaultAccountCode as string;
|
||||
}
|
||||
|
||||
if (additionalFields.salesDefaultAccountCode) {
|
||||
body.SalesDefaultAccountCode = additionalFields.salesDefaultAccountCode as string;
|
||||
}
|
||||
|
||||
if (additionalFields.skypeUserName) {
|
||||
body.SkypeUserName = additionalFields.skypeUserName as string;
|
||||
}
|
||||
|
||||
if (additionalFields.taxNumber) {
|
||||
body.taxNumber = additionalFields.taxNumber as string;
|
||||
}
|
||||
|
||||
if (additionalFields.xeroNetworkKey) {
|
||||
body.xeroNetworkKey = additionalFields.xeroNetworkKey as string;
|
||||
}
|
||||
|
||||
if (phonesUi) {
|
||||
const phoneValues = phonesUi?.phonesValues as IDataObject[];
|
||||
if (phoneValues) {
|
||||
const phones: IPhone[] = [];
|
||||
for (const phoneValue of phoneValues) {
|
||||
const phone: IPhone = {};
|
||||
phone.PhoneType = phoneValue.phoneType as string;
|
||||
phone.PhoneNumber = phoneValue.phoneNumber as string;
|
||||
phone.PhoneAreaCode = phoneValue.phoneAreaCode as string;
|
||||
phone.PhoneCountryCode = phoneValue.phoneCountryCode as string;
|
||||
phones.push(phone);
|
||||
}
|
||||
body.Phones = phones;
|
||||
}
|
||||
}
|
||||
|
||||
if (addressesUi) {
|
||||
const addressValues = addressesUi?.addressesValues as IDataObject[];
|
||||
if (addressValues) {
|
||||
const addresses: IAddress[] = [];
|
||||
for (const addressValue of addressValues) {
|
||||
const address: IAddress = {};
|
||||
address.AddressType = addressValue.type as string;
|
||||
address.AddressLine1 = addressValue.line1 as string;
|
||||
address.AddressLine2 = addressValue.line2 as string;
|
||||
address.City = addressValue.city as string;
|
||||
address.Region = addressValue.region as string;
|
||||
address.PostalCode = addressValue.postalCode as string;
|
||||
address.Country = addressValue.country as string;
|
||||
address.AttentionTo = addressValue.attentionTo as string;
|
||||
addresses.push(address);
|
||||
}
|
||||
body.Addresses = addresses;
|
||||
}
|
||||
}
|
||||
|
||||
responseData = await xeroApiRequest.call(this, 'POST', '/Contacts', {
|
||||
organizationId,
|
||||
Contacts: [body],
|
||||
});
|
||||
responseData = responseData.Contacts;
|
||||
}
|
||||
if (operation === 'get') {
|
||||
const organizationId = this.getNodeParameter('organizationId', i) as string;
|
||||
const contactId = this.getNodeParameter('contactId', i) as string;
|
||||
responseData = await xeroApiRequest.call(this, 'GET', `/Contacts/${contactId}`, {
|
||||
organizationId,
|
||||
});
|
||||
responseData = responseData.Contacts;
|
||||
}
|
||||
if (operation === 'getAll') {
|
||||
const organizationId = this.getNodeParameter('organizationId', i) as string;
|
||||
const returnAll = this.getNodeParameter('returnAll', i);
|
||||
const options = this.getNodeParameter('options', i);
|
||||
if (options.includeArchived) {
|
||||
qs.includeArchived = options.includeArchived as boolean;
|
||||
}
|
||||
if (options.orderBy) {
|
||||
qs.order = `${options.orderBy} ${
|
||||
options.sortOrder === undefined ? 'DESC' : options.sortOrder
|
||||
}`;
|
||||
}
|
||||
if (options.where) {
|
||||
qs.where = options.where;
|
||||
}
|
||||
if (returnAll) {
|
||||
responseData = await xeroApiRequestAllItems.call(
|
||||
this,
|
||||
'Contacts',
|
||||
'GET',
|
||||
'/Contacts',
|
||||
{ organizationId },
|
||||
qs,
|
||||
);
|
||||
} else {
|
||||
const limit = this.getNodeParameter('limit', i);
|
||||
responseData = await xeroApiRequest.call(
|
||||
this,
|
||||
'GET',
|
||||
'/Contacts',
|
||||
{ organizationId },
|
||||
qs,
|
||||
);
|
||||
responseData = responseData.Contacts;
|
||||
responseData = responseData.splice(0, limit);
|
||||
}
|
||||
}
|
||||
if (operation === 'update') {
|
||||
const organizationId = this.getNodeParameter('organizationId', i) as string;
|
||||
const contactId = this.getNodeParameter('contactId', i) as string;
|
||||
const updateFields = this.getNodeParameter('updateFields', i);
|
||||
const addressesUi = updateFields.addressesUi as IDataObject;
|
||||
const phonesUi = updateFields.phonesUi as IDataObject;
|
||||
|
||||
const body: IContact = {};
|
||||
|
||||
if (updateFields.accountNumber) {
|
||||
body.AccountNumber = updateFields.accountNumber as string;
|
||||
}
|
||||
|
||||
if (updateFields.name) {
|
||||
body.Name = updateFields.name as string;
|
||||
}
|
||||
|
||||
if (updateFields.bankAccountDetails) {
|
||||
body.BankAccountDetails = updateFields.bankAccountDetails as string;
|
||||
}
|
||||
|
||||
if (updateFields.contactNumber) {
|
||||
body.ContactNumber = updateFields.contactNumber as string;
|
||||
}
|
||||
|
||||
if (updateFields.contactStatus) {
|
||||
body.ContactStatus = updateFields.contactStatus as string;
|
||||
}
|
||||
|
||||
if (updateFields.defaultCurrency) {
|
||||
body.DefaultCurrency = updateFields.defaultCurrency as string;
|
||||
}
|
||||
|
||||
if (updateFields.emailAddress) {
|
||||
body.EmailAddress = updateFields.emailAddress as string;
|
||||
}
|
||||
|
||||
if (updateFields.firstName) {
|
||||
body.FirstName = updateFields.firstName as string;
|
||||
}
|
||||
|
||||
if (updateFields.lastName) {
|
||||
body.LastName = updateFields.lastName as string;
|
||||
}
|
||||
|
||||
if (updateFields.purchasesDefaultAccountCode) {
|
||||
body.PurchasesDefaultAccountCode = updateFields.purchasesDefaultAccountCode as string;
|
||||
}
|
||||
|
||||
if (updateFields.salesDefaultAccountCode) {
|
||||
body.SalesDefaultAccountCode = updateFields.salesDefaultAccountCode as string;
|
||||
}
|
||||
|
||||
if (updateFields.skypeUserName) {
|
||||
body.SkypeUserName = updateFields.skypeUserName as string;
|
||||
}
|
||||
|
||||
if (updateFields.taxNumber) {
|
||||
body.taxNumber = updateFields.taxNumber as string;
|
||||
}
|
||||
|
||||
if (updateFields.xeroNetworkKey) {
|
||||
body.xeroNetworkKey = updateFields.xeroNetworkKey as string;
|
||||
}
|
||||
|
||||
if (phonesUi) {
|
||||
const phoneValues = phonesUi?.phonesValues as IDataObject[];
|
||||
if (phoneValues) {
|
||||
const phones: IPhone[] = [];
|
||||
for (const phoneValue of phoneValues) {
|
||||
const phone: IPhone = {};
|
||||
phone.PhoneType = phoneValue.phoneType as string;
|
||||
phone.PhoneNumber = phoneValue.phoneNumber as string;
|
||||
phone.PhoneAreaCode = phoneValue.phoneAreaCode as string;
|
||||
phone.PhoneCountryCode = phoneValue.phoneCountryCode as string;
|
||||
phones.push(phone);
|
||||
}
|
||||
body.Phones = phones;
|
||||
}
|
||||
}
|
||||
|
||||
if (addressesUi) {
|
||||
const addressValues = addressesUi?.addressesValues as IDataObject[];
|
||||
if (addressValues) {
|
||||
const addresses: IAddress[] = [];
|
||||
for (const addressValue of addressValues) {
|
||||
const address: IAddress = {};
|
||||
address.AddressType = addressValue.type as string;
|
||||
address.AddressLine1 = addressValue.line1 as string;
|
||||
address.AddressLine2 = addressValue.line2 as string;
|
||||
address.City = addressValue.city as string;
|
||||
address.Region = addressValue.region as string;
|
||||
address.PostalCode = addressValue.postalCode as string;
|
||||
address.Country = addressValue.country as string;
|
||||
address.AttentionTo = addressValue.attentionTo as string;
|
||||
addresses.push(address);
|
||||
}
|
||||
body.Addresses = addresses;
|
||||
}
|
||||
}
|
||||
|
||||
responseData = await xeroApiRequest.call(this, 'POST', `/Contacts/${contactId}`, {
|
||||
organizationId,
|
||||
Contacts: [body],
|
||||
});
|
||||
responseData = responseData.Contacts;
|
||||
}
|
||||
}
|
||||
const executionData = this.helpers.constructExecutionMetaData(
|
||||
this.helpers.returnJsonArray(responseData as IDataObject[]),
|
||||
{ itemData: { item: i } },
|
||||
);
|
||||
returnData.push(...executionData);
|
||||
} catch (error) {
|
||||
if (this.continueOnFail()) {
|
||||
returnData.push({ json: { error: (error as JsonObject).message } });
|
||||
continue;
|
||||
}
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
return [returnData];
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,76 @@
|
||||
{
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"Addresses": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"AddressType": {
|
||||
"type": "string"
|
||||
},
|
||||
"City": {
|
||||
"type": "string"
|
||||
},
|
||||
"Country": {
|
||||
"type": "string"
|
||||
},
|
||||
"PostalCode": {
|
||||
"type": "string"
|
||||
},
|
||||
"Region": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"BankAccountDetails": {
|
||||
"type": "string"
|
||||
},
|
||||
"ContactID": {
|
||||
"type": "string"
|
||||
},
|
||||
"ContactStatus": {
|
||||
"type": "string"
|
||||
},
|
||||
"EmailAddress": {
|
||||
"type": "string"
|
||||
},
|
||||
"HasValidationErrors": {
|
||||
"type": "boolean"
|
||||
},
|
||||
"IsCustomer": {
|
||||
"type": "boolean"
|
||||
},
|
||||
"IsSupplier": {
|
||||
"type": "boolean"
|
||||
},
|
||||
"Name": {
|
||||
"type": "string"
|
||||
},
|
||||
"Phones": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"PhoneAreaCode": {
|
||||
"type": "string"
|
||||
},
|
||||
"PhoneCountryCode": {
|
||||
"type": "string"
|
||||
},
|
||||
"PhoneNumber": {
|
||||
"type": "string"
|
||||
},
|
||||
"PhoneType": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"UpdatedDateUTC": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"version": 1
|
||||
}
|
||||
@@ -0,0 +1,122 @@
|
||||
{
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"Addresses": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"AddressLine1": {
|
||||
"type": "string"
|
||||
},
|
||||
"AddressType": {
|
||||
"type": "string"
|
||||
},
|
||||
"City": {
|
||||
"type": "string"
|
||||
},
|
||||
"Country": {
|
||||
"type": "string"
|
||||
},
|
||||
"PostalCode": {
|
||||
"type": "string"
|
||||
},
|
||||
"Region": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"BankAccountDetails": {
|
||||
"type": "string"
|
||||
},
|
||||
"ContactGroups": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"ContactGroupID": {
|
||||
"type": "string"
|
||||
},
|
||||
"HasValidationErrors": {
|
||||
"type": "boolean"
|
||||
},
|
||||
"Name": {
|
||||
"type": "string"
|
||||
},
|
||||
"Status": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"ContactID": {
|
||||
"type": "string"
|
||||
},
|
||||
"ContactPersons": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"EmailAddress": {
|
||||
"type": "string"
|
||||
},
|
||||
"FirstName": {
|
||||
"type": "string"
|
||||
},
|
||||
"IncludeInEmails": {
|
||||
"type": "boolean"
|
||||
},
|
||||
"LastName": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"ContactStatus": {
|
||||
"type": "string"
|
||||
},
|
||||
"EmailAddress": {
|
||||
"type": "string"
|
||||
},
|
||||
"HasAttachments": {
|
||||
"type": "boolean"
|
||||
},
|
||||
"HasValidationErrors": {
|
||||
"type": "boolean"
|
||||
},
|
||||
"IsCustomer": {
|
||||
"type": "boolean"
|
||||
},
|
||||
"IsSupplier": {
|
||||
"type": "boolean"
|
||||
},
|
||||
"Name": {
|
||||
"type": "string"
|
||||
},
|
||||
"Phones": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"PhoneAreaCode": {
|
||||
"type": "string"
|
||||
},
|
||||
"PhoneCountryCode": {
|
||||
"type": "string"
|
||||
},
|
||||
"PhoneNumber": {
|
||||
"type": "string"
|
||||
},
|
||||
"PhoneType": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"UpdatedDateUTC": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"version": 1
|
||||
}
|
||||
@@ -0,0 +1,79 @@
|
||||
{
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"Addresses": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"AddressType": {
|
||||
"type": "string"
|
||||
},
|
||||
"City": {
|
||||
"type": "string"
|
||||
},
|
||||
"Country": {
|
||||
"type": "string"
|
||||
},
|
||||
"PostalCode": {
|
||||
"type": "string"
|
||||
},
|
||||
"Region": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"BankAccountDetails": {
|
||||
"type": "string"
|
||||
},
|
||||
"ContactID": {
|
||||
"type": "string"
|
||||
},
|
||||
"ContactStatus": {
|
||||
"type": "string"
|
||||
},
|
||||
"EmailAddress": {
|
||||
"type": "string"
|
||||
},
|
||||
"HasAttachments": {
|
||||
"type": "boolean"
|
||||
},
|
||||
"HasValidationErrors": {
|
||||
"type": "boolean"
|
||||
},
|
||||
"IsCustomer": {
|
||||
"type": "boolean"
|
||||
},
|
||||
"IsSupplier": {
|
||||
"type": "boolean"
|
||||
},
|
||||
"Name": {
|
||||
"type": "string"
|
||||
},
|
||||
"Phones": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"PhoneAreaCode": {
|
||||
"type": "string"
|
||||
},
|
||||
"PhoneCountryCode": {
|
||||
"type": "string"
|
||||
},
|
||||
"PhoneNumber": {
|
||||
"type": "string"
|
||||
},
|
||||
"PhoneType": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"UpdatedDateUTC": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"version": 2
|
||||
}
|
||||
@@ -0,0 +1,186 @@
|
||||
{
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"AmountPaid": {
|
||||
"type": "integer"
|
||||
},
|
||||
"BrandingThemeID": {
|
||||
"type": "string"
|
||||
},
|
||||
"Contact": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"Addresses": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"AddressType": {
|
||||
"type": "string"
|
||||
},
|
||||
"City": {
|
||||
"type": "string"
|
||||
},
|
||||
"Country": {
|
||||
"type": "string"
|
||||
},
|
||||
"PostalCode": {
|
||||
"type": "string"
|
||||
},
|
||||
"Region": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"BankAccountDetails": {
|
||||
"type": "string"
|
||||
},
|
||||
"ContactGroups": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"ContactGroupID": {
|
||||
"type": "string"
|
||||
},
|
||||
"HasValidationErrors": {
|
||||
"type": "boolean"
|
||||
},
|
||||
"Name": {
|
||||
"type": "string"
|
||||
},
|
||||
"Status": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"ContactID": {
|
||||
"type": "string"
|
||||
},
|
||||
"ContactPersons": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"EmailAddress": {
|
||||
"type": "string"
|
||||
},
|
||||
"FirstName": {
|
||||
"type": "string"
|
||||
},
|
||||
"IncludeInEmails": {
|
||||
"type": "boolean"
|
||||
},
|
||||
"LastName": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"ContactStatus": {
|
||||
"type": "string"
|
||||
},
|
||||
"EmailAddress": {
|
||||
"type": "string"
|
||||
},
|
||||
"HasValidationErrors": {
|
||||
"type": "boolean"
|
||||
},
|
||||
"IsCustomer": {
|
||||
"type": "boolean"
|
||||
},
|
||||
"IsSupplier": {
|
||||
"type": "boolean"
|
||||
},
|
||||
"Name": {
|
||||
"type": "string"
|
||||
},
|
||||
"Phones": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"PhoneAreaCode": {
|
||||
"type": "string"
|
||||
},
|
||||
"PhoneCountryCode": {
|
||||
"type": "string"
|
||||
},
|
||||
"PhoneNumber": {
|
||||
"type": "string"
|
||||
},
|
||||
"PhoneType": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"UpdatedDateUTC": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
},
|
||||
"CurrencyCode": {
|
||||
"type": "string"
|
||||
},
|
||||
"CurrencyRate": {
|
||||
"type": "integer"
|
||||
},
|
||||
"Date": {
|
||||
"type": "string"
|
||||
},
|
||||
"DateString": {
|
||||
"type": "string"
|
||||
},
|
||||
"HasErrors": {
|
||||
"type": "boolean"
|
||||
},
|
||||
"InvoiceID": {
|
||||
"type": "string"
|
||||
},
|
||||
"InvoiceNumber": {
|
||||
"type": "string"
|
||||
},
|
||||
"IsDiscounted": {
|
||||
"type": "boolean"
|
||||
},
|
||||
"LineAmountTypes": {
|
||||
"type": "string"
|
||||
},
|
||||
"LineItems": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"Description": {
|
||||
"type": "string"
|
||||
},
|
||||
"LineItemID": {
|
||||
"type": "string"
|
||||
},
|
||||
"TaxType": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"Reference": {
|
||||
"type": "string"
|
||||
},
|
||||
"SentToContact": {
|
||||
"type": "boolean"
|
||||
},
|
||||
"Status": {
|
||||
"type": "string"
|
||||
},
|
||||
"Type": {
|
||||
"type": "string"
|
||||
},
|
||||
"UpdatedDateUTC": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"version": 1
|
||||
}
|
||||
@@ -0,0 +1,310 @@
|
||||
{
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"Attachments": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"AttachmentID": {
|
||||
"type": "string"
|
||||
},
|
||||
"ContentLength": {
|
||||
"type": "integer"
|
||||
},
|
||||
"FileName": {
|
||||
"type": "string"
|
||||
},
|
||||
"MimeType": {
|
||||
"type": "string"
|
||||
},
|
||||
"Url": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"BrandingThemeID": {
|
||||
"type": "string"
|
||||
},
|
||||
"Contact": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"AccountsReceivableTaxType": {
|
||||
"type": "string"
|
||||
},
|
||||
"Addresses": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"AddressLine1": {
|
||||
"type": "string"
|
||||
},
|
||||
"AddressType": {
|
||||
"type": "string"
|
||||
},
|
||||
"City": {
|
||||
"type": "string"
|
||||
},
|
||||
"Country": {
|
||||
"type": "string"
|
||||
},
|
||||
"PostalCode": {
|
||||
"type": "string"
|
||||
},
|
||||
"Region": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"BankAccountDetails": {
|
||||
"type": "string"
|
||||
},
|
||||
"ContactGroups": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"ContactGroupID": {
|
||||
"type": "string"
|
||||
},
|
||||
"HasValidationErrors": {
|
||||
"type": "boolean"
|
||||
},
|
||||
"Name": {
|
||||
"type": "string"
|
||||
},
|
||||
"Status": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"ContactID": {
|
||||
"type": "string"
|
||||
},
|
||||
"ContactPersons": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"EmailAddress": {
|
||||
"type": "string"
|
||||
},
|
||||
"FirstName": {
|
||||
"type": "string"
|
||||
},
|
||||
"IncludeInEmails": {
|
||||
"type": "boolean"
|
||||
},
|
||||
"LastName": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"ContactStatus": {
|
||||
"type": "string"
|
||||
},
|
||||
"DefaultCurrency": {
|
||||
"type": "string"
|
||||
},
|
||||
"EmailAddress": {
|
||||
"type": "string"
|
||||
},
|
||||
"FirstName": {
|
||||
"type": "string"
|
||||
},
|
||||
"HasValidationErrors": {
|
||||
"type": "boolean"
|
||||
},
|
||||
"IsCustomer": {
|
||||
"type": "boolean"
|
||||
},
|
||||
"IsSupplier": {
|
||||
"type": "boolean"
|
||||
},
|
||||
"LastName": {
|
||||
"type": "string"
|
||||
},
|
||||
"Name": {
|
||||
"type": "string"
|
||||
},
|
||||
"Phones": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"PhoneAreaCode": {
|
||||
"type": "string"
|
||||
},
|
||||
"PhoneCountryCode": {
|
||||
"type": "string"
|
||||
},
|
||||
"PhoneNumber": {
|
||||
"type": "string"
|
||||
},
|
||||
"PhoneType": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"PurchasesTrackingCategories": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"TrackingCategoryName": {
|
||||
"type": "string"
|
||||
},
|
||||
"TrackingOptionName": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"SalesTrackingCategories": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"TrackingCategoryName": {
|
||||
"type": "string"
|
||||
},
|
||||
"TrackingOptionName": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"UpdatedDateUTC": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
},
|
||||
"CurrencyCode": {
|
||||
"type": "string"
|
||||
},
|
||||
"Date": {
|
||||
"type": "string"
|
||||
},
|
||||
"DateString": {
|
||||
"type": "string"
|
||||
},
|
||||
"DueDate": {
|
||||
"type": "string"
|
||||
},
|
||||
"DueDateString": {
|
||||
"type": "string"
|
||||
},
|
||||
"HasAttachments": {
|
||||
"type": "boolean"
|
||||
},
|
||||
"HasErrors": {
|
||||
"type": "boolean"
|
||||
},
|
||||
"InvoiceID": {
|
||||
"type": "string"
|
||||
},
|
||||
"InvoiceNumber": {
|
||||
"type": "string"
|
||||
},
|
||||
"IsDiscounted": {
|
||||
"type": "boolean"
|
||||
},
|
||||
"LineAmountTypes": {
|
||||
"type": "string"
|
||||
},
|
||||
"LineItems": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"AccountCode": {
|
||||
"type": "string"
|
||||
},
|
||||
"AccountID": {
|
||||
"type": "string"
|
||||
},
|
||||
"Description": {
|
||||
"type": "string"
|
||||
},
|
||||
"LineItemID": {
|
||||
"type": "string"
|
||||
},
|
||||
"TaxType": {
|
||||
"type": "string"
|
||||
},
|
||||
"Tracking": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"Name": {
|
||||
"type": "string"
|
||||
},
|
||||
"Option": {
|
||||
"type": "string"
|
||||
},
|
||||
"TrackingCategoryID": {
|
||||
"type": "string"
|
||||
},
|
||||
"TrackingOptionID": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"Overpayments": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"AppliedAmount": {
|
||||
"type": "number"
|
||||
},
|
||||
"CurrencyRate": {
|
||||
"type": "integer"
|
||||
},
|
||||
"Date": {
|
||||
"type": "string"
|
||||
},
|
||||
"DateString": {
|
||||
"type": "string"
|
||||
},
|
||||
"OverpaymentID": {
|
||||
"type": "string"
|
||||
},
|
||||
"Total": {
|
||||
"type": "number"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"Reference": {
|
||||
"type": "string"
|
||||
},
|
||||
"SentToContact": {
|
||||
"type": "boolean"
|
||||
},
|
||||
"Status": {
|
||||
"type": "string"
|
||||
},
|
||||
"Type": {
|
||||
"type": "string"
|
||||
},
|
||||
"UpdatedDateUTC": {
|
||||
"type": "string"
|
||||
},
|
||||
"Url": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"version": 1
|
||||
}
|
||||
@@ -0,0 +1,197 @@
|
||||
{
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"BrandingThemeID": {
|
||||
"type": "string"
|
||||
},
|
||||
"Contact": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"ContactID": {
|
||||
"type": "string"
|
||||
},
|
||||
"HasValidationErrors": {
|
||||
"type": "boolean"
|
||||
},
|
||||
"Name": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
},
|
||||
"CreditNotes": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"CreditNoteID": {
|
||||
"type": "string"
|
||||
},
|
||||
"CreditNoteNumber": {
|
||||
"type": "string"
|
||||
},
|
||||
"Date": {
|
||||
"type": "string"
|
||||
},
|
||||
"DateString": {
|
||||
"type": "string"
|
||||
},
|
||||
"HasErrors": {
|
||||
"type": "boolean"
|
||||
},
|
||||
"ID": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"CurrencyCode": {
|
||||
"type": "string"
|
||||
},
|
||||
"Date": {
|
||||
"type": "string"
|
||||
},
|
||||
"DateString": {
|
||||
"type": "string"
|
||||
},
|
||||
"DueDate": {
|
||||
"type": "string"
|
||||
},
|
||||
"DueDateString": {
|
||||
"type": "string"
|
||||
},
|
||||
"HasAttachments": {
|
||||
"type": "boolean"
|
||||
},
|
||||
"HasErrors": {
|
||||
"type": "boolean"
|
||||
},
|
||||
"InvoiceID": {
|
||||
"type": "string"
|
||||
},
|
||||
"InvoiceNumber": {
|
||||
"type": "string"
|
||||
},
|
||||
"IsDiscounted": {
|
||||
"type": "boolean"
|
||||
},
|
||||
"LineAmountTypes": {
|
||||
"type": "string"
|
||||
},
|
||||
"LineItems": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"AccountCode": {
|
||||
"type": "string"
|
||||
},
|
||||
"AccountID": {
|
||||
"type": "string"
|
||||
},
|
||||
"Description": {
|
||||
"type": "string"
|
||||
},
|
||||
"Item": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"Code": {
|
||||
"type": "string"
|
||||
},
|
||||
"ItemID": {
|
||||
"type": "string"
|
||||
},
|
||||
"Name": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
},
|
||||
"ItemCode": {
|
||||
"type": "string"
|
||||
},
|
||||
"LineItemID": {
|
||||
"type": "string"
|
||||
},
|
||||
"TaxType": {
|
||||
"type": "string"
|
||||
},
|
||||
"Tracking": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"Name": {
|
||||
"type": "string"
|
||||
},
|
||||
"Option": {
|
||||
"type": "string"
|
||||
},
|
||||
"TrackingCategoryID": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"Overpayments": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"AppliedAmount": {
|
||||
"type": "integer"
|
||||
},
|
||||
"Date": {
|
||||
"type": "string"
|
||||
},
|
||||
"DateString": {
|
||||
"type": "string"
|
||||
},
|
||||
"OverpaymentID": {
|
||||
"type": "string"
|
||||
},
|
||||
"Total": {
|
||||
"type": "integer"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"Payments": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"Date": {
|
||||
"type": "string"
|
||||
},
|
||||
"HasAccount": {
|
||||
"type": "boolean"
|
||||
},
|
||||
"HasValidationErrors": {
|
||||
"type": "boolean"
|
||||
},
|
||||
"Reference": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"Reference": {
|
||||
"type": "string"
|
||||
},
|
||||
"SentToContact": {
|
||||
"type": "boolean"
|
||||
},
|
||||
"Status": {
|
||||
"type": "string"
|
||||
},
|
||||
"Type": {
|
||||
"type": "string"
|
||||
},
|
||||
"UpdatedDateUTC": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"version": 1
|
||||
}
|
||||
@@ -0,0 +1,178 @@
|
||||
{
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"AmountPaid": {
|
||||
"type": "integer"
|
||||
},
|
||||
"BrandingThemeID": {
|
||||
"type": "string"
|
||||
},
|
||||
"Contact": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"Addresses": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"AddressType": {
|
||||
"type": "string"
|
||||
},
|
||||
"City": {
|
||||
"type": "string"
|
||||
},
|
||||
"Country": {
|
||||
"type": "string"
|
||||
},
|
||||
"PostalCode": {
|
||||
"type": "string"
|
||||
},
|
||||
"Region": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"BankAccountDetails": {
|
||||
"type": "string"
|
||||
},
|
||||
"ContactID": {
|
||||
"type": "string"
|
||||
},
|
||||
"ContactStatus": {
|
||||
"type": "string"
|
||||
},
|
||||
"EmailAddress": {
|
||||
"type": "string"
|
||||
},
|
||||
"HasValidationErrors": {
|
||||
"type": "boolean"
|
||||
},
|
||||
"IsCustomer": {
|
||||
"type": "boolean"
|
||||
},
|
||||
"IsSupplier": {
|
||||
"type": "boolean"
|
||||
},
|
||||
"Name": {
|
||||
"type": "string"
|
||||
},
|
||||
"Phones": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"PhoneAreaCode": {
|
||||
"type": "string"
|
||||
},
|
||||
"PhoneCountryCode": {
|
||||
"type": "string"
|
||||
},
|
||||
"PhoneNumber": {
|
||||
"type": "string"
|
||||
},
|
||||
"PhoneType": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"UpdatedDateUTC": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
},
|
||||
"CurrencyCode": {
|
||||
"type": "string"
|
||||
},
|
||||
"CurrencyRate": {
|
||||
"type": "integer"
|
||||
},
|
||||
"Date": {
|
||||
"type": "string"
|
||||
},
|
||||
"DateString": {
|
||||
"type": "string"
|
||||
},
|
||||
"DueDate": {
|
||||
"type": "string"
|
||||
},
|
||||
"DueDateString": {
|
||||
"type": "string"
|
||||
},
|
||||
"HasErrors": {
|
||||
"type": "boolean"
|
||||
},
|
||||
"InvoiceID": {
|
||||
"type": "string"
|
||||
},
|
||||
"InvoiceNumber": {
|
||||
"type": "string"
|
||||
},
|
||||
"IsDiscounted": {
|
||||
"type": "boolean"
|
||||
},
|
||||
"LineAmountTypes": {
|
||||
"type": "string"
|
||||
},
|
||||
"LineItems": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"AccountCode": {
|
||||
"type": "string"
|
||||
},
|
||||
"AccountID": {
|
||||
"type": "string"
|
||||
},
|
||||
"Description": {
|
||||
"type": "string"
|
||||
},
|
||||
"Item": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"Code": {
|
||||
"type": "string"
|
||||
},
|
||||
"ItemID": {
|
||||
"type": "string"
|
||||
},
|
||||
"Name": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
},
|
||||
"ItemCode": {
|
||||
"type": "string"
|
||||
},
|
||||
"LineItemID": {
|
||||
"type": "string"
|
||||
},
|
||||
"Quantity": {
|
||||
"type": "integer"
|
||||
},
|
||||
"TaxType": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"Reference": {
|
||||
"type": "string"
|
||||
},
|
||||
"SentToContact": {
|
||||
"type": "boolean"
|
||||
},
|
||||
"Status": {
|
||||
"type": "string"
|
||||
},
|
||||
"Type": {
|
||||
"type": "string"
|
||||
},
|
||||
"UpdatedDateUTC": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"version": 1
|
||||
}
|
||||
@@ -0,0 +1,79 @@
|
||||
import { mock, mockDeep } from 'jest-mock-extended';
|
||||
import type { ILoadOptionsFunctions, INode } from 'n8n-workflow';
|
||||
|
||||
import { Xero } from '../Xero.node';
|
||||
|
||||
describe('Xero Node', () => {
|
||||
describe('loadOptions', () => {
|
||||
describe('getCurrencies', () => {
|
||||
it('should return currencies with description as display name and code as value', async () => {
|
||||
// Setup mock
|
||||
const xero = new Xero();
|
||||
const loadOptionsFunctions = mockDeep<ILoadOptionsFunctions>();
|
||||
|
||||
loadOptionsFunctions.getNode.mockReturnValue(mock<INode>());
|
||||
loadOptionsFunctions.getCurrentNodeParameter.mockReturnValue('test-org-id');
|
||||
|
||||
// Mock Xero API response via requestOAuth2
|
||||
loadOptionsFunctions.helpers.requestOAuth2.mockResolvedValue({
|
||||
Currencies: [
|
||||
{
|
||||
Code: 'EUR',
|
||||
Description: 'Euro',
|
||||
},
|
||||
{
|
||||
Code: 'GBP',
|
||||
Description: 'British Pound',
|
||||
},
|
||||
{
|
||||
Code: 'USD',
|
||||
Description: 'US Dollar',
|
||||
},
|
||||
],
|
||||
});
|
||||
|
||||
// Call getCurrencies
|
||||
const result = await xero.methods.loadOptions.getCurrencies.call(loadOptionsFunctions);
|
||||
|
||||
// Verify dropdown shows description but sends code
|
||||
expect(result).toEqual([
|
||||
{ name: 'Euro', value: 'EUR' },
|
||||
{ name: 'British Pound', value: 'GBP' },
|
||||
{ name: 'US Dollar', value: 'USD' },
|
||||
]);
|
||||
|
||||
// Verify API was called correctly
|
||||
expect(loadOptionsFunctions.helpers.requestOAuth2).toHaveBeenCalledWith(
|
||||
'xeroOAuth2Api',
|
||||
expect.objectContaining({
|
||||
method: 'GET',
|
||||
uri: 'https://api.xero.com/api.xro/2.0/Currencies',
|
||||
headers: expect.objectContaining({
|
||||
'Xero-tenant-id': 'test-org-id',
|
||||
}),
|
||||
}),
|
||||
);
|
||||
});
|
||||
|
||||
it('should handle empty currency list', async () => {
|
||||
// Setup mock
|
||||
const xero = new Xero();
|
||||
const loadOptionsFunctions = mockDeep<ILoadOptionsFunctions>();
|
||||
|
||||
loadOptionsFunctions.getNode.mockReturnValue(mock<INode>());
|
||||
loadOptionsFunctions.getCurrentNodeParameter.mockReturnValue('test-org-id');
|
||||
|
||||
// Mock empty response via requestOAuth2
|
||||
loadOptionsFunctions.helpers.requestOAuth2.mockResolvedValue({
|
||||
Currencies: [],
|
||||
});
|
||||
|
||||
// Call getCurrencies
|
||||
const result = await xero.methods.loadOptions.getCurrencies.call(loadOptionsFunctions);
|
||||
|
||||
// Verify returns empty array
|
||||
expect(result).toEqual([]);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="60" height="60"><g fill="none" fill-rule="evenodd" stroke-linecap="round" stroke-linejoin="round"><path fill="#00B2D5" d="M30 59.538c16.336 0 29.538-13.202 29.538-29.538S46.336.462 30 .462.462 13.664.462 30 13.664 59.538 30 59.538"/><path fill="#FFF" d="m14.588 29.908 5.035-5.035a.95.95 0 0 0 .256-.616.92.92 0 0 0-.925-.925c-.256 0-.461.092-.667.256l-5.034 5.035-5.035-5.035a.95.95 0 0 0-.616-.256.92.92 0 0 0-.925.925c0 .256.092.461.256.667l5.035 5.034-5.045 5.027c-.206.154-.257.41-.257.667 0 .514.411.925.925.925a.85.85 0 0 0 .617-.257l5.034-5.034 5.035 5.034a.85.85 0 0 0 .667.257.92.92 0 0 0 .925-.925.85.85 0 0 0-.256-.617zm29.95 0c0 .925.72 1.643 1.644 1.643s1.643-.72 1.643-1.643-.72-1.643-1.643-1.643c-.874 0-1.644.77-1.644 1.643m-4.984 0a6.646 6.646 0 0 0 6.627 6.626 6.646 6.646 0 0 0 6.626-6.626 6.646 6.646 0 0 0-6.626-6.627 6.646 6.646 0 0 0-6.627 6.627m1.901 0a4.77 4.77 0 0 1 4.778-4.778 4.77 4.77 0 0 1 4.778 4.778 4.735 4.735 0 0 1-4.778 4.778 4.77 4.77 0 0 1-4.778-4.778m-2.363-6.474h-.256a3.78 3.78 0 0 0-2.312.77c-.092-.41-.461-.72-.873-.72a.865.865 0 0 0-.873.874v11.148c0 .514.41.925.925.925a.92.92 0 0 0 .925-.925v-6.832c0-2.262.206-3.185 2.157-3.444h.37c.513 0 .924-.369.924-.873-.052-.565-.461-.925-.976-.925zm-6.215 5.23c-.41-1.849-1.387-3.338-2.928-4.315-2.261-1.438-5.24-1.336-7.397.206-1.747 1.233-2.774 3.339-2.774 5.446 0 .514.052 1.08.206 1.592.667 2.62 2.928 4.616 5.6 4.932a6.1 6.1 0 0 0 2.362-.154 7.2 7.2 0 0 0 2.003-.83c.668-.411 1.182-.976 1.696-1.593l.052-.052c.369-.461.308-1.08-.093-1.387-.308-.257-.873-.37-1.335.206-.093.154-.206.256-.309.41a5.4 5.4 0 0 1-1.292 1.08 4.6 4.6 0 0 1-2.209.565c-2.62-.051-4.006-1.848-4.52-3.184a5.4 5.4 0 0 1-.206-.77v-.155h9.452c1.233-.052 1.902-.976 1.696-2.003zm-11.095.154v-.092c.514-2.055 2.415-3.596 4.615-3.596 2.262 0 4.161 1.592 4.675 3.699z"/><path fill="#00B2D5" d="M29.538 59.077c16.336 0 29.539-13.203 29.539-29.539C59.077 13.203 45.874 0 29.538 0 13.203 0 0 13.203 0 29.538s13.203 29.539 29.538 29.539"/><path fill="#FFF" d="m14.127 29.446 5.034-5.034a.95.95 0 0 0 .257-.617.92.92 0 0 0-.925-.925c-.257 0-.462.092-.667.257L12.79 28.16l-5.034-5.034a.95.95 0 0 0-.617-.257.92.92 0 0 0-.925.925c0 .257.092.462.257.667l5.034 5.035-5.044 5.026c-.206.154-.257.41-.257.667 0 .515.41.925.925.925a.85.85 0 0 0 .616-.256l5.035-5.035 5.034 5.035a.85.85 0 0 0 .668.256.92.92 0 0 0 .925-.925.85.85 0 0 0-.257-.616l-5.024-5.128zm29.95 0c0 .925.72 1.643 1.643 1.643s1.643-.72 1.643-1.643-.72-1.643-1.643-1.643c-.873 0-1.643.77-1.643 1.643m-4.985 0a6.646 6.646 0 0 0 6.627 6.627 6.646 6.646 0 0 0 6.627-6.627 6.646 6.646 0 0 0-6.627-6.627 6.646 6.646 0 0 0-6.627 6.627m1.902 0a4.77 4.77 0 0 1 4.778-4.778 4.77 4.77 0 0 1 4.778 4.778 4.735 4.735 0 0 1-4.778 4.778 4.77 4.77 0 0 1-4.778-4.778m-2.363-6.473h-.257c-.83 0-1.643.256-2.311.77-.093-.41-.462-.72-.873-.72a.865.865 0 0 0-.874.874v11.148c0 .514.411.925.925.925a.92.92 0 0 0 .925-.925v-6.833c0-2.262.206-3.185 2.157-3.443h.37c.514 0 .925-.37.925-.873-.052-.565-.462-.925-.976-.925zm-6.215 5.23c-.411-1.85-1.388-3.339-2.928-4.316-2.262-1.438-5.24-1.335-7.398.206-1.746 1.233-2.774 3.339-2.774 5.446 0 .515.052 1.08.206 1.593.668 2.62 2.928 4.615 5.6 4.932.79.104 1.593.051 2.363-.154a7.2 7.2 0 0 0 2.003-.831c.667-.411 1.181-.976 1.695-1.593l.052-.051c.37-.462.308-1.08-.092-1.388-.309-.256-.873-.369-1.336.206-.092.154-.206.257-.308.411-.37.41-.771.77-1.293 1.08a4.6 4.6 0 0 1-2.208.565c-2.62-.052-4.007-1.849-4.52-3.185a5.4 5.4 0 0 1-.207-.77v-.155h9.453c1.233-.051 1.901-.975 1.695-2.003zm-11.096.154v-.092c.514-2.055 2.415-3.597 4.616-3.597 2.261 0 4.16 1.593 4.674 3.7z"/></g></svg>
|
||||
|
After Width: | Height: | Size: 3.6 KiB |
Reference in New Issue
Block a user