mirror of
https://github.com/n8n-io/n8n.git
synced 2025-01-11 12:57:29 -08:00
⚡ 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:
parent
224a26c922
commit
91a5bc3bc4
|
@ -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',
|
||||
|
|
|
@ -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: {
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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[];
|
|
@ -6,3 +6,4 @@ export * from './Invoice/InvoiceDescription';
|
|||
export * from './Item/ItemDescription';
|
||||
export * from './Payment/PaymentDescription';
|
||||
export * from './Vendor/VendorDescription';
|
||||
export * from './Purchase/PurchaseDescription';
|
||||
|
|
8
packages/nodes-base/nodes/QuickBooks/types.d.ts
vendored
Normal file
8
packages/nodes-base/nodes/QuickBooks/types.d.ts
vendored
Normal file
|
@ -0,0 +1,8 @@
|
|||
export type QuickBooksOAuth2Credentials = {
|
||||
environment: 'production' | 'sandbox';
|
||||
oauthTokenData: {
|
||||
callbackQueryString: {
|
||||
realmId: string;
|
||||
}
|
||||
};
|
||||
};
|
Loading…
Reference in a new issue