n8n/packages/nodes-base/nodes/Onfleet/Onfleet.ts
Iván Ovejero 027dfb2f0a
Enable esModuleInterop compiler option and upgrade to TypeScript 4.6 (#3106)
*  Enable `esModuleInterop` for /core

*  Adjust imports in /core

*  Enable `esModuleInterop` for /cli

*  Adjust imports in /cli

*  Enable `esModuleInterop` for /nodes-base

*  Adjust imports in /nodes-base

*  Make imports consistent

* ⬆️ Upgrade TypeScript to 4.6 (#3109)

* ⬆️ Upgrade TypeScript to 4.6

* 📦 Update package-lock.json

* 🔧 Avoid erroring on untyped errors

* 📘 Fix type error

Co-authored-by: Jan Oberhauser <jan.oberhauser@gmail.com>
2022-04-08 23:32:08 +02:00

1344 lines
58 KiB
TypeScript

import {
IDataObject,
IExecuteFunctions,
IHookFunctions,
ILoadOptionsFunctions,
INodeExecutionData,
IWebhookFunctions,
NodeOperationError,
} from 'n8n-workflow';
import {
OnfleetAdmins,
OnfleetCloneOverrideTaskOptions,
OnfleetCloneTask,
OnfleetCloneTaskOptions,
OnfleetDestination,
OnfleetHubs,
OnfleetListTaskFilters,
OnfleetRecipient,
OnfleetTask,
OnfleetTaskComplete,
OnfleetTaskUpdate,
OnfleetTeamAutoDispatch,
OnfleetTeams,
OnfleetWebhook,
OnfleetWorker,
OnfleetWorkerEstimates,
OnfleetWorkerFilter,
OnfleetWorkerSchedule,
OnfleetWorkerScheduleEntry
} from './interfaces';
import {
onfleetApiRequest,
onfleetApiRequestAllItems,
} from './GenericFunctions';
import moment from 'moment-timezone';
const formatAddress = (
unparsed: boolean,
address: string | undefined,
addressNumber: string | undefined,
addressStreet: string | undefined,
addressCity: string | undefined,
addressCountry: string | undefined,
additionalFields: IDataObject,
): OnfleetDestination => {
let destination: OnfleetDestination;
if (unparsed) {
destination = { address: { unparsed: address } };
} else {
destination = {
address: {
number: addressNumber,
street: addressStreet,
city: addressCity,
country: addressCountry,
},
};
}
// Adding destination extra fields
if (additionalFields.addressName) {
destination.address.name = additionalFields.addressName as string;
}
if (additionalFields.addressApartment) {
destination.address.apartment = additionalFields.addressApartment as string;
}
if (additionalFields.addressState) {
destination.address.state = additionalFields.addressState as string;
}
if (additionalFields.addressPostalCode) {
destination.address.postalCode = additionalFields.addressPostalCode as string;
}
if (additionalFields.addressNotes) {
destination.notes = additionalFields.addressNotes as string;
}
return destination;
};
export class Onfleet {
/**
* Returns a valid formatted destination object
* @param unparsed Whether the address is parsed or not
* @param address Destination address
* @param addressNumber Destination number
* @param addressStreet Destination street
* @param addressCity Destination city
* @param addressCountry Destination country
* @param additionalFields Destination additional fields
* @returns
*/
/**
* Gets the properties of a destination according to the operation chose
* @param item Current execution data
* @param operation Current destination operation
* @param shared Whether the collection is in other resource or not
* @returns {OnfleetDestination} Destination information
*/
static getDestinationFields(
this: IWebhookFunctions | IHookFunctions | IExecuteFunctions | ILoadOptionsFunctions,
item: number, operation: string, shared: { parent: string } | boolean = false,
): OnfleetDestination | OnfleetDestination[] | null {
if (['create', 'update'].includes(operation)) {
/* -------------------------------------------------------------------------- */
/* Get fields for create and update a destination */
/* -------------------------------------------------------------------------- */
if (shared !== false) {
let destination;
if (typeof shared === 'boolean' && shared) {
const { destinationProperties = {} } = this.getNodeParameter('destination', item) as IDataObject;
destination = destinationProperties;
} else if (typeof shared !== 'boolean') {
const { destination: destinationCollection = {} } = this.getNodeParameter(shared.parent, item) as IDataObject;
destination = (destinationCollection as IDataObject).destinationProperties;
}
if (!destination || Object.keys((destination) as IDataObject).length === 0) {
return [];
}
const {
unparsed, address, addressNumber, addressStreet, addressCity, addressCountry, ...additionalFields
} = destination as IDataObject;
return formatAddress(
unparsed as boolean,
address as string,
addressNumber as string,
addressStreet as string,
addressCity as string,
addressCountry as string,
additionalFields as IDataObject,
) as OnfleetDestination;
} else {
let unparsed, address, addressNumber, addressStreet, addressCity, addressCountry, additionalFields;
unparsed = this.getNodeParameter('unparsed', item) as boolean;
if (unparsed) {
address = this.getNodeParameter('address', item) as string;
} else {
addressNumber = this.getNodeParameter('addressNumber', item) as string;
addressStreet = this.getNodeParameter('addressStreet', item) as string;
addressCity = this.getNodeParameter('addressCity', item) as string;
addressCountry = this.getNodeParameter('addressCountry', item) as string;
}
additionalFields = this.getNodeParameter('additionalFields', item) as IDataObject;
return formatAddress(
unparsed, address, addressNumber, addressStreet, addressCity, addressCountry, additionalFields,
) as OnfleetDestination;
}
}
return null;
}
/**
* Gets the properties of an administrator according to the operation chose
* @param item Current execution data
* @param operation Current administrator operation
* @returns {OnfleetAdmins} Administrator information
*/
static getAdminFields(this: IExecuteFunctions, item: number, operation: string): OnfleetAdmins | null {
if (operation === 'create') {
/* -------------------------------------------------------------------------- */
/* Get fields for create admin */
/* -------------------------------------------------------------------------- */
const name = this.getNodeParameter('name', item) as string;
const email = this.getNodeParameter('email', item) as string;
const additionalFields = this.getNodeParameter('additionalFields', item) as IDataObject;
const adminData: OnfleetAdmins = { name, email };
// Adding additional fields
Object.assign(adminData, additionalFields);
return adminData;
} else if (operation === 'update') {
/* -------------------------------------------------------------------------- */
/* Get fields for update admin */
/* -------------------------------------------------------------------------- */
const updateFields = this.getNodeParameter('updateFields', item) as IDataObject;
const adminData: OnfleetAdmins = {};
if (!Object.keys(updateFields).length) {
throw new NodeOperationError(this.getNode(), 'Select at least one field to be updated');
}
// Adding additional fields
Object.assign(adminData, updateFields);
return adminData;
}
return null;
}
/**
* Gets the properties of a hub according to the operation chose
* @param item Current execution data
* @param operation Current hub operation
* @returns {OnfleetHubs|null} Hub information
*/
static getHubFields(this: IExecuteFunctions, item: number, operation: string): OnfleetHubs | null {
if (operation === 'create') {
/* -------------------------------------------------------------------------- */
/* Get fields for create hub */
/* -------------------------------------------------------------------------- */
const destination = Onfleet.getDestinationFields.call(this, item, operation, true) as OnfleetDestination;
const name = this.getNodeParameter('name', item) as string;
const additionalFields = this.getNodeParameter('additionalFields', item) as IDataObject;
const hubData: OnfleetHubs = { name, ...destination };
// Adding additional fields
Object.assign(hubData, additionalFields);
return hubData;
} else if (operation === 'update') {
/* -------------------------------------------------------------------------- */
/* Get fields for update hub */
/* -------------------------------------------------------------------------- */
const destination = Onfleet.getDestinationFields.call(this, item, operation, { parent: 'updateFields' }) as OnfleetDestination;
const hubData: OnfleetHubs = { ...destination };
// Adding additional fields
const updateFields = this.getNodeParameter('updateFields', item) as IDataObject;
if (!Object.keys(updateFields).length) {
throw new NodeOperationError(this.getNode(), 'Select at least one field to be updated');
}
Object.assign(hubData, updateFields);
return hubData;
}
return null;
}
/**
* Gets the properties of a worker according to the operation chose
* @param item Current execution data
* @param operation Current worker operation
* @returns {OnfleetWorker|OnfleetWorkerFilter|OnfleetWorkerSchedule|null} Worker information
*/
static getWorkerFields(this: IExecuteFunctions, item: number, operation: string): OnfleetWorker | OnfleetWorkerFilter | OnfleetWorkerSchedule | null {
if (operation === 'create') {
/* -------------------------------------------------------------------------- */
/* Get fields for create worker */
/* -------------------------------------------------------------------------- */
const name = this.getNodeParameter('name', item) as string;
const phone = this.getNodeParameter('phone', item) as string;
const teams = this.getNodeParameter('teams', item) as string[];
const workerData: OnfleetWorker = { name, phone, teams };
// Adding additional fields
const additionalFields = this.getNodeParameter('additionalFields', item) as IDataObject;
if (additionalFields.vehicle) {
const { vehicleProperties } = additionalFields.vehicle as IDataObject;
Object.assign(workerData, { vehicle: vehicleProperties });
delete additionalFields.vehicle;
}
Object.assign(workerData, additionalFields);
return workerData;
} else if (operation === 'update') {
/* -------------------------------------------------------------------------- */
/* Get fields for update worker */
/* -------------------------------------------------------------------------- */
const workerData: OnfleetWorker = {};
// Adding additional fields
const updateFields = this.getNodeParameter('updateFields', item) as IDataObject;
if (!Object.keys(updateFields).length) {
throw new NodeOperationError(this.getNode(), 'Select at least one field to be updated');
}
Object.assign(workerData, updateFields);
return workerData;
} else if (operation === 'get') {
const options = this.getNodeParameter('options', item, {}) as IDataObject;
const workerFilter: OnfleetWorkerFilter = {};
if (options.filter) {
options.filter = (options.filter as string[]).join(',');
}
if (typeof options.analytics === 'boolean') {
options.analytics = options.analytics ? 'true' : 'false';
}
Object.assign(workerFilter, options);
return workerFilter;
} else if (operation === 'getAll') {
/* -------------------------------------------------------------------------- */
/* Get fields for get and getAll workers */
/* -------------------------------------------------------------------------- */
const options = this.getNodeParameter('options', item, {}) as IDataObject;
const filters = this.getNodeParameter('filters', item, {}) as IDataObject;
const workerFilter: OnfleetWorkerFilter = {};
if (filters.states) {
filters.states = (filters.states as number[]).join(',');
}
if (filters.teams) {
filters.teams = (filters.teams as string[]).join(',');
}
if (filters.phones) {
filters.phones = (filters.phones as string[]).join(',');
}
if (options.filter) {
options.filter = (options.filter as string[]).join(',');
}
Object.assign(workerFilter, options);
Object.assign(workerFilter, filters);
return workerFilter;
} else if (operation === 'setSchedule') {
/* -------------------------------------------------------------------------- */
/* Set a worker schedule */
/* -------------------------------------------------------------------------- */
const { scheduleProperties } = this.getNodeParameter('schedule', item) as IDataObject;
const entries = (scheduleProperties as IDataObject[] || []).map(entry => {
const { timezone, date, shifts } = entry as IDataObject;
const { shiftsProperties } = shifts as IDataObject;
return {
timezone: timezone as string,
date: moment(date as Date).format('YYYY-MM-DD'),
shifts: (shiftsProperties as IDataObject[]).map(({ start, end }) => [
new Date(start as Date).getTime(),
new Date(end as Date).getTime(),
]),
} as OnfleetWorkerScheduleEntry;
}) as OnfleetWorkerScheduleEntry[];
return { entries } as OnfleetWorkerSchedule;
}
return null;
}
/**
* Gets the properties of a webhooks according to the operation chose
* @param item Current execution data
* @param operation Current webhooks operation
* @returns {OnfleetWebhook} Webhooks information
*/
static getWebhookFields(this: IExecuteFunctions, item: number, operation: string): OnfleetWebhook | null {
if (operation === 'create') {
/* -------------------------------------------------------------------------- */
/* Get fields for create webhook */
/* -------------------------------------------------------------------------- */
const url = this.getNodeParameter('url', item) as string;
const name = this.getNodeParameter('name', item) as string;
const trigger = this.getNodeParameter('trigger', item) as number;
const additionalFields = this.getNodeParameter('additionalFields', item) as IDataObject;
const webhookData: OnfleetWebhook = { url, name, trigger };
// Adding additional fields
Object.assign(webhookData, additionalFields);
return webhookData;
}
return null;
}
/**
* Returns a valid formatted recipient object
* @param name Recipient name
* @param phone Recipient phone
* @param additionalFields Recipient additional fields
* @returns
*/
static formatRecipient(
name: string, phone: string, additionalFields: IDataObject,
options: IDataObject = {},
): OnfleetRecipient {
const recipient: OnfleetRecipient = { name, phone };
// Adding recipient extra fields
if (additionalFields.recipientNotes) {
recipient.notes = additionalFields.recipientNotes as string;
}
if (additionalFields.recipientSkipSMSNotifications) {
recipient.skipSMSNotifications = additionalFields.recipientSkipSMSNotifications as boolean;
}
if ('recipientSkipPhoneNumberValidation' in options) {
recipient.skipPhoneNumberValidation = options.recipientSkipPhoneNumberValidation as boolean || false;
}
return recipient;
}
/**
* Gets the properties of a recipient according to the operation chose
* @param item Current execution data
* @param operation Current recipient operation
* @param shared Whether the collection is in other resource or not
* @returns {OnfleetRecipient} Recipient information
*/
static getRecipientFields(
this: IWebhookFunctions | IHookFunctions | IExecuteFunctions | ILoadOptionsFunctions,
item: number, operation: string, shared = false,
): OnfleetRecipient | OnfleetRecipient[] | null {
if (operation === 'create') {
/* -------------------------------------------------------------------------- */
/* Get fields to create recipient */
/* -------------------------------------------------------------------------- */
if (shared) {
const { recipient: recipientData = {} } = this.getNodeParameter('additionalFields', item, {}) as IDataObject;
const options = this.getNodeParameter('options', item, {}) as IDataObject;
const { recipientProperties: recipient = {} } = recipientData as IDataObject;
if (!recipient || Object.keys(recipient).length === 0) {
return null;
}
const { recipientName: name, recipientPhone: phone, ...additionalFields } = recipient as IDataObject;
return Onfleet.formatRecipient(
name as string,
phone as string,
additionalFields as IDataObject,
options,
);
} else {
const name = this.getNodeParameter('recipientName', item) as string;
const phone = this.getNodeParameter('recipientPhone', item) as string;
const additionalFields = this.getNodeParameter('additionalFields', item) as IDataObject;
const options = this.getNodeParameter('options', item) as IDataObject;
return Onfleet.formatRecipient(name, phone, additionalFields, options) as OnfleetRecipient;
}
} else if (operation === 'update') {
/* -------------------------------------------------------------------------- */
/* Get fields to update recipient */
/* -------------------------------------------------------------------------- */
const {
recipientName: name = '', recipientPhone: phone = '', ...additionalFields
} = this.getNodeParameter('updateFields', item) as IDataObject;
const recipientData: OnfleetRecipient = {};
// Adding additional fields
if (name) {
recipientData.name = name as string;
}
if (phone) {
recipientData.phone = phone as string;
}
Object.assign(recipientData, additionalFields);
return recipientData;
}
return null;
}
/**
* Gets the properties of a task according to the operation chose
* @param item Current execution data
* @param operation Current task operation
* @returns {OnfleetListTaskFilters | OnfleetTask } Task information
*/
static getTaskFields(this: IWebhookFunctions | IHookFunctions | IExecuteFunctions | ILoadOptionsFunctions,
item: number, operation: string):
OnfleetListTaskFilters | OnfleetTask | OnfleetCloneTask | OnfleetTaskComplete | OnfleetTaskUpdate | null {
if (operation === 'create') {
/* -------------------------------------------------------------------------- */
/* Get fields to create a task */
/* -------------------------------------------------------------------------- */
const additionalFields = this.getNodeParameter('additionalFields', item) as IDataObject;
const destination = Onfleet.getDestinationFields.call(this, item, operation, true) as OnfleetDestination;
// Adding recipients information
const recipient = Onfleet.getRecipientFields.call(this, item, operation, true) as OnfleetRecipient;
const taskData: OnfleetTask = { destination, recipients: [recipient] };
const { completeAfter = null, completeBefore = null, ...extraFields } = additionalFields;
if (completeAfter) taskData.completeAfter = new Date(completeAfter as Date).getTime();
if (completeBefore) taskData.completeBefore = new Date(completeBefore as Date).getTime();
Object.assign(taskData, extraFields);
return taskData;
} else if (operation === 'update') {
/* -------------------------------------------------------------------------- */
/* Get fields to update task */
/* -------------------------------------------------------------------------- */
const updateFields = this.getNodeParameter('updateFields', item) as IDataObject;
const taskData: OnfleetTaskUpdate = {};
if (!Object.keys(updateFields).length) {
throw new NodeOperationError(this.getNode(), 'Select at least one field to be updated');
}
const { completeAfter = null, completeBefore = null, ...extraFields } = updateFields;
if (completeAfter) taskData.completeAfter = new Date(completeAfter as Date).getTime();
if (completeBefore) taskData.completeBefore = new Date(completeBefore as Date).getTime();
Object.assign(taskData, extraFields);
return taskData;
} else if (operation === 'clone') {
/* -------------------------------------------------------------------------- */
/* Get fields to clone task */
/* -------------------------------------------------------------------------- */
const overrideFields = this.getNodeParameter('overrideFields', item) as IDataObject;
const options: OnfleetCloneTaskOptions = {};
if (overrideFields.includeMetadata) options.includeMetadata = overrideFields.includeMetadata as boolean;
if (overrideFields.includeBarcodes) options.includeBarcodes = overrideFields.includeBarcodes as boolean;
if (overrideFields.includeDependencies) options.includeDependencies = overrideFields.includeDependencies as boolean;
// Adding overrides data
const {
notes, pickupTask, serviceTime, completeAfter, completeBefore,
} = overrideFields as IDataObject;
const overridesData = {} as OnfleetCloneOverrideTaskOptions;
if (notes) overridesData.notes = notes as string;
if (typeof pickupTask !== 'undefined') overridesData.pickupTask = pickupTask as boolean;
if (serviceTime) overridesData.serviceTime = serviceTime as number;
if (completeAfter) overridesData.completeAfter = new Date(completeAfter as Date).getTime();
if (completeBefore) overridesData.completeBefore = new Date(completeBefore as Date).getTime();
if (overridesData && Object.keys(overridesData).length > 0) {
options.overrides = overridesData;
}
return { options } as OnfleetCloneTask;
} else if (operation === 'getAll') {
/* -------------------------------------------------------------------------- */
/* Get fields to list tasks */
/* -------------------------------------------------------------------------- */
const filters = this.getNodeParameter('filters', item) as IDataObject;
const listTaskData: OnfleetListTaskFilters = {};
const allStates = '0,1,2,3';
const twoWeeksInMilisecods = () => (604800 * 1000);
// Adding extra fields to search tasks
if (filters.from) {
listTaskData.from = new Date(filters.from as Date).getTime();
} else {
listTaskData.from = new Date().getTime() - twoWeeksInMilisecods();
}
if (filters.to) {
listTaskData.to = new Date(filters.to as Date).getTime();
}
if (filters.state) {
listTaskData.state = (filters.state as number[]).join(',');
if (listTaskData.state.includes('all')) {
listTaskData.state = allStates;
}
}
return listTaskData;
} else if (operation === 'complete') {
/* -------------------------------------------------------------------------- */
/* Get fields to complete a task */
/* -------------------------------------------------------------------------- */
const additionalFields = this.getNodeParameter('additionalFields', item) as IDataObject;
const success = this.getNodeParameter('success', item) as boolean;
const taskData: OnfleetTaskComplete = { completionDetails: { success } };
if (additionalFields.notes) taskData.completionDetails.notes = additionalFields.notes as string;
return taskData;
}
return null;
}
/**
* Gets the properties of a team according to the operation chose
* @param item Current execution data
* @param operation Current team operation
* @returns {OnfleetTeams} Team information
*/
static getTeamFields(this: IExecuteFunctions, item: number, operation: string): OnfleetTeams | OnfleetWorkerEstimates | OnfleetTeamAutoDispatch | null {
if (operation === 'create') {
/* -------------------------------------------------------------------------- */
/* Get fields to create a team */
/* -------------------------------------------------------------------------- */
const name = this.getNodeParameter('name', item) as string;
const workers = this.getNodeParameter('workers', item) as string[];
const managers = this.getNodeParameter('managers', item) as string[];
const additionalFields = this.getNodeParameter('additionalFields', item) as IDataObject;
const teamData: OnfleetTeams = { name, workers, managers };
// Adding additional fields
Object.assign(teamData, additionalFields);
return teamData;
} else if (operation === 'update') {
/* -------------------------------------------------------------------------- */
/* Get fields to update a team */
/* -------------------------------------------------------------------------- */
const teamData: OnfleetTeams = {};
// Adding additional fields
const updateFields = this.getNodeParameter('updateFields', item) as IDataObject;
if (!Object.keys(updateFields).length) {
throw new NodeOperationError(this.getNode(), 'Select at least one field to be updated');
}
Object.assign(teamData, updateFields);
return teamData;
} else if (operation === 'getTimeEstimates') {
/* -------------------------------------------------------------------------- */
/* Get driver time estimates for tasks that haven't been created yet */
/* -------------------------------------------------------------------------- */
const { dropOff = {}, pickUp = {}, ...additionalFields } = this.getNodeParameter('filters', item) as IDataObject;
const { dropOffProperties = {} } = dropOff as IDataObject;
const { pickUpProperties = {} } = pickUp as IDataObject;
const hasPickUp = pickUp && Object.keys(pickUpProperties as IDataObject).length > 0;
const hasDropOff = dropOffProperties && Object.keys(dropOffProperties as IDataObject).length > 0;
if (!hasPickUp && !hasDropOff) {
throw new NodeOperationError(
this.getNode(), 'At least 1 of Drop-Off location or Pick-Up location must be selected',
);
}
const workerTimeEstimates = {} as OnfleetWorkerEstimates;
if (hasPickUp) {
const {
pickupLongitude: longitude, pickupLatitude: latitude, pickupTime,
} = pickUpProperties as IDataObject;
workerTimeEstimates.pickupLocation = `${longitude},${latitude}`;
if (pickupTime) {
workerTimeEstimates.pickupTime = moment(new Date(pickupTime as Date)).local().unix();
}
}
if (hasDropOff) {
const { dropOffLongitude: longitude, dropOffLatitude: latitude } = dropOffProperties as IDataObject;
workerTimeEstimates.dropoffLocation = `${longitude},${latitude}`;
}
Object.assign(workerTimeEstimates, additionalFields);
return workerTimeEstimates;
} else if (operation === 'autoDispatch') {
/* -------------------------------------------------------------------------- */
/* Dynamically dispatching tasks on the fly */
/* -------------------------------------------------------------------------- */
const teamAutoDispatch = {} as OnfleetTeamAutoDispatch;
const {
scheduleTimeWindow = {}, taskTimeWindow = {}, endingRoute = {}, ...additionalFields
} = this.getNodeParameter('additionalFields', item) as IDataObject;
const { endingRouteProperties = {} } = endingRoute as IDataObject;
const { scheduleTimeWindowProperties = {} } = scheduleTimeWindow as IDataObject;
const { taskTimeWindowProperties = {} } = taskTimeWindow as IDataObject;
if (scheduleTimeWindowProperties && Object.keys((scheduleTimeWindowProperties as IDataObject)).length > 0) {
const { startTime, endTime } = scheduleTimeWindowProperties as IDataObject;
teamAutoDispatch.scheduleTimeWindow = [
moment(new Date(startTime as Date)).local().unix(), moment(new Date(endTime as Date)).local().unix(),
];
}
if (endingRouteProperties && Object.keys((endingRouteProperties as IDataObject)).length > 0) {
const { routeEnd, hub } = endingRouteProperties as IDataObject;
teamAutoDispatch.routeEnd = ({
'anywhere': null,
'hub': `hub://${hub}`,
'team_hub': 'teams://DEFAULT',
'worker_routing_address': 'workers://ROUTING_ADDRESS',
})[routeEnd as string] as string;
}
if (taskTimeWindowProperties && Object.keys((taskTimeWindowProperties as IDataObject)).length > 0) {
const { startTime, endTime } = taskTimeWindowProperties as IDataObject;
teamAutoDispatch.taskTimeWindow = [
moment(new Date(startTime as Date)).local().unix(), moment(new Date(endTime as Date)).local().unix(),
];
}
Object.assign(teamAutoDispatch, additionalFields);
return teamAutoDispatch;
}
return null;
}
/**
* Execute the task operations
* @param resource Resource to be executed (Task)
* @param operation Operation to be executed
* @param items Number of items to process by the node
* @returns Task information
*/
static async executeTaskOperations(
this: IWebhookFunctions | IHookFunctions | IExecuteFunctions | ILoadOptionsFunctions,
resource: string,
operation: string,
items: INodeExecutionData[],
): Promise<IDataObject | IDataObject[]> {
if (operation === 'create' && Object.keys(items).length > 1) {
/* -------------------------------------------------------------------------- */
/* Create multiple tasks by batch */
/* -------------------------------------------------------------------------- */
const path = `${resource}/batch`;
const tasksData = { tasks: items.map((_item, index) => Onfleet.getTaskFields.call(this, index, operation)) };
//@ts-ignore
const { tasks: tasksCreated } = await onfleetApiRequest.call(this, 'POST', path, tasksData);
return tasksCreated;
}
const responseData = [];
for (const key of Object.keys(items)) {
const index = Number(key);
try {
if (operation === 'create') {
/* -------------------------------------------------------------------------- */
/* Create a new task */
/* -------------------------------------------------------------------------- */
const taskData = Onfleet.getTaskFields.call(this, index, operation);
if (!taskData) { continue; }
responseData.push(await onfleetApiRequest.call(this, 'POST', resource, taskData));
} else if (operation === 'get') {
/* -------------------------------------------------------------------------- */
/* Get a single task */
/* -------------------------------------------------------------------------- */
const id = this.getNodeParameter('id', index) as string;
const shortId = String(id).length <= 8;
const path = `${resource}${(shortId ? '/shortId' : '')}/${id}`;
responseData.push(await onfleetApiRequest.call(this, 'GET', path));
} else if (operation === 'clone') {
/* -------------------------------------------------------------------------- */
/* Clone a task */
/* -------------------------------------------------------------------------- */
const id = this.getNodeParameter('id', index) as string;
// tslint:disable-next-line: no-any
const taskData = Onfleet.getTaskFields.call(this, index, operation) as any;
if (!taskData) { continue; }
const path = `${resource}/${id}/clone`;
responseData.push(await onfleetApiRequest.call(this, 'POST', path, taskData));
} else if (operation === 'delete') {
/* -------------------------------------------------------------------------- */
/* Delete a single task */
/* -------------------------------------------------------------------------- */
const id = this.getNodeParameter('id', index) as string;
const path = `${resource}/${id}`;
await onfleetApiRequest.call(this, 'DELETE', path);
responseData.push({ success: true });
} else if (operation === 'getAll') {
/* -------------------------------------------------------------------------- */
/* Get all tasks */
/* -------------------------------------------------------------------------- */
const taskData = Onfleet.getTaskFields.call(this, 0, operation) as IDataObject;
if (!taskData) return [];
const returnAll = this.getNodeParameter('returnAll', 0, false);
const path = `${resource}/all`;
let tasks;
if (returnAll === true) {
tasks = await onfleetApiRequestAllItems.call(this, 'tasks', 'GET', path, {}, taskData);
} else {
const limit = this.getNodeParameter('limit', 0);
tasks = await onfleetApiRequest.call(this, 'GET', path, {}, taskData);
tasks = tasks.tasks;
tasks = tasks.splice(0, limit);
}
responseData.push(...tasks);
} else if (operation === 'complete') {
/* -------------------------------------------------------------------------- */
/* Force complete a task */
/* -------------------------------------------------------------------------- */
const id = this.getNodeParameter('id', index) as string;
const taskData = Onfleet.getTaskFields.call(this, index, operation);
if (!taskData) { continue; }
const path = `${resource}/${id}/complete`;
await onfleetApiRequest.call(this, 'POST', path, taskData);
responseData.push({ success: true });
} else if (operation === 'update') {
/* -------------------------------------------------------------------------- */
/* Update a task */
/* -------------------------------------------------------------------------- */
const id = this.getNodeParameter('id', 0) as string;
const path = `${resource}/${id}`;
const taskData = Onfleet.getTaskFields.call(this, index, operation);
if (!taskData) { continue; }
responseData.push(await onfleetApiRequest.call(this, 'PUT', path, taskData));
}
} catch (error) {
//@ts-ignore
if (this.continueOnFail()) {
responseData.push({ error: (error as IDataObject).toString() });
continue;
}
throw error;
}
}
return responseData;
}
/**
* Execute the destination operations
* @param resource Resource to be executed (Destination)
* @param operation Operation to be executed
* @param items Number of items to process by the node
* @returns Destination information
*/
static async executeDestinationOperations(
this: IExecuteFunctions,
resource: string,
operation: string,
items: INodeExecutionData[],
): Promise<IDataObject | IDataObject[]> {
const responseData = [];
for (const key of Object.keys(items)) {
const index = Number(key);
try {
if (operation === 'create') {
/* -------------------------------------------------------------------------- */
/* Create destination */
/* -------------------------------------------------------------------------- */
const destinationData = Onfleet.getDestinationFields.call(this, index, operation);
if (!destinationData) { continue; }
responseData.push(await onfleetApiRequest.call(this, 'POST', resource, destinationData));
} else if (operation === 'get') {
/* -------------------------------------------------------------------------- */
/* Get single destination */
/* -------------------------------------------------------------------------- */
const id = this.getNodeParameter('id', index) as string;
const path = `${resource}/${id}`;
responseData.push(await onfleetApiRequest.call(this, 'GET', path));
}
} catch (error) {
if (this.continueOnFail()) {
responseData.push({ error: (error as IDataObject).toString() });
continue;
}
throw error;
}
}
return responseData;
}
/**
* Execute the organization operations
* @param resource Resource to be executed (Organization)
* @param operation Operation to be executed
* @param items Number of items to process by the node
* @returns Organization information
*/
static async executeOrganizationOperations(
this: IExecuteFunctions,
resource: string,
operation: string,
items: INodeExecutionData[],
): Promise<IDataObject | IDataObject[]> {
const responseData = [];
for (const key of Object.keys(items)) {
const index = Number(key);
try {
if (operation === 'get') {
/* -------------------------------------------------------------------------- */
/* Get organization details */
/* -------------------------------------------------------------------------- */
const path = 'organization';
responseData.push(await onfleetApiRequest.call(this, 'GET', path));
} else if (operation === 'getDelegatee') {
/* -------------------------------------------------------------------------- */
/* Get organization delegatee */
/* -------------------------------------------------------------------------- */
const id = this.getNodeParameter('id', index) as string;
const path = `${resource}/${id}`;
responseData.push(await onfleetApiRequest.call(this, 'GET', path));
}
} catch (error) {
if (this.continueOnFail()) {
responseData.push({ error: (error as IDataObject).toString() });
continue;
}
throw error;
}
}
return responseData;
}
/**
* Execute the recipient operations
* @param resource Resource to be executed (Recipient)
* @param operation Operation to be executed
* @param items Number of items to process by the node
* @returns Recipient information
*/
static async executeRecipientOperations(this: IExecuteFunctions,
resource: string,
operation: string,
items: INodeExecutionData[],
): Promise<IDataObject | IDataObject[]> {
const responseData = [];
for (const key of Object.keys(items)) {
const index = Number(key);
try {
if (operation === 'create') {
/* -------------------------------------------------------------------------- */
/* Create a new recipient */
/* -------------------------------------------------------------------------- */
const recipientData = Onfleet.getRecipientFields.call(this, index, operation);
if (!recipientData) { continue; }
responseData.push(await onfleetApiRequest.call(this, 'POST', resource, recipientData));
} else if (operation === 'update') {
/* -------------------------------------------------------------------------- */
/* Update a recipient */
/* -------------------------------------------------------------------------- */
const recipientData = Onfleet.getRecipientFields.call(this, index, operation);
if (!recipientData) { continue; }
const id = this.getNodeParameter('id', index) as string;
const path = `${resource}/${id}`;
responseData.push(await onfleetApiRequest.call(this, 'PUT', path, recipientData));
} else if (operation === 'get') {
/* -------------------------------------------------------------------------- */
/* Get recipient information */
/* -------------------------------------------------------------------------- */
const lookupBy = this.getNodeParameter('getBy', index) as string;
const lookupByValue = this.getNodeParameter(lookupBy, index) as string;
const path = `${resource}${lookupBy === 'id' ? '' : ('/' + lookupBy)}/${lookupByValue}`;
responseData.push(await onfleetApiRequest.call(this, 'GET', path));
}
} catch (error) {
if (this.continueOnFail()) {
responseData.push({ error: (error as IDataObject).toString() });
continue;
}
throw error;
}
}
return responseData;
}
/**
* Execute the administrator operations
* @param resource Resource to be executed (Administrator)
* @param operation Operation to be executed
* @param items Number of items to process by the node
* @returns Administrator information
*/
static async executeAdministratorOperations(
this: IExecuteFunctions,
resource: string,
operation: string,
items: INodeExecutionData[],
): Promise<IDataObject | IDataObject[]> {
const responseData = [];
for (const key of Object.keys(items)) {
const index = Number(key);
try {
if (operation === 'getAll') {
/* -------------------------------------------------------------------------- */
/* Get administrators */
/* -------------------------------------------------------------------------- */
const returnAll = this.getNodeParameter('returnAll', 0, false);
let adminUsers = await onfleetApiRequest.call(this, 'GET', resource);
if (!returnAll) {
const limit = this.getNodeParameter('limit', 0);
adminUsers = adminUsers.slice(0, limit);
}
responseData.push(...adminUsers);
} else if (operation === 'create') {
/* -------------------------------------------------------------------------- */
/* Create a new admin */
/* -------------------------------------------------------------------------- */
const adminData = Onfleet.getAdminFields.call(this, index, operation);
responseData.push(await onfleetApiRequest.call(this, 'POST', resource, adminData));
} else if (operation === 'update') {
/* -------------------------------------------------------------------------- */
/* Update admin */
/* -------------------------------------------------------------------------- */
const id = this.getNodeParameter('id', index) as string;
const adminData = Onfleet.getAdminFields.call(this, index, operation);
const path = `${resource}/${id}`;
responseData.push(await onfleetApiRequest.call(this, 'PUT', path, adminData));
} else if (operation === 'delete') {
/* -------------------------------------------------------------------------- */
/* Delete admin */
/* -------------------------------------------------------------------------- */
const id = this.getNodeParameter('id', index) as string;
const path = `${resource}/${id}`;
await onfleetApiRequest.call(this, 'DELETE', path);
responseData.push({ success: true });
}
} catch (error) {
if (this.continueOnFail()) {
responseData.push({ error: (error as IDataObject).toString() });
continue;
}
throw error;
}
}
return responseData;
}
/**
* Execute the hub operations
* @param resource Resource to be executed (Hub)
* @param operation Operation to be executed
* @param items Number of items to process by the node
* @returns Hub information
*/
static async executeHubOperations(
this: IExecuteFunctions,
resource: string,
operation: string,
items: INodeExecutionData[],
): Promise<IDataObject | IDataObject[]> {
const responseData = [];
for (const key of Object.keys(items)) {
const index = Number(key);
try {
if (operation === 'getAll') {
/* -------------------------------------------------------------------------- */
/* Get all hubs */
/* -------------------------------------------------------------------------- */
const returnAll = this.getNodeParameter('returnAll', 0, false);
let hubs = await onfleetApiRequest.call(this, 'GET', resource);
if (returnAll === false) {
const limit = this.getNodeParameter('limit', 0);
hubs = hubs.slice(0, limit);
}
responseData.push(...hubs);
} else if (operation === 'create') {
/* -------------------------------------------------------------------------- */
/* Create a new hub */
/* -------------------------------------------------------------------------- */
const hubData = Onfleet.getHubFields.call(this, index, operation);
responseData.push(await onfleetApiRequest.call(this, 'POST', resource, hubData));
}
if (operation === 'update') {
/* -------------------------------------------------------------------------- */
/* Update a hub */
/* -------------------------------------------------------------------------- */
const id = this.getNodeParameter('id', index) as string;
const hubData = Onfleet.getHubFields.call(this, index, operation);
const path = `${resource}/${id}`;
responseData.push(await onfleetApiRequest.call(this, 'PUT', path, hubData));
}
} catch (error) {
if (this.continueOnFail()) {
responseData.push({ error: (error as IDataObject).toString() });
continue;
}
throw error;
}
}
return responseData;
}
/**
* Execute the worker operations
* @param resource Resource to be executed (Worker)
* @param operation Operation to be executed
* @param items Number of items to process by the node
* @returns Workers information
*/
static async executeWorkerOperations(
this: IExecuteFunctions,
resource: string,
operation: string,
items: INodeExecutionData[],
): Promise<IDataObject | IDataObject[]> {
const responseData = [];
for (const key of Object.keys(items)) {
const index = Number(key);
try {
if (operation === 'getAll') {
/* -------------------------------------------------------------------------- */
/* Get all workers */
/* -------------------------------------------------------------------------- */
const byLocation = this.getNodeParameter('byLocation', index) as boolean;
const returnAll = this.getNodeParameter('returnAll', index, false) as boolean;
let workers;
if (byLocation) {
const longitude = this.getNodeParameter('longitude', index) as string;
const latitude = this.getNodeParameter('latitude', index) as number;
const filters = this.getNodeParameter('filters', index) as IDataObject;
const path = `${resource}/location`;
workers = await onfleetApiRequest.call(
this, 'GET', path, {}, { longitude, latitude, ...filters },
);
workers = workers.workers;
} else {
const workerFilters = Onfleet.getWorkerFields.call(this, 0, operation) as OnfleetWorkerFilter;
workers = await onfleetApiRequest.call(this, 'GET', resource, {}, workerFilters);
}
if (!returnAll) {
const limit = this.getNodeParameter('limit', index) as number;
workers = workers.slice(0, limit);
}
responseData.push(...workers);
} else if (operation === 'get') {
/* -------------------------------------------------------------------------- */
/* Get a worker */
/* -------------------------------------------------------------------------- */
const id = this.getNodeParameter('id', index) as string;
const workerFilters = Onfleet.getWorkerFields.call(this, index, operation) as OnfleetWorkerFilter;
const path = `${resource}/${id}`;
responseData.push(await onfleetApiRequest.call(this, 'GET', path, {}, workerFilters));
} else if (operation === 'create') {
/* -------------------------------------------------------------------------- */
/* Create a new worker */
/* -------------------------------------------------------------------------- */
const workerData = Onfleet.getWorkerFields.call(this, index, operation);
responseData.push(await onfleetApiRequest.call(this, 'POST', resource, workerData));
} else if (operation === 'update') {
/* -------------------------------------------------------------------------- */
/* Update worker */
/* -------------------------------------------------------------------------- */
const id = this.getNodeParameter('id', index) as string;
const workerData = Onfleet.getWorkerFields.call(this, index, operation);
const path = `${resource}/${id}`;
responseData.push(await onfleetApiRequest.call(this, 'PUT', path, workerData));
} else if (operation === 'delete') {
/* -------------------------------------------------------------------------- */
/* Delete worker */
/* -------------------------------------------------------------------------- */
const id = this.getNodeParameter('id', index) as string;
const path = `${resource}/${id}`;
await onfleetApiRequest.call(this, 'DELETE', path);
responseData.push({ success: true });
} else if (operation === 'getSchedule') {
/* -------------------------------------------------------------------------- */
/* Get worker schedule */
/* -------------------------------------------------------------------------- */
const id = this.getNodeParameter('id', index) as string;
const path = `${resource}/${id}/schedule`;
responseData.push(await onfleetApiRequest.call(this, 'GET', path));
} else if (operation === 'setSchedule') {
/* -------------------------------------------------------------------------- */
/* Set a worker schedule */
/* -------------------------------------------------------------------------- */
const id = this.getNodeParameter('id', index) as string;
const workerSchedule = Onfleet.getWorkerFields.call(this, index, operation) as OnfleetWorkerSchedule;
const path = `${resource}/${id}/schedule`;
responseData.push(await onfleetApiRequest.call(this, 'POST', path, workerSchedule));
}
} catch (error) {
if (this.continueOnFail()) {
responseData.push({ error: (error as IDataObject).toString() });
continue;
}
throw error;
}
}
return responseData;
}
/**
* Execute the webhook operations
* @param resource Resource to be executed (Webhook)
* @param operation Operation to be executed
* @param items Number of items to process by the node
* @returns Webhook information
*/
static async executeWebhookOperations(
this: IExecuteFunctions,
resource: string,
operation: string,
items: INodeExecutionData[],
): Promise<IDataObject | IDataObject[]> {
const responseData = [];
for (const key of Object.keys(items)) {
const index = Number(key);
try {
if (operation === 'getAll') {
/* -------------------------------------------------------------------------- */
/* Get all webhooks */
/* -------------------------------------------------------------------------- */
responseData.push(...await onfleetApiRequest.call(this, 'GET', resource));
} else if (operation === 'create') {
/* -------------------------------------------------------------------------- */
/* Create a new webhook */
/* -------------------------------------------------------------------------- */
const webhookData = Onfleet.getWebhookFields.call(this, index, operation);
responseData.push(await onfleetApiRequest.call(this, 'POST', resource, webhookData));
} else if (operation === 'delete') {
/* -------------------------------------------------------------------------- */
/* Delete a webhook */
/* -------------------------------------------------------------------------- */
const id = this.getNodeParameter('id', index) as string;
const path = `${resource}/${id}`;
await onfleetApiRequest.call(this, 'DELETE', path);
responseData.push({ success: true });
}
} catch (error) {
if (this.continueOnFail()) {
responseData.push({ error: (error as IDataObject).toString() });
continue;
}
throw error;
}
}
return responseData;
}
/**
* Execute the containers operations
* @param resource Resource to be executed (Container)
* @param operation Operation to be executed
* @param items Number of items to process by the node
* @returns Container information
*/
static async executeContainerOperations(
this: IExecuteFunctions,
resource: string,
operation: string,
items: INodeExecutionData[],
): Promise<IDataObject | IDataObject[]> {
const responseData = [];
for (const key of Object.keys(items)) {
const index = Number(key);
try {
if (operation === 'get') {
/* -------------------------------------------------------------------------- */
/* Get container by id and type */
/* -------------------------------------------------------------------------- */
const containerId = this.getNodeParameter('containerId', index) as string;
const containerType = this.getNodeParameter('containerType', index) as string;
const path = `${resource}/${containerType}/${containerId}`;
responseData.push(await onfleetApiRequest.call(this, 'GET', path));
} else if (['addTask', 'updateTask'].includes(operation)) {
/* -------------------------------------------------------------------------- */
/* Add or update tasks to container */
/* -------------------------------------------------------------------------- */
const containerId = this.getNodeParameter('containerId', index) as string;
const containerType = this.getNodeParameter('containerType', index, 'workers') as string;
const options = this.getNodeParameter('options', index) as IDataObject;
const tasks = this.getNodeParameter('tasks', index) as Array<string | number>;
if (operation === 'addTask') {
const type = this.getNodeParameter('type', index) as number;
if (type === 1) {
const tasksIndex = this.getNodeParameter('index', index) as number;
tasks.unshift(tasksIndex);
} else {
tasks.unshift(type);
}
}
const path = `${resource}/${containerType}/${containerId}`;
responseData.push(
await onfleetApiRequest.call(this, 'PUT', path, { tasks, ...options }),
);
}
} catch (error) {
if (this.continueOnFail()) {
responseData.push({ error: (error as IDataObject).toString() });
continue;
}
throw error;
}
}
return responseData;
}
/**
* Execute the team operations
* @param resource Resource to be executed (Team)
* @param operation Operation to be executed
* @param items Number of items to process by the node
* @returns Team information
*/
static async executeTeamOperations(
this: IExecuteFunctions,
resource: string,
operation: string,
items: INodeExecutionData[],
): Promise<IDataObject | IDataObject[]> {
const responseData = [];
for (const key of Object.keys(items)) {
const index = Number(key);
try {
if (operation === 'getAll') {
/* -------------------------------------------------------------------------- */
/* Get all teams */
/* -------------------------------------------------------------------------- */
const returnAll = this.getNodeParameter('returnAll', 0, false) as boolean;
let teams = await onfleetApiRequest.call(this, 'GET', resource);
if (!returnAll) {
const limit = this.getNodeParameter('limit', 0) as number;
teams = teams.slice(0, limit);
}
responseData.push(...teams);
} else if (operation === 'get') {
/* -------------------------------------------------------------------------- */
/* Get a single team */
/* -------------------------------------------------------------------------- */
const id = this.getNodeParameter('id', index) as string;
const path = `${resource}/${id}`;
responseData.push(await onfleetApiRequest.call(this, 'GET', path));
} else if (operation === 'create') {
/* -------------------------------------------------------------------------- */
/* Create a new team */
/* -------------------------------------------------------------------------- */
const teamData = Onfleet.getTeamFields.call(this, index, operation);
responseData.push(await onfleetApiRequest.call(this, 'POST', resource, teamData));
} else if (operation === 'update') {
/* -------------------------------------------------------------------------- */
/* Update a team */
/* -------------------------------------------------------------------------- */
const id = this.getNodeParameter('id', index) as string;
const teamData = Onfleet.getTeamFields.call(this, index, operation);
const path = `${resource}/${id}`;
responseData.push(await onfleetApiRequest.call(this, 'PUT', path, teamData));
} else if (operation === 'delete') {
/* -------------------------------------------------------------------------- */
/* Delete a team */
/* -------------------------------------------------------------------------- */
const id = this.getNodeParameter('id', index) as string;
const path = `${resource}/${id}`;
await onfleetApiRequest.call(this, 'DELETE', path);
responseData.push({ success: true });
} else if (operation === 'getTimeEstimates') {
/* -------------------------------------------------------------------------- */
/* Get driver time estimates for tasks that haven't been created yet */
/* -------------------------------------------------------------------------- */
const id = this.getNodeParameter('id', index) as string;
const workerTimeEstimates = Onfleet.getTeamFields.call(this, index, operation) as OnfleetWorkerSchedule;
const path = `${resource}/${id}/estimate`;
responseData.push(await onfleetApiRequest.call(this, 'GET', path, {}, workerTimeEstimates));
} else if (operation === 'autoDispatch') {
/* -------------------------------------------------------------------------- */
/* Dynamically dispatching tasks on the fly */
/* -------------------------------------------------------------------------- */
const id = this.getNodeParameter('id', index) as string;
const teamAutoDispatch = Onfleet.getTeamFields.call(this, index, operation) as OnfleetWorkerSchedule;
const path = `${resource}/${id}/dispatch`;
responseData.push(await onfleetApiRequest.call(this, 'POST', path, teamAutoDispatch));
}
} catch (error) {
if (this.continueOnFail()) {
responseData.push({ error: (error as IDataObject).toString() });
continue;
}
throw error;
}
}
return responseData;
}
}