UNPKG

@pixelinfinito/n8n-nodes-vendus

Version:

Vendus API integration for n8n - Invoicing and business management automation

555 lines 26.1 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.Vendus = void 0; const n8n_workflow_1 = require("n8n-workflow"); const VendusDescription_1 = require("./VendusDescription"); class Vendus { constructor() { this.description = { displayName: 'Vendus', name: 'vendus', icon: 'file:vendus.svg', group: ['transform'], version: 1, subtitle: '={{$parameter["operation"] + ": " + $parameter["resource"]}}', description: 'Interact with Vendus API for invoicing and business management. Developed by Pixel Infinito (https://pixel.ao)', defaults: { name: 'Vendus', }, inputs: ["main"], outputs: ["main"], credentials: [ { name: 'vendusApi', required: true, }, ], requestDefaults: { baseURL: '={{$credentials?.baseUrl}}', url: '', headers: { Accept: 'application/json', 'Content-Type': 'application/json', }, }, properties: [ { displayName: 'Resource', name: 'resource', type: 'options', noDataExpression: true, options: [ { name: 'Account', value: 'account', }, { name: 'Client', value: 'client', }, { name: 'Document', value: 'document', }, { name: 'Product', value: 'product', }, { name: 'Receipt', value: 'receipt', }, { name: 'Store', value: 'store', }, { name: 'Supplier', value: 'supplier', }, ], default: 'account', }, ...VendusDescription_1.vendusOperations, ...VendusDescription_1.vendusFields, { displayName: 'Options', name: 'options', type: 'collection', placeholder: 'Add Option', default: {}, options: [ { displayName: 'Enable Debug Logging', name: 'enableDebugLogging', type: 'boolean', default: false, description: 'Whether to enable detailed debug logging for troubleshooting API calls', }, ], }, ], }; this.methods = { loadOptions: { async getProductCategories() { try { const response = await this.helpers.httpRequestWithAuthentication.call(this, 'vendusApi', { method: 'GET', url: '/products/categories', }); if (Array.isArray(response)) { return response.map((category) => ({ name: category.title || category.name || `Category ${category.id}`, value: category.id, })); } return []; } catch (error) { return [ { name: 'General', value: '1' }, { name: 'Electronics', value: '2' }, { name: 'Clothing', value: '3' }, ]; } }, async getProductBrands() { try { const response = await this.helpers.httpRequestWithAuthentication.call(this, 'vendusApi', { method: 'GET', url: '/products/brands', }); if (Array.isArray(response)) { return response.map((brand) => ({ name: brand.title || brand.name || `Brand ${brand.id}`, value: brand.id, })); } return []; } catch (error) { return [ { name: 'Generic', value: '1' }, { name: 'Premium', value: '2' }, ]; } }, async getProductUnits() { try { const response = await this.helpers.httpRequestWithAuthentication.call(this, 'vendusApi', { method: 'GET', url: '/products/units', }); if (Array.isArray(response)) { return response.map((unit) => ({ name: unit.title || unit.name || `Unit ${unit.id}`, value: unit.id, })); } return []; } catch (error) { return [ { name: 'Each (Un)', value: '1' }, { name: 'Kilogram (Kg)', value: '2' }, { name: 'Liter (L)', value: '3' }, { name: 'Meter (M)', value: '4' }, ]; } }, async getStores() { try { const response = await this.helpers.httpRequestWithAuthentication.call(this, 'vendusApi', { method: 'GET', url: '/stores', }); if (Array.isArray(response)) { return response.map((store) => ({ name: store.title || store.name || `Store ${store.id}`, value: store.id, })); } return []; } catch (error) { return [ { name: 'Main Store', value: '1' }, ]; } }, async getPaymentMethods() { try { const response = await this.helpers.httpRequestWithAuthentication.call(this, 'vendusApi', { method: 'GET', url: '/documents/paymentmethods', }); if (Array.isArray(response)) { return response.map((method) => ({ name: method.title || method.name || `Payment Method ${method.id}`, value: method.id, })); } return []; } catch (error) { return [ { name: 'Cash', value: '1' }, { name: 'Credit Card', value: '2' }, { name: 'Bank Transfer', value: '3' }, { name: 'Check', value: '4' }, ]; } }, async getDocumentTypes() { try { const response = await this.helpers.httpRequestWithAuthentication.call(this, 'vendusApi', { method: 'GET', url: '/documents/types', }); if (Array.isArray(response)) { return response.map((type) => ({ name: type.title || type.name || `Document Type ${type.id}`, value: type.id, })); } return []; } catch (error) { return [ { name: 'Invoice', value: 'FT' }, { name: 'Simplified Invoice', value: 'FS' }, { name: 'Invoice Receipt', value: 'FR' }, { name: 'Credit Note', value: 'NC' }, { name: 'Table Consultation', value: 'DC' }, { name: 'Pro-Forma Invoice', value: 'PF' }, { name: 'Quote', value: 'OT' }, { name: 'Order', value: 'EC' }, { name: 'Receipt', value: 'RG' }, ]; } }, async getPriceGroups() { try { const response = await this.helpers.httpRequestWithAuthentication.call(this, 'vendusApi', { method: 'GET', url: '/products/pricegroups', }); if (Array.isArray(response)) { return response.map((group) => ({ name: group.title || group.name || `Price Group ${group.id}`, value: group.id, })); } return []; } catch (error) { return [ { name: 'Standard', value: '1' }, { name: 'VIP', value: '2' }, { name: 'Wholesale', value: '3' }, ]; } }, async getClients() { try { const response = await this.helpers.httpRequestWithAuthentication.call(this, 'vendusApi', { method: 'GET', url: '/clients', qs: { per_page: 100, }, }); if (Array.isArray(response)) { return response.map((client) => ({ name: `${client.name} (${client.fiscal_id || client.id})`, value: client.id, })); } return []; } catch (error) { return []; } }, async getSuppliers() { try { const response = await this.helpers.httpRequestWithAuthentication.call(this, 'vendusApi', { method: 'GET', url: '/suppliers', qs: { per_page: 100, }, }); if (Array.isArray(response)) { return response.map((supplier) => ({ name: `${supplier.name} (${supplier.fiscal_id || supplier.id})`, value: supplier.id, })); } return []; } catch (error) { return []; } }, async getProducts() { try { const response = await this.helpers.httpRequestWithAuthentication.call(this, 'vendusApi', { method: 'GET', url: '/products', qs: { per_page: 100, }, }); if (Array.isArray(response)) { return response.map((product) => ({ name: `${product.title || product.name} (${product.reference || product.id})`, value: product.id, })); } return []; } catch (error) { return []; } }, }, }; } async execute() { var _a, _b, _c, _d, _e, _f, _g, _h; 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); const debugLogging = this.getNodeParameter('options.enableDebugLogging', i, false); if (debugLogging) { this.logger.info('🔍 Vendus Debug - Execution Start', { resource, operation, itemIndex: i, timestamp: new Date().toISOString(), }); } const operationDef = Vendus.getOperationDefinition(resource, operation); if (!operationDef || !operationDef.routing) { throw new n8n_workflow_1.NodeOperationError(this.getNode(), `No routing configuration found for ${resource}.${operation}`); } let url = operationDef.routing.request.url; const method = operationDef.routing.request.method || 'GET'; if (debugLogging) { this.logger.info('🔍 Vendus Debug - URL Template', { originalTemplate: url, method, resource, operation, }); } if (url.includes('{{$parameter.')) { const paramMatches = url.match(/\{\{\$parameter\.(\w+)\}\}/g); if (paramMatches) { for (const match of paramMatches) { const paramName = match.replace('{{$parameter.', '').replace('}}', ''); try { const paramValue = this.getNodeParameter(paramName, i); if (debugLogging) { this.logger.info('🔍 Vendus Debug - Parameter Substitution', { paramName, paramValue, match, resource, operation, }); } url = url.replace(match, paramValue || ''); } catch (error) { if (debugLogging) { this.logger.error('🔍 Vendus Debug - Parameter Error', { paramName, error: error.message, match, resource, operation, }); } throw new n8n_workflow_1.NodeOperationError(this.getNode(), `Parameter '${paramName}' is required but not provided`); } } } } const credentials = await this.getCredentials('vendusApi'); if (debugLogging) { this.logger.info('🔍 Vendus Debug - Final URL', { relativePath: url, baseURL: credentials === null || credentials === void 0 ? void 0 : credentials.baseUrl, completeURL: `${credentials === null || credentials === void 0 ? void 0 : credentials.baseUrl}${url}`, method, resource, operation, }); } const requestOptions = { method: method, baseURL: credentials === null || credentials === void 0 ? void 0 : credentials.baseUrl, url: url, headers: { 'Accept': 'application/json', 'Content-Type': 'application/json', }, }; if (((_b = (_a = operationDef.routing) === null || _a === void 0 ? void 0 : _a.request) === null || _b === void 0 ? void 0 : _b.body) && (method === 'POST' || method === 'PUT' || method === 'PATCH')) { const bodyTemplate = operationDef.routing.request.body; requestOptions.body = Vendus.buildRequestBody(bodyTemplate, this, i, debugLogging); if (debugLogging) { this.logger.info('🔍 Vendus Debug - Request Body', { bodyTemplate: JSON.stringify(bodyTemplate, null, 2), builtBody: JSON.stringify(requestOptions.body, null, 2), resource, operation, }); } } if (debugLogging) { this.logger.info('🔍 Vendus Debug - Request Details', { requestOptions: JSON.stringify(requestOptions, null, 2), credentials: { baseUrl: credentials === null || credentials === void 0 ? void 0 : credentials.baseUrl, hasApiKey: !!(credentials === null || credentials === void 0 ? void 0 : credentials.apiKey), }, resource, operation, }); } const responseData = await this.helpers.httpRequestWithAuthentication.call(this, 'vendusApi', requestOptions); if (debugLogging) { this.logger.info('🔍 Vendus Debug - Response Success', { responseType: typeof responseData, responseSize: JSON.stringify(responseData).length, responsePreview: JSON.stringify(responseData).substring(0, 300) + '...', resource, operation, }); } returnData.push({ json: responseData, }); } catch (error) { const debugLogging = this.getNodeParameter('options.enableDebugLogging', i, false); if (debugLogging) { this.logger.error('🔍 Vendus Debug - Request Failed', { error: error.message, stack: error.stack, resource: this.getNodeParameter('resource', i), operation: this.getNodeParameter('operation', i), errorCode: error.code, errorResponse: ((_c = error.response) === null || _c === void 0 ? void 0 : _c.data) || 'No response data', requestUrl: ((_d = error.config) === null || _d === void 0 ? void 0 : _d.url) || 'No URL', requestMethod: ((_e = error.config) === null || _e === void 0 ? void 0 : _e.method) || 'No method', itemIndex: i, timestamp: new Date().toISOString(), }); } if (this.continueOnFail()) { returnData.push({ json: { error: error.message, errorDetails: { code: error.code, response: (_f = error.response) === null || _f === void 0 ? void 0 : _f.data, url: (_g = error.config) === null || _g === void 0 ? void 0 : _g.url, method: (_h = error.config) === null || _h === void 0 ? void 0 : _h.method, }, }, }); continue; } throw error; } } return [returnData]; } static getOperationDefinition(resource, operation) { var _a, _b, _c, _d; for (const resourceOps of VendusDescription_1.vendusOperations) { if ((_c = (_b = (_a = resourceOps.displayOptions) === null || _a === void 0 ? void 0 : _a.show) === null || _b === void 0 ? void 0 : _b.resource) === null || _c === void 0 ? void 0 : _c.includes(resource)) { const operationDef = (_d = resourceOps.options) === null || _d === void 0 ? void 0 : _d.find((op) => op.value === operation); if (operationDef) { return operationDef; } } } return null; } static buildRequestBody(bodyTemplate, context, itemIndex, debugLogging) { if (typeof bodyTemplate === 'string' && bodyTemplate.startsWith('={{') && bodyTemplate.endsWith('}}')) { const expression = bodyTemplate.slice(3, -2); if (expression.startsWith('$parameter.')) { const paramPath = expression.replace('$parameter.', ''); if (paramPath.includes('?.')) { const [mainParam, subParam] = paramPath.split('?.'); try { const mainValue = context.getNodeParameter(mainParam, itemIndex); if (mainValue && typeof mainValue === 'object' && subParam in mainValue) { let result = mainValue[subParam]; if (mainParam === 'items' && subParam === 'itemsValues' && Array.isArray(result)) { result = result.map((item) => { let productIdentifier = {}; if (item.productId && item.productId !== '') { productIdentifier.id = item.productId; } else if (item.productReference && item.productReference !== '') { productIdentifier.reference = item.productReference; } return { ...productIdentifier, qty: item.quantity, discount: item.discount, tax_rate: item.taxRate, unit_price: item.unitPrice, }; }); } return result; } return []; } catch (error) { if (debugLogging) { context.logger.warn(`🔍 Vendus Debug - Optional parameter '${mainParam}' not found, using default`); } return []; } } else { try { return context.getNodeParameter(paramPath, itemIndex); } catch (error) { if (debugLogging) { context.logger.error(`🔍 Vendus Debug - Parameter '${paramPath}' not found:`, error.message); } throw new n8n_workflow_1.NodeOperationError(context.getNode(), `Parameter '${paramPath}' is required but not provided`); } } } } else if (Array.isArray(bodyTemplate)) { return bodyTemplate.map(item => Vendus.buildRequestBody(item, context, itemIndex, debugLogging)); } else if (typeof bodyTemplate === 'object' && bodyTemplate !== null) { const result = {}; for (const [key, value] of Object.entries(bodyTemplate)) { result[key] = Vendus.buildRequestBody(value, context, itemIndex, debugLogging); } return result; } return bodyTemplate; } } exports.Vendus = Vendus; //# sourceMappingURL=Vendus.node.js.map