diff --git a/packages/nodes-base/credentials/QuickBooksOAuth2Api.credentials.ts b/packages/nodes-base/credentials/QuickBooksOAuth2Api.credentials.ts index 32c808adfe..d1683dea49 100644 --- a/packages/nodes-base/credentials/QuickBooksOAuth2Api.credentials.ts +++ b/packages/nodes-base/credentials/QuickBooksOAuth2Api.credentials.ts @@ -3,11 +3,6 @@ import { INodeProperties, } from 'n8n-workflow'; -const scopes = [ - 'com.intuit.quickbooks.accounting', - 'com.intuit.quickbooks.payment', -]; - // https://developer.intuit.com/app/developer/qbo/docs/develop/authentication-and-authorization export class QuickBooksOAuth2Api implements ICredentialType { @@ -15,7 +10,7 @@ export class QuickBooksOAuth2Api implements ICredentialType { extends = [ 'oAuth2Api', ]; - displayName = 'QuickBooks OAuth2 API'; + displayName = 'QuickBooks Online OAuth2 API'; documentationUrl = 'quickbooks'; properties: INodeProperties[] = [ { @@ -34,7 +29,7 @@ export class QuickBooksOAuth2Api implements ICredentialType { displayName: 'Scope', name: 'scope', type: 'hidden', - default: scopes.join(' '), + default: 'com.intuit.quickbooks.accounting', }, { displayName: 'Auth URI Query Parameters', diff --git a/packages/nodes-base/nodes/QuickBooks/GenericFunctions.ts b/packages/nodes-base/nodes/QuickBooks/GenericFunctions.ts index 3d9953a216..44a7bc5d04 100644 --- a/packages/nodes-base/nodes/QuickBooks/GenericFunctions.ts +++ b/packages/nodes-base/nodes/QuickBooks/GenericFunctions.ts @@ -29,6 +29,10 @@ import { OptionsWithUri, } from 'request'; +import { + QuickBooksOAuth2Credentials, +} from './types'; + /** * Make an authenticated API request to QuickBooks. */ @@ -53,7 +57,7 @@ export async function quickBooksApiRequest( const productionUrl = 'https://quickbooks.api.intuit.com'; const sandboxUrl = 'https://sandbox-quickbooks.api.intuit.com'; - const credentials = this.getCredentials('quickBooksOAuth2Api') as IDataObject; + const credentials = this.getCredentials('quickBooksOAuth2Api') as QuickBooksOAuth2Credentials; const options: OptionsWithUri = { headers: { diff --git a/packages/nodes-base/nodes/QuickBooks/QuickBooks.node.ts b/packages/nodes-base/nodes/QuickBooks/QuickBooks.node.ts index 98645002ee..9f3ad7a81d 100644 --- a/packages/nodes-base/nodes/QuickBooks/QuickBooks.node.ts +++ b/packages/nodes-base/nodes/QuickBooks/QuickBooks.node.ts @@ -26,6 +26,8 @@ import { itemOperations, paymentFields, paymentOperations, + purchaseFields, + purchaseOperations, vendorFields, vendorOperations, } from './descriptions'; @@ -49,17 +51,21 @@ import { isEmpty, } from 'lodash'; +import { + QuickBooksOAuth2Credentials, +} from './types'; + export class QuickBooks implements INodeType { description: INodeTypeDescription = { - displayName: 'QuickBooks', + displayName: 'QuickBooks Online', name: 'quickbooks', icon: 'file:quickbooks.svg', group: ['transform'], version: 1, subtitle: '={{$parameter["operation"] + ": " + $parameter["resource"]}}', - description: 'Consume the QuickBooks API', + description: 'Consume the QuickBooks Online API', defaults: { - name: 'QuickBooks', + name: 'QuickBooks Online', color: '#2CA01C', }, inputs: ['main'], @@ -104,6 +110,10 @@ export class QuickBooks implements INodeType { name: 'Payment', value: 'payment', }, + { + name: 'Purchase', + value: 'purchase', + }, { name: 'Vendor', value: 'vendor', @@ -126,6 +136,8 @@ export class QuickBooks implements INodeType { ...itemFields, ...paymentOperations, ...paymentFields, + ...purchaseOperations, + ...purchaseFields, ...vendorOperations, ...vendorFields, ], @@ -145,6 +157,10 @@ export class QuickBooks implements INodeType { return await loadResource.call(this, 'item'); }, + async getPurchases(this: ILoadOptionsFunctions) { + return await loadResource.call(this, 'purchase'); + }, + async getVendors(this: ILoadOptionsFunctions) { return await loadResource.call(this, 'vendor'); }, @@ -160,8 +176,8 @@ export class QuickBooks implements INodeType { let responseData; const returnData: IDataObject[] = []; - const { oauthTokenData } = this.getCredentials('quickBooksOAuth2Api') as IDataObject; - // @ts-ignore + const { oauthTokenData } = this.getCredentials('quickBooksOAuth2Api') as QuickBooksOAuth2Credentials; + const companyId = oauthTokenData.callbackQueryString.realmId; for (let i = 0; i < items.length; i++) { @@ -169,10 +185,10 @@ export class QuickBooks implements INodeType { if (resource === 'bill') { // ********************************************************************* - // bill + // bill // ********************************************************************* - // https://developer.intuit.com/app/developer/qbo/docs/api/accounting/most-commonly-used/estimate + // https://developer.intuit.com/app/developer/qbo/docs/api/accounting/most-commonly-used/bill if (operation === 'create') { @@ -288,7 +304,7 @@ export class QuickBooks implements INodeType { } else if (resource === 'customer') { // ********************************************************************* - // customer + // customer // ********************************************************************* // https://developer.intuit.com/app/developer/qbo/docs/api/accounting/most-commonly-used/customer @@ -360,7 +376,7 @@ export class QuickBooks implements INodeType { } else if (resource === 'employee') { // ********************************************************************* - // employee + // employee // ********************************************************************* if (operation === 'create') { @@ -431,7 +447,7 @@ export class QuickBooks implements INodeType { } else if (resource === 'estimate') { // ********************************************************************* - // estimate + // estimate // ********************************************************************* // https://developer.intuit.com/app/developer/qbo/docs/api/accounting/most-commonly-used/estimate @@ -574,7 +590,7 @@ export class QuickBooks implements INodeType { } else if (resource === 'invoice') { // ********************************************************************* - // invoice + // invoice // ********************************************************************* // https://developer.intuit.com/app/developer/qbo/docs/api/accounting/most-commonly-used/invoice @@ -733,7 +749,7 @@ export class QuickBooks implements INodeType { } else if (resource === 'item') { // ********************************************************************* - // item + // item // ********************************************************************* // https://developer.intuit.com/app/developer/qbo/docs/api/accounting/most-commonly-used/item @@ -763,7 +779,7 @@ export class QuickBooks implements INodeType { } else if (resource === 'payment') { // ********************************************************************* - // payment + // payment // ********************************************************************* // https://developer.intuit.com/app/developer/qbo/docs/api/accounting/most-commonly-used/payment @@ -902,10 +918,40 @@ export class QuickBooks implements INodeType { } + } else if (resource === 'purchase') { + + // ********************************************************************* + // purchase + // ********************************************************************* + + // https://developer.intuit.com/app/developer/qbo/docs/api/accounting/all-entities/purchase + + if (operation === 'get') { + + // ---------------------------------- + // purchase: get + // ---------------------------------- + + const purchaseId = this.getNodeParameter('purchaseId', i); + const endpoint = `/v3/company/${companyId}/${resource}/${purchaseId}`; + responseData = await quickBooksApiRequest.call(this, 'GET', endpoint, {}, {}); + responseData = responseData[capitalCase(resource)]; + + } else if (operation === 'getAll') { + + // ---------------------------------- + // purchase: getAll + // ---------------------------------- + + const endpoint = `/v3/company/${companyId}/query`; + responseData = await handleListing.call(this, i, endpoint, resource); + + } + } else if (resource === 'vendor') { // ********************************************************************* - // vendor + // vendor // ********************************************************************* // https://developer.intuit.com/app/developer/qbo/docs/api/accounting/most-commonly-used/vendor @@ -975,6 +1021,7 @@ export class QuickBooks implements INodeType { } } + Array.isArray(responseData) ? returnData.push(...responseData) : returnData.push(responseData); diff --git a/packages/nodes-base/nodes/QuickBooks/descriptions/Purchase/PurchaseDescription.ts b/packages/nodes-base/nodes/QuickBooks/descriptions/Purchase/PurchaseDescription.ts new file mode 100644 index 0000000000..f4491dae1b --- /dev/null +++ b/packages/nodes-base/nodes/QuickBooks/descriptions/Purchase/PurchaseDescription.ts @@ -0,0 +1,129 @@ +import { + INodeProperties, +} from 'n8n-workflow'; + +export const purchaseOperations = [ + { + displayName: 'Operation', + name: 'operation', + type: 'options', + default: 'get', + description: 'Operation to perform', + options: [ + { + name: 'Get', + value: 'get', + }, + { + name: 'Get All', + value: 'getAll', + }, + ], + displayOptions: { + show: { + resource: [ + 'purchase', + ], + }, + }, + }, +] as INodeProperties[]; + +export const purchaseFields = [ + // ---------------------------------- + // purchase: get + // ---------------------------------- + { + displayName: 'Purchase ID', + name: 'purchaseId', + type: 'string', + required: true, + default: '', + description: 'The ID of the purchase to retrieve.', + displayOptions: { + show: { + resource: [ + 'purchase', + ], + operation: [ + 'get', + ], + }, + }, + }, + + // ---------------------------------- + // purchase: getAll + // ---------------------------------- + { + displayName: 'Return All', + name: 'returnAll', + type: 'boolean', + default: false, + description: 'Return all results.', + displayOptions: { + show: { + resource: [ + 'purchase', + ], + operation: [ + 'getAll', + ], + }, + }, + }, + { + displayName: 'Limit', + name: 'limit', + type: 'number', + default: 5, + description: 'The number of results to return.', + typeOptions: { + minValue: 1, + maxValue: 1000, + }, + displayOptions: { + show: { + resource: [ + 'purchase', + ], + operation: [ + 'getAll', + ], + returnAll: [ + false, + ], + }, + }, + }, + { + displayName: 'Filters', + name: 'filters', + type: 'collection', + placeholder: 'Add Field', + default: {}, + options: [ + { + displayName: 'Query', + name: 'query', + type: 'string', + default: '', + placeholder: 'WHERE Metadata.LastUpdatedTime > \'2021-01-01\'', + description: 'The condition for selecting purchases. See the guide for supported syntax.', + typeOptions: { + alwaysOpenEditWindow: true, + }, + }, + ], + displayOptions: { + show: { + resource: [ + 'purchase', + ], + operation: [ + 'getAll', + ], + }, + }, + }, +] as INodeProperties[]; diff --git a/packages/nodes-base/nodes/QuickBooks/descriptions/index.ts b/packages/nodes-base/nodes/QuickBooks/descriptions/index.ts index d8573f7223..58d4d48173 100644 --- a/packages/nodes-base/nodes/QuickBooks/descriptions/index.ts +++ b/packages/nodes-base/nodes/QuickBooks/descriptions/index.ts @@ -6,3 +6,4 @@ export * from './Invoice/InvoiceDescription'; export * from './Item/ItemDescription'; export * from './Payment/PaymentDescription'; export * from './Vendor/VendorDescription'; +export * from './Purchase/PurchaseDescription'; diff --git a/packages/nodes-base/nodes/QuickBooks/types.d.ts b/packages/nodes-base/nodes/QuickBooks/types.d.ts new file mode 100644 index 0000000000..0145bf65af --- /dev/null +++ b/packages/nodes-base/nodes/QuickBooks/types.d.ts @@ -0,0 +1,8 @@ +export type QuickBooksOAuth2Credentials = { + environment: 'production' | 'sandbox'; + oauthTokenData: { + callbackQueryString: { + realmId: string; + } + }; +};