UNPKG

@arathron/n8n-nodes-zoho-books

Version:

n8n community nodes for Zoho Books and Zoho Inventory API integration - Complete CRUD operations for Sales Orders, Invoices, Items, Vendors, Credit Notes, Payments, Purchase Orders, Bills, Composite Items, and Assemblies

766 lines 31.2 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.ZohoInventory = void 0; const n8n_workflow_1 = require("n8n-workflow"); const GenericFunctions_1 = require("./utils/GenericFunctions"); class ZohoInventory { description = { displayName: 'Zoho Inventory', name: 'zohoInventory', icon: 'file:zoho-inventory.svg', group: ['transform'], version: 1, subtitle: '={{$parameter["operation"] + ": " + $parameter["resource"]}}', description: 'Consume Zoho Inventory API', defaults: { name: 'Zoho Inventory', }, inputs: ['main'], outputs: ['main'], credentials: [ { name: 'zohoInventoryOAuth2', required: true, }, ], properties: [ { displayName: 'Resource', name: 'resource', type: 'options', noDataExpression: true, options: [ { name: 'Assembly', value: 'assembly', }, { name: 'Composite Item', value: 'compositeItem', }, { name: 'Item', value: 'item', }, ], default: 'compositeItem', required: true, }, { displayName: 'Operation', name: 'operation', type: 'options', noDataExpression: true, displayOptions: { show: { resource: ['compositeItem'], }, }, options: [ { name: 'Create', value: 'create', description: 'Create a new composite item', action: 'Create a composite item', }, { name: 'Delete', value: 'delete', description: 'Delete a composite item', action: 'Delete a composite item', }, { name: 'Get', value: 'get', description: 'Get a composite item', action: 'Get a composite item', }, { name: 'Get All', value: 'getAll', description: 'Get all composite items', action: 'Get all composite items', }, { name: 'Update', value: 'update', description: 'Update a composite item', action: 'Update a composite item', }, ], default: 'create', }, { displayName: 'Operation', name: 'operation', type: 'options', noDataExpression: true, displayOptions: { show: { resource: ['assembly'], }, }, options: [ { name: 'Create', value: 'create', description: 'Create a new assembly', action: 'Create an assembly', }, { name: 'Delete', value: 'delete', description: 'Delete an assembly', action: 'Delete an assembly', }, { name: 'Get', value: 'get', description: 'Get an assembly', action: 'Get an assembly', }, { name: 'Get History', value: 'getHistory', description: 'Get assembly history', action: 'Get assembly history', }, ], default: 'create', }, { displayName: 'Operation', name: 'operation', type: 'options', noDataExpression: true, displayOptions: { show: { resource: ['item'], }, }, options: [ { name: 'Create', value: 'create', description: 'Create a new item', action: 'Create an item', }, { name: 'Delete', value: 'delete', description: 'Delete an item', action: 'Delete an item', }, { name: 'Get', value: 'get', description: 'Get an item by ID', action: 'Get an item', }, { name: 'Get All', value: 'getAll', description: 'Get all items', action: 'Get all items', }, { name: 'Get by SKU', value: 'getBySku', description: 'Get an item by SKU code', action: 'Get item by SKU', }, { name: 'Update', value: 'update', description: 'Update an item', action: 'Update an item', }, ], default: 'getAll', }, { displayName: 'SKU Code', name: 'skuCode', type: 'string', required: true, default: '', displayOptions: { show: { resource: ['item'], operation: ['getBySku'], }, }, description: 'The SKU code of the item to retrieve', placeholder: 'e.g., ITEM-001', }, { displayName: 'Item ID', name: 'itemId', type: 'string', required: true, default: '', displayOptions: { show: { resource: ['item'], operation: ['get', 'delete', 'update'], }, }, description: 'The ID of the item', }, { displayName: 'Return All', name: 'returnAll', type: 'boolean', displayOptions: { show: { resource: ['item'], 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: ['item'], operation: ['getAll'], returnAll: [false], }, }, typeOptions: { minValue: 1, maxValue: 200, }, default: 50, description: 'Max number of results to return', }, { displayName: 'Composite Item ID', name: 'compositeItemId', type: 'string', required: true, displayOptions: { show: { resource: ['compositeItem'], operation: ['get', 'delete', 'update'], }, }, default: '', description: 'The ID of the composite item', }, { displayName: 'Name', name: 'name', type: 'string', required: true, displayOptions: { show: { resource: ['compositeItem'], operation: ['create', 'update'], }, }, default: '', description: 'Name of the composite item', }, { displayName: 'SKU', name: 'sku', type: 'string', required: true, displayOptions: { show: { resource: ['compositeItem'], operation: ['create'], }, }, default: '', description: 'Stock Keeping Unit (SKU) of the composite item', }, { displayName: 'Rate', name: 'rate', type: 'number', typeOptions: { numberPrecision: 2, }, required: true, displayOptions: { show: { resource: ['compositeItem'], operation: ['create', 'update'], }, }, default: 0, description: 'Selling price of the composite item', }, { displayName: 'Line Items', name: 'lineItems', type: 'fixedCollection', typeOptions: { multipleValues: true, }, displayOptions: { show: { resource: ['compositeItem'], operation: ['create', 'update'], }, }, default: {}, placeholder: 'Add Line Item', options: [ { name: 'lineItem', displayName: 'Line Item', values: [ { displayName: 'Item ID', name: 'item_id', type: 'string', default: '', required: true, description: 'ID of the component item', }, { displayName: 'Quantity', name: 'quantity', type: 'number', typeOptions: { numberPrecision: 3, }, default: 1, required: true, description: 'Quantity of the component item', }, ], }, ], }, { displayName: 'Additional Fields', name: 'additionalFields', type: 'collection', placeholder: 'Add Field', default: {}, displayOptions: { show: { resource: ['compositeItem'], operation: ['create', 'update'], }, }, options: [ { displayName: 'Description', name: 'description', type: 'string', typeOptions: { rows: 4, }, default: '', description: 'Description of the composite item', }, { displayName: 'Purchase Rate', name: 'purchase_rate', type: 'number', typeOptions: { numberPrecision: 2, }, default: 0, description: 'Cost price of the composite item', }, { displayName: 'Reorder Level', name: 'reorder_level', type: 'number', default: 0, description: 'Reorder level of the composite item', }, { displayName: 'Initial Stock', name: 'initial_stock', type: 'number', default: 0, description: 'Initial stock quantity', }, { displayName: 'Initial Stock Rate', name: 'initial_stock_rate', type: 'number', typeOptions: { numberPrecision: 2, }, default: 0, description: 'Initial stock rate per unit', }, ], }, { displayName: 'Return All', name: 'returnAll', type: 'boolean', displayOptions: { show: { resource: ['compositeItem'], 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: ['compositeItem'], operation: ['getAll'], returnAll: [false], }, }, typeOptions: { minValue: 1, maxValue: 200, }, default: 50, description: 'Max number of results to return', }, { displayName: 'Assembly ID', name: 'assemblyId', type: 'string', required: true, displayOptions: { show: { resource: ['assembly'], operation: ['get', 'delete'], }, }, default: '', description: 'The ID of the assembly', }, { displayName: 'Composite Item ID', name: 'compositeItemId', type: 'string', required: true, displayOptions: { show: { resource: ['assembly'], operation: ['create', 'getHistory'], }, }, default: '', description: 'The ID of the composite item to assemble', }, { displayName: 'Quantity', name: 'quantity', type: 'number', required: true, displayOptions: { show: { resource: ['assembly'], operation: ['create'], }, }, default: 1, description: 'Quantity to assemble', }, { displayName: 'Date', name: 'date', type: 'dateTime', required: true, displayOptions: { show: { resource: ['assembly'], operation: ['create'], }, }, default: '', description: 'Date of assembly', }, { displayName: 'Reference Number', name: 'reference_number', type: 'string', displayOptions: { show: { resource: ['assembly'], operation: ['create'], }, }, default: '', description: 'Reference number for the assembly', }, ], }; methods = { loadOptions: { async getItems() { const returnData = []; try { const { items } = await zohoApiRequest.call(this, 'GET', '/items'); for (const item of items) { returnData.push({ name: `${item.name} (${item.sku})`, value: item.item_id, }); } return returnData; } catch (error) { throw new n8n_workflow_1.NodeApiError(this.getNode(), { message: 'Failed to load items', description: `Could not retrieve items from Zoho Inventory: ${error.message}`, }); } }, async getCompositeItems() { const returnData = []; try { const { composite_items } = await zohoApiRequest.call(this, 'GET', '/compositeitems'); for (const item of composite_items) { returnData.push({ name: `${item.name} (${item.sku})`, value: item.composite_item_id, }); } return returnData; } catch (error) { throw new n8n_workflow_1.NodeApiError(this.getNode(), { message: 'Failed to load composite items', description: `Could not retrieve composite items from Zoho Inventory: ${error.message}`, }); } }, }, }; async execute() { const items = this.getInputData(); const returnData = []; const resource = this.getNodeParameter('resource', 0); const operation = this.getNodeParameter('operation', 0); for (let i = 0; i < items.length; i++) { try { if (resource === 'compositeItem') { if (operation === 'create') { const name = this.getNodeParameter('name', i); const sku = this.getNodeParameter('sku', i); const rate = this.getNodeParameter('rate', i); const lineItems = this.getNodeParameter('lineItems', i); const additionalFields = this.getNodeParameter('additionalFields', i); const body = { name, sku, rate, mapped_items: lineItems.lineItem || [], ...additionalFields, }; const response = await zohoApiRequest.call(this, 'POST', '/compositeitems', body); returnData.push({ json: response.composite_item }); } if (operation === 'get') { const compositeItemId = this.getNodeParameter('compositeItemId', i); const response = await zohoApiRequest.call(this, 'GET', `/compositeitems/${compositeItemId}`); returnData.push({ json: response.composite_item }); } if (operation === 'getAll') { const returnAll = this.getNodeParameter('returnAll', i); const limit = this.getNodeParameter('limit', i, 50); const response = await zohoApiRequest.call(this, 'GET', '/compositeitems', {}, { page: 1, per_page: returnAll ? 200 : limit }); if (returnAll) { returnData.push(...response.composite_items.map(item => ({ json: item }))); let page = 2; let currentResponse = response; while (currentResponse.page_context && currentResponse.page_context.has_more_page) { currentResponse = await zohoApiRequest.call(this, 'GET', '/compositeitems', {}, { page, per_page: 200 }); returnData.push(...currentResponse.composite_items.map(item => ({ json: item }))); page++; } } else { returnData.push(...response.composite_items.slice(0, limit).map(item => ({ json: item }))); } } if (operation === 'update') { const compositeItemId = this.getNodeParameter('compositeItemId', i); const name = this.getNodeParameter('name', i); const rate = this.getNodeParameter('rate', i); const lineItems = this.getNodeParameter('lineItems', i); const additionalFields = this.getNodeParameter('additionalFields', i); const body = { name, rate, mapped_items: lineItems.lineItem || [], ...additionalFields, }; const response = await zohoApiRequest.call(this, 'PUT', `/compositeitems/${compositeItemId}`, body); returnData.push({ json: response.composite_item }); } if (operation === 'delete') { const compositeItemId = this.getNodeParameter('compositeItemId', i); await zohoApiRequest.call(this, 'DELETE', `/compositeitems/${compositeItemId}`); returnData.push({ json: { success: true, message: 'Composite item deleted successfully' } }); } } if (resource === 'assembly') { if (operation === 'create') { const compositeItemId = this.getNodeParameter('compositeItemId', i); const quantity = this.getNodeParameter('quantity', i); const date = this.getNodeParameter('date', i); const referenceNumber = this.getNodeParameter('reference_number', i, ''); const body = { composite_item_id: compositeItemId, quantity_to_assemble: quantity, date, }; if (referenceNumber) { body.reference_number = referenceNumber; } const response = await zohoApiRequest.call(this, 'POST', '/compositeitems/assemblies', body); returnData.push({ json: response.assembly }); } if (operation === 'get') { const assemblyId = this.getNodeParameter('assemblyId', i); const response = await zohoApiRequest.call(this, 'GET', `/compositeitems/assemblies/${assemblyId}`); returnData.push({ json: response.assembly }); } if (operation === 'getHistory') { const compositeItemId = this.getNodeParameter('compositeItemId', i); const response = await zohoApiRequest.call(this, 'GET', `/compositeitems/${compositeItemId}/assemblies`); returnData.push(...response.assemblies.map(item => ({ json: item }))); } if (operation === 'delete') { const assemblyId = this.getNodeParameter('assemblyId', i); await zohoApiRequest.call(this, 'DELETE', `/compositeitems/assemblies/${assemblyId}`); returnData.push({ json: { success: true, message: 'Assembly deleted successfully' } }); } } if (resource === 'item') { if (operation === 'getBySku') { const skuCode = this.getNodeParameter('skuCode', i); const item = await GenericFunctions_1.getItemBySku.call(this, skuCode); returnData.push({ json: item }); } else if (operation === 'get') { const itemId = this.getNodeParameter('itemId', i); const response = await zohoApiRequest.call(this, 'GET', `/items/${itemId}`); returnData.push({ json: response.item }); } else if (operation === 'getAll') { const returnAll = this.getNodeParameter('returnAll', i, false); if (returnAll) { const allItems = await GenericFunctions_1.zohoApiRequestAllItems.call(this, 'GET', '/items'); returnData.push(...allItems.map(item => ({ json: item }))); } else { const limit = this.getNodeParameter('limit', i, 50); const response = await zohoApiRequest.call(this, 'GET', '/items', {}, { per_page: limit }); const items = response.items || []; returnData.push(...items.slice(0, limit).map((item) => ({ json: item }))); } } else if (operation === 'delete') { const itemId = this.getNodeParameter('itemId', i); await zohoApiRequest.call(this, 'DELETE', `/items/${itemId}`); returnData.push({ json: { success: true, message: 'Item deleted successfully' } }); } else if (operation === 'create') { const body = this.getNodeParameter('itemData', i, {}); const response = await zohoApiRequest.call(this, 'POST', '/items', body); returnData.push({ json: response.item }); } else if (operation === 'update') { const itemId = this.getNodeParameter('itemId', i); const body = this.getNodeParameter('itemData', i, {}); const response = await zohoApiRequest.call(this, 'PUT', `/items/${itemId}`, body); returnData.push({ json: response.item }); } } } catch (error) { if (this.continueOnFail()) { returnData.push({ json: { error: error.message } }); continue; } throw error; } } return [returnData]; } } exports.ZohoInventory = ZohoInventory; async function zohoApiRequest(method, endpoint, body = {}, qs = {}) { const credentials = await this.getCredentials('zohoInventoryOAuth2'); if (!credentials) { throw new n8n_workflow_1.NodeApiError(this.getNode(), { message: 'Zoho Inventory credentials not found', description: 'Please configure your Zoho Inventory OAuth2 credentials first.', httpCode: '401', }); } const organizationId = credentials.organizationId; if (!organizationId || organizationId.trim() === '') { throw new n8n_workflow_1.NodeApiError(this.getNode(), { message: 'Organization ID is missing', description: 'Please configure Organization ID in your Zoho Inventory OAuth2 credentials. You can find it in Zoho Inventory → Settings → Organization Profile.', httpCode: '400', }); } const baseUrl = getBaseUrl(credentials); const options = { method, url: `${baseUrl}${endpoint}`, qs: { organization_id: organizationId, ...qs, }, json: true, headers: { 'X-com-zoho-inventory-organizationid': organizationId, }, }; if (Object.keys(body).length > 0) { options.body = body; } try { const response = await this.helpers.httpRequestWithAuthentication.call(this, 'zohoInventoryOAuth2', options); if (response.code !== 0) { throw new n8n_workflow_1.NodeApiError(this.getNode(), { message: response.message || 'Zoho Inventory API Error', description: `Error Code: ${response.code}`, }); } return response; } catch (error) { if (error instanceof n8n_workflow_1.NodeApiError) { throw error; } throw new n8n_workflow_1.NodeApiError(this.getNode(), error); } } function getBaseUrl(credentials) { const dataCenter = credentials.dataCenter; if (dataCenter === 'COM') { return 'https://www.zohoapis.com/inventory/v1'; } else if (dataCenter === 'AU') { return 'https://www.zohoapis.com.au/inventory/v1'; } else if (dataCenter === 'CN') { return 'https://www.zohoapis.com.cn/inventory/v1'; } else { return `https://www.zohoapis.${dataCenter.toLowerCase()}/inventory/v1`; } } //# sourceMappingURL=ZohoInventory.node.js.map