Separate scopes and add purchase operations to QuickBooks node (#1859)

* allow qbo to use accounting or payment scopes separately

* added purchase get and getall

* removed irrelevant field options

*  Sort alphabetically

* 🔥 Remove unused file

* ✏️ Fix description casing

*  Add credentials type

* ✏️ Fix resource dividers

* 🔨 Format import

* ✏️ Fix documentation link

*  Refactor credentials

*  Use multiOptions for scopes

* 🔥 Remove payment scope

The payment scope is used only by the QuickBooks Payments API, but this node implements the QuickBooks Online API, which only needs the accounting scope.

* 🚚 Rename node to QuickBooks Online

This reflects the specific API implemented in this node and allows for a future QuickBooks Payments node. Until node versioning is released, only display name changed.

Co-authored-by: Calvin Tan <calvin14@gmail.com>
This commit is contained in:
Iván Ovejero 2021-06-27 13:21:11 +02:00 committed by GitHub
parent 224a26c922
commit 91a5bc3bc4
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
6 changed files with 206 additions and 22 deletions

View file

@ -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',

View file

@ -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: {

View file

@ -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);

View file

@ -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 <a href="https://developer.intuit.com/app/developer/qbo/docs/develop/explore-the-quickbooks-online-api/data-queries" target="_blank">guide</a> for supported syntax.',
typeOptions: {
alwaysOpenEditWindow: true,
},
},
],
displayOptions: {
show: {
resource: [
'purchase',
],
operation: [
'getAll',
],
},
},
},
] as INodeProperties[];

View file

@ -6,3 +6,4 @@ export * from './Invoice/InvoiceDescription';
export * from './Item/ItemDescription';
export * from './Payment/PaymentDescription';
export * from './Vendor/VendorDescription';
export * from './Purchase/PurchaseDescription';

View file

@ -0,0 +1,8 @@
export type QuickBooksOAuth2Credentials = {
environment: 'production' | 'sandbox';
oauthTokenData: {
callbackQueryString: {
realmId: string;
}
};
};