n8n/packages/nodes-base/nodes/QuickBooks/QuickBooks.node.ts
Omar Ajoue 7ce7285f7a
Load credentials from the database (#1741)
* Changes to types so that credentials can be always loaded from DB

This first commit changes all return types from the execute functions
and calls to get credentials to be async so we can use await.

This is a first step as previously credentials were loaded in memory and
always available. We will now be loading them from the DB which requires
turning the whole call chain async.

* Fix updated files

* Removed unnecessary credential loading to improve performance

* Fix typo

*  Fix issue

* Updated new nodes to load credentials async

*  Remove not needed comment

Co-authored-by: Jan Oberhauser <jan.oberhauser@gmail.com>
2021-08-20 18:57:30 +02:00

1142 lines
36 KiB
TypeScript

import {
IExecuteFunctions,
} from 'n8n-core';
import {
IDataObject,
ILoadOptionsFunctions,
INodeExecutionData,
INodeType,
INodeTypeDescription,
NodeOperationError,
} from 'n8n-workflow';
import {
billFields,
billOperations,
customerFields,
customerOperations,
employeeFields,
employeeOperations,
estimateFields,
estimateOperations,
invoiceFields,
invoiceOperations,
itemFields,
itemOperations,
paymentFields,
paymentOperations,
purchaseFields,
purchaseOperations,
transactionFields,
transactionOperations,
vendorFields,
vendorOperations,
} from './descriptions';
import {
adjustTransactionDates,
getRefAndSyncToken,
getSyncToken,
handleBinaryData,
handleListing,
loadResource,
populateFields,
processLines,
quickBooksApiRequest,
simplifyTransactionReport,
} from './GenericFunctions';
import {
capitalCase,
} from 'change-case';
import {
isEmpty,
} from 'lodash';
import {
DateFieldsUi,
QuickBooksOAuth2Credentials,
TransactionFields,
} from './types';
export class QuickBooks implements INodeType {
description: INodeTypeDescription = {
displayName: 'QuickBooks Online',
name: 'quickbooks',
icon: 'file:quickbooks.svg',
group: ['transform'],
version: 1,
subtitle: '={{$parameter["operation"] + ": " + $parameter["resource"]}}',
description: 'Consume the QuickBooks Online API',
defaults: {
name: 'QuickBooks Online',
color: '#2CA01C',
},
inputs: ['main'],
outputs: ['main'],
credentials: [
{
name: 'quickBooksOAuth2Api',
required: true,
},
],
properties: [
{
displayName: 'Resource',
name: 'resource',
type: 'options',
options: [
{
name: 'Bill',
value: 'bill',
},
{
name: 'Customer',
value: 'customer',
},
{
name: 'Employee',
value: 'employee',
},
{
name: 'Estimate',
value: 'estimate',
},
{
name: 'Invoice',
value: 'invoice',
},
{
name: 'Item',
value: 'item',
},
{
name: 'Payment',
value: 'payment',
},
{
name: 'Purchase',
value: 'purchase',
},
{
name: 'Transaction',
value: 'transaction',
},
{
name: 'Vendor',
value: 'vendor',
},
],
default: 'customer',
description: 'Resource to consume',
},
...billOperations,
...billFields,
...customerOperations,
...customerFields,
...employeeOperations,
...employeeFields,
...estimateOperations,
...estimateFields,
...invoiceOperations,
...invoiceFields,
...itemOperations,
...itemFields,
...paymentOperations,
...paymentFields,
...purchaseOperations,
...purchaseFields,
...transactionOperations,
...transactionFields,
...vendorOperations,
...vendorFields,
],
};
methods = {
loadOptions: {
async getCustomers(this: ILoadOptionsFunctions) {
return await loadResource.call(this, 'customer');
},
async getCustomFields(this: ILoadOptionsFunctions) {
return await loadResource.call(this, 'preferences');
},
async getDepartments(this: ILoadOptionsFunctions) {
return await loadResource.call(this, 'department');
},
async getItems(this: ILoadOptionsFunctions) {
return await loadResource.call(this, 'item');
},
async getMemos(this: ILoadOptionsFunctions) {
return await loadResource.call(this, 'CreditMemo');
},
async getPurchases(this: ILoadOptionsFunctions) {
return await loadResource.call(this, 'purchase');
},
async getTerms(this: ILoadOptionsFunctions) {
return await loadResource.call(this, 'Term');
},
async getVendors(this: ILoadOptionsFunctions) {
return await loadResource.call(this, 'vendor');
},
},
};
async execute(this: IExecuteFunctions): Promise<INodeExecutionData[][]> {
const items = this.getInputData();
const resource = this.getNodeParameter('resource', 0) as string;
const operation = this.getNodeParameter('operation', 0) as string;
let responseData;
const returnData: IDataObject[] = [];
const { oauthTokenData } = await this.getCredentials('quickBooksOAuth2Api') as QuickBooksOAuth2Credentials;
const companyId = oauthTokenData.callbackQueryString.realmId;
for (let i = 0; i < items.length; i++) {
try {
if (resource === 'bill') {
// *********************************************************************
// bill
// *********************************************************************
// https://developer.intuit.com/app/developer/qbo/docs/api/accounting/most-commonly-used/bill
if (operation === 'create') {
// ----------------------------------
// bill: create
// ----------------------------------
const lines = this.getNodeParameter('Line', i) as IDataObject[];
if (!lines.length) {
throw new NodeOperationError(this.getNode(), `Please enter at least one line for the ${resource}.`);
}
if (lines.some(line => line.DetailType === undefined || line.Amount === undefined || line.Description === undefined)) {
throw new NodeOperationError(this.getNode(), 'Please enter detail type, amount and description for every line.');
}
lines.forEach(line => {
if (line.DetailType === 'AccountBasedExpenseLineDetail' && line.accountId === undefined) {
throw new NodeOperationError(this.getNode(), 'Please enter an account ID for the associated line.');
} else if (line.DetailType === 'ItemBasedExpenseLineDetail' && line.itemId === undefined) {
throw new NodeOperationError(this.getNode(), 'Please enter an item ID for the associated line.');
}
});
let body = {
VendorRef: {
value: this.getNodeParameter('VendorRef', i),
},
} as IDataObject;
body.Line = processLines.call(this, body, lines, resource);
const additionalFields = this.getNodeParameter('additionalFields', i) as IDataObject;
body = populateFields.call(this, body, additionalFields, resource);
const endpoint = `/v3/company/${companyId}/${resource}`;
responseData = await quickBooksApiRequest.call(this, 'POST', endpoint, {}, body);
responseData = responseData[capitalCase(resource)];
} else if (operation === 'delete') {
// ----------------------------------
// bill: delete
// ----------------------------------
const qs = {
operation: 'delete',
} as IDataObject;
const body = {
Id: this.getNodeParameter('billId', i),
SyncToken: await getSyncToken.call(this, i, companyId, resource),
} as IDataObject;
const endpoint = `/v3/company/${companyId}/${resource}`;
responseData = await quickBooksApiRequest.call(this, 'POST', endpoint, qs, body);
responseData = responseData[capitalCase(resource)];
} else if (operation === 'get') {
// ----------------------------------
// bill: get
// ----------------------------------
const billId = this.getNodeParameter('billId', i);
const endpoint = `/v3/company/${companyId}/${resource}/${billId}`;
responseData = await quickBooksApiRequest.call(this, 'GET', endpoint, {}, {});
responseData = responseData[capitalCase(resource)];
} else if (operation === 'getAll') {
// ----------------------------------
// bill: getAll
// ----------------------------------
const endpoint = `/v3/company/${companyId}/query`;
responseData = await handleListing.call(this, i, endpoint, resource);
} else if (operation === 'update') {
// ----------------------------------
// bill: update
// ----------------------------------
const { ref, syncToken } = await getRefAndSyncToken.call(this, i, companyId, resource, 'VendorRef');
let body = {
Id: this.getNodeParameter('billId', i),
SyncToken: syncToken,
sparse: true,
VendorRef: {
name: ref.name,
value: ref.value,
},
} as IDataObject;
const updateFields = this.getNodeParameter('updateFields', i) as IDataObject;
if (isEmpty(updateFields)) {
throw new NodeOperationError(this.getNode(), `Please enter at least one field to update for the ${resource}.`);
}
body = populateFields.call(this, body, updateFields, resource);
const endpoint = `/v3/company/${companyId}/${resource}`;
responseData = await quickBooksApiRequest.call(this, 'POST', endpoint, {}, body);
responseData = responseData[capitalCase(resource)];
}
} else if (resource === 'customer') {
// *********************************************************************
// customer
// *********************************************************************
// https://developer.intuit.com/app/developer/qbo/docs/api/accounting/most-commonly-used/customer
if (operation === 'create') {
// ----------------------------------
// customer: create
// ----------------------------------
let body = {
DisplayName: this.getNodeParameter('displayName', i),
} as IDataObject;
const additionalFields = this.getNodeParameter('additionalFields', i) as IDataObject;
body = populateFields.call(this, body, additionalFields, resource);
const endpoint = `/v3/company/${companyId}/${resource}`;
responseData = await quickBooksApiRequest.call(this, 'POST', endpoint, {}, body);
responseData = responseData[capitalCase(resource)];
} else if (operation === 'get') {
// ----------------------------------
// customer: get
// ----------------------------------
const customerId = this.getNodeParameter('customerId', i);
const endpoint = `/v3/company/${companyId}/${resource}/${customerId}`;
responseData = await quickBooksApiRequest.call(this, 'GET', endpoint, {}, {});
responseData = responseData[capitalCase(resource)];
} else if (operation === 'getAll') {
// ----------------------------------
// customer: getAll
// ----------------------------------
const endpoint = `/v3/company/${companyId}/query`;
responseData = await handleListing.call(this, i, endpoint, resource);
} else if (operation === 'update') {
// ----------------------------------
// customer: update
// ----------------------------------
let body = {
Id: this.getNodeParameter('customerId', i),
SyncToken: await getSyncToken.call(this, i, companyId, resource),
sparse: true,
} as IDataObject;
const updateFields = this.getNodeParameter('updateFields', i) as IDataObject;
if (isEmpty(updateFields)) {
throw new NodeOperationError(this.getNode(), `Please enter at least one field to update for the ${resource}.`);
}
body = populateFields.call(this, body, updateFields, resource);
const endpoint = `/v3/company/${companyId}/${resource}`;
responseData = await quickBooksApiRequest.call(this, 'POST', endpoint, {}, body);
responseData = responseData[capitalCase(resource)];
}
} else if (resource === 'employee') {
// *********************************************************************
// employee
// *********************************************************************
if (operation === 'create') {
// ----------------------------------
// employee: create
// ----------------------------------
let body = {
FamilyName: this.getNodeParameter('FamilyName', i),
GivenName: this.getNodeParameter('GivenName', i),
} as IDataObject;
const additionalFields = this.getNodeParameter('additionalFields', i) as IDataObject;
body = populateFields.call(this, body, additionalFields, resource);
const endpoint = `/v3/company/${companyId}/${resource}`;
responseData = await quickBooksApiRequest.call(this, 'POST', endpoint, {}, body);
responseData = responseData[capitalCase(resource)];
} else if (operation === 'get') {
// ----------------------------------
// employee: get
// ----------------------------------
const employeeId = this.getNodeParameter('employeeId', i);
const endpoint = `/v3/company/${companyId}/${resource}/${employeeId}`;
responseData = await quickBooksApiRequest.call(this, 'GET', endpoint, {}, {});
responseData = responseData[capitalCase(resource)];
} else if (operation === 'getAll') {
// ----------------------------------
// employee: getAll
// ----------------------------------
const endpoint = `/v3/company/${companyId}/query`;
responseData = await handleListing.call(this, i, endpoint, resource);
} else if (operation === 'update') {
// ----------------------------------
// employee: update
// ----------------------------------
let body = {
Id: this.getNodeParameter('employeeId', i),
SyncToken: await getSyncToken.call(this, i, companyId, resource),
sparse: true,
} as IDataObject;
const updateFields = this.getNodeParameter('updateFields', i) as IDataObject;
if (isEmpty(updateFields)) {
throw new NodeOperationError(this.getNode(), `Please enter at least one field to update for the ${resource}.`);
}
body = populateFields.call(this, body, updateFields, resource);
const endpoint = `/v3/company/${companyId}/${resource}`;
responseData = await quickBooksApiRequest.call(this, 'POST', endpoint, {}, body);
responseData = responseData[capitalCase(resource)];
}
} else if (resource === 'estimate') {
// *********************************************************************
// estimate
// *********************************************************************
// https://developer.intuit.com/app/developer/qbo/docs/api/accounting/most-commonly-used/estimate
if (operation === 'create') {
// ----------------------------------
// estimate: create
// ----------------------------------
const lines = this.getNodeParameter('Line', i) as IDataObject[];
if (!lines.length) {
throw new NodeOperationError(this.getNode(), `Please enter at least one line for the ${resource}.`);
}
if (lines.some(line => line.DetailType === undefined || line.Amount === undefined || line.Description === undefined)) {
throw new NodeOperationError(this.getNode(), 'Please enter detail type, amount and description for every line.');
}
lines.forEach(line => {
if (line.DetailType === 'SalesItemLineDetail' && line.itemId === undefined) {
throw new NodeOperationError(this.getNode(), 'Please enter an item ID for the associated line.');
}
});
let body = {
CustomerRef: {
value: this.getNodeParameter('CustomerRef', i),
},
} as IDataObject;
body.Line = processLines.call(this, body, lines, resource);
const additionalFields = this.getNodeParameter('additionalFields', i) as IDataObject;
body = populateFields.call(this, body, additionalFields, resource);
const endpoint = `/v3/company/${companyId}/${resource}`;
responseData = await quickBooksApiRequest.call(this, 'POST', endpoint, {}, body);
responseData = responseData[capitalCase(resource)];
} else if (operation === 'delete') {
// ----------------------------------
// estimate: delete
// ----------------------------------
const qs = {
operation: 'delete',
} as IDataObject;
const body = {
Id: this.getNodeParameter('estimateId', i),
SyncToken: await getSyncToken.call(this, i, companyId, resource),
} as IDataObject;
const endpoint = `/v3/company/${companyId}/${resource}`;
responseData = await quickBooksApiRequest.call(this, 'POST', endpoint, qs, body);
responseData = responseData[capitalCase(resource)];
} else if (operation === 'get') {
// ----------------------------------
// estimate: get
// ----------------------------------
const estimateId = this.getNodeParameter('estimateId', i) as string;
const download = this.getNodeParameter('download', i) as boolean;
if (download) {
responseData = await handleBinaryData.call(this, items, i, companyId, resource, estimateId);
} else {
const endpoint = `/v3/company/${companyId}/${resource}/${estimateId}`;
responseData = await quickBooksApiRequest.call(this, 'GET', endpoint, {}, {});
responseData = responseData[capitalCase(resource)];
}
} else if (operation === 'getAll') {
// ----------------------------------
// estimate: getAll
// ----------------------------------
const endpoint = `/v3/company/${companyId}/query`;
responseData = await handleListing.call(this, i, endpoint, resource);
} else if (operation === 'send') {
// ----------------------------------
// estimate: send
// ----------------------------------
const estimateId = this.getNodeParameter('estimateId', i) as string;
const qs = {
sendTo: this.getNodeParameter('email', i) as string,
} as IDataObject;
const endpoint = `/v3/company/${companyId}/${resource}/${estimateId}/send`;
responseData = await quickBooksApiRequest.call(this, 'POST', endpoint, qs, {});
responseData = responseData[capitalCase(resource)];
} else if (operation === 'update') {
// ----------------------------------
// estimate: update
// ----------------------------------
const { ref, syncToken } = await getRefAndSyncToken.call(this, i, companyId, resource, 'CustomerRef');
let body = {
Id: this.getNodeParameter('estimateId', i),
SyncToken: syncToken,
sparse: true,
CustomerRef: {
name: ref.name,
value: ref.value,
},
} as IDataObject;
const updateFields = this.getNodeParameter('updateFields', i) as IDataObject;
if (isEmpty(updateFields)) {
throw new NodeOperationError(this.getNode(), `Please enter at least one field to update for the ${resource}.`);
}
body = populateFields.call(this, body, updateFields, resource);
const endpoint = `/v3/company/${companyId}/${resource}`;
responseData = await quickBooksApiRequest.call(this, 'POST', endpoint, {}, body);
responseData = responseData[capitalCase(resource)];
}
} else if (resource === 'invoice') {
// *********************************************************************
// invoice
// *********************************************************************
// https://developer.intuit.com/app/developer/qbo/docs/api/accounting/most-commonly-used/invoice
if (operation === 'create') {
// ----------------------------------
// invoice: create
// ----------------------------------
const lines = this.getNodeParameter('Line', i) as IDataObject[];
if (!lines.length) {
throw new NodeOperationError(this.getNode(), `Please enter at least one line for the ${resource}.`);
}
if (lines.some(line => line.DetailType === undefined || line.Amount === undefined || line.Description === undefined)) {
throw new NodeOperationError(this.getNode(), 'Please enter detail type, amount and description for every line.');
}
lines.forEach(line => {
if (line.DetailType === 'SalesItemLineDetail' && line.itemId === undefined) {
throw new NodeOperationError(this.getNode(), 'Please enter an item ID for the associated line.');
}
});
let body = {
CustomerRef: {
value: this.getNodeParameter('CustomerRef', i),
},
} as IDataObject;
body.Line = processLines.call(this, body, lines, resource);
const additionalFields = this.getNodeParameter('additionalFields', i) as IDataObject;
body = populateFields.call(this, body, additionalFields, resource);
const endpoint = `/v3/company/${companyId}/${resource}`;
responseData = await quickBooksApiRequest.call(this, 'POST', endpoint, {}, body);
responseData = responseData[capitalCase(resource)];
} else if (operation === 'delete') {
// ----------------------------------
// invoice: delete
// ----------------------------------
const qs = {
operation: 'delete',
} as IDataObject;
const body = {
Id: this.getNodeParameter('invoiceId', i),
SyncToken: await getSyncToken.call(this, i, companyId, resource),
} as IDataObject;
const endpoint = `/v3/company/${companyId}/${resource}`;
responseData = await quickBooksApiRequest.call(this, 'POST', endpoint, qs, body);
responseData = responseData[capitalCase(resource)];
} else if (operation === 'get') {
// ----------------------------------
// invoice: get
// ----------------------------------
const invoiceId = this.getNodeParameter('invoiceId', i) as string;
const download = this.getNodeParameter('download', i) as boolean;
if (download) {
responseData = await handleBinaryData.call(this, items, i, companyId, resource, invoiceId);
} else {
const endpoint = `/v3/company/${companyId}/${resource}/${invoiceId}`;
responseData = await quickBooksApiRequest.call(this, 'GET', endpoint, {}, {});
responseData = responseData[capitalCase(resource)];
}
} else if (operation === 'getAll') {
// ----------------------------------
// invoice: getAll
// ----------------------------------
const endpoint = `/v3/company/${companyId}/query`;
responseData = await handleListing.call(this, i, endpoint, resource);
} else if (operation === 'send') {
// ----------------------------------
// invoice: send
// ----------------------------------
const invoiceId = this.getNodeParameter('invoiceId', i) as string;
const qs = {
sendTo: this.getNodeParameter('email', i) as string,
} as IDataObject;
const endpoint = `/v3/company/${companyId}/${resource}/${invoiceId}/send`;
responseData = await quickBooksApiRequest.call(this, 'POST', endpoint, qs, {});
responseData = responseData[capitalCase(resource)];
} else if (operation === 'update') {
// ----------------------------------
// invoice: update
// ----------------------------------
const { ref, syncToken } = await getRefAndSyncToken.call(this, i, companyId, resource, 'CustomerRef');
let body = {
Id: this.getNodeParameter('invoiceId', i),
SyncToken: syncToken,
sparse: true,
CustomerRef: {
name: ref.name,
value: ref.value,
},
} as IDataObject;
const updateFields = this.getNodeParameter('updateFields', i) as IDataObject;
if (isEmpty(updateFields)) {
throw new NodeOperationError(this.getNode(), `Please enter at least one field to update for the ${resource}.`);
}
body = populateFields.call(this, body, updateFields, resource);
const endpoint = `/v3/company/${companyId}/${resource}`;
responseData = await quickBooksApiRequest.call(this, 'POST', endpoint, {}, body);
responseData = responseData[capitalCase(resource)];
} else if (operation === 'void') {
// ----------------------------------
// invoice: void
// ----------------------------------
const qs = {
Id: this.getNodeParameter('invoiceId', i),
SyncToken: await getSyncToken.call(this, i, companyId, resource),
operation: 'void',
} as IDataObject;
const endpoint = `/v3/company/${companyId}/${resource}`;
responseData = await quickBooksApiRequest.call(this, 'POST', endpoint, qs, {});
responseData = responseData[capitalCase(resource)];
}
} else if (resource === 'item') {
// *********************************************************************
// item
// *********************************************************************
// https://developer.intuit.com/app/developer/qbo/docs/api/accounting/most-commonly-used/item
if (operation === 'get') {
// ----------------------------------
// item: get
// ----------------------------------
const item = this.getNodeParameter('itemId', i);
const endpoint = `/v3/company/${companyId}/${resource}/${item}`;
responseData = await quickBooksApiRequest.call(this, 'GET', endpoint, {}, {});
responseData = responseData[capitalCase(resource)];
} else if (operation === 'getAll') {
// ----------------------------------
// item: getAll
// ----------------------------------
const endpoint = `/v3/company/${companyId}/query`;
responseData = await handleListing.call(this, i, endpoint, resource);
}
} else if (resource === 'payment') {
// *********************************************************************
// payment
// *********************************************************************
// https://developer.intuit.com/app/developer/qbo/docs/api/accounting/most-commonly-used/payment
if (operation === 'create') {
// ----------------------------------
// payment: create
// ----------------------------------
let body = {
CustomerRef: {
value: this.getNodeParameter('CustomerRef', i),
},
TotalAmt: this.getNodeParameter('TotalAmt', i),
} as IDataObject;
const additionalFields = this.getNodeParameter('additionalFields', i) as IDataObject;
body = populateFields.call(this, body, additionalFields, resource);
const endpoint = `/v3/company/${companyId}/${resource}`;
responseData = await quickBooksApiRequest.call(this, 'POST', endpoint, {}, body);
responseData = responseData[capitalCase(resource)];
} else if (operation === 'delete') {
// ----------------------------------
// payment: delete
// ----------------------------------
const qs = {
operation: 'delete',
} as IDataObject;
const body = {
Id: this.getNodeParameter('paymentId', i),
SyncToken: await getSyncToken.call(this, i, companyId, resource),
} as IDataObject;
const endpoint = `/v3/company/${companyId}/${resource}`;
responseData = await quickBooksApiRequest.call(this, 'POST', endpoint, qs, body);
responseData = responseData[capitalCase(resource)];
} else if (operation === 'get') {
// ----------------------------------
// payment: get
// ----------------------------------
const paymentId = this.getNodeParameter('paymentId', i) as string;
const download = this.getNodeParameter('download', i) as boolean;
if (download) {
responseData = await handleBinaryData.call(this, items, i, companyId, resource, paymentId);
} else {
const endpoint = `/v3/company/${companyId}/${resource}/${paymentId}`;
responseData = await quickBooksApiRequest.call(this, 'GET', endpoint, {}, {});
responseData = responseData[capitalCase(resource)];
}
} else if (operation === 'getAll') {
// ----------------------------------
// payment: getAll
// ----------------------------------
const endpoint = `/v3/company/${companyId}/query`;
responseData = await handleListing.call(this, i, endpoint, resource);
} else if (operation === 'send') {
// ----------------------------------
// payment: send
// ----------------------------------
const paymentId = this.getNodeParameter('paymentId', i) as string;
const qs = {
sendTo: this.getNodeParameter('email', i) as string,
} as IDataObject;
const endpoint = `/v3/company/${companyId}/${resource}/${paymentId}/send`;
responseData = await quickBooksApiRequest.call(this, 'POST', endpoint, qs, {});
responseData = responseData[capitalCase(resource)];
} else if (operation === 'update') {
// ----------------------------------
// payment: update
// ----------------------------------
const { ref, syncToken } = await getRefAndSyncToken.call(this, i, companyId, resource, 'CustomerRef');
let body = {
Id: this.getNodeParameter('paymentId', i),
SyncToken: syncToken,
sparse: true,
CustomerRef: {
name: ref.name,
value: ref.value,
},
} as IDataObject;
const updateFields = this.getNodeParameter('updateFields', i) as IDataObject;
if (isEmpty(updateFields)) {
throw new NodeOperationError(this.getNode(), `Please enter at least one field to update for the ${resource}.`);
}
body = populateFields.call(this, body, updateFields, resource);
const endpoint = `/v3/company/${companyId}/${resource}`;
responseData = await quickBooksApiRequest.call(this, 'POST', endpoint, {}, body);
responseData = responseData[capitalCase(resource)];
} else if (operation === 'void') {
// ----------------------------------
// payment: void
// ----------------------------------
const qs = {
Id: this.getNodeParameter('paymentId', i),
SyncToken: await getSyncToken.call(this, i, companyId, resource),
operation: 'void',
} as IDataObject;
const endpoint = `/v3/company/${companyId}/${resource}`;
responseData = await quickBooksApiRequest.call(this, 'POST', endpoint, qs, {});
responseData = responseData[capitalCase(resource)];
}
} 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 === 'transaction') {
// *********************************************************************
// transaction
// *********************************************************************
// https://developer.intuit.com/app/developer/qbo/docs/api/accounting/all-entities/transactionlist
if (operation === 'getReport') {
// ----------------------------------
// transaction: getReport
// ----------------------------------
const {
columns,
memo,
term,
customer,
vendor,
...rest
} = this.getNodeParameter('filters', i) as TransactionFields;
let qs = { ...rest };
if (columns?.length) {
qs.columns = columns.join(',');
}
if (memo?.length) {
qs.memo = memo.join(',');
}
if (term?.length) {
qs.term = term.join(',');
}
if (customer?.length) {
qs.customer = customer.join(',');
}
if (vendor?.length) {
qs.vendor = vendor.join(',');
}
qs = adjustTransactionDates(qs);
const endpoint = `/v3/company/${companyId}/reports/TransactionList`;
responseData = await quickBooksApiRequest.call(this, 'GET', endpoint, qs, {});
const simplifyResponse = this.getNodeParameter('simple', i, true) as boolean;
if (!Object.keys(responseData?.Rows).length) {
responseData = [];
}
if (simplifyResponse && !Array.isArray(responseData)) {
responseData = simplifyTransactionReport(responseData);
}
}
} else if (resource === 'vendor') {
// *********************************************************************
// vendor
// *********************************************************************
// https://developer.intuit.com/app/developer/qbo/docs/api/accounting/most-commonly-used/vendor
if (operation === 'create') {
// ----------------------------------
// vendor: create
// ----------------------------------
let body = {
DisplayName: this.getNodeParameter('displayName', i),
} as IDataObject;
const additionalFields = this.getNodeParameter('additionalFields', i) as IDataObject;
body = populateFields.call(this, body, additionalFields, resource);
const endpoint = `/v3/company/${companyId}/${resource}`;
responseData = await quickBooksApiRequest.call(this, 'POST', endpoint, {}, body);
responseData = responseData[capitalCase(resource)];
} else if (operation === 'get') {
// ----------------------------------
// vendor: get
// ----------------------------------
const vendorId = this.getNodeParameter('vendorId', i);
const endpoint = `/v3/company/${companyId}/${resource}/${vendorId}`;
responseData = await quickBooksApiRequest.call(this, 'GET', endpoint, {}, {});
responseData = responseData[capitalCase(resource)];
} else if (operation === 'getAll') {
// ----------------------------------
// vendor: getAll
// ----------------------------------
const endpoint = `/v3/company/${companyId}/query`;
responseData = await handleListing.call(this, i, endpoint, resource);
} else if (operation === 'update') {
// ----------------------------------
// vendor: update
// ----------------------------------
let body = {
Id: this.getNodeParameter('vendorId', i),
SyncToken: await getSyncToken.call(this, i, companyId, resource),
sparse: true,
} as IDataObject;
const updateFields = this.getNodeParameter('updateFields', i) as IDataObject;
if (isEmpty(updateFields)) {
throw new NodeOperationError(this.getNode(), `Please enter at least one field to update for the ${resource}.`);
}
body = populateFields.call(this, body, updateFields, resource);
const endpoint = `/v3/company/${companyId}/${resource}`;
responseData = await quickBooksApiRequest.call(this, 'POST', endpoint, {}, body);
responseData = responseData[capitalCase(resource)];
}
}
} catch (error) {
if (this.continueOnFail()) {
const download = this.getNodeParameter('download', 0, false) as boolean;
if (['invoice', 'estimate', 'payment'].includes(resource) && ['get'].includes(operation) && download) {
// in this case responseDate? === items
if (!responseData){
items[i].json = { error: error.message };
responseData = items;
}else {
responseData[i].json = { error: error.message };
}
}else {
returnData.push({ error: error.message });
}
continue;
}
throw error;
}
Array.isArray(responseData)
? returnData.push(...responseData)
: returnData.push(responseData);
}
const download = this.getNodeParameter('download', 0, false) as boolean;
if (['invoice', 'estimate', 'payment'].includes(resource) && ['get'].includes(operation) && download) {
return this.prepareOutputData(responseData);
} else {
return [this.helpers.returnJsonArray(returnData)];
}
}
}