@pixelinfinito/n8n-nodes-vendus
Version:
Vendus API integration for n8n - Invoicing and business management automation
555 lines • 26.1 kB
JavaScript
"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