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

1,306 lines 76.9 kB
"use strict"; var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { if (k2 === undefined) k2 = k; var desc = Object.getOwnPropertyDescriptor(m, k); if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) { desc = { enumerable: true, get: function() { return m[k]; } }; } Object.defineProperty(o, k2, desc); }) : (function(o, m, k, k2) { if (k2 === undefined) k2 = k; o[k2] = m[k]; })); var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) { Object.defineProperty(o, "default", { enumerable: true, value: v }); }) : function(o, v) { o["default"] = v; }); var __importStar = (this && this.__importStar) || (function () { var ownKeys = function(o) { ownKeys = Object.getOwnPropertyNames || function (o) { var ar = []; for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k; return ar; }; return ownKeys(o); }; return function (mod) { if (mod && mod.__esModule) return mod; var result = {}; if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]); __setModuleDefault(result, mod); return result; }; })(); Object.defineProperty(exports, "__esModule", { value: true }); exports.ZohoBooks = exports.checkRateLimit = exports.zohoApiRequestWithFormData = exports.zohoApiRequestAllItems = exports.zohoApiRequest = void 0; const n8n_workflow_1 = require("n8n-workflow"); const SalesOrderNormalizer_1 = require("./utils/SalesOrderNormalizer"); const GenericFunctions_1 = require("./utils/GenericFunctions"); Object.defineProperty(exports, "zohoApiRequest", { enumerable: true, get: function () { return GenericFunctions_1.zohoApiRequest; } }); Object.defineProperty(exports, "zohoApiRequestAllItems", { enumerable: true, get: function () { return GenericFunctions_1.zohoApiRequestAllItems; } }); Object.defineProperty(exports, "zohoApiRequestWithFormData", { enumerable: true, get: function () { return GenericFunctions_1.zohoApiRequestWithFormData; } }); Object.defineProperty(exports, "checkRateLimit", { enumerable: true, get: function () { return GenericFunctions_1.checkRateLimit; } }); const SalesOrderUtils_1 = require("./utils/SalesOrderUtils"); class ZohoBooks { description = { displayName: 'Zoho Books', name: 'zohoBooks', icon: 'file:zohobooks.svg', group: ['transform'], version: 1, subtitle: '={{$parameter["operation"] + ": " + $parameter["resource"]}}', description: 'Consume Zoho Books API', defaults: { name: 'Zoho Books', }, inputs: ['main'], outputs: ['main'], credentials: [ { name: 'zohoBooksOAuth2', required: true, }, ], properties: [ { displayName: 'Resource', name: 'resource', type: 'options', noDataExpression: true, options: [ { name: 'Bill', value: 'bill', }, { name: 'Composite Item', value: 'compositeItem', }, { name: 'Credit Note', value: 'creditNote', }, { name: 'Invoice', value: 'invoice', }, { name: 'Item', value: 'item', }, { name: 'Payment', value: 'payment', }, { name: 'Purchase Order', value: 'purchaseOrder', }, { name: 'Sales Order', value: 'salesOrder', }, { name: 'Vendor', value: 'vendor', }, { name: 'Contact', value: 'contact', }, ], default: 'invoice', required: true, }, { displayName: 'Operation', name: 'operation', type: 'options', noDataExpression: true, displayOptions: { show: { resource: ['salesOrder', 'item', 'vendor', 'creditNote', 'payment', 'purchaseOrder', 'bill', 'compositeItem', 'contact'], }, }, options: [ { name: 'Create', value: 'create', description: 'Create a new record', action: 'Create a record', }, { name: 'Delete', value: 'delete', description: 'Delete a record', action: 'Delete a record', }, { name: 'Get', value: 'get', description: 'Get a record by ID', action: 'Get a record', }, { name: 'Get Many', value: 'getAll', description: 'Get many records', action: 'Get many records', }, { name: 'Update', value: 'update', description: 'Update a record', action: 'Update a record', }, { name: 'Add Attachment', value: 'addAttachment', description: 'Add an attachment to a bill', action: 'Add an attachment to a bill', }, { name: 'Get Attachment', value: 'getAttachment', description: 'Get a bill attachment', action: 'Get a bill attachment', }, { name: 'Delete Attachment', value: 'deleteAttachment', description: 'Delete a bill attachment', action: 'Delete a bill attachment', }, { name: 'Get by SKU', value: 'getBySku', description: 'Get an item by SKU code', action: 'Get item by SKU', }, { name: 'Search', value: 'search', description: 'Search contacts by name', action: 'Search contacts by name', }, { name: 'Create From Sales Order', value: 'createFromSalesOrder', description: 'Create an instant invoice from a sales order', action: 'Create invoice from sales order', }, { name: 'Confirm Sales Order', value: 'confirm', description: 'Convert a draft sales order to confirmed/open status', action: 'Confirm a sales order', }, ], default: 'getAll', }, { displayName: 'Operation', name: 'operation', type: 'options', noDataExpression: true, displayOptions: { show: { resource: ['invoice'], }, }, options: [ { name: 'Create', value: 'create', description: 'Create a new record', action: 'Create a record', }, { name: 'Delete', value: 'delete', description: 'Delete a record', action: 'Delete a record', }, { name: 'Get', value: 'get', description: 'Get a record by ID', action: 'Get a record', }, { name: 'Get Many', value: 'getAll', description: 'Get many records', action: 'Get many records', }, { name: 'Update', value: 'update', description: 'Update a record', action: 'Update a record', }, { name: 'Create From Sales Order', value: 'createFromSalesOrder', description: 'Create an instant invoice from a sales order', action: 'Create invoice from sales order', }, { name: 'Mark as Sent', value: 'markAsSent', description: 'Mark an invoice as sent', action: 'Mark invoice as sent', }, ], default: 'getAll', }, { displayName: 'Input Method', name: 'inputMethod', type: 'options', options: [ { name: 'Form Fields', value: 'form', description: 'Use the form fields below', }, { name: 'Raw JSON', value: 'json', description: 'Provide complete sales order data as JSON', }, { name: 'Hybrid', value: 'hybrid', description: 'Choose customer from dropdown, provide rest as JSON', }, ], default: 'form', displayOptions: { show: { resource: ['salesOrder'], operation: ['create'], }, }, description: 'Choose how to provide sales order data', }, { displayName: 'Rates Include Tax', name: 'rateIncludesTax', type: 'boolean', default: false, displayOptions: { show: { resource: ['salesOrder'], operation: ['create'], inputMethod: ['form', 'hybrid'], }, }, description: 'If true, line-item rates are gross (tax-inclusive). Tax will be calculated and deducted automatically.', }, { displayName: 'Raw JSON Data', name: 'rawJsonData', type: 'json', required: true, default: '', displayOptions: { show: { resource: ['salesOrder'], operation: ['create'], inputMethod: ['json', 'hybrid'], }, }, description: 'Complete sales order data in JSON format. See documentation for schema.', typeOptions: { rows: 10, }, }, { displayName: 'Customer Name or ID', name: 'customerId', type: 'options', required: true, default: '', typeOptions: { loadOptionsMethod: 'getCustomers', }, displayOptions: { show: { resource: ['salesOrder'], operation: ['create'], inputMethod: ['form', 'hybrid'], }, }, description: 'The customer for this sales order. Choose from the list, or specify an ID using an <a href="https://docs.n8n.io/code-examples/expressions/">expression</a>.', }, { displayName: 'Sales Order Date', name: 'salesOrderDate', type: 'dateTime', default: '', displayOptions: { show: { resource: ['salesOrder'], operation: ['create'], inputMethod: ['form', 'hybrid'], }, }, description: 'Document date (YYYY-MM-DD). Defaults to today if omitted.', }, { displayName: 'Sales Order Number', name: 'salesOrderNumber', type: 'string', default: '', displayOptions: { show: { resource: ['salesOrder'], operation: ['create'], inputMethod: ['form', 'hybrid'], }, }, description: 'Sales order number. Leave blank to let Zoho auto-number.', }, { displayName: 'Line Items', name: 'lineItems', type: 'fixedCollection', typeOptions: { multipleValues: true, }, required: true, default: {}, displayOptions: { show: { resource: ['salesOrder'], operation: ['create'], inputMethod: ['form'], }, }, options: [ { name: 'item', displayName: 'Item', values: [ { displayName: 'Item Name or ID', name: 'item_id', type: 'options', default: '', typeOptions: { loadOptionsMethod: 'getItems', }, description: 'Choose from the list, or specify an ID using an <a href="https://docs.n8n.io/code-examples/expressions/">expression</a>', }, { displayName: 'Quantity', name: 'quantity', type: 'number', default: 1, typeOptions: { minValue: 0.01, }, }, { displayName: 'Rate', name: 'rate', type: 'number', default: 0, typeOptions: { numberPrecision: 2, }, }, ], }, ], }, { displayName: 'Search Type', name: 'searchType', type: 'options', options: [ { name: 'By ID', value: 'id', }, { name: 'By Number', value: 'number', }, ], default: 'id', displayOptions: { show: { resource: ['salesOrder'], operation: ['get'], }, }, description: 'How to search for the sales order', }, { displayName: 'Sales Order ID', name: 'salesOrderId', type: 'string', required: false, default: '', displayOptions: { show: { resource: ['salesOrder'], operation: ['get', 'delete', 'update', 'confirm'], }, }, description: 'The ID of the sales order', }, { displayName: 'Sales Order Number', name: 'salesOrderNumber', type: 'string', required: true, default: '', displayOptions: { show: { resource: ['salesOrder'], operation: ['get'], searchType: ['number'], }, }, description: 'The Sales Order Number (e.g., SO-00001)', }, { displayName: 'Return All', name: 'returnAll', type: 'boolean', displayOptions: { show: { resource: ['salesOrder'], 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: ['salesOrder'], operation: ['getAll'], returnAll: [false], }, }, typeOptions: { minValue: 1, maxValue: 200, }, default: 50, description: 'Max number of results to return', }, { displayName: 'Contact Name', name: 'contactName', type: 'string', required: true, default: '', displayOptions: { show: { resource: ['contact'], operation: ['create', 'update'], }, }, description: 'The name of the contact', }, { displayName: 'Company Name', name: 'companyName', type: 'string', required: false, default: '', displayOptions: { show: { resource: ['contact'], operation: ['create', 'update'], }, }, description: 'The company name for this contact', }, { displayName: 'Email', name: 'email', type: 'string', required: false, default: '', displayOptions: { show: { resource: ['contact'], operation: ['create', 'update'], }, }, description: 'The email address of the contact', }, { displayName: 'Phone', name: 'phone', type: 'string', required: false, default: '', displayOptions: { show: { resource: ['contact'], operation: ['create', 'update'], }, }, description: 'The phone number of the contact', }, { displayName: 'Website', name: 'website', type: 'string', required: false, default: '', displayOptions: { show: { resource: ['contact'], operation: ['create', 'update'], }, }, description: 'The website URL of the contact', }, { displayName: 'Currency Code', name: 'currencyCode', type: 'options', required: false, default: 'USD', options: [ { name: 'USD', value: 'USD' }, { name: 'EUR', value: 'EUR' }, { name: 'GBP', value: 'GBP' }, { name: 'CAD', value: 'CAD' }, { name: 'AUD', value: 'AUD' }, { name: 'INR', value: 'INR' }, ], displayOptions: { show: { resource: ['contact'], operation: ['create', 'update'], }, }, description: 'The currency code for this contact', }, { displayName: 'Opening Balance', name: 'openingBalance', type: 'number', required: false, default: 0, typeOptions: { numberPrecision: 2, }, displayOptions: { show: { resource: ['contact'], operation: ['create', 'update'], }, }, description: 'The opening balance for this contact', }, { displayName: 'Billing Address', name: 'billingAddress', type: 'fixedCollection', required: false, default: {}, displayOptions: { show: { resource: ['contact'], operation: ['create', 'update'], }, }, options: [ { name: 'address', displayName: 'Address', values: [ { displayName: 'Street', name: 'street', type: 'string', default: '', description: 'Street address', }, { displayName: 'City', name: 'city', type: 'string', default: '', description: 'City', }, { displayName: 'State', name: 'state', type: 'string', default: '', description: 'State or province', }, { displayName: 'ZIP', name: 'zip', type: 'string', default: '', description: 'ZIP or postal code', }, { displayName: 'Country', name: 'country', type: 'string', default: '', description: 'Country', }, ], }, ], }, { displayName: 'Shipping Address', name: 'shippingAddress', type: 'fixedCollection', required: false, default: {}, displayOptions: { show: { resource: ['contact'], operation: ['create', 'update'], }, }, options: [ { name: 'address', displayName: 'Address', values: [ { displayName: 'Street', name: 'street', type: 'string', default: '', description: 'Street address', }, { displayName: 'City', name: 'city', type: 'string', default: '', description: 'City', }, { displayName: 'State', name: 'state', type: 'string', default: '', description: 'State or province', }, { displayName: 'ZIP', name: 'zip', type: 'string', default: '', description: 'ZIP or postal code', }, { displayName: 'Country', name: 'country', type: 'string', default: '', description: 'Country', }, ], }, ], }, { displayName: 'Custom Fields', name: 'customFields', type: 'collection', required: false, default: {}, displayOptions: { show: { resource: ['contact'], operation: ['create', 'update'], }, }, description: 'Additional custom fields for the contact', }, { displayName: 'Contact ID', name: 'contactId', type: 'string', required: true, default: '', displayOptions: { show: { resource: ['contact'], operation: ['get', 'delete', 'update'], }, }, description: 'The ID of the contact', }, { displayName: 'Return All', name: 'returnAll', type: 'boolean', displayOptions: { show: { resource: ['contact'], 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: ['contact'], operation: ['getAll'], returnAll: [false], }, }, typeOptions: { minValue: 1, maxValue: 200, }, default: 50, description: 'Max number of results to return', }, { displayName: 'Updated After', name: 'updatedAfter', type: 'dateTime', required: false, default: '', typeOptions: { dateTimeFormat: 'YYYY-MM-DD', }, displayOptions: { show: { resource: ['contact'], operation: ['getAll'], }, }, description: 'Filter contacts updated after this date (leave empty to get all contacts)', }, { displayName: 'Search Name', name: 'searchName', type: 'string', required: true, default: '', displayOptions: { show: { resource: ['contact'], operation: ['search'], }, }, description: 'Full or partial customer name to search for', }, { displayName: 'Customer Name or ID', name: 'customerId', type: 'options', required: true, default: '', typeOptions: { loadOptionsMethod: 'getCustomers', }, displayOptions: { show: { resource: ['invoice'], operation: ['create'], }, }, description: 'The customer for this invoice. Choose from the list, or specify an ID using an <a href="https://docs.n8n.io/code-examples/expressions/">expression</a>.', }, { displayName: 'Line Items', name: 'lineItems', type: 'fixedCollection', typeOptions: { multipleValues: true, }, required: true, default: {}, displayOptions: { show: { resource: ['invoice'], operation: ['create'], }, }, options: [ { name: 'item', displayName: 'Item', values: [ { displayName: 'Item Name or ID', name: 'item_id', type: 'options', default: '', typeOptions: { loadOptionsMethod: 'getItems', }, description: 'Choose from the list, or specify an ID using an <a href="https://docs.n8n.io/code-examples/expressions/">expression</a>', }, { displayName: 'Quantity', name: 'quantity', type: 'number', default: 1, typeOptions: { minValue: 0.01, }, }, { displayName: 'Rate', name: 'rate', type: 'number', default: 0, typeOptions: { numberPrecision: 2, }, }, ], }, ], }, { displayName: 'Invoice ID', name: 'invoiceId', type: 'string', required: true, default: '', displayOptions: { show: { resource: ['invoice'], operation: ['get', 'delete', 'update', 'markAsSent'], }, }, description: 'The ID of the invoice', }, { displayName: 'Update Fields', name: 'updateFields', type: 'collection', placeholder: 'Add Field', default: {}, displayOptions: { show: { resource: ['invoice'], operation: ['update'], }, }, options: [ { displayName: 'Date', name: 'date', type: 'dateTime', default: '', description: 'The date of the invoice (YYYY-MM-DD format)', }, { displayName: 'Invoice Number', name: 'invoice_number', type: 'string', default: '', description: 'Custom invoice number', }, { displayName: 'Place of Supply', name: 'place_of_supply', type: 'string', default: '', description: 'Place of supply for tax calculations', }, { displayName: 'GST Treatment', name: 'gst_treatment', type: 'options', options: [ { name: 'Business – GST', value: 'business_gst', }, { name: 'Consumer', value: 'consumer', }, { name: 'Overseas', value: 'overseas', }, { name: 'SEZ – Without Tax', value: 'sezwp', }, { name: 'SEZ – With Tax', value: 'sez', }, { name: 'Unregistered', value: 'unregistered', }, ], default: 'business_gst', description: 'GST treatment type for the invoice', }, { displayName: 'GST Number', name: 'gst_no', type: 'string', default: '', description: 'GST number (GSTIN) for the invoice', }, { displayName: 'Due Date', name: 'due_date', type: 'dateTime', default: '', description: 'The due date of the invoice', }, { displayName: 'Reference Number', name: 'reference_number', type: 'string', default: '', description: 'Reference number for the invoice', }, { displayName: 'Notes', name: 'notes', type: 'string', typeOptions: { rows: 3, }, default: '', description: 'Notes for the invoice', }, { displayName: 'Terms', name: 'terms', type: 'string', typeOptions: { rows: 3, }, default: '', description: 'Terms and conditions for the invoice', }, { displayName: 'Reason for Update', name: 'reason', type: 'string', typeOptions: { rows: 2, }, default: '', description: 'Reason for updating the invoice (required for sent invoices)', }, ], }, { displayName: 'Line Items', name: 'lineItems', type: 'fixedCollection', typeOptions: { multipleValues: true, }, default: {}, displayOptions: { show: { resource: ['invoice'], operation: ['update'], }, }, options: [ { name: 'item', displayName: 'Item', values: [ { displayName: 'Item Name or ID', name: 'item_id', type: 'options', default: '', typeOptions: { loadOptionsMethod: 'getItems', }, description: 'Choose from the list, or specify an ID using an <a href="https://docs.n8n.io/code-examples/expressions/">expression</a>', }, { displayName: 'Quantity', name: 'quantity', type: 'number', default: 1, typeOptions: { minValue: 0.01, }, }, { displayName: 'Rate', name: 'rate', type: 'number', default: 0, typeOptions: { numberPrecision: 2, }, }, ], }, ], description: 'Line items for the invoice (leave empty to keep existing items)', }, { displayName: 'Return All', name: 'returnAll', type: 'boolean', displayOptions: { show: { resource: ['invoice'], 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: ['invoice'], operation: ['getAll'], returnAll: [false], }, }, typeOptions: { minValue: 1, maxValue: 200, }, default: 50, description: 'Max number of results to return', }, { displayName: 'Sales Order ID', name: 'salesOrderId', type: 'string', required: true, default: '', displayOptions: { show: { resource: ['invoice'], operation: ['createFromSalesOrder'], }, }, description: 'The ID of the sales order to convert to an invoice', }, { displayName: 'Additional Fields', name: 'additionalFields', type: 'collection', placeholder: 'Add Field', default: {}, displayOptions: { show: { resource: ['invoice'], operation: ['createFromSalesOrder'], }, }, options: [ { displayName: 'Date', name: 'date', type: 'dateTime', default: '', description: 'The date of the invoice (defaults to today)', }, { displayName: 'Due Date', name: 'due_date', type: 'dateTime', default: '', description: 'The due date of the invoice', }, { displayName: 'Invoice Number', name: 'invoice_number', type: 'string', default: '', description: 'Custom invoice number (auto-generated if not provided)', }, { displayName: 'Reference Number', name: 'reference_number', type: 'string', default: '', description: 'Reference number for the invoice', }, { displayName: 'Notes', name: 'notes', type: 'string', typeOptions: { rows: 3, }, default: '', description: 'Notes for the invoice', }, { displayName: 'Terms', name: 'terms', type: 'string', typeOptions: { rows: 3, }, default: '', description: 'Terms and conditions for the invoice', }, { displayName: 'Discount', name: 'discount', type: 'number', typeOptions: { numberPrecision: 2, }, default: 0, description: 'Discount amount or percentage', }, { displayName: 'Discount Type', name: 'discount_type', type: 'options', options: [ { name: 'Entity Level', value: 'entity_level', }, { name: 'Item Level', value: 'item_level', }, ], default: 'entity_level', description: 'How the discount is applied', }, { displayName: 'Exchange Rate', name: 'exchange_rate', type: 'number', typeOptions: { numberPrecision: 4, }, default: 1, description: 'Exchange rate for multi-currency invoices', }, ], }, { 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', }, ], }; methods = { loadOptions: { async getCustomers() { const returnData = []; try { const customers = await GenericFunctions_1.zohoApiRequestAllItems.call(this, 'GET', '/contacts?contact_type=customer'); for (const customer of customers) { returnData.push({ name: customer.contact_name, value: customer.contact_id, }); } if (returnData.length === 0) { const allContacts = await GenericFunctions_1.zohoApiRequestAllItems.call(this, 'GET', '/contacts'); for (const contact of allContacts) { returnData.push({ name: contact.contact_name, value: contact.contact_id, }); } } } catch (error) { console.error('Failed to load customers:', error); } return returnData; }, async getItems() { const returnData = []; const items = await GenericFunctions_1.zohoApiRequestAllItems.call(this, 'GET', '/items'); for (const item of items) { returnData.pus