UNPKG

@netair-tech/n8n-nodes-tiny-erp-auth2

Version:

n8n custom node for Tiny ERP integration with OAuth2 authentication

949 lines 43.7 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.TinyErp = void 0; const n8n_workflow_1 = require("n8n-workflow"); const GenericFunctions_1 = require("./GenericFunctions"); class TinyErp { constructor() { this.description = { displayName: 'Tiny ERP', name: 'tinyErp', icon: 'file:tinyerp.svg', group: ['transform'], version: 1, subtitle: '={{$parameter["operation"] + ": " + $parameter["resource"]}}', description: 'Interact with Tiny ERP API', defaults: { name: 'Tiny ERP', }, inputs: ['main'], outputs: ['main'], credentials: [ { name: 'tinyOAuth2Api', required: true, }, ], properties: [ { displayName: 'Resource', name: 'resource', type: 'options', noDataExpression: true, options: [ { name: 'Product', value: 'product', }, { name: 'Product Stock', value: 'produto_estoque', }, ], default: 'product', }, { displayName: 'Operation', name: 'operation', type: 'options', noDataExpression: true, options: [ { name: 'Create', value: 'create', description: 'Create a new product', action: 'Create a product', }, { name: 'Create Variation', value: 'createVariation', description: 'Create a product variation', action: 'Create a product variation', }, { name: 'Delete Variation', value: 'deleteVariation', description: 'Delete a product variation', action: 'Delete a product variation', }, { name: 'Get', value: 'get', description: 'Get a product by ID', action: 'Get a product', }, { name: 'Get Costs', value: 'getCosts', description: 'Get product costs', action: 'Get product costs', }, { name: 'Get Kit', value: 'getKit', description: 'Get product kit information', action: 'Get product kit', }, { name: 'Get Manufacturing', value: 'getManufacturing', description: 'Get product manufacturing information', action: 'Get product manufacturing', }, { name: 'Get Many', value: 'getAll', description: 'Get many products', action: 'Get many products', }, { name: 'Get Tags', value: 'getTags', description: 'Get product tags', action: 'Get product tags', }, { name: 'Update', value: 'update', description: 'Update a product', action: 'Update a product', }, { name: 'Update Kit', value: 'updateKit', description: 'Update product kit', action: 'Update product kit', }, { name: 'Update Manufacturing', value: 'updateManufacturing', description: 'Update product manufacturing', action: 'Update product manufacturing', }, { name: 'Update Price', value: 'updatePrice', description: 'Update product price', action: 'Update product price', }, { name: 'Update Stock', value: 'updateStock', description: 'Update a product stock', action: 'Update a product stock', }, { name: 'Update Variation', value: 'updateVariation', description: 'Update product variation', action: 'Update product variation', }, ], default: 'get', }, { displayName: 'Product ID', name: 'productId', type: 'number', required: true, displayOptions: { show: { resource: ['product', 'produto_estoque'], operation: [ 'get', 'update', 'updatePrice', 'getManufacturing', 'updateManufacturing', 'getKit', 'updateKit', 'updateVariation', 'deleteVariation', 'createVariation', 'getCosts', 'getTags', 'updateStock', ], }, }, default: 0, description: 'The ID of the product', }, // Variation ID field { displayName: 'Variation ID', name: 'variationId', type: 'number', required: true, displayOptions: { show: { resource: ['product'], operation: ['updateVariation', 'deleteVariation'], }, }, default: 0, description: 'The ID of the product variation', }, // Deposit ID field { displayName: 'Deposit ID', name: 'depositId', type: 'number', required: true, displayOptions: { show: { resource: ['produto_estoque'], operation: ['updateStock'], }, }, default: 0, description: 'The ID of the deposit', }, // Quantity field { displayName: 'Quantity', name: 'quantity', type: 'number', required: true, displayOptions: { show: { resource: ['produto_estoque'], operation: ['updateStock'], }, }, default: 0, description: 'The quantity of the product in stock', }, // Get All Products filters { displayName: 'Additional Fields', name: 'additionalFields', type: 'collection', placeholder: 'Add Field', default: {}, displayOptions: { show: { resource: ['product'], operation: ['getAll'], }, }, options: [ { displayName: 'Code', name: 'codigo', type: 'string', default: '', description: 'Search by product code', }, { displayName: 'Creation Date', name: 'dataCriacao', type: 'dateTime', default: '', description: 'Search by creation date', }, { displayName: 'GTIN', name: 'gtin', type: 'string', default: '', description: 'Search by GTIN code', }, { displayName: 'Limit', name: 'limit', type: 'number', default: 50, description: 'Max number of results to return', typeOptions: { minValue: 1, }, }, { displayName: 'Modification Date', name: 'dataAlteracao', type: 'dateTime', default: '', description: 'Search by last modification date', }, { displayName: 'Name', name: 'nome', type: 'string', default: '', description: 'Search by partial or complete product name', }, { displayName: 'Offset', name: 'offset', type: 'number', default: 0, description: 'Number of results to skip', typeOptions: { minValue: 0, }, }, { displayName: 'Status', name: 'situacao', type: 'options', options: [ { name: 'Active', value: 'A', }, { name: 'Inactive', value: 'I', }, ], default: 'A', description: 'Product status', }, ], }, // Product creation/update fields { displayName: 'Product Data', name: 'productData', type: 'collection', placeholder: 'Add Field', default: {}, displayOptions: { show: { resource: ['product'], operation: ['create', 'update'], }, }, options: [ { displayName: 'Complementary Description', name: 'descricaoComplementar', type: 'string', default: '', }, { displayName: 'Description', name: 'descricao', type: 'string', default: '', description: 'Product description', }, { displayName: 'GTIN', name: 'gtin', type: 'string', default: '', description: 'GTIN barcode', }, { displayName: 'NCM', name: 'ncm', type: 'string', default: '', description: 'NCM classification', }, { displayName: 'Observations', name: 'observacoes', type: 'string', default: '', description: 'Additional observations', }, { displayName: 'Origin', name: 'origem', type: 'number', default: 0, description: 'Product origin', }, { displayName: 'SKU', name: 'sku', type: 'string', default: '', description: 'Product SKU', }, { displayName: 'Type', name: 'tipo', type: 'options', options: [ { name: 'Kit', value: 'K', }, { name: 'Manufactured Product', value: 'F', }, { name: 'Product with Variations', value: 'V', }, { name: 'Raw Material', value: 'M', }, { name: 'Simple Product', value: 'S', }, ], default: 'S', description: 'Product type', }, { displayName: 'Unit', name: 'unidade', type: 'string', default: '', description: 'Unit of measurement', }, { displayName: 'Warranty', name: 'garantia', type: 'string', default: '', description: 'Warranty information', }, ], }, // Price update fields { displayName: 'Price Data', name: 'priceData', type: 'collection', placeholder: 'Add Field', default: {}, displayOptions: { show: { resource: ['product'], operation: ['updatePrice'], }, }, options: [ { displayName: 'Price', name: 'preco', type: 'number', default: 0, description: 'Product price', typeOptions: { numberPrecision: 2, }, }, { displayName: 'Promotional Price', name: 'precoPromocional', type: 'number', default: 0, typeOptions: { numberPrecision: 2, }, }, ], }, // Costs query fields { displayName: 'Cost Filters', name: 'costFilters', type: 'collection', placeholder: 'Add Field', default: {}, displayOptions: { show: { resource: ['product'], operation: ['getCosts'], }, }, options: [ { displayName: 'Start Date', name: 'dataInicial', type: 'dateTime', default: '', description: 'Start date for cost filtering', }, { displayName: 'End Date', name: 'dataFinal', type: 'dateTime', default: '', description: 'End date for cost filtering', }, { displayName: 'Limit', name: 'limit', type: 'number', default: 50, description: 'Max number of results to return', typeOptions: { minValue: 1, }, }, { displayName: 'Offset', name: 'offset', type: 'number', default: 0, description: 'Number of results to skip', typeOptions: { minValue: 0, }, }, ], }, // Kit data for update { displayName: 'Kit Items', name: 'kitItems', type: 'fixedCollection', default: { items: [] }, displayOptions: { show: { resource: ['product'], operation: ['updateKit'], }, }, typeOptions: { multipleValues: true, }, options: [ { name: 'items', displayName: 'Kit Item', values: [ { displayName: 'Product ID', name: 'id', type: 'number', default: 0, description: 'ID of the product in the kit', }, { displayName: 'Quantity', name: 'quantidade', type: 'number', default: 1, description: 'Quantity of the product in the kit', }, ], }, ], }, // Manufacturing data for update { displayName: 'Manufacturing Data', name: 'manufacturingData', type: 'collection', placeholder: 'Add Field', default: {}, displayOptions: { show: { resource: ['product'], operation: ['updateManufacturing'], }, }, options: [ { displayName: 'Products', name: 'produtos', type: 'fixedCollection', default: { items: [] }, typeOptions: { multipleValues: true, }, options: [ { name: 'items', displayName: 'Product', values: [ { displayName: 'Product ID', name: 'id', type: 'number', default: 0, description: 'ID of the product used in manufacturing', }, { displayName: 'Quantity', name: 'quantidade', type: 'number', default: 1, description: 'Quantity needed for manufacturing', }, ], }, ], }, { displayName: 'Steps', name: 'etapas', type: 'fixedCollection', default: { items: [] }, typeOptions: { multipleValues: true, }, options: [ { name: 'items', displayName: 'Step', values: [ { displayName: 'Step Name', name: 'step', type: 'string', default: '', description: 'Manufacturing step description', }, ], }, ], }, ], }, // Variation data for create/update { displayName: 'Variation Data', name: 'variationData', type: 'collection', placeholder: 'Add Field', default: {}, displayOptions: { show: { resource: ['product'], operation: ['createVariation', 'updateVariation'], }, }, options: [ { displayName: 'GTIN', name: 'gtin', type: 'string', default: '', description: 'Variation GTIN', }, { displayName: 'Initial Stock', name: 'inicial', type: 'number', default: 0, description: 'Initial stock quantity', }, { displayName: 'Price', name: 'preco', type: 'number', default: 0, description: 'Variation price', typeOptions: { numberPrecision: 2, }, }, { displayName: 'Promotional Price', name: 'precoPromocional', type: 'number', default: 0, description: 'Variation promotional price', typeOptions: { numberPrecision: 2, }, }, { displayName: 'SKU', name: 'sku', type: 'string', default: '', description: 'Variation SKU', }, ], }, ], }; } async execute() { var _a, _b, _c; const items = this.getInputData(); const returnData = []; for (let i = 0; i < items.length; i++) { try { const resource = this.getNodeParameter('resource', i); const operation = this.getNodeParameter('operation', i); if (resource === 'product') { if (operation === 'create') { // Create product const productData = this.getNodeParameter('productData', i); // Ensure 'tipo' is just the code if (productData.tipo && typeof productData.tipo === 'string' && productData.tipo.includes(' - ')) { productData.tipo = productData.tipo.split(' - ')[0]; } // Send the product data directly as the request body (API v3 format) const response = await GenericFunctions_1.tinyErpApiRequest.call(this, 'POST', '/produtos', productData); returnData.push({ json: response, pairedItem: { item: i }, }); } else if (operation === 'get') { // Get product by ID const productId = this.getNodeParameter('productId', i); const response = await GenericFunctions_1.tinyErpApiRequest.call(this, 'GET', `/produtos/${productId}`); returnData.push({ json: response, pairedItem: { item: i }, }); } else if (operation === 'getAll') { // Get all products const additionalFields = this.getNodeParameter('additionalFields', i); const qs = {}; if (additionalFields.nome) qs.nome = additionalFields.nome; if (additionalFields.codigo) qs.codigo = additionalFields.codigo; if (additionalFields.gtin) qs.gtin = additionalFields.gtin; if (additionalFields.situacao) qs.situacao = additionalFields.situacao; if (additionalFields.dataCriacao) qs.dataCriacao = additionalFields.dataCriacao; if (additionalFields.dataAlteracao) qs.dataAlteracao = additionalFields.dataAlteracao; if (additionalFields.limit) qs.limit = additionalFields.limit; if (additionalFields.offset) qs.offset = additionalFields.offset; const response = await GenericFunctions_1.tinyErpApiRequest.call(this, 'GET', '/produtos', {}, qs); returnData.push({ json: response, pairedItem: { item: i }, }); } else if (operation === 'update') { // Update product const productId = this.getNodeParameter('productId', i); const productData = this.getNodeParameter('productData', i); // The 'tipo' property cannot be updated, so we remove it from the body. if (productData.tipo !== undefined) { delete productData.tipo; } // Send the product data directly as the request body (API v3 format) await GenericFunctions_1.tinyErpApiRequest.call(this, 'PUT', `/produtos/${productId}`, productData); returnData.push({ json: { success: true, productId }, pairedItem: { item: i }, }); } else if (operation === 'updatePrice') { // Update product price const productId = this.getNodeParameter('productId', i); const priceData = this.getNodeParameter('priceData', i); const response = await GenericFunctions_1.tinyErpApiRequest.call(this, 'PUT', `/produtos/${productId}/preco`, priceData); returnData.push({ json: response, pairedItem: { item: i }, }); } else if (operation === 'getManufacturing') { // Get manufacturing data const productId = this.getNodeParameter('productId', i); const response = await GenericFunctions_1.tinyErpApiRequest.call(this, 'GET', `/produtos/${productId}/fabricado`); returnData.push({ json: response, pairedItem: { item: i }, }); } else if (operation === 'updateManufacturing') { // Update manufacturing data const productId = this.getNodeParameter('productId', i); const manufacturingData = this.getNodeParameter('manufacturingData', i); // Transform the data structure const body = {}; if ((_a = manufacturingData.produtos) === null || _a === void 0 ? void 0 : _a.items) { body.produtos = manufacturingData.produtos.items.map((item) => ({ produto: { id: item.id }, quantidade: item.quantidade, })); } if ((_b = manufacturingData.etapas) === null || _b === void 0 ? void 0 : _b.items) { body.etapas = manufacturingData.etapas.items.map((item) => item.step); } await GenericFunctions_1.tinyErpApiRequest.call(this, 'PUT', `/produtos/${productId}/fabricado`, body); returnData.push({ json: { success: true, productId }, pairedItem: { item: i }, }); } else if (operation === 'getKit') { // Get kit data const productId = this.getNodeParameter('productId', i); const response = await GenericFunctions_1.tinyErpApiRequest.call(this, 'GET', `/produtos/${productId}/kit`); returnData.push({ json: response, pairedItem: { item: i }, }); } else if (operation === 'updateKit') { // Update kit data const productId = this.getNodeParameter('productId', i); const kitItems = this.getNodeParameter('kitItems', i); // Transform the data structure const body = ((_c = kitItems.items) === null || _c === void 0 ? void 0 : _c.map((item) => ({ produto: { id: item.id }, quantidade: item.quantidade, }))) || []; await GenericFunctions_1.tinyErpApiRequest.call(this, 'PUT', `/produtos/${productId}/kit`, body); returnData.push({ json: { success: true, productId }, pairedItem: { item: i }, }); } else if (operation === 'createVariation') { // Create product variation const productId = this.getNodeParameter('productId', i); const variationData = this.getNodeParameter('variationData', i); // Transform the data structure const body = { sku: variationData.sku, gtin: variationData.gtin, }; if (variationData.preco || variationData.precoPromocional) { body.precos = {}; if (variationData.preco) body.precos.preco = variationData.preco; if (variationData.precoPromocional) body.precos.precoPromocional = variationData.precoPromocional; } if (variationData.inicial) { body.estoque = { inicial: variationData.inicial }; } const response = await GenericFunctions_1.tinyErpApiRequest.call(this, 'POST', `/produtos/${productId}/variacoes`, body); returnData.push({ json: response, pairedItem: { item: i }, }); } else if (operation === 'updateVariation') { // Update product variation const productId = this.getNodeParameter('productId', i); const variationId = this.getNodeParameter('variationId', i); const variationData = this.getNodeParameter('variationData', i); await GenericFunctions_1.tinyErpApiRequest.call(this, 'PUT', `/produtos/${productId}/variacoes/${variationId}`, variationData); returnData.push({ json: { success: true, productId, variationId }, pairedItem: { item: i }, }); } else if (operation === 'deleteVariation') { // Delete product variation const productId = this.getNodeParameter('productId', i); const variationId = this.getNodeParameter('variationId', i); await GenericFunctions_1.tinyErpApiRequest.call(this, 'DELETE', `/produtos/${productId}/variacoes/${variationId}`); returnData.push({ json: { success: true, productId, variationId }, pairedItem: { item: i }, }); } else if (operation === 'getCosts') { // Get product costs const productId = this.getNodeParameter('productId', i); const costFilters = this.getNodeParameter('costFilters', i); const qs = {}; if (costFilters.dataInicial) qs.dataInicial = costFilters.dataInicial; if (costFilters.dataFinal) qs.dataFinal = costFilters.dataFinal; if (costFilters.limit) qs.limit = costFilters.limit; if (costFilters.offset) qs.offset = costFilters.offset; const response = await GenericFunctions_1.tinyErpApiRequest.call(this, 'GET', `/produtos/${productId}/custos`, {}, qs); returnData.push({ json: response, pairedItem: { item: i }, }); } else if (operation === 'getTags') { // Get product tags const productId = this.getNodeParameter('productId', i); const response = await GenericFunctions_1.tinyErpApiRequest.call(this, 'GET', `/produtos/${productId}/tags`); returnData.push({ json: response, pairedItem: { item: i }, }); } else { throw new n8n_workflow_1.NodeOperationError(this.getNode(), `The operation "${operation}" is not supported!`, { itemIndex: i }); } } else if (resource === 'produto_estoque') { if (operation === 'updateStock') { const productId = this.getNodeParameter('productId', i); const depositId = this.getNodeParameter('depositId', i); const quantity = this.getNodeParameter('quantity', i); const body = { deposito: { id: depositId, }, quantidade: quantity, tipo: 'B', }; const endpoint = `/estoque/${productId}`; const responseData = await GenericFunctions_1.tinyErpApiRequest.call(this, 'PUT', endpoint, body); returnData.push({ json: responseData, pairedItem: { item: i }, }); } else { throw new n8n_workflow_1.NodeOperationError(this.getNode(), `The operation "${operation}" is not supported for resource "${resource}"!`, { itemIndex: i }); } } else { throw new n8n_workflow_1.NodeOperationError(this.getNode(), `The resource "${resource}" is not supported!`, { itemIndex: i }); } if (items[i] !== undefined) { // Helper function to safely get parameters const safeGetParameter = (paramName, defaultValue = undefined) => { try { return this.getNodeParameter(paramName, i); } catch { return defaultValue; } }; items[i].json.request = { resource: resource, operation: operation, productId: safeGetParameter('productId'), variationId: safeGetParameter('variationId'), depositId: safeGetParameter('depositId'), quantity: safeGetParameter('quantity'), productData: safeGetParameter('productData'), priceData: safeGetParameter('priceData'), costFilters: safeGetParameter('costFilters'), kitItems: safeGetParameter('kitItems'), manufacturingData: safeGetParameter('manufacturingData'), variationData: safeGetParameter('variationData'), additionalFields: safeGetParameter('additionalFields'), }; } } catch (error) { if (this.continueOnFail()) { returnData.push({ json: { error: error instanceof Error ? error.message : String(error) }, pairedItem: { item: i }, }); continue; } throw error; } } return [returnData]; } } exports.TinyErp = TinyErp; //# sourceMappingURL=TinyErp.node.js.map