UNPKG

@progtechbr/n8n-nodes-rdsme

Version:

Send events through API to RD Station Marketing para Ecommerce

609 lines (567 loc) 16.8 kB
import { IExecuteFunctions, INodeExecutionData, IDataObject, INodeType, INodeTypeDescription, NodeConnectionType, } from 'n8n-workflow'; import { ecommerceIdentifiers, orderPlacedIdentifiers, orderExplicitIdentifiers } from './Fields/IdentifierFields' import { ecommerceLineItems } from './Fields/LineItemsFields'; import { ecommerceShippingFields } from './Fields/ShippingFields'; import { ecommerceTrackingFields } from './Fields/TrackingFields'; import { appendLegalBaseOption } from './Fields/AddicionalFields'; import { buildLineItems } from './Utils/PayloadBuilders'; import { validateEmail } from './Utils/Validations'; import { isEmpty } from 'validator'; import { rdStationApiRequest } from './Utils/GenericFunctions'; import { ECOMMERCE_EVENT_TYPE_MAP, EVENT_FAMILY, LEGAL_BASES_OBJECT, } from './Utils/GenericConstants'; export class RdsmEcommerce implements INodeType { description: INodeTypeDescription = { name: 'rdsmEcommerce', displayName: 'RD Station Marketing para Ecommerce', icon: 'file:RdsmEcommerce.svg', group: ['transform'], version: 1, subtitle: '={{$parameter["operation"] + ": " + $parameter["resource"]}}', description: 'Insert ecommerce events to RD Station Marketing through API', // usableAsTool: true, defaults: { name: 'RD Station Marketing para Ecommerce', }, inputs: ['main' as NodeConnectionType], outputs: ['main' as NodeConnectionType], credentials: [ { name: 'rdsmEcommerceOAuth2Api', required: true, } ], properties: [ /* Start Default Fields */ { displayName: 'Resource', name: 'resource', type: 'options', options: [ { name: 'Ecommerce Event', value: 'ecommerceEvents', } ], default: 'ecommerceEvents', description: 'Create a new ecommerce event', noDataExpression: true, required: true, }, { displayName: 'Operation', name: 'operation', type: 'options', displayOptions: { show: { resource: ['ecommerceEvents'], }, }, options: [ { name: 'New Ecommerce Event', value: 'newEcommerceEvent', description: 'Register a new ecommerce event', action: 'Register a new ecommerce event', }, ], default: 'newEcommerceEvent', noDataExpression: true, }, { displayName: 'Ecommerce Event Type', name: 'eventType', type: 'options', displayOptions: { show: { operation: ['newEcommerceEvent'], resource: ['ecommerceEvents'], }, }, options: [ { name: 'Cart Abandoned', value: 'ecommerceCartAbandoned', description: 'Cart abandoned event', }, { name: 'Checkout Started', value: 'ecommerceCheckoutStarted', description: 'Checkout started event', }, { name: 'Order Cancelled', value: 'ecommerceOrderCancelled', description: 'Order cancelled event', }, { name: 'Order Fulfilled', value: 'ecommerceOrderFulfilled', description: 'Order fulfilled event', }, { name: 'Order Paid', value: 'ecommerceOrderPaid', description: 'Order paid event', }, { name: 'Order Placed', value: 'ecommerceOrderPlaced', description: 'Order placed event', }, { name: 'Order Refunded', value: 'ecommerceOrderRefunded', description: 'Order refunded event', }, { name: 'Shipment Delivered', value: 'ecommerceShipmentDelivered', description: 'Shipment delivered event', }, ], default: 'ecommerceCartAbandoned', description: 'Ecommerce event type for lead conversion', noDataExpression: true, required: true, }, /* End Default Fields */ /* Start Payload Fields */ ...ecommerceIdentifiers, // Identifier Fields { displayName: 'Lead Email', name: 'email', type: 'string', displayOptions: { show: { operation: ['newEcommerceEvent'], resource: ['ecommerceEvents'], }, }, default: '', placeholder: 'lead@email.com', description: 'Primary email for the lead', required: true, }, { displayName: 'Lead Name', name: 'name', type: 'string', displayOptions: { show: { operation: ['newEcommerceEvent'], resource: ['ecommerceEvents'], }, }, default: '', description: 'Lead\'s fullname', }, { displayName: 'Lead Mobile Phone', name: 'mobilePhone', type: 'string', displayOptions: { show: { operation: ['newEcommerceEvent'], resource: ['ecommerceEvents'], }, }, default: '', description: 'Lead\'s mobile phone', }, { displayName: 'Lead Personal Phone', name: 'personalPhone', type: 'string', displayOptions: { show: { operation: ['newEcommerceEvent'], resource: ['ecommerceEvents'], }, }, default: '', description: 'Lead\'s personal phone', }, { displayName: 'Checkout URL', name: 'checkoutUrl', type: 'string', displayOptions: { show: { operation: ['newEcommerceEvent'], resource: ['ecommerceEvents'], eventType: ['ecommerceCheckoutStarted', 'ecommerceCartAbandoned'], }, }, default: '', description: 'Checkout URL - HTTP or HTTPS address', required: true, }, { displayName: 'Order URL', name: 'orderUrl', type: 'string', displayOptions: { show: { operation: ['newEcommerceEvent'], resource: ['ecommerceEvents'], eventType: ['ecommerceOrderPlaced', 'ecommerceOrderPaid'], }, }, default: '', description: 'Order URL - HTTP or HTTPS address', }, ...orderPlacedIdentifiers, // Order Placed Identifiers ...orderExplicitIdentifiers, // Order Explicit Identifiers { displayName: 'Cancel Reason', name: 'cancelReason', type: 'options', displayOptions: { show: { operation: ['newEcommerceEvent'], resource: ['ecommerceEvents'], eventType: ['ecommerceOrderCancelled'], }, }, options: [ { // eslint-disable-next-line n8n-nodes-base/node-param-display-name-miscased name: 'Customer changed or cancelled the order', value: 'customer', }, { // eslint-disable-next-line n8n-nodes-base/node-param-display-name-miscased name: 'Fraud order', value: 'fraud', }, { // eslint-disable-next-line n8n-nodes-base/node-param-display-name-miscased name: 'Other reason', value: 'other', }, { // eslint-disable-next-line n8n-nodes-base/node-param-display-name-miscased name: 'Refused payment', value: 'declined', }, { // eslint-disable-next-line n8n-nodes-base/node-param-display-name-miscased name: 'Unavailable items', value: 'inventory', }, ], default: 'other', description: 'Cancellation reason for order cancelled event', }, { displayName: 'Currency', name: 'currency', type: 'options', displayOptions: { show: { operation: ['newEcommerceEvent'], resource: ['ecommerceEvents'], }, hide: { eventType: [ 'ecommerceOrderCancelled', 'ecommerceOrderFulfilled', 'ecommerceShipmentDelivered', ], }, }, options: [ { name: 'ARS', value: 'ARS', description: 'Argentine Peso', }, { name: 'BRL', value: 'BRL', description: 'Brazilian Real', }, { name: 'CAD', value: 'CAD', description: 'Canadian Dollar', }, { name: 'CLP', value: 'CLP', description: 'Chilean Peso', }, { name: 'COP', value: 'COP', description: 'Colombian Peso', }, { name: 'EUR', value: 'EUR', description: 'Euro', }, { name: 'MXN', value: 'MXN', description: 'Mexican Peso', }, { name: 'PEN', value: 'PEN', description: 'Peruvian Nuevo Sol', }, { name: 'USD', value: 'USD', description: 'United States Dollar', }, { name: 'UYU', value: 'UYU', description: 'Uruguayan Peso', }, ], default: 'BRL', description: 'Currency of the store', noDataExpression: true, required: true, }, { displayName: 'Price', name: 'price', type: 'number', displayOptions: { show: { operation: ['newEcommerceEvent'], resource: ['ecommerceEvents'], }, hide: { eventType: [ 'ecommerceOrderCancelled', 'ecommerceOrderFulfilled', 'ecommerceShipmentDelivered', ], }, }, default: 0, typeOptions: { minValue: 0, }, description: 'Price of the checkout/order', required: true, }, ...ecommerceShippingFields, // Shipping Fields ...ecommerceTrackingFields, // Tracking Fields { displayName: 'Total Items', name: 'totalItems', type: 'number', displayOptions: { show: { operation: ['newEcommerceEvent'], resource: ['ecommerceEvents'], }, hide: { eventType: [ 'ecommerceOrderCancelled', 'ecommerceOrderFulfilled', 'ecommerceShipmentDelivered', ], }, }, default: 0, typeOptions: { minValue: 0, }, description: 'Total items of products in the checkout', required: true, }, ...ecommerceLineItems, // LineItems Fields { displayName: 'Additional Fields', name: 'additionalFields', type: 'collection', placeholder: 'Add Field', displayOptions: { show: { operation: ['newEcommerceEvent'], resource: ['ecommerceEvents'], }, }, default: {}, options: [ { ...appendLegalBaseOption, description: 'Whether to include the phrase “This message was sent automatically with n8n” to the end of the message', }, ], }, ], }; async execute(this: IExecuteFunctions): Promise<INodeExecutionData[][]> { // const items = this.getInputData(); const returnData: INodeExecutionData[] = []; let responseData; const resource = this.getNodeParameter('resource', 0) as string; const operation = this.getNodeParameter('operation', 0) as string; if (resource == 'ecommerceEvents' && operation == 'newEcommerceEvent') { const eventType = this.getNodeParameter('eventType', 0) as string; const eventFamily = EVENT_FAMILY; const event = ECOMMERCE_EVENT_TYPE_MAP[eventType]; const additionalFields = this.getNodeParameter('additionalFields', 0) as IDataObject; const appendLegalBase = additionalFields.apppendLegalBase as boolean; const leadEmail = validateEmail(this, this.getNodeParameter('email', 0), 'Lead Email') as string; const leadName = (this.getNodeParameter('name', 0) as string).trim(); const mobilePhone = (this.getNodeParameter('mobilePhone', 0 ) as string).trim(); const personalPhone = (this.getNodeParameter('personalPhone', 0 ) as string).trim(); const legalBases = LEGAL_BASES_OBJECT; let identifier; let specificPayload: any = {}; const isCartAbandoned = eventType == 'ecommerceCartAbandoned'; const isCheckoutStarted = eventType == 'ecommerceCheckoutStarted'; const isOrderPlaced = eventType == 'ecommerceOrderPlaced'; const isOrderPaid = eventType == 'ecommerceOrderPaid'; const isOrderRefunded = eventType == 'ecommerceOrderRefunded'; const isOrderCancelled = eventType == 'ecommerceOrderCancelled'; const isOrderFulfilled = eventType == 'ecommerceOrderFulfilled'; const isShipmentDelivered = eventType == 'ecommerceShipmentDelivered'; const basePayload: IDataObject = { email: leadEmail, ...(!isEmpty(leadName) && { name: leadName }), ...(!isEmpty(mobilePhone) && { mobile_phone: mobilePhone }), ...(!isEmpty(personalPhone) && { personal_phone: personalPhone }), ...(appendLegalBase && { legal_bases: legalBases }), }; if ( isCartAbandoned || isCheckoutStarted || isOrderPlaced || isOrderPaid || isOrderRefunded ) { let lineItems: any; let lineItemsBuilded: any; const currency = (this.getNodeParameter('currency', 0 ) as string).trim(); const price = this.getNodeParameter('price', 0) as number; const totalItems = this.getNodeParameter('totalItems', 0) as number; if(!isOrderRefunded) { lineItems = this.getNodeParameter('lineItemsUi', 0); lineItemsBuilded = buildLineItems(lineItems); // console.info('lineItemsBuilded', lineItemsBuilded); } if (isCartAbandoned || isCheckoutStarted) { const checkoutUrl = (this.getNodeParameter('checkoutUrl', 0) as string).trim(); specificPayload = { checkout_url: checkoutUrl, currency: currency, price: price, total_items: totalItems, line_items: lineItemsBuilded, }; if(isCartAbandoned) { identifier = (this.getNodeParameter('identifierCartAbandoned', 0) as string).trim(); } else if(isCheckoutStarted) { identifier = (this.getNodeParameter('identifierCheckoutStarted', 0) as string).trim(); } specificPayload.identifier = identifier; } if (isOrderPlaced || isOrderPaid || isOrderRefunded) { identifier = (this.getNodeParameter('identifierOrder', 0) as string).trim(); specificPayload = { currency: currency, price: price, total_items: totalItems, ...(!isOrderRefunded && { line_items: lineItemsBuilded }), }; if (isOrderPlaced || isOrderPaid) { const orderUrl = (this.getNodeParameter('orderUrl', 0) as string).trim(); const shippingPrice = this.getNodeParameter('shippingPrice', 0) as number; const shippingCity = (this.getNodeParameter('shippingCity', 0) as string).trim(); const shippingState = (this.getNodeParameter('shippingState', 0) as string).trim(); const shippingCountry = (this.getNodeParameter('shippingCountry', 0) as string).trim(); if(!isEmpty(orderUrl)) { specificPayload.order_url = orderUrl; } if(shippingPrice > 0) { specificPayload.shipping_price = shippingPrice; } if(!isEmpty(shippingCity)) { specificPayload.shipping_city = shippingCity; } if(!isEmpty(shippingState)) { specificPayload.shipping_state = shippingState; } if(!isEmpty(shippingCountry)) { specificPayload.shipping_country = shippingCountry; } } if(isOrderPlaced) { const cartIdentifier = (this.getNodeParameter('cartIdentifier', 0) as string).trim(); const checkoutIdentifier = (this.getNodeParameter('checkoutIdentifier', 0) as string).trim(); if(!isEmpty(cartIdentifier)) { specificPayload.cart_identifier = cartIdentifier; } if(!isEmpty(checkoutIdentifier)) { specificPayload.checkout_identifier = checkoutIdentifier; } } specificPayload.identifier = identifier; } } if (isOrderCancelled) { identifier = (this.getNodeParameter('identifierOrder', 0) as string).trim(); const cancelReason = (this.getNodeParameter('cancelReason', 0) as string).trim(); specificPayload = { identifier, ...(!isEmpty(cancelReason) && { cancel_reason: cancelReason }), }; } if (isOrderFulfilled || isShipmentDelivered) { identifier = (this.getNodeParameter('identifierShipment', 0) as string).trim(); const orderIdentifier = (this.getNodeParameter('orderIdentifierExplicit', 0) as string).trim(); if(isOrderFulfilled) { const trackingCompany = (this.getNodeParameter('trackingCompany', 0) as string).trim(); const trackingCode = (this.getNodeParameter('trackingCode', 0) as string).trim(); const trackingUrl = (this.getNodeParameter('trackingUrl', 0) as string).trim(); specificPayload = { ...(!isEmpty(trackingCompany) && { tracking_company: trackingCompany }), ...(!isEmpty(trackingCode) && { tracking_code: trackingCode }), ...(!isEmpty(trackingUrl) && { tracking_url: trackingUrl }), }; } specificPayload.identifier = identifier; specificPayload.order_identifier = orderIdentifier; } const payload: IDataObject = { ...basePayload, ...specificPayload }; const body: IDataObject = { event_type: event, event_family: eventFamily, payload: payload, }; // console.info('body', body); responseData = await rdStationApiRequest.call(this, 'POST', `/events?event_type=${event}`, body); const executionData = this.helpers.constructExecutionMetaData( this.helpers.returnJsonArray(responseData as IDataObject), { itemData: { item: 0 } }, ); returnData.push(...executionData); } return this.prepareOutputData(returnData); }; };