From 4aaa1719143a6cb4bbb1a960adfe26a0b982e12e Mon Sep 17 00:00:00 2001 From: Luan Cazarine Date: Tue, 10 Sep 2024 12:20:24 -0300 Subject: [PATCH 1/3] agiliron init --- .../actions/create-contact/create-contact.mjs | 96 +++++++ .../actions/create-event/create-event.mjs | 174 ++++++++++++ .../actions/create-lead/create-lead.mjs | 247 ++++++++++++++++++ components/agiliron/agiliron.app.mjs | 143 +++++++++- components/agiliron/package.json | 2 +- .../new-contact-created.mjs | 73 ++++++ .../new-lead-created/new-lead-created.mjs | 64 +++++ .../new-task-created/new-task-created.mjs | 45 ++++ 8 files changed, 838 insertions(+), 6 deletions(-) create mode 100644 components/agiliron/actions/create-contact/create-contact.mjs create mode 100644 components/agiliron/actions/create-event/create-event.mjs create mode 100644 components/agiliron/actions/create-lead/create-lead.mjs create mode 100644 components/agiliron/sources/new-contact-created/new-contact-created.mjs create mode 100644 components/agiliron/sources/new-lead-created/new-lead-created.mjs create mode 100644 components/agiliron/sources/new-task-created/new-task-created.mjs diff --git a/components/agiliron/actions/create-contact/create-contact.mjs b/components/agiliron/actions/create-contact/create-contact.mjs new file mode 100644 index 0000000000000..009dbd06c66d8 --- /dev/null +++ b/components/agiliron/actions/create-contact/create-contact.mjs @@ -0,0 +1,96 @@ +import agiliron from "../../agiliron.app.mjs"; +import { axios } from "@pipedream/platform"; + +export default { + key: "agiliron-create-contact", + name: "Create Contact", + description: "Generates a new contact within Agiliron. [See the documentation](https://api.agiliron.com/docs/add-contact-1)", + version: "0.0.{{ts}}", + type: "action", + props: { + agiliron, + lastname: { + propDefinition: [ + agiliron, + "lastname", + ], + }, + firstname: { + type: "string", + label: "First Name", + description: "The first name of the contact", + optional: true, + }, + email: { + type: "string", + label: "Email", + description: "The email of the contact", + optional: true, + }, + phone: { + type: "string", + label: "Phone", + description: "The phone number of the contact", + optional: true, + }, + company: { + propDefinition: [ + agiliron, + "company", + ], + optional: true, + }, + subject: { + propDefinition: [ + agiliron, + "subject", + ], + optional: true, + }, + startdate: { + propDefinition: [ + agiliron, + "startdate", + ], + optional: true, + }, + starttime: { + propDefinition: [ + agiliron, + "starttime", + ], + optional: true, + }, + }, + async run({ $ }) { + const data = { + LastName: this.lastname, + ...(this.firstname && { + FirstName: this.firstname, + }), + ...(this.email && { + Email: this.email, + }), + ...(this.phone && { + Phone: this.phone, + }), + ...(this.company && { + Company: this.company, + }), + ...(this.subject && { + Subject: this.subject, + }), + ...(this.startdate && { + StartDate: this.startdate, + }), + ...(this.starttime && { + StartTime: this.starttime, + }), + }; + + const response = await this.agiliron.addContact(data); + + $.export("$summary", `Successfully created contact: ${this.lastname}`); + return response; + }, +}; diff --git a/components/agiliron/actions/create-event/create-event.mjs b/components/agiliron/actions/create-event/create-event.mjs new file mode 100644 index 0000000000000..dc688d102a973 --- /dev/null +++ b/components/agiliron/actions/create-event/create-event.mjs @@ -0,0 +1,174 @@ +import agiliron from "../../agiliron.app.mjs"; +import { axios } from "@pipedream/platform"; + +export default { + key: "agiliron-create-event", + name: "Create Event", + description: "Creates a new event within Agiliron. [See the documentation](https://api.agiliron.com/docs/add-event-2)", + version: "0.0.{{ts}}", + type: "action", + props: { + agiliron, + subject: { + propDefinition: [ + agiliron, + "subject", + ], + }, + startdate: { + propDefinition: [ + agiliron, + "startdate", + ], + }, + starttime: { + propDefinition: [ + agiliron, + "starttime", + ], + }, + durationInHours: { + type: "string", + label: "Duration in Hours", + description: "The duration of the event in hours", + optional: true, + }, + durationInMinutes: { + type: "string", + label: "Duration in Minutes", + description: "The duration of the event in minutes", + optional: true, + }, + recurringEvents: { + type: "string", + label: "Recurring Events", + description: "Details of the recurring events", + optional: true, + }, + repeatUntil: { + type: "string", + label: "Repeat Until", + description: "The end date of the recurring events (format: MM-DD-YYYY)", + optional: true, + }, + accountName: { + type: "string", + label: "Account Name", + description: "The name of the account related to the event", + optional: true, + }, + contactName: { + type: "string", + label: "Contact Name", + description: "The name of the contact related to the event", + optional: true, + }, + relatedToType: { + type: "string", + label: "Related To Type", + description: "The type of the entity related to the event (e.g., Accounts, Leads)", + optional: true, + }, + relatedToValue: { + type: "string", + label: "Related To Value", + description: "The value of the entity related to the event", + optional: true, + }, + sendReminder: { + type: "string", + label: "Send Reminder", + description: "Whether to send a reminder for the event (Yes/No)", + optional: true, + }, + reminderDays: { + type: "string", + label: "Reminder Days", + description: "Number of days before the event to send a reminder", + optional: true, + }, + reminderHours: { + type: "string", + label: "Reminder Hours", + description: "Number of hours before the event to send a reminder", + optional: true, + }, + reminderMinutes: { + type: "string", + label: "Reminder Minutes", + description: "Number of minutes before the event to send a reminder", + optional: true, + }, + status: { + type: "string", + label: "Status", + description: "The status of the event (e.g., Planned, Completed)", + optional: true, + }, + sendNotification: { + type: "string", + label: "Send Notification", + description: "Whether to send a notification for the event (Yes/No)", + optional: true, + }, + activityType: { + type: "string", + label: "Activity Type", + description: "The type of activity for the event (e.g., Call, Meeting)", + optional: true, + }, + location: { + type: "string", + label: "Location", + description: "The location of the event", + optional: true, + }, + description: { + type: "string", + label: "Description", + description: "The description of the event", + optional: true, + }, + eventCustomFields: { + type: "string[]", + label: "Event Custom Fields", + description: "An array of custom fields for the event, each item should be a JSON string with 'Name' and 'Value' keys", + optional: true, + }, + }, + async run({ $ }) { + const eventCustomFields = this.eventCustomFields?.map(JSON.parse); + + const data = { + Subject: this.subject, + StartDate: this.startdate, + StartTime: this.starttime, + DurationInHours: this.durationInHours, + DurationInMinutes: this.durationInMinutes, + RecurringEvents: this.recurringEvents, + RepeatUntil: this.repeatUntil, + AccountName: this.accountName, + ContactName: this.contactName, + RelatedToType: this.relatedToType, + RelatedToValue: this.relatedToValue, + SendReminder: this.sendReminder, + ReminderDays: this.reminderDays, + ReminderHours: this.reminderHours, + ReminderMinutes: this.reminderMinutes, + Status: this.status, + SendNotification: this.sendNotification, + ActivityType: this.activityType, + Location: this.location, + Description: this.description, + EventCustomFields: eventCustomFields + ? { + CustomField: eventCustomFields, + } + : undefined, + }; + + const response = await this.agiliron.addEvent(data); + $.export("$summary", `Successfully created event with subject: ${this.subject}`); + return response; + }, +}; diff --git a/components/agiliron/actions/create-lead/create-lead.mjs b/components/agiliron/actions/create-lead/create-lead.mjs new file mode 100644 index 0000000000000..726046cac9731 --- /dev/null +++ b/components/agiliron/actions/create-lead/create-lead.mjs @@ -0,0 +1,247 @@ +import agiliron from "../../agiliron.app.mjs"; +import { axios } from "@pipedream/platform"; + +export default { + key: "agiliron-create-lead", + name: "Create Lead", + description: "Establishes a new lead within Agiliron. [See the documentation](https://api.agiliron.com/docs/add-lead-1)", + version: "0.0.{{ts}}", + type: "action", + props: { + agiliron, + lastname: { + propDefinition: [ + agiliron, + "lastname", + ], + }, + company: { + propDefinition: [ + agiliron, + "company", + ], + }, + salutation: { + type: "string", + label: "Salutation", + description: "The salutation of the contact or lead", + optional: true, + }, + firstName: { + type: "string", + label: "First Name", + description: "The first name of the contact or lead", + optional: true, + }, + designation: { + type: "string", + label: "Designation", + description: "The designation of the contact or lead", + optional: true, + }, + phone: { + type: "string", + label: "Phone", + description: "The phone number of the contact or lead", + optional: true, + }, + mobile: { + type: "string", + label: "Mobile", + description: "The mobile number of the contact or lead", + optional: true, + }, + fax: { + type: "string", + label: "Fax", + description: "The fax number of the contact or lead", + optional: true, + }, + email: { + type: "string", + label: "Email", + description: "The email address of the contact or lead", + optional: true, + }, + website: { + type: "string", + label: "Website", + description: "The website of the contact or lead", + optional: true, + }, + industry: { + type: "string", + label: "Industry", + description: "The industry of the contact or lead", + optional: true, + }, + sicCode: { + type: "string", + label: "SIC Code", + description: "The SIC code of the contact or lead", + optional: true, + }, + annualRevenue: { + type: "string", + label: "Annual Revenue", + description: "The annual revenue of the contact or lead", + optional: true, + }, + numberOfEmployees: { + type: "string", + label: "Number of Employees", + description: "The number of employees of the contact or lead", + optional: true, + }, + contactType: { + type: "string", + label: "Contact Type", + description: "The contact type of the contact or lead", + optional: true, + }, + leadSource: { + type: "string", + label: "Lead Source", + description: "The lead source of the contact or lead", + optional: true, + }, + leadStatus: { + type: "string", + label: "Lead Status", + description: "The lead status of the contact or lead", + optional: true, + }, + rating: { + type: "string", + label: "Rating", + description: "The rating of the contact or lead", + optional: true, + }, + emailOptOut: { + type: "string", + label: "Email Opt Out", + description: "The email opt-out status of the contact or lead", + optional: true, + }, + yahooID: { + type: "string", + label: "Yahoo ID", + description: "The Yahoo ID of the contact or lead", + optional: true, + }, + createdTime: { + type: "string", + label: "Created Time", + description: "The created time of the contact or lead (format: MM-DD-YYYY HH:MM:SS)", + optional: true, + }, + modifiedTime: { + type: "string", + label: "Modified Time", + description: "The modified time of the contact or lead (format: MM-DD-YYYY HH:MM:SS)", + optional: true, + }, + street: { + type: "string", + label: "Street", + description: "The street address of the contact or lead", + optional: true, + }, + city: { + type: "string", + label: "City", + description: "The city of the contact or lead", + optional: true, + }, + state: { + type: "string", + label: "State", + description: "The state of the contact or lead", + optional: true, + }, + zip: { + type: "string", + label: "Zip", + description: "The zip code of the contact or lead", + optional: true, + }, + country: { + type: "string", + label: "Country", + description: "The country of the contact or lead", + optional: true, + }, + description: { + type: "string", + label: "Description", + description: "The description of the contact or lead", + optional: true, + }, + assignedTo: { + type: "string", + label: "Assigned To", + description: "The user to whom the contact or lead is assigned", + optional: true, + }, + assignedGroupName: { + type: "string", + label: "Assigned Group Name", + description: "The group to which the contact or lead is assigned", + optional: true, + }, + defaultCurrency: { + type: "string", + label: "Default Currency", + description: "The default currency of the contact or lead", + optional: true, + }, + leadCustomFields: { + type: "string[]", + label: "Lead Custom Fields", + description: "An array of custom fields for the lead", + optional: true, + }, + }, + async run({ $ }) { + const data = { + Salutation: this.salutation, + FirstName: this.firstName, + LastName: this.lastname, + Company: this.company, + Designation: this.designation, + Phone: this.phone, + Mobile: this.mobile, + Fax: this.fax, + Email: this.email, + Website: this.website, + Industry: this.industry, + SICCode: this.sicCode, + AnnualRevenue: this.annualRevenue, + NumberOfEmployees: this.numberOfEmployees, + ContactType: this.contactType, + LeadSource: this.leadSource, + LeadStatus: this.leadStatus, + Rating: this.rating, + EmailOptOut: this.emailOptOut, + YahooID: this.yahooID, + CreatedTime: this.createdTime, + ModifiedTime: this.modifiedTime, + Street: this.street, + City: this.city, + State: this.state, + Zip: this.zip, + Country: this.country, + Description: this.description, + AssignedTo: this.assignedTo, + AssignedGroupName: this.assignedGroupName, + DefaultCurrency: this.defaultCurrency, + LeadCustomFields: this.leadCustomFields + ? this.leadCustomFields.map(JSON.parse) + : undefined, + }; + + const response = await this.agiliron.addLead(data); + $.export("$summary", `Successfully created lead with ID ${response.MCM.parameters.results.message.success_message.lead_id}`); + return response; + }, +}; diff --git a/components/agiliron/agiliron.app.mjs b/components/agiliron/agiliron.app.mjs index d127c39dc7f74..d3ea5ed3a3c39 100644 --- a/components/agiliron/agiliron.app.mjs +++ b/components/agiliron/agiliron.app.mjs @@ -1,11 +1,144 @@ +import { axios } from "@pipedream/platform"; + export default { type: "app", app: "agiliron", - propDefinitions: {}, + propDefinitions: { + lastname: { + type: "string", + label: "Last Name", + description: "The last name of the contact or lead", + }, + company: { + type: "string", + label: "Company", + description: "The company of the lead", + }, + subject: { + type: "string", + label: "Subject", + description: "The subject of the event", + }, + startdate: { + type: "string", + label: "Start Date", + description: "The start date of the event (format: MM-DD-YYYY)", + }, + starttime: { + type: "string", + label: "Start Time", + description: "The start time of the event (format: HH:MM:SS)", + }, + }, methods: { - // this.$auth contains connected account data - authKeys() { - console.log(Object.keys(this.$auth)); + _baseUrl() { + return `https://${this.$auth.company}.agiliron.net/agiliron/api-40.php`; + }, + async _makeRequest(opts = {}) { + const { + $ = this, + method = "GET", + path = "/", + headers, + ...otherOpts + } = opts; + return axios($, { + ...otherOpts, + method, + url: this._baseUrl() + path, + headers: { + ...headers, + Accept: "application/json", + apiKey: this.$auth.api_key, + }, + }); + }, + async addContact(data) { + return this._makeRequest({ + method: "POST", + path: "/Contact", + data: { + Contacts: { + Contact: [ + data, + ], + }, + }, + }); + }, + async addLead(data) { + return this._makeRequest({ + method: "POST", + path: "/Leads", + data: { + Leads: { + Lead: [ + data, + ], + }, + }, + }); + }, + async addEvent(data) { + return this._makeRequest({ + method: "POST", + path: "/Event", + data: { + Events: { + Event: [ + data, + ], + }, + }, + }); + }, + async getContacts(opts = {}) { + return this._makeRequest({ + path: "/Contact", + ...opts, + }); + }, + async getLeads(opts = {}) { + return this._makeRequest({ + path: "/Leads", + ...opts, + }); + }, + async getEvents(opts = {}) { + return this._makeRequest({ + path: "/Event", + ...opts, + }); + }, + async emitNewContactEvents() { + const contacts = await this.getContacts(); + for (const contact of contacts.Contacts.Contact) { + this.$emit(contact, { + id: contact.ContactId, + summary: `New contact: ${contact.FirstName} ${contact.LastName}`, + ts: new Date(contact.CreatedTimeUTC).getTime(), + }); + } + }, + async emitNewLeadEvents() { + const leads = await this.getLeads(); + for (const lead of leads.Leads.Lead) { + this.$emit(lead, { + id: lead.LeadId, + summary: `New lead: ${lead.FirstName} ${lead.LastName}`, + ts: new Date(lead.CreatedTimeUTC).getTime(), + }); + } + }, + async emitNewTaskEvents() { + const tasks = await this.getEvents(); + for (const task of tasks.Events.Event) { + this.$emit(task, { + id: task.EventId, + summary: `New task: ${task.Subject}`, + ts: new Date(task.CreatedTimeUTC).getTime(), + }); + } }, }, -}; \ No newline at end of file +}; diff --git a/components/agiliron/package.json b/components/agiliron/package.json index 77f6e23db10e8..b061131d427c4 100644 --- a/components/agiliron/package.json +++ b/components/agiliron/package.json @@ -12,4 +12,4 @@ "publishConfig": { "access": "public" } -} \ No newline at end of file +} diff --git a/components/agiliron/sources/new-contact-created/new-contact-created.mjs b/components/agiliron/sources/new-contact-created/new-contact-created.mjs new file mode 100644 index 0000000000000..ab39b67897ceb --- /dev/null +++ b/components/agiliron/sources/new-contact-created/new-contact-created.mjs @@ -0,0 +1,73 @@ +import agiliron from "../../agiliron.app.mjs"; +import { axios } from "@pipedream/platform"; + +export default { + key: "agiliron-new-contact-created", + name: "New Contact Created", + description: "Emit new event when a new contact is created in Agiliron. [See the documentation](https://api.agiliron.com/docs/read-contact-1)", + version: "0.0.{{ts}}", + type: "source", + dedupe: "unique", + props: { + agiliron, + db: "$.service.db", + timer: { + type: "$.interface.timer", + default: { + intervalSeconds: 60 * 15, // Poll every 15 minutes + }, + }, + }, + methods: { + _getLastTimestamp() { + return this.db.get("lastTimestamp") || 0; + }, + _setLastTimestamp(ts) { + this.db.set("lastTimestamp", ts); + }, + }, + hooks: { + async deploy() { + const contacts = await this.agiliron.getContacts(); + const lastTimestamp = this._getLastTimestamp(); + const newContacts = contacts.Contacts.Contact.filter((contact) => { + const contactTimestamp = new Date(contact.CreatedTimeUTC).getTime(); + return contactTimestamp > lastTimestamp; + }); + + newContacts.slice(0, 50).forEach((contact) => { + this.$emit(contact, { + id: contact.ContactId, + summary: `New contact: ${contact.FirstName} ${contact.LastName}`, + ts: new Date(contact.CreatedTimeUTC).getTime(), + }); + }); + + if (newContacts.length > 0) { + const latestTimestamp = newContacts[0].CreatedTimeUTC; + this._setLastTimestamp(new Date(latestTimestamp).getTime()); + } + }, + }, + async run() { + const lastTimestamp = this._getLastTimestamp(); + const contacts = await this.agiliron.getContacts({ + params: { + filter: `CreatedTimeUTC,gt,${new Date(lastTimestamp).toISOString()}`, + }, + }); + + for (const contact of contacts.Contacts.Contact) { + this.$emit(contact, { + id: contact.ContactId, + summary: `New contact: ${contact.FirstName} ${contact.LastName}`, + ts: new Date(contact.CreatedTimeUTC).getTime(), + }); + } + + if (contacts.Contacts.Contact.length > 0) { + const latestContact = contacts.Contacts.Contact[contacts.Contacts.Contact.length - 1]; + this._setLastTimestamp(new Date(latestContact.CreatedTimeUTC).getTime()); + } + }, +}; diff --git a/components/agiliron/sources/new-lead-created/new-lead-created.mjs b/components/agiliron/sources/new-lead-created/new-lead-created.mjs new file mode 100644 index 0000000000000..e440ad8249f74 --- /dev/null +++ b/components/agiliron/sources/new-lead-created/new-lead-created.mjs @@ -0,0 +1,64 @@ +import { axios } from "@pipedream/platform"; +import agiliron from "../../agiliron.app.mjs"; + +export default { + key: "agiliron-new-lead-created", + name: "New Lead Created", + description: "Emit new event when a new lead is created in Agiliron. [See the documentation](https://api.agiliron.com/reference/add-lead)", + version: "0.0.1", + type: "source", + dedupe: "unique", + props: { + agiliron, + db: "$.service.db", + timer: { + type: "$.interface.timer", + default: { + intervalSeconds: 60 * 15, // Poll every 15 minutes + }, + }, + }, + hooks: { + async deploy() { + await this.emitNewLeadEvents(); + }, + async activate() { + // No webhook support, rely on polling + }, + async deactivate() { + // No webhook support, nothing to clean up + }, + }, + methods: { + _getLastTimestamp() { + return this.db.get("lastTimestamp") || 0; + }, + _setLastTimestamp(ts) { + this.db.set("lastTimestamp", ts); + }, + async emitNewLeadEvents() { + const leads = await this.agiliron.getLeads({ + params: { + filter: `CreatedTimeUTC,gt,${this._getLastTimestamp()}`, + pageSize: 50, + }, + }); + + for (const lead of leads.Leads.Lead) { + this.$emit(lead, { + id: lead.LeadId, + summary: `New lead: ${lead.FirstName} ${lead.LastName}`, + ts: new Date(lead.CreatedTimeUTC).getTime(), + }); + } + + if (leads.Leads.Lead.length > 0) { + const lastLead = leads.Leads.Lead[leads.Leads.Lead.length - 1]; + this._setLastTimestamp(new Date(lastLead.CreatedTimeUTC).getTime()); + } + }, + }, + async run() { + await this.emitNewLeadEvents(); + }, +}; diff --git a/components/agiliron/sources/new-task-created/new-task-created.mjs b/components/agiliron/sources/new-task-created/new-task-created.mjs new file mode 100644 index 0000000000000..2b5dfba7982e7 --- /dev/null +++ b/components/agiliron/sources/new-task-created/new-task-created.mjs @@ -0,0 +1,45 @@ +import agiliron from "../../agiliron.app.mjs"; +import { axios } from "@pipedream/platform"; + +export default { + key: "agiliron-new-task-created", + name: "New Task Created", + description: "Emit new event when a new task is created in Agiliron. [See the documentation](https://learn.agiliron.com/docs/getting-started)", + version: "0.0.{{ts}}", + type: "source", + dedupe: "unique", + props: { + agiliron, + db: "$.service.db", + timer: { + type: "$.interface.timer", + default: { + intervalSeconds: 60, + }, + }, + }, + hooks: { + async deploy() { + const tasks = await this.agiliron.getEvents(); + for (const task of tasks.Events.Event.slice(-50)) { + this.$emit(task, { + id: task.EventId, + summary: `New task: ${task.Subject}`, + ts: new Date(task.CreatedTimeUTC).getTime(), + }); + } + }, + async activate() {}, + async deactivate() {}, + }, + async run() { + const tasks = await this.agiliron.getEvents(); + for (const task of tasks.Events.Event) { + this.$emit(task, { + id: task.EventId, + summary: `New task: ${task.Subject}`, + ts: new Date(task.CreatedTimeUTC).getTime(), + }); + } + }, +}; From 2982c704795a73cc9e34b93bfe42eab77884044d Mon Sep 17 00:00:00 2001 From: Luan Cazarine Date: Wed, 11 Sep 2024 09:32:59 -0300 Subject: [PATCH 2/3] [Components] agiliron #13871 Sources - New Contact Created - New Lead Created - New Task Created Actions - Create Contact - Create Lead - Create Event --- .../actions/create-contact/create-contact.mjs | 281 +++++++++++++++--- .../actions/create-event/create-event.mjs | 124 +++++--- .../actions/create-lead/create-lead.mjs | 184 ++++++------ components/agiliron/agiliron.app.mjs | 233 +++++++++------ components/agiliron/common/constants.mjs | 210 +++++++++++++ components/agiliron/common/utils.mjs | 24 ++ components/agiliron/package.json | 5 +- components/agiliron/sources/common/base.mjs | 67 +++++ .../new-contact-created.mjs | 77 ++--- .../new-contact-created/test-event.mjs | 58 ++++ .../new-lead-created/new-lead-created.mjs | 68 ++--- .../sources/new-lead-created/test-event.mjs | 48 +++ .../new-task-created/new-task-created.mjs | 55 ++-- .../sources/new-task-created/test-event.mjs | 32 ++ 14 files changed, 1057 insertions(+), 409 deletions(-) create mode 100644 components/agiliron/common/constants.mjs create mode 100644 components/agiliron/common/utils.mjs create mode 100644 components/agiliron/sources/common/base.mjs create mode 100644 components/agiliron/sources/new-contact-created/test-event.mjs create mode 100644 components/agiliron/sources/new-lead-created/test-event.mjs create mode 100644 components/agiliron/sources/new-task-created/test-event.mjs diff --git a/components/agiliron/actions/create-contact/create-contact.mjs b/components/agiliron/actions/create-contact/create-contact.mjs index 009dbd06c66d8..323227d28cfea 100644 --- a/components/agiliron/actions/create-contact/create-contact.mjs +++ b/components/agiliron/actions/create-contact/create-contact.mjs @@ -1,96 +1,291 @@ import agiliron from "../../agiliron.app.mjs"; -import { axios } from "@pipedream/platform"; +import { parseObject } from "../../common/utils.mjs"; export default { key: "agiliron-create-contact", name: "Create Contact", description: "Generates a new contact within Agiliron. [See the documentation](https://api.agiliron.com/docs/add-contact-1)", - version: "0.0.{{ts}}", + version: "0.0.1", type: "action", props: { agiliron, + salutation: { + propDefinition: [ + agiliron, + "salutation", + ], + optional: true, + }, lastname: { propDefinition: [ agiliron, "lastname", ], + description: "The last name of the contact.", }, - firstname: { - type: "string", - label: "First Name", + firstName: { + propDefinition: [ + agiliron, + "firstName", + ], description: "The first name of the contact", optional: true, }, - email: { + officePhone: { + type: "string", + label: "Office Phone", + description: "The office phone number of the contact", + optional: true, + }, + mobile: { + propDefinition: [ + agiliron, + "mobile", + ], + description: "The mobile number of the contact", + optional: true, + }, + homePhone: { + type: "string", + label: "Home Phone", + description: "The home phone number of the contact", + optional: true, + }, + otherPhone: { + type: "string", + label: "Other Phone", + description: "An additional phone number of the contact", + optional: true, + }, + fax: { + propDefinition: [ + agiliron, + "fax", + ], + description: "The fax number of the contact", + optional: true, + }, + accountName: { + type: "string", + label: "Account Name", + description: "The account name of the contact", + optional: true, + }, + accountId: { + type: "string", + label: "Account ID", + description: "The account id of the contact", + optional: true, + }, + vendorName: { + type: "string", + label: "Vendor Name", + description: "The vendor name of the contact", + optional: true, + }, + vendorId: { + type: "string", + label: "Vendor ID", + description: "The vendor id of the contact", + optional: true, + }, + contactType: { + propDefinition: [ + agiliron, + "contactType", + ], + description: "The contact type of the contact", + optional: true, + }, + title: { type: "string", - label: "Email", - description: "The email of the contact", + label: "Title", + description: "The title of the contact.", optional: true, }, - phone: { + department: { type: "string", - label: "Phone", - description: "The phone number of the contact", + label: "Department", + description: "The department of the contact.", optional: true, }, - company: { + email: { propDefinition: [ agiliron, - "company", + "email", ], + description: "The email address of the contact", optional: true, }, - subject: { + yahooId: { propDefinition: [ agiliron, - "subject", + "yahooId", ], + description: "The Yahoo ID of the contact", + optional: true, + }, + emailOptOut: { + propDefinition: [ + agiliron, + "emailOptOut", + ], + description: "The email opt-out status of the contact", + optional: true, + }, + assignedTo: { + propDefinition: [ + agiliron, + "assignedTo", + ], + description: "The user to whom the contact is assigned", + optional: true, + }, + leadSource: { + propDefinition: [ + agiliron, + "leadSource", + ], + description: "The lead source of the contact", + optional: true, + }, + birthday: { + type: "string", + label: "Birthday", + description: "The birthday of the contact.", + optional: true, + }, + mailingStreet: { + type: "string", + label: "Mailing Street", + description: "The mailing street address of the contact", + optional: true, + }, + mailingCity: { + type: "string", + label: "Mailing City", + description: "The mailing city of the contact", + optional: true, + }, + mailingState: { + type: "string", + label: "Mailing State", + description: "The mailing state of the contact", + optional: true, + }, + mailingZip: { + type: "string", + label: "Mailing Zip", + description: "The mailing zip code of the contact", + optional: true, + }, + mailingCountry: { + type: "string", + label: "Mailing Country", + description: "The mailing country of the contact", + optional: true, + }, + otherStreet: { + type: "string", + label: "Other Street", + description: "The other street address of the contact", + optional: true, + }, + otherCity: { + type: "string", + label: "Other City", + description: "The other city of the contact", + optional: true, + }, + otherState: { + type: "string", + label: "Other State", + description: "The other state of the contact", + optional: true, + }, + otherZip: { + type: "string", + label: "Other Zip", + description: "The other zip code of the contact", + optional: true, + }, + otherCountry: { + type: "string", + label: "Other Country", + description: "The other country of the contact", optional: true, }, - startdate: { + description: { propDefinition: [ agiliron, - "startdate", + "description", ], + description: "The description of the contact", optional: true, }, - starttime: { + customFields: { propDefinition: [ agiliron, - "starttime", + "customFields", ], + description: "An object of custom fields for the contact. **Format: {customFieldName01: \"Value 01\"}**", optional: true, }, }, async run({ $ }) { - const data = { + const parsedCustomFields = parseObject(this.customFields); + const customFields = parsedCustomFields && Object.keys(parsedCustomFields).map((key) => ({ + Name: key, + value: parsedCustomFields[key], + })); + const contact = { + Salutation: this.salutation, LastName: this.lastname, - ...(this.firstname && { - FirstName: this.firstname, - }), - ...(this.email && { - Email: this.email, - }), - ...(this.phone && { - Phone: this.phone, - }), - ...(this.company && { - Company: this.company, - }), - ...(this.subject && { - Subject: this.subject, - }), - ...(this.startdate && { - StartDate: this.startdate, - }), - ...(this.starttime && { - StartTime: this.starttime, - }), + FirstName: this.firstName, + OfficePhone: this.officePhone, + Mobile: this.mobile, + HomePhone: this.homePhone, + OtherPhone: this.otherPhone, + Fax: this.fax, + AccountName: this.accountName, + AccountID: this.accountId, + VendorName: this.vendorName, + VendorID: this.vendorId, + ContactType: this.contactType, + Title: this.title, + Department: this.department, + Email: this.email, + YahooID: this.yahooId, + EmailOptOut: this.emailOptOut, + AssignedTo: this.assignedTo, + LeadSource: this.leadSource, + Birthday: this.birthday, + MailingStreet: this.mailingStreet, + MailingCity: this.mailingCity, + MailingState: this.mailingState, + MailingZip: this.mailingZip, + MailingCountry: this.mailingCountry, + OtherStreet: this.otherStreet, + OtherCity: this.otherCity, + OtherState: this.otherState, + OtherZip: this.otherZip, + OtherCountry: this.otherCountry, + Description: this.description, + CustomFields: { + CustomField: customFields, + }, }; - const response = await this.agiliron.addContact(data); + const response = await this.agiliron.addContact({ + $, + data: { + "Contacts": { + "Contact": contact, + }, + }, + }); - $.export("$summary", `Successfully created contact: ${this.lastname}`); + $.export("$summary", `Successfully created contact with Id: ${response?.MCM?.parameters?.results?.message?.success_message?.contact_id}`); return response; }, }; diff --git a/components/agiliron/actions/create-event/create-event.mjs b/components/agiliron/actions/create-event/create-event.mjs index dc688d102a973..e0c862cdb77d0 100644 --- a/components/agiliron/actions/create-event/create-event.mjs +++ b/components/agiliron/actions/create-event/create-event.mjs @@ -1,31 +1,29 @@ import agiliron from "../../agiliron.app.mjs"; -import { axios } from "@pipedream/platform"; +import constants from "../../common/constants.mjs"; +import { parseObject } from "../../common/utils.mjs"; export default { key: "agiliron-create-event", name: "Create Event", description: "Creates a new event within Agiliron. [See the documentation](https://api.agiliron.com/docs/add-event-2)", - version: "0.0.{{ts}}", + version: "0.0.1", type: "action", props: { agiliron, subject: { - propDefinition: [ - agiliron, - "subject", - ], + type: "string", + label: "Subject", + description: "The subject of the event", }, startdate: { - propDefinition: [ - agiliron, - "startdate", - ], + type: "string", + label: "Start Date", + description: "The start date of the event (format: MM-DD-YYYY)", }, starttime: { - propDefinition: [ - agiliron, - "starttime", - ], + type: "string", + label: "Start Time", + description: "The start time of the event (format: HH:MM)", }, durationInHours: { type: "string", @@ -43,6 +41,7 @@ export default { type: "string", label: "Recurring Events", description: "Details of the recurring events", + options: constants.RECURRING_EVENT_OPTIONS, optional: true, }, repeatUntil: { @@ -58,27 +57,17 @@ export default { optional: true, }, contactName: { - type: "string", - label: "Contact Name", - description: "The name of the contact related to the event", - optional: true, - }, - relatedToType: { - type: "string", - label: "Related To Type", - description: "The type of the entity related to the event (e.g., Accounts, Leads)", - optional: true, - }, - relatedToValue: { - type: "string", - label: "Related To Value", - description: "The value of the entity related to the event", + propDefinition: [ + agiliron, + "contactName", + ], optional: true, }, sendReminder: { type: "string", label: "Send Reminder", - description: "Whether to send a reminder for the event (Yes/No)", + description: "Whether to send a reminder for the event", + options: constants.BOOL_OPTIONS, optional: true, }, reminderDays: { @@ -102,19 +91,22 @@ export default { status: { type: "string", label: "Status", - description: "The status of the event (e.g., Planned, Completed)", + description: "The status of the event", + options: constants.STATUS_OPTIONS, optional: true, }, sendNotification: { type: "string", label: "Send Notification", - description: "Whether to send a notification for the event (Yes/No)", + description: "Whether to send a notification for the event", + options: constants.BOOL_OPTIONS, optional: true, }, activityType: { type: "string", label: "Activity Type", - description: "The type of activity for the event (e.g., Call, Meeting)", + description: "The type of activity for the event", + options: constants.ACTIVITY_TYPE_OPTIONS, optional: true, }, location: { @@ -129,24 +121,57 @@ export default { description: "The description of the event", optional: true, }, - eventCustomFields: { - type: "string[]", - label: "Event Custom Fields", - description: "An array of custom fields for the event, each item should be a JSON string with 'Name' and 'Value' keys", + customFields: { + propDefinition: [ + agiliron, + "customFields", + ], + optional: true, + }, + relatedToType: { + type: "string", + label: "Related To Type", + description: "The type of the entity related to the event", + options: constants.RELATED_TO_TYPE_OPTIONS, optional: true, + reloadProps: true, }, }, + async additionalProps() { + const props = {}; + if (this.relatedToType) { + props.relatedToValue = { + type: "string", + label: "Related To Value", + description: "The value of the entity related to the event", + options: async ({ page }) => { + return this.agiliron.prepareItems({ + type: this.relatedToType, + page: page + 1, + }); + }, + optional: true, + }; + } + return props; + }, async run({ $ }) { - const eventCustomFields = this.eventCustomFields?.map(JSON.parse); + const parsedCustomFields = parseObject(this.customFields); + const customFields = parsedCustomFields && Object.keys(parsedCustomFields).map((key) => ({ + Name: key, + value: parsedCustomFields[key], + })); - const data = { + const event = { Subject: this.subject, StartDate: this.startdate, StartTime: this.starttime, DurationInHours: this.durationInHours, DurationInMinutes: this.durationInMinutes, RecurringEvents: this.recurringEvents, - RepeatUntil: this.repeatUntil, + RepeatUntil: this.repeatUntil + ? this.repeatUntil + : this.startdate, AccountName: this.accountName, ContactName: this.contactName, RelatedToType: this.relatedToType, @@ -160,15 +185,20 @@ export default { ActivityType: this.activityType, Location: this.location, Description: this.description, - EventCustomFields: eventCustomFields - ? { - CustomField: eventCustomFields, - } - : undefined, + EventCustomFields: { + CustomField: customFields, + }, }; - const response = await this.agiliron.addEvent(data); - $.export("$summary", `Successfully created event with subject: ${this.subject}`); + const response = await this.agiliron.addEvent({ + $, + data: { + Events: { + Event: event, + }, + }, + }); + $.export("$summary", `Successfully created event with Id: ${response?.MCM?.parameters?.results?.message?.success_message?.event_id}`); return response; }, }; diff --git a/components/agiliron/actions/create-lead/create-lead.mjs b/components/agiliron/actions/create-lead/create-lead.mjs index 726046cac9731..64ae2e05b2ddb 100644 --- a/components/agiliron/actions/create-lead/create-lead.mjs +++ b/components/agiliron/actions/create-lead/create-lead.mjs @@ -1,11 +1,13 @@ +import { ConfigurationError } from "@pipedream/platform"; import agiliron from "../../agiliron.app.mjs"; -import { axios } from "@pipedream/platform"; +import constants from "../../common/constants.mjs"; +import { parseObject } from "../../common/utils.mjs"; export default { key: "agiliron-create-lead", name: "Create Lead", description: "Establishes a new lead within Agiliron. [See the documentation](https://api.agiliron.com/docs/add-lead-1)", - version: "0.0.{{ts}}", + version: "0.0.1", type: "action", props: { agiliron, @@ -16,194 +18,200 @@ export default { ], }, company: { + type: "string", + label: "Company", + description: "The company of the lead", + }, + salutation: { propDefinition: [ agiliron, - "company", + "salutation", ], - }, - salutation: { - type: "string", - label: "Salutation", - description: "The salutation of the contact or lead", optional: true, }, firstName: { - type: "string", - label: "First Name", - description: "The first name of the contact or lead", + propDefinition: [ + agiliron, + "firstName", + ], optional: true, }, designation: { type: "string", label: "Designation", - description: "The designation of the contact or lead", + description: "The designation of the lead", optional: true, }, phone: { type: "string", label: "Phone", - description: "The phone number of the contact or lead", + description: "The phone number of the lead", optional: true, }, mobile: { - type: "string", - label: "Mobile", - description: "The mobile number of the contact or lead", + propDefinition: [ + agiliron, + "mobile", + ], optional: true, }, fax: { - type: "string", - label: "Fax", - description: "The fax number of the contact or lead", + propDefinition: [ + agiliron, + "fax", + ], optional: true, }, email: { - type: "string", - label: "Email", - description: "The email address of the contact or lead", + propDefinition: [ + agiliron, + "email", + ], optional: true, }, website: { type: "string", label: "Website", - description: "The website of the contact or lead", + description: "The website of the lead. Without http:// or https://", optional: true, }, industry: { type: "string", label: "Industry", - description: "The industry of the contact or lead", + description: "The industry of the lead", + options: constants.INDUSTRY_OPTIONS, optional: true, }, sicCode: { type: "string", label: "SIC Code", - description: "The SIC code of the contact or lead", + description: "The SIC code of the lead", optional: true, }, annualRevenue: { type: "string", label: "Annual Revenue", - description: "The annual revenue of the contact or lead", + description: "The annual revenue of the lead. **(US Dollar : $)**", optional: true, }, numberOfEmployees: { type: "string", label: "Number of Employees", - description: "The number of employees of the contact or lead", + description: "The number of employees of the lead", optional: true, }, contactType: { - type: "string", - label: "Contact Type", - description: "The contact type of the contact or lead", + propDefinition: [ + agiliron, + "contactType", + ], optional: true, }, leadSource: { - type: "string", - label: "Lead Source", - description: "The lead source of the contact or lead", + propDefinition: [ + agiliron, + "leadSource", + ], optional: true, }, leadStatus: { type: "string", label: "Lead Status", - description: "The lead status of the contact or lead", + description: "The lead status of the lead", + options: constants.LEAD_STATUS_OPTIONS, optional: true, }, rating: { type: "string", label: "Rating", - description: "The rating of the contact or lead", + description: "The rating of the lead", + options: constants.RATING_OPTIONS, optional: true, }, emailOptOut: { - type: "string", - label: "Email Opt Out", - description: "The email opt-out status of the contact or lead", - optional: true, - }, - yahooID: { - type: "string", - label: "Yahoo ID", - description: "The Yahoo ID of the contact or lead", - optional: true, - }, - createdTime: { - type: "string", - label: "Created Time", - description: "The created time of the contact or lead (format: MM-DD-YYYY HH:MM:SS)", + propDefinition: [ + agiliron, + "emailOptOut", + ], optional: true, }, - modifiedTime: { - type: "string", - label: "Modified Time", - description: "The modified time of the contact or lead (format: MM-DD-YYYY HH:MM:SS)", + yahooId: { + propDefinition: [ + agiliron, + "yahooId", + ], optional: true, }, street: { type: "string", label: "Street", - description: "The street address of the contact or lead", + description: "The street address of the lead", optional: true, }, city: { type: "string", label: "City", - description: "The city of the contact or lead", + description: "The city of the lead", optional: true, }, state: { type: "string", label: "State", - description: "The state of the contact or lead", + description: "The state of the lead", optional: true, }, zip: { type: "string", label: "Zip", - description: "The zip code of the contact or lead", + description: "The zip code of the lead", optional: true, }, country: { type: "string", label: "Country", - description: "The country of the contact or lead", + description: "The country of the lead", optional: true, }, description: { - type: "string", - label: "Description", - description: "The description of the contact or lead", + propDefinition: [ + agiliron, + "description", + ], optional: true, }, assignedTo: { - type: "string", - label: "Assigned To", - description: "The user to whom the contact or lead is assigned", + propDefinition: [ + agiliron, + "assignedTo", + ], optional: true, }, assignedGroupName: { type: "string", label: "Assigned Group Name", description: "The group to which the contact or lead is assigned", + options: constants.ASSIGNED_TO_GROUP_OPTIONS, optional: true, }, - defaultCurrency: { - type: "string", - label: "Default Currency", - description: "The default currency of the contact or lead", - optional: true, - }, - leadCustomFields: { - type: "string[]", - label: "Lead Custom Fields", - description: "An array of custom fields for the lead", + customFields: { + propDefinition: [ + agiliron, + "customFields", + ], optional: true, }, }, async run({ $ }) { - const data = { + if (this.assignedTo && this.assignedGroupName) { + throw new ConfigurationError("You must provite either Assigned To or Assigned to Group Name"); + } + const parsedCustomFields = parseObject(this.customFields); + const leadCustomFields = parsedCustomFields && Object.keys(parsedCustomFields).map((key) => ({ + Name: key, + value: parsedCustomFields[key], + })); + + const lead = { Salutation: this.salutation, FirstName: this.firstName, LastName: this.lastname, @@ -223,9 +231,7 @@ export default { LeadStatus: this.leadStatus, Rating: this.rating, EmailOptOut: this.emailOptOut, - YahooID: this.yahooID, - CreatedTime: this.createdTime, - ModifiedTime: this.modifiedTime, + YahooID: this.yahooId, Street: this.street, City: this.city, State: this.state, @@ -234,14 +240,22 @@ export default { Description: this.description, AssignedTo: this.assignedTo, AssignedGroupName: this.assignedGroupName, - DefaultCurrency: this.defaultCurrency, - LeadCustomFields: this.leadCustomFields - ? this.leadCustomFields.map(JSON.parse) - : undefined, + DefaultCurrency: "USD", + LeadCustomFields: { + CustomField: leadCustomFields, + }, }; - const response = await this.agiliron.addLead(data); - $.export("$summary", `Successfully created lead with ID ${response.MCM.parameters.results.message.success_message.lead_id}`); + const response = await this.agiliron.addLead({ + $, + data: { + Leads: { + Lead: lead, + }, + }, + }); + + $.export("$summary", `Successfully created lead with ID ${response?.MCM?.parameters?.results?.message?.success_message?.lead_id}`); return response; }, }; diff --git a/components/agiliron/agiliron.app.mjs b/components/agiliron/agiliron.app.mjs index d3ea5ed3a3c39..1ca0154b7ee93 100644 --- a/components/agiliron/agiliron.app.mjs +++ b/components/agiliron/agiliron.app.mjs @@ -1,144 +1,203 @@ import { axios } from "@pipedream/platform"; +import constants from "./common/constants.mjs"; export default { type: "app", app: "agiliron", propDefinitions: { + contactName: { + type: "string", + label: "Contact Name", + description: "The name of the contact related to the event", + async options({ page }) { + const { Contacts: { Contact } } = await this.getContacts({ + params: { + filter: "CreatedTime,ge,01-01-1970", + page: page + 1, + }, + }); + + return Contact.map(({ + FirstName, LastName, + }) => `${FirstName} ${LastName}`); + }, + }, + firstName: { + type: "string", + label: "First Name", + description: "The first name of the lead", + }, lastname: { type: "string", label: "Last Name", - description: "The last name of the contact or lead", + description: "The last name of the lead.", + }, + salutation: { + type: "string", + label: "Salutation", + description: "The salutation of the lead", + options: constants.SALUTATION_OPTIONS, + }, + mobile: { + type: "string", + label: "Mobile", + description: "The mobile number of the lead", }, - company: { + fax: { type: "string", - label: "Company", - description: "The company of the lead", + label: "Fax", + description: "The fax number of the lead", }, - subject: { + email: { type: "string", - label: "Subject", - description: "The subject of the event", + label: "Email", + description: "The email address of the lead", }, - startdate: { + contactType: { type: "string", - label: "Start Date", - description: "The start date of the event (format: MM-DD-YYYY)", + label: "Contact Type", + description: "The contact type of the lead", + options: constants.CONTACT_TYPE_OPTIONS, }, - starttime: { + leadSource: { type: "string", - label: "Start Time", - description: "The start time of the event (format: HH:MM:SS)", + label: "Lead Source", + description: "The lead source of the lead", + options: constants.LEAD_SOURCE_OPTIONS, + }, + emailOptOut: { + type: "string", + label: "Email Opt Out", + description: "The email opt-out status of the lead", + options: constants.BOOL_OPTIONS, + }, + yahooId: { + type: "string", + label: "Yahoo ID", + description: "The Yahoo ID of the lead", + }, + description: { + type: "string", + label: "Description", + description: "The description of the lead", + }, + assignedTo: { + type: "string", + label: "Assigned To", + description: "The user to whom the lead is assigned", + options: constants.ASSIGNED_TO_OPTIONS, + }, + customFields: { + type: "object", + label: "Custom Fields", + description: "An object of custom fields for the lead. **Format: {customFieldName01: \"Value 01\"}**", }, }, methods: { _baseUrl() { - return `https://${this.$auth.company}.agiliron.net/agiliron/api-40.php`; - }, - async _makeRequest(opts = {}) { - const { - $ = this, - method = "GET", - path = "/", - headers, - ...otherOpts - } = opts; + return `https://${this.$auth.subdomain}.agiliron.net/agiliron/api-40`; + }, + _headers(headers) { + return { + ...headers, + Accept: "application/json", + apiKey: this.$auth.api_key, + }; + }, + _makeRequest({ + $ = this, path, headers, ...opts + }) { return axios($, { - ...otherOpts, - method, url: this._baseUrl() + path, - headers: { - ...headers, - Accept: "application/json", - apiKey: this.$auth.api_key, - }, + headers: this._headers(headers), + ...opts, }); }, - async addContact(data) { + addContact(opts = {}) { return this._makeRequest({ method: "POST", path: "/Contact", - data: { - Contacts: { - Contact: [ - data, - ], - }, - }, + ...opts, }); }, - async addLead(data) { + addLead(opts = {}) { return this._makeRequest({ method: "POST", path: "/Leads", - data: { - Leads: { - Lead: [ - data, - ], - }, - }, + ...opts, }); }, - async addEvent(data) { + addEvent(opts = {}) { return this._makeRequest({ method: "POST", path: "/Event", - data: { - Events: { - Event: [ - data, - ], - }, - }, + ...opts, }); }, - async getContacts(opts = {}) { + getContacts(opts = {}) { return this._makeRequest({ path: "/Contact", ...opts, }); }, - async getLeads(opts = {}) { + getLeads(opts = {}) { return this._makeRequest({ path: "/Leads", ...opts, }); }, - async getEvents(opts = {}) { + getTasks(opts = {}) { return this._makeRequest({ - path: "/Event", + path: "/Task", ...opts, }); }, - async emitNewContactEvents() { - const contacts = await this.getContacts(); - for (const contact of contacts.Contacts.Contact) { - this.$emit(contact, { - id: contact.ContactId, - summary: `New contact: ${contact.FirstName} ${contact.LastName}`, - ts: new Date(contact.CreatedTimeUTC).getTime(), - }); - } - }, - async emitNewLeadEvents() { - const leads = await this.getLeads(); - for (const lead of leads.Leads.Lead) { - this.$emit(lead, { - id: lead.LeadId, - summary: `New lead: ${lead.FirstName} ${lead.LastName}`, - ts: new Date(lead.CreatedTimeUTC).getTime(), - }); - } - }, - async emitNewTaskEvents() { - const tasks = await this.getEvents(); - for (const task of tasks.Events.Event) { - this.$emit(task, { - id: task.EventId, - summary: `New task: ${task.Subject}`, - ts: new Date(task.CreatedTimeUTC).getTime(), - }); - } + async prepareItems({ + type, page, + }) { + if (type === "Invoice" || type === "Potentials") return []; + + const parsedType = type.replace(/ +/g, ""); + const typeFields = constants.TYPE_FIELDS[parsedType]; + + const response = await this._makeRequest({ + path: `/${typeFields.path || parsedType}`, + params: { + filter: `${typeFields.filterField},ge,01-01-1970`, + page, + }, + }); + + const items = response[typeFields.item][typeFields.subItem]; + return items.map((item) => { + let nameString = ""; + typeFields.names.map((name) => {nameString += `${item[name]} `;}); + return nameString; + }); + }, + async *paginate({ + fn, params = {}, fields, + }) { + let hasMore = false; + let page = 0; + + do { + try { + params.page = ++page; + const response = await fn({ + params, + }); + const pagination = response[fields.item]; + const data = pagination[fields.subItem]; + for (const d of data) { + yield d; + } + + hasMore = !(pagination.CurrentPage === pagination.TotalPages); + } catch (e) { + return false; + } + } while (hasMore); }, }, }; diff --git a/components/agiliron/common/constants.mjs b/components/agiliron/common/constants.mjs new file mode 100644 index 0000000000000..2217f994be002 --- /dev/null +++ b/components/agiliron/common/constants.mjs @@ -0,0 +1,210 @@ +const SALUTATION_OPTIONS = [ + "--None--", + "Mr.", + "Ms.", + "Mrs.", + "Dr.", + "Prof.", +]; + +const INDUSTRY_OPTIONS = [ + "--None--", + "Apparel", + "Banking", + "Education", + "Electronics", + "Finance", + "Government", + "Healthcare", + "Hospitality", + "Insurance", + "Retail", + "Technology", + "Telecommunications", + "Utilities", + "Other", +]; + +const CONTACT_TYPE_OPTIONS = [ + "--None--", + "Analyst", + "Competitor", + "Customer", + "Integrator", + "Investor", + "Partner", + "Press", + "Prospect", + "Reseller", + "Other", + "Media", + "Suppliers", + "Customers", +]; + +const LEAD_SOURCE_OPTIONS = [ + "--None--", + "Cold Call", + "Existing Customer", + "Self Generated", + "Employee", + "Partner", + "Public Relations", + "Direct Mail", + "Conference", + "Trade Show", + "Web Site", + "Word of mouth", + "Other", +]; + +const LEAD_STATUS_OPTIONS = [ + "--None--", + "Attempted to Contact", + "Cold", + "Contact in Future", + "Contacted", + "Hot", + "Junk Lead", + "Lost Lead", + "Not Contacted", + "Pre Qualified", + "Qualified", + "Warm", +]; + +const RATING_OPTIONS = [ + "--None--", + "Acquired", + "Active", + "Market Failed", + "Project Cancelled", + "Shutdown", +]; + +const BOOL_OPTIONS = [ + "Yes", + "No", +]; + +const ASSIGNED_TO_OPTIONS = [ + "admin", + "posuser", +]; + +const ASSIGNED_TO_GROUP_OPTIONS = [ + "Administrator", + "Channel Management", + "Finance", + "Fulfillment", + "Management", + "Marketing", + "Product Management", + "Production", + "Purchasing", + "Retail Management", + "Retail Sales", + "Sales", + "Sales Reps", + "Support", + "Warehouse Management", +]; + +const RECURRING_EVENT_OPTIONS = [ + "--None--", + "Daily", + "Weekly", + "Monthly", + "Yearly", +]; + +const RELATED_TO_TYPE_OPTIONS = [ + "Leads", + "Accounts", + "Potentials", + "Quotes", + "Purchase Order", + "Sales Order", + "Invoice", +]; + +const STATUS_OPTIONS = [ + "Planned", + "Held", + "Not Held", +]; + +const ACTIVITY_TYPE_OPTIONS = [ + "Call", + "Meeting", +]; + +const TYPE_FIELDS = { + Leads: { + item: "Leads", + subItem: "Lead", + names: [ + "FirstName", + "LastName", + ], + filterField: "CreatedTime", + }, + Accounts: { + item: "Accounts", + subItem: "Account", + names: [ + "AccountName", + ], + filterField: "CreatedTime", + }, + Quotes: { + path: "Quote", + item: "Quotes", + subItem: "Quote", + names: [ + "Subject", + ], + filterField: "OrderDate", + }, + PurchaseOrder: { + item: "POOrders", + subItem: "Order", + names: [ + "Subject", + ], + filterField: "OrderDate", + }, + SalesOrder: { + item: "Orders", + subItem: "Order", + names: [ + "Subject", + ], + filterField: "OrderDate", + }, + Contacts: { + item: "Contacts", + subItem: "Contact", + }, + Tasks: { + item: "Tasks", + subItem: "Task", + }, +}; + +export default { + CONTACT_TYPE_OPTIONS, + INDUSTRY_OPTIONS, + LEAD_SOURCE_OPTIONS, + LEAD_STATUS_OPTIONS, + SALUTATION_OPTIONS, + RATING_OPTIONS, + BOOL_OPTIONS, + ASSIGNED_TO_OPTIONS, + ASSIGNED_TO_GROUP_OPTIONS, + RECURRING_EVENT_OPTIONS, + RELATED_TO_TYPE_OPTIONS, + STATUS_OPTIONS, + ACTIVITY_TYPE_OPTIONS, + TYPE_FIELDS, +}; diff --git a/components/agiliron/common/utils.mjs b/components/agiliron/common/utils.mjs new file mode 100644 index 0000000000000..dcc9cc61f6f41 --- /dev/null +++ b/components/agiliron/common/utils.mjs @@ -0,0 +1,24 @@ +export const parseObject = (obj) => { + if (!obj) return undefined; + + if (Array.isArray(obj)) { + return obj.map((item) => { + if (typeof item === "string") { + try { + return JSON.parse(item); + } catch (e) { + return item; + } + } + return item; + }); + } + if (typeof obj === "string") { + try { + return JSON.parse(obj); + } catch (e) { + return obj; + } + } + return obj; +}; diff --git a/components/agiliron/package.json b/components/agiliron/package.json index b061131d427c4..a9d5a7e44e1ed 100644 --- a/components/agiliron/package.json +++ b/components/agiliron/package.json @@ -1,6 +1,6 @@ { "name": "@pipedream/agiliron", - "version": "0.0.1", + "version": "0.1.0", "description": "Pipedream Agiliron Components", "main": "agiliron.app.mjs", "keywords": [ @@ -11,5 +11,8 @@ "author": "Pipedream (https://pipedream.com/)", "publishConfig": { "access": "public" + }, + "dependencies": { + "@pipedream/platform": "^3.0.1" } } diff --git a/components/agiliron/sources/common/base.mjs b/components/agiliron/sources/common/base.mjs new file mode 100644 index 0000000000000..d00f77a4305d1 --- /dev/null +++ b/components/agiliron/sources/common/base.mjs @@ -0,0 +1,67 @@ +import { DEFAULT_POLLING_SOURCE_TIMER_INTERVAL } from "@pipedream/platform"; +import agiliron from "../../agiliron.app.mjs"; + +export default { + props: { + agiliron, + db: "$.service.db", + timer: { + type: "$.interface.timer", + default: { + intervalSeconds: DEFAULT_POLLING_SOURCE_TIMER_INTERVAL, + }, + }, + }, + methods: { + _getLastDate() { + return this.db.get("lastDate") || "01-01-1970"; + }, + _setLastDate(lastDate) { + this.db.set("lastDate", lastDate); + }, + async emitEvent(maxResults = false) { + const lastDate = this._getLastDate(); + const fields = this.getFields(); + + const response = this.agiliron.paginate({ + fn: this.getFunction(), + params: { + filter: `CreatedTime,gt,${lastDate}`, + }, + fields, + }); + + let responseArray = []; + for await (const item of response) { + responseArray.push(item); + } + + responseArray = responseArray.sort( + (a, b) => (Date.parse(b[fields.date]) - Date.parse(a[fields.date])), + ); + + if (responseArray.length) { + if (maxResults && (responseArray.length > maxResults)) { + responseArray.length = maxResults; + } + this._setLastDate(responseArray[0][fields.date]); + } + + for (const item of responseArray.reverse()) { + this.$emit(item, { + id: item[fields.id], + summary: this.getSummary(item), + ts: Date.parse(item[fields.date]), + }); + } + }, + }, + hooks: { + async deploy() { + await this.emitEvent(25); + }, + }, + async run() { + await this.emitEvent(); + }, +}; diff --git a/components/agiliron/sources/new-contact-created/new-contact-created.mjs b/components/agiliron/sources/new-contact-created/new-contact-created.mjs index ab39b67897ceb..49dbbc0cdcf15 100644 --- a/components/agiliron/sources/new-contact-created/new-contact-created.mjs +++ b/components/agiliron/sources/new-contact-created/new-contact-created.mjs @@ -1,73 +1,30 @@ -import agiliron from "../../agiliron.app.mjs"; -import { axios } from "@pipedream/platform"; +import constants from "../../common/constants.mjs"; +import common from "../common/base.mjs"; +import sampleEmit from "./test-event.mjs"; export default { + ...common, key: "agiliron-new-contact-created", name: "New Contact Created", description: "Emit new event when a new contact is created in Agiliron. [See the documentation](https://api.agiliron.com/docs/read-contact-1)", - version: "0.0.{{ts}}", + version: "0.0.1", type: "source", dedupe: "unique", - props: { - agiliron, - db: "$.service.db", - timer: { - type: "$.interface.timer", - default: { - intervalSeconds: 60 * 15, // Poll every 15 minutes - }, - }, - }, methods: { - _getLastTimestamp() { - return this.db.get("lastTimestamp") || 0; + ...common.methods, + getFields() { + return { + date: "CreatedTime", + id: "ContactId", + ...constants.TYPE_FIELDS.Contacts, + }; }, - _setLastTimestamp(ts) { - this.db.set("lastTimestamp", ts); + getFunction() { + return this.agiliron.getContacts; }, - }, - hooks: { - async deploy() { - const contacts = await this.agiliron.getContacts(); - const lastTimestamp = this._getLastTimestamp(); - const newContacts = contacts.Contacts.Contact.filter((contact) => { - const contactTimestamp = new Date(contact.CreatedTimeUTC).getTime(); - return contactTimestamp > lastTimestamp; - }); - - newContacts.slice(0, 50).forEach((contact) => { - this.$emit(contact, { - id: contact.ContactId, - summary: `New contact: ${contact.FirstName} ${contact.LastName}`, - ts: new Date(contact.CreatedTimeUTC).getTime(), - }); - }); - - if (newContacts.length > 0) { - const latestTimestamp = newContacts[0].CreatedTimeUTC; - this._setLastTimestamp(new Date(latestTimestamp).getTime()); - } + getSummary(contact) { + return `New contact: ${contact.FirstName} ${contact.LastName}`; }, }, - async run() { - const lastTimestamp = this._getLastTimestamp(); - const contacts = await this.agiliron.getContacts({ - params: { - filter: `CreatedTimeUTC,gt,${new Date(lastTimestamp).toISOString()}`, - }, - }); - - for (const contact of contacts.Contacts.Contact) { - this.$emit(contact, { - id: contact.ContactId, - summary: `New contact: ${contact.FirstName} ${contact.LastName}`, - ts: new Date(contact.CreatedTimeUTC).getTime(), - }); - } - - if (contacts.Contacts.Contact.length > 0) { - const latestContact = contacts.Contacts.Contact[contacts.Contacts.Contact.length - 1]; - this._setLastTimestamp(new Date(latestContact.CreatedTimeUTC).getTime()); - } - }, + sampleEmit, }; diff --git a/components/agiliron/sources/new-contact-created/test-event.mjs b/components/agiliron/sources/new-contact-created/test-event.mjs new file mode 100644 index 0000000000000..067594ab87d9b --- /dev/null +++ b/components/agiliron/sources/new-contact-created/test-event.mjs @@ -0,0 +1,58 @@ +export default { + "ContactId": "123", + "Salutation": "--None--", + "FirstName": "Test", + "LastName": "New Contact", + "OfficePhone": "56412356", + "Mobile": "7412536589", + "HomePhone": "56412356", + "OtherPhone": "", + "Fax": "5689746", + "AccountName": "Account1", + "AccountID": "234", + "VendorName": "Vendor1", + "VendorID": "30", + "ContactType": "Competitor", + "Title": "Test Title", + "Department": "Test Department", + "Email": "abctest123@gmail.com", + "ReportsTo": "", + "ReportsToID": "", + "Assistant": "", + "YahooID": "abc@yahoo.com", + "AssistantPhone": "5989654", + "DoNotCall": "No", + "EmailOptOut": "No", + "AssignedToUser": "Administrator", + "LeadSource": "Self Generated", + "Birthday": "01-21-2020", + "ContactProfile": "Buyer", + "MailingStreet": "1515 Clay Street", + "MailingCity": "Oakland", + "MailingState": "CA", + "MailingZip": "94624", + "MailingCountry": "United States", + "OtherStreet": "1515 Clay Street", + "OtherCity": "Oakland", + "OtherState": "CA", + "OtherZip": "94624", + "OtherCountry": "United States", + "CreatedTime": "01-24-2020 05:32:01", + "CreatedTimeUTC": "01-24-2020 15:01:35", + "ModifiedTime": "01-24-2020 05:32:01", + "ModifiedTimeUTC": "01-24-2020 15:05:56", + "Description": "The Description Goes here.", + "B2BCustomer": "Yes", + "B2BChannels": "Ebay", + "CustomFields": { + "CustomField": [{ + "Name": "CustomFied1", + "Value": "Custom info 1" + }, + { + "Name": "CustomFied2", + "Value": "Custom info 2" + } + ] + } +} \ No newline at end of file diff --git a/components/agiliron/sources/new-lead-created/new-lead-created.mjs b/components/agiliron/sources/new-lead-created/new-lead-created.mjs index e440ad8249f74..0a36a74963332 100644 --- a/components/agiliron/sources/new-lead-created/new-lead-created.mjs +++ b/components/agiliron/sources/new-lead-created/new-lead-created.mjs @@ -1,64 +1,30 @@ -import { axios } from "@pipedream/platform"; -import agiliron from "../../agiliron.app.mjs"; +import constants from "../../common/constants.mjs"; +import common from "../common/base.mjs"; +import sampleEmit from "./test-event.mjs"; export default { + ...common, key: "agiliron-new-lead-created", name: "New Lead Created", - description: "Emit new event when a new lead is created in Agiliron. [See the documentation](https://api.agiliron.com/reference/add-lead)", + description: "Emit new event when a new lead is created in Agiliron.", version: "0.0.1", type: "source", dedupe: "unique", - props: { - agiliron, - db: "$.service.db", - timer: { - type: "$.interface.timer", - default: { - intervalSeconds: 60 * 15, // Poll every 15 minutes - }, - }, - }, - hooks: { - async deploy() { - await this.emitNewLeadEvents(); - }, - async activate() { - // No webhook support, rely on polling - }, - async deactivate() { - // No webhook support, nothing to clean up - }, - }, methods: { - _getLastTimestamp() { - return this.db.get("lastTimestamp") || 0; + ...common.methods, + getFields() { + return { + date: "CreatedTime", + id: "LeadId", + ...constants.TYPE_FIELDS.Leads, + }; }, - _setLastTimestamp(ts) { - this.db.set("lastTimestamp", ts); + getFunction() { + return this.agiliron.getLeads; }, - async emitNewLeadEvents() { - const leads = await this.agiliron.getLeads({ - params: { - filter: `CreatedTimeUTC,gt,${this._getLastTimestamp()}`, - pageSize: 50, - }, - }); - - for (const lead of leads.Leads.Lead) { - this.$emit(lead, { - id: lead.LeadId, - summary: `New lead: ${lead.FirstName} ${lead.LastName}`, - ts: new Date(lead.CreatedTimeUTC).getTime(), - }); - } - - if (leads.Leads.Lead.length > 0) { - const lastLead = leads.Leads.Lead[leads.Leads.Lead.length - 1]; - this._setLastTimestamp(new Date(lastLead.CreatedTimeUTC).getTime()); - } + getSummary(lead) { + return `New lead: ${lead.FirstName} ${lead.LastName}`; }, }, - async run() { - await this.emitNewLeadEvents(); - }, + sampleEmit, }; diff --git a/components/agiliron/sources/new-lead-created/test-event.mjs b/components/agiliron/sources/new-lead-created/test-event.mjs new file mode 100644 index 0000000000000..c2141ab665aef --- /dev/null +++ b/components/agiliron/sources/new-lead-created/test-event.mjs @@ -0,0 +1,48 @@ +export default { + "LeadId": "123", + "Salutation": "--None--", + "FirstName": "Test", + "LastName": "New Lead", + "Company": "Test Company", + "Designation": "Test Title", + "Phone": "56412356", + "Mobile": "7412536589", + "Fax": "5689746", + "Email": "abctest123@gmail.com", + "Website": "", + "Industry": "Recreation", + "SICCode": "10", + "AnnualRevenue": "65", + "NumberOfEmployees": "25", + "ContactType": "Customer", + "LeadSource": "Self Generated", + "LeadStatus": "Contacted", + "Rating": "Acquired", + "EmailOptOut": "No", + "YahooID": "abc@yahoo.com", + "CreatedTime": "01-24-2020 05:01:35", + "CreatedTimeUTC": "01-24-2020 15:01:35", + "ModifiedTime": "01-24-2020 05:05:56", + "ModifiedTimeUTC": "01-24-2020 15:05:56", + "Street": "1515 Clay Street", + "City": "Oakland", + "State": "CA", + "Zip": "94624", + "Country": "United States", + "Description": "The Description Goes here.", + "AssignedTo": "admin", + "AssignedGroupName": "", + "DefaultCurrency": "USD", + "LeadCustomFields": { + "CustomField": [ + { + "Name": "CustomFied1", + "Value": "Custom info 1" + }, + { + "Name": "CustomFied2", + "Value": "Custom info 2" + } + ] + } +} \ No newline at end of file diff --git a/components/agiliron/sources/new-task-created/new-task-created.mjs b/components/agiliron/sources/new-task-created/new-task-created.mjs index 2b5dfba7982e7..b9d517fa579fd 100644 --- a/components/agiliron/sources/new-task-created/new-task-created.mjs +++ b/components/agiliron/sources/new-task-created/new-task-created.mjs @@ -1,45 +1,30 @@ -import agiliron from "../../agiliron.app.mjs"; -import { axios } from "@pipedream/platform"; +import constants from "../../common/constants.mjs"; +import common from "../common/base.mjs"; +import sampleEmit from "./test-event.mjs"; export default { + ...common, key: "agiliron-new-task-created", name: "New Task Created", - description: "Emit new event when a new task is created in Agiliron. [See the documentation](https://learn.agiliron.com/docs/getting-started)", - version: "0.0.{{ts}}", + description: "Emit new event when a new task is created in Agiliron.", + version: "0.0.1", type: "source", dedupe: "unique", - props: { - agiliron, - db: "$.service.db", - timer: { - type: "$.interface.timer", - default: { - intervalSeconds: 60, - }, + methods: { + ...common.methods, + getFields() { + return { + date: "CreatedTime", + id: "TaskId", + ...constants.TYPE_FIELDS.Tasks, + }; }, - }, - hooks: { - async deploy() { - const tasks = await this.agiliron.getEvents(); - for (const task of tasks.Events.Event.slice(-50)) { - this.$emit(task, { - id: task.EventId, - summary: `New task: ${task.Subject}`, - ts: new Date(task.CreatedTimeUTC).getTime(), - }); - } + getFunction() { + return this.agiliron.getTasks; + }, + getSummary(task) { + return `New task: ${task.Subject}`; }, - async activate() {}, - async deactivate() {}, - }, - async run() { - const tasks = await this.agiliron.getEvents(); - for (const task of tasks.Events.Event) { - this.$emit(task, { - id: task.EventId, - summary: `New task: ${task.Subject}`, - ts: new Date(task.CreatedTimeUTC).getTime(), - }); - } }, + sampleEmit, }; diff --git a/components/agiliron/sources/new-task-created/test-event.mjs b/components/agiliron/sources/new-task-created/test-event.mjs new file mode 100644 index 0000000000000..01f47d943b0fa --- /dev/null +++ b/components/agiliron/sources/new-task-created/test-event.mjs @@ -0,0 +1,32 @@ +export default { + "TaskId": "3422", + "Subject": "Test New Task", + "StartDate": "01-24-2020", + "StartTime": "05:47:00", + "DueDate": "01-25-2020", + "AccountName": "Account1", + "ContactName": "Contact1", + "RelatedToType": "Accounts", + "RelatedToValue": "Account1", + "Status": "In Progress", + "SendNotification": "No", + "ActivityType": "Task", + "Priority": "High", + "CreatedTime": "01-24-2020 05:51:01", + "CreatedTimeUTC": "01-24-2020 15:01:35", + "ModifiedTime": "01-24-2020 05:53:00", + "ModifiedTimeUTC": "01-24-2020 15:05:56", + "Description": "The Description Goes here.", + "TaskCustomFields": { + "CustomField": [ + { + "Name": "CustomFied1", + "Value": "Custom info 1" + }, + { + "Name": "CustomFied2", + "Value": "Custom info 2" + } + ] + } +} \ No newline at end of file From 1843e69928be905a5deffd61edddc1d1056a2cd0 Mon Sep 17 00:00:00 2001 From: Luan Cazarine Date: Wed, 11 Sep 2024 09:34:02 -0300 Subject: [PATCH 3/3] pnpm update --- pnpm-lock.yaml | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 8917112461412..5c37172bc448a 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -307,7 +307,10 @@ importers: '@pipedream/platform': 1.6.0 components/agiliron: - specifiers: {} + specifiers: + '@pipedream/platform': ^3.0.1 + dependencies: + '@pipedream/platform': 3.0.1 components/agility_cms: specifiers: {}