diff --git a/components/offorte/actions/create-contact-organisation/create-contact-organisation.mjs b/components/offorte/actions/create-contact-organisation/create-contact-organisation.mjs new file mode 100644 index 0000000000000..6ca9d668cd167 --- /dev/null +++ b/components/offorte/actions/create-contact-organisation/create-contact-organisation.mjs @@ -0,0 +1,150 @@ +import { parseObject } from "../../common/utils.mjs"; +import offorte from "../../offorte.app.mjs"; + +export default { + key: "offorte-create-contact-organisation", + name: "Create Contact Organisation", + description: "Create a new contact organisation in Offorte. [See the documentation](https://www.offorte.com/api-docs/api#tag/Contacts/operation/createContactOrganisation)", + version: "0.0.1", + type: "action", + props: { + offorte, + name: { + propDefinition: [ + offorte, + "name", + ], + }, + street: { + propDefinition: [ + offorte, + "street", + ], + }, + zipcode: { + propDefinition: [ + offorte, + "zipcode", + ], + }, + city: { + propDefinition: [ + offorte, + "city", + ], + }, + state: { + propDefinition: [ + offorte, + "state", + ], + }, + country: { + propDefinition: [ + offorte, + "country", + ], + }, + phone: { + propDefinition: [ + offorte, + "phone", + ], + }, + fax: { + type: "string", + label: "Fax", + description: "The fax number of the contact", + optional: true, + }, + email: { + propDefinition: [ + offorte, + "email", + ], + optional: true, + }, + internet: { + propDefinition: [ + offorte, + "internet", + ], + optional: true, + }, + linkedin: { + propDefinition: [ + offorte, + "linkedin", + ], + optional: true, + }, + facebook: { + propDefinition: [ + offorte, + "facebook", + ], + optional: true, + }, + twitter: { + propDefinition: [ + offorte, + "twitter", + ], + optional: true, + }, + instagram: { + propDefinition: [ + offorte, + "instagram", + ], + optional: true, + }, + coc_number: { + type: "string", + label: "COC Number", + description: "The COC number of the contact", + optional: true, + }, + vat_number: { + type: "string", + label: "VAT Number", + description: "The VAT number of the contact", + optional: true, + }, + tags: { + propDefinition: [ + offorte, + "tags", + ], + optional: true, + }, + }, + async run({ $ }) { + const response = await this.offorte.createContactOrganisation({ + $, + data: { + name: this.name, + type: "organisation", + street: this.street, + zipcode: this.zipcode, + city: this.city, + state: this.state, + country: this.country, + phone: this.phone, + fax: this.fax, + email: this.email, + internet: this.internet, + linkedin: this.linkedin, + facebook: this.facebook, + twitter: this.twitter, + instagram: this.instagram, + coc_number: this.coc_number, + vat_number: this.vat_number, + tags: parseObject(this.tags), + }, + }); + + $.export("$summary", "Contact organisation created successfully"); + return response.data; + }, +}; diff --git a/components/offorte/actions/create-contact-person/create-contact-person.mjs b/components/offorte/actions/create-contact-person/create-contact-person.mjs new file mode 100644 index 0000000000000..ce6c7df451a5a --- /dev/null +++ b/components/offorte/actions/create-contact-person/create-contact-person.mjs @@ -0,0 +1,160 @@ +import { parseObject } from "../../common/utils.mjs"; +import offorte from "../../offorte.app.mjs"; + +export default { + key: "offorte-create-contact-person", + name: "Create Contact Person", + description: "Create a new contact person in Offorte. [See the documentation](https://www.offorte.com/api-docs/api#tag/Contacts/operation/createContactPerson)", + version: "0.0.1", + type: "action", + props: { + offorte, + organisationId: { + propDefinition: [ + offorte, + "organisationId", + ], + }, + fullname: { + propDefinition: [ + offorte, + "name", + ], + }, + firstname: { + type: "string", + label: "First Name", + description: "The first name of the contact", + optional: true, + }, + lastname: { + type: "string", + label: "Last Name", + description: "The last name of the contact", + optional: true, + }, + salutation: { + type: "string", + label: "Salutation", + description: "The salutation of the contact", + optional: true, + }, + street: { + propDefinition: [ + offorte, + "street", + ], + optional: true, + }, + zipcode: { + propDefinition: [ + offorte, + "zipcode", + ], + optional: true, + }, + city: { + propDefinition: [ + offorte, + "city", + ], + optional: true, + }, + state: { + propDefinition: [ + offorte, + "state", + ], + optional: true, + }, + country: { + propDefinition: [ + offorte, + "country", + ], + optional: true, + }, + phone: { + propDefinition: [ + offorte, + "phone", + ], + optional: true, + }, + mobile: { + type: "string", + label: "Mobile", + description: "The mobile number of the contact", + optional: true, + }, + email: { + propDefinition: [ + offorte, + "email", + ], + optional: true, + }, + internet: { + propDefinition: [ + offorte, + "internet", + ], + optional: true, + }, + linkedin: { + propDefinition: [ + offorte, + "linkedin", + ], + optional: true, + }, + facebook: { + propDefinition: [ + offorte, + "facebook", + ], + optional: true, + }, + twitter: { + propDefinition: [ + offorte, + "twitter", + ], + optional: true, + }, + instagram: { + propDefinition: [ + offorte, + "instagram", + ], + optional: true, + }, + tags: { + propDefinition: [ + offorte, + "tags", + ], + optional: true, + }, + }, + async run({ $ }) { + const { + offorte, + organisationId, + tags, + ...data + } = this; + + const response = await offorte.createContactPerson({ + $, + organisationId, + data: { + ...data, + tags: parseObject(tags), + }, + }); + + $.export("$summary", "Contact person created successfully"); + return response.data; + }, +}; diff --git a/components/offorte/actions/create-proposal/create-proposal.mjs b/components/offorte/actions/create-proposal/create-proposal.mjs new file mode 100644 index 0000000000000..5a0639695516c --- /dev/null +++ b/components/offorte/actions/create-proposal/create-proposal.mjs @@ -0,0 +1,114 @@ +import { STATUS_OPTIONS } from "../../common/constants.mjs"; +import { + clearObject, parseObject, +} from "../../common/utils.mjs"; +import offorte from "../../offorte.app.mjs"; + +export default { + key: "offorte-create-proposal", + name: "Create Proposal", + description: "Create a new proposal in Offorte. [See the documentation](https://www.offorte.com/api-docs/api#tag/Proposals/operation/createProposal)", + version: "0.0.1", + type: "action", + props: { + offorte, + accountUserId: { + propDefinition: [ + offorte, + "userId", + ], + label: "Account User ID", + optional: true, + }, + contactPeople: { + propDefinition: [ + offorte, + "contactId", + ], + optional: true, + type: "string[]", + label: "Contact People IDs", + description: "List with people who are going to receive the proposal. These are the contacts belonging to an organisation who are going to receive the proposal. Make sure they got an email filled in.", + }, + contactId: { + propDefinition: [ + offorte, + "contactId", + () => ({ + fieldId: "contact_id", + }), + ], + description: "The proposal is assigned to this main contact id", + }, + proposalTemplateId: { + propDefinition: [ + offorte, + "proposalTemplateId", + ], + }, + designTemplateId: { + propDefinition: [ + offorte, + "designTemplateId", + ], + }, + name: { + type: "string", + label: "Name", + description: "The name of the proposal", + optional: true, + }, + priceTotal: { + type: "string", + label: "Price Total", + description: "Proposal value as calculated by pricetables", + optional: true, + }, + status: { + type: "string", + label: "Status", + description: "The status of the proposal", + options: STATUS_OPTIONS, + }, + textTemplateId: { + propDefinition: [ + offorte, + "textTemplateId", + ], + }, + content: { + type: "string[]", + label: "Content", + description: "A list of content items of the proposal. [See the documentation](https://www.offorte.com/api-docs/api#tag/Proposals/operation/createProposal)", + optional: true, + }, + tags: { + propDefinition: [ + offorte, + "tags", + ], + optional: true, + }, + }, + async run({ $ }) { + const response = await this.offorte.createProposal({ + $, + data: clearObject({ + account_user_id: this.accountUserId, + contact_people: parseObject(this.contactPeople), + contact_id: this.contactId, + proposal_template_id: this.proposalTemplateId, + design_template_id: this.designTemplateId, + name: this.name, + price_total: this.priceTotal && parseFloat(this.priceTotal), + status: this.status, + text_template_id: this.textTemplateId, + content: parseObject(this.content), + tags: parseObject(this.tags), + }), + }); + + $.export("$summary", `Created proposal with ID: ${response.id}`); + return response; + }, +}; diff --git a/components/offorte/actions/get-contact-details/get-contact-details.mjs b/components/offorte/actions/get-contact-details/get-contact-details.mjs new file mode 100644 index 0000000000000..4ea88984d5b42 --- /dev/null +++ b/components/offorte/actions/get-contact-details/get-contact-details.mjs @@ -0,0 +1,30 @@ +import offorte from "../../offorte.app.mjs"; + +export default { + key: "offorte-get-contact-details", + name: "Get Contact Details", + description: "Get the details of a contact in Offorte. [See the documentation](https://www.offorte.com/api-docs/api#tag/Contacts/operation/contactDetails)", + version: "0.0.1", + type: "action", + props: { + offorte, + contactId: { + propDefinition: [ + offorte, + "contactId", + () => ({ + fieldId: "contact_id", + }), + ], + }, + }, + async run({ $ }) { + const response = await this.offorte.getContactDetails({ + $, + contactId: this.contactId, + }); + + $.export("$summary", `Fetched contact details for ${this.contactId}`); + return response; + }, +}; diff --git a/components/offorte/actions/list-proposal-templates/list-proposal-templates.mjs b/components/offorte/actions/list-proposal-templates/list-proposal-templates.mjs new file mode 100644 index 0000000000000..4334e55d67e29 --- /dev/null +++ b/components/offorte/actions/list-proposal-templates/list-proposal-templates.mjs @@ -0,0 +1,20 @@ +import offorte from "../../offorte.app.mjs"; + +export default { + key: "offorte-list-proposal-templates", + name: "List Proposal Templates", + description: "List all proposal templates in Offorte. [See the documentation](https://www.offorte.com/api-docs/api#tag/Proposals/operation/favoriteTemplatesList)", + version: "0.0.1", + type: "action", + props: { + offorte, + }, + async run({ $ }) { + const response = await this.offorte.listProposalTemplates({ + $, + }); + + $.export("$summary", `Successfully fetched ${response.length} proposal templates`); + return response; + }, +}; diff --git a/components/offorte/actions/list-proposals/list-proposals.mjs b/components/offorte/actions/list-proposals/list-proposals.mjs new file mode 100644 index 0000000000000..c80b67160c4e9 --- /dev/null +++ b/components/offorte/actions/list-proposals/list-proposals.mjs @@ -0,0 +1,28 @@ +import { STATUS_OPTIONS } from "../../common/constants.mjs"; +import offorte from "../../offorte.app.mjs"; + +export default { + key: "offorte-list-proposals", + name: "List Proposals", + description: "List all proposals in Offorte. [See the documentation](https://www.offorte.com/api-docs/api#tag/Proposals/operation/proposalsList)", + version: "0.0.1", + type: "action", + props: { + offorte, + status: { + type: "string", + label: "Status", + description: "The status of the proposals to list", + options: STATUS_OPTIONS, + }, + }, + async run({ $ }) { + const response = await this.offorte.listProposals({ + $, + status: this.status, + }); + + $.export("$summary", `Successfully fetched ${response.length} proposals`); + return response; + }, +}; diff --git a/components/offorte/actions/list-users/list-users.mjs b/components/offorte/actions/list-users/list-users.mjs new file mode 100644 index 0000000000000..32e66242b3e3c --- /dev/null +++ b/components/offorte/actions/list-users/list-users.mjs @@ -0,0 +1,20 @@ +import offorte from "../../offorte.app.mjs"; + +export default { + key: "offorte-list-users", + name: "List Users", + description: "List all users in Offorte. [See the documentation](https://www.offorte.com/api-docs/api#tag/Account/operation/usersList)", + version: "0.0.1", + type: "action", + props: { + offorte, + }, + async run({ $ }) { + const response = await this.offorte.listUsers({ + $, + }); + + $.export("$summary", `Successfully fetched ${response.length} users`); + return response; + }, +}; diff --git a/components/offorte/actions/search-contact-organisation/search-contact-organisation.mjs b/components/offorte/actions/search-contact-organisation/search-contact-organisation.mjs new file mode 100644 index 0000000000000..c59d6d11466d1 --- /dev/null +++ b/components/offorte/actions/search-contact-organisation/search-contact-organisation.mjs @@ -0,0 +1,28 @@ +import offorte from "../../offorte.app.mjs"; + +export default { + key: "offorte-search-contact-organisation", + name: "Search Contact Organisation", + description: "Search for a contact organisation in Offorte. [See the documentation](https://www.offorte.com/api-docs/api#tag/Contacts/operation/contactsOrganisationsList)", + version: "0.0.1", + type: "action", + props: { + offorte, + query: { + type: "string", + label: "Query", + description: "The query to search by name or email", + }, + }, + async run({ $ }) { + const response = await this.offorte.listOrganisations({ + $, + params: { + query: this.query, + }, + }); + + $.export("$summary", `Successfully found ${response.length} contact(s)`); + return response; + }, +}; diff --git a/components/offorte/actions/search-contact-people/search-contact-people.mjs b/components/offorte/actions/search-contact-people/search-contact-people.mjs new file mode 100644 index 0000000000000..b4b29acd002f1 --- /dev/null +++ b/components/offorte/actions/search-contact-people/search-contact-people.mjs @@ -0,0 +1,28 @@ +import offorte from "../../offorte.app.mjs"; + +export default { + key: "offorte-search-contact-people", + name: "Search Contact People", + description: "Search for a contact person in Offorte. [See the documentation](https://www.offorte.com/api-docs/api#tag/Contacts/operation/contactsPeopleList)", + version: "0.0.1", + type: "action", + props: { + offorte, + query: { + type: "string", + label: "Query", + description: "The query to search by name or email", + }, + }, + async run({ $ }) { + const response = await this.offorte.listContacts({ + $, + params: { + query: this.query, + }, + }); + + $.export("$summary", `Successfully found ${response.length} contact(s)`); + return response; + }, +}; diff --git a/components/offorte/actions/send-proposal/send-proposal.mjs b/components/offorte/actions/send-proposal/send-proposal.mjs new file mode 100644 index 0000000000000..a8dace9962996 --- /dev/null +++ b/components/offorte/actions/send-proposal/send-proposal.mjs @@ -0,0 +1,77 @@ +import { ConfigurationError } from "@pipedream/platform"; +import { + SEND_METHOD_OPTIONS, + STATUS_OPTIONS, +} from "../../common/constants.mjs"; +import offorte from "../../offorte.app.mjs"; + +export default { + key: "offorte-send-proposal", + name: "Send Proposal", + description: "Send a proposal in Offorte. [See the documentation](https://www.offorte.com/api-docs/api#tag/Proposals/operation/sendProposal)", + version: "0.0.1", + type: "action", + props: { + offorte, + status: { + type: "string", + label: "Status", + description: "The status of the proposal", + options: STATUS_OPTIONS, + }, + proposalId: { + propDefinition: [ + offorte, + "proposalId", + ({ status }) => ({ + status, + }), + ], + }, + passwordReset: { + type: "boolean", + label: "Password Reset", + description: "Reset the existing passwords when proposal was send before", + optional: true, + }, + sendMethod: { + type: "string", + label: "Send Method", + description: "Choose if you want to send it through Offorte or send the proposal your self", + optional: true, + options: SEND_METHOD_OPTIONS, + }, + sendMessage: { + type: "string", + label: "Send Message", + description: "The actual message you want to send in plain text", + optional: true, + }, + sendMessageId: { + propDefinition: [ + offorte, + "emailTemplateId", + ], + optional: true, + }, + }, + async run({ $ }) { + if (!this.sendMessageId && !this.sendMessage) { + throw new ConfigurationError("Either `Send Message Id` or `Send Message` must be provided"); + } + + const response = await this.offorte.sendProposal({ + $, + proposalId: this.proposalId, + data: { + password_reset: this.passwordReset, + send_method: this.sendMethod, + send_message: this.sendMessage, + send_message_id: this.sendMessageId, + }, + }); + + $.export("$summary", `Successfully sent proposal with ID: ${this.proposalId}`); + return response; + }, +}; diff --git a/components/offorte/common/constants.mjs b/components/offorte/common/constants.mjs new file mode 100644 index 0000000000000..916918a30df4e --- /dev/null +++ b/components/offorte/common/constants.mjs @@ -0,0 +1,116 @@ +export const STATUS_OPTIONS = [ + { + label: "Edit", + value: "edit", + }, + { + label: "Open", + value: "open", + }, + { + label: "Won", + value: "won", + }, + { + label: "Lost", + value: "lost", + }, + { + label: "Closed", + value: "closed", + }, +]; + +export const SEND_METHOD_OPTIONS = [ + { + label: "Offorte", + value: "offorte", + }, + { + label: "Self", + value: "self", + }, +]; + +export const EVENTS_OPTIONS = [ + { + label: "Contact Created", + value: "contact_created", + }, + { + label: "Contact Updated", + value: "contact_updated", + }, + { + label: "Contact Deleted", + value: "contact_deleted", + }, + { + label: "Contact Person Created", + value: "contact_person_created", + }, + { + label: "Contact Person Updated", + value: "contact_person_updated", + }, + { + label: "Contact Person Deleted", + value: "contact_person_deleted", + }, + { + label: "Proposal Created", + value: "proposal_created", + }, + { + label: "Proposal Details Updated", + value: "proposal_details_updated", + }, + { + label: "Proposal Deleted", + value: "proposal_deleted", + }, + { + label: "Proposal Send", + value: "proposal_send", + }, + { + label: "Proposal Won", + value: "proposal_won", + }, + { + label: "Proposal Lost", + value: "proposal_lost", + }, + { + label: "Proposal Viewed", + value: "proposal_viewed", + }, + { + label: "Proposal Comment Received", + value: "proposal_comment_received", + }, + { + label: "Product Directory Created", + value: "product_directory_created", + }, + { + label: "Product Directory Updated", + value: "product_directory_updated", + }, + { + label: "Product Directory Deleted", + value: "product_directory_deleted", + }, + { + label: "Product Created", + value: "product_created", + }, + { + label: "Product Updated", + value: "product_updated", + }, + { + label: "Product Deleted", + value: "product_deleted", + }, +]; diff --git a/components/offorte/common/utils.mjs b/components/offorte/common/utils.mjs new file mode 100644 index 0000000000000..8640e50d22a51 --- /dev/null +++ b/components/offorte/common/utils.mjs @@ -0,0 +1,46 @@ +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; +}; + +export const clearObject = (obj) => { + return Object.entries(obj) + .filter(([ + _, + v, + ]) => (v != null && v != "" && _ != undefined)) + .reduce((acc, [ + k, + v, + ]) => ({ + ...acc, + [k]: (!Array.isArray(v) && v === Object(v)) + ? clearObject(v) + : v, + }), {}); +}; + +export const snakeCaseToTitleCase = (s) => + s.replace(/^_*(.)|_+(.)/g, (s, c, d) => c + ? c.toUpperCase() + : " " + d.toUpperCase()); diff --git a/components/offorte/offorte.app.mjs b/components/offorte/offorte.app.mjs index 20108dc5a0b94..e1e01191d8771 100644 --- a/components/offorte/offorte.app.mjs +++ b/components/offorte/offorte.app.mjs @@ -1,11 +1,322 @@ +import { axios } from "@pipedream/platform"; + export default { type: "app", app: "offorte", - propDefinitions: {}, + propDefinitions: { + contactId: { + type: "string", + label: "Contact ID", + description: "The ID of the contact", + async options({ fieldId = "id" }) { + const response = await this.listContacts(); + return response.map((item) => ({ + label: `${item.fullname || item.email}`, + value: item[fieldId], + })); + }, + }, + organisationId: { + type: "string", + label: "Organisation ID", + description: "The ID of the organisation", + async options() { + const response = await this.listOrganisations(); + return response.map(({ + id: value, name: label, + }) => ({ + label, + value, + })); + }, + }, + tags: { + type: "string[]", + label: "Tags", + description: "The tags of the contact", + async options() { + const response = await this.listTags(); + return response.map(({ name }) => name); + }, + }, + userId: { + type: "string", + label: "User ID", + description: "The ID of the user", + async options() { + const response = await this.listUsers(); + return response.map(({ + id: value, email: label, + }) => ({ + label, + value, + })); + }, + }, + proposalTemplateId: { + type: "string", + label: "Proposal Template ID", + description: "The ID of the proposal template", + async options() { + const response = await this.listProposalTemplates(); + return response.map(({ + id: value, name: label, + }) => ({ + label, + value, + })); + }, + }, + designTemplateId: { + type: "string", + label: "Design Template ID", + description: "The ID of the design template", + async options() { + const response = await this.listDesignTemplates(); + return response.map(({ + id: value, name: label, + }) => ({ + label, + value, + })); + }, + }, + textTemplateId: { + type: "string", + label: "Text Template ID", + description: "The ID of the text template", + async options() { + const response = await this.listTextTemplates(); + return response.map(({ + id: value, name: label, + }) => ({ + label, + value, + })); + }, + }, + proposalId: { + type: "string", + label: "Proposal ID", + description: "The ID of the proposal", + async options({ status }) { + const response = await this.listProposals({ + status, + }); + return response.map(({ + id: value, name: label, + }) => ({ + label, + value, + })); + }, + }, + emailTemplateId: { + type: "string", + label: "Email Template ID", + description: "The ID of the email template", + async options() { + const response = await this.listEmailTemplates(); + return response.map(({ + id: value, name: label, + }) => ({ + label, + value, + })); + }, + }, + name: { + type: "string", + label: "Name", + description: "The name of the contact", + }, + street: { + type: "string", + label: "Street", + description: "The street of the contact", + }, + zipcode: { + type: "string", + label: "Zipcode", + description: "The zipcode of the contact", + }, + city: { + type: "string", + label: "City", + description: "The city of the contact", + }, + state: { + type: "string", + label: "State", + description: "The state of the contact", + }, + country: { + type: "string", + label: "Country", + description: "The country of the contact", + }, + phone: { + type: "string", + label: "Phone", + description: "The phone of the contact", + }, + email: { + type: "string", + label: "Email", + description: "The email address of the contact", + }, + internet: { + type: "string", + label: "Internet", + description: "The internet address of the contact", + }, + linkedin: { + type: "string", + label: "LinkedIn", + description: "The LinkedIn address of the contact", + }, + facebook: { + type: "string", + label: "Facebook", + description: "The Facebook address of the contact", + }, + twitter: { + type: "string", + label: "Twitter", + description: "The Twitter address of the contact", + }, + instagram: { + type: "string", + label: "Instagram", + description: "The Instagram address of the contact", + }, + }, methods: { - // this.$auth contains connected account data - authKeys() { - console.log(Object.keys(this.$auth)); + _headers() { + return { + "authorization": `${this.$auth.api_key}`, + }; + }, + _baseUrl() { + return `https://connect.offorte.com/api/v2/${this.$auth.account_name}`; + }, + _makeRequest({ + $ = this, path, ...opts + }) { + return axios($, { + url: this._baseUrl() + path, + headers: this._headers(), + ...opts, + }); + }, + listUsers(opts = {}) { + return this._makeRequest({ + path: "/account/users", + ...opts, + }); + }, + createContactOrganisation(opts = {}) { + return this._makeRequest({ + method: "POST", + path: "/contacts", + ...opts, + }); + }, + createContactPerson({ + organisationId, ...opts + }) { + return this._makeRequest({ + method: "POST", + path: `/contacts/${organisationId}/people`, + ...opts, + }); + }, + listTags(opts = {}) { + return this._makeRequest({ + path: "/settings/tags", + ...opts, + }); + }, + listOrganisations(opts = {}) { + return this._makeRequest({ + path: "/contacts/organisations", + ...opts, + }); + }, + listContacts(opts = {}) { + return this._makeRequest({ + path: "/contacts/people", + ...opts, + }); + }, + getContactDetails({ + contactId, ...opts + }) { + return this._makeRequest({ + path: `/contacts/${contactId}`, + ...opts, + }); + }, + createProposal(opts = {}) { + return this._makeRequest({ + method: "POST", + path: "/proposals", + ...opts, + }); + }, + listDesignTemplates(opts = {}) { + return this._makeRequest({ + path: "/settings/design-templates", + ...opts, + }); + }, + listTextTemplates(opts = {}) { + return this._makeRequest({ + path: "/settings/text-templates", + ...opts, + }); + }, + listProposalTemplates(opts = {}) { + return this._makeRequest({ + path: "/favorites/proposals", + ...opts, + }); + }, + listEmailTemplates(opts = {}) { + return this._makeRequest({ + path: "/settings/email-templates", + ...opts, + }); + }, + listProposals({ + status, ...opts + }) { + return this._makeRequest({ + path: `/proposals/${status}/`, + ...opts, + }); + }, + sendProposal({ + proposalId, ...opts + }) { + return this._makeRequest({ + method: "POST", + path: `/proposals/${proposalId}/send`, + ...opts, + }); + }, + createHook(opts = {}) { + return this._makeRequest({ + method: "POST", + path: "/webhooks", + ...opts, + }); + }, + deleteHook(webhookId) { + return this._makeRequest({ + method: "DELETE", + path: `/webhooks/${webhookId}`, + }); }, }, -}; \ No newline at end of file +}; diff --git a/components/offorte/package.json b/components/offorte/package.json index 0e76379eddd77..fd9464cdc6bac 100644 --- a/components/offorte/package.json +++ b/components/offorte/package.json @@ -1,6 +1,6 @@ { "name": "@pipedream/offorte", - "version": "0.0.1", + "version": "0.1.0", "description": "Pipedream Offorte Components", "main": "offorte.app.mjs", "keywords": [ @@ -11,5 +11,8 @@ "author": "Pipedream (https://pipedream.com/)", "publishConfig": { "access": "public" + }, + "dependencies": { + "@pipedream/platform": "^3.1.0" } -} \ No newline at end of file +} diff --git a/components/offorte/sources/new-event-instant/new-event-instant.mjs b/components/offorte/sources/new-event-instant/new-event-instant.mjs new file mode 100644 index 0000000000000..972a76b6fb982 --- /dev/null +++ b/components/offorte/sources/new-event-instant/new-event-instant.mjs @@ -0,0 +1,49 @@ +import { EVENTS_OPTIONS } from "../../common/constants.mjs"; +import { snakeCaseToTitleCase } from "../../common/utils.mjs"; +import offorte from "../../offorte.app.mjs"; +import sampleEmit from "./test-event.mjs"; + +export default { + key: "offorte-new-event-instant", + name: "New Event (Instant)", + description: "Emit new event when an event is created. [See the documentation](https://www.offorte.com/api-docs/api#tag/Webhooks/operation/webhookDetails)", + version: "0.0.1", + type: "source", + dedupe: "unique", + props: { + offorte, + db: "$.service.db", + http: "$.interface.http", + events: { + type: "string[]", + label: "Events", + description: "The events to listen for", + options: EVENTS_OPTIONS, + }, + }, + hooks: { + async activate() { + const response = await this.offorte.createHook({ + data: { + payload_url: this.http.endpoint, + payload_content_type: "json", + active: true, + events: this.events, + }, + }); + this.db.set("webhookId", response.webhook_id); + }, + async deactivate() { + const webhookId = this.db.get("webhookId"); + await this.offorte.deleteHook(webhookId); + }, + }, + async run({ body }) { + this.$emit(body, { + id: `${body.data.id}-${body.date_created}`, + summary: `New **${snakeCaseToTitleCase(body.type)}** event with ID: ${body.data.id}`, + ts: Date.parse(body.date_created), + }); + }, + sampleEmit, +}; diff --git a/components/offorte/sources/new-event-instant/test-event.mjs b/components/offorte/sources/new-event-instant/test-event.mjs new file mode 100644 index 0000000000000..41d1fa7a0b00c --- /dev/null +++ b/components/offorte/sources/new-event-instant/test-event.mjs @@ -0,0 +1,31 @@ +export default { + "type": "contact_created", + "date_created": "2025-06-16T19:31:42.000000Z", + "data": { + "account_user_id": "17689", + "type": "person", + "name": "test 03", + "street": "", + "zipcode": "", + "city": "", + "state": "", + "country": "", + "phone": "", + "email": "test03@email.com", + "internet": "", + "linkedin": "", + "facebook": "", + "twitter": "", + "instagram": "", + "account_user_name": "sergio wong", + "date_created": "2025-06-16T19:31:42.000000Z", + "tags": [], + "firstname": "test", + "lastname": "03", + "fullname": "test 03", + "salutation": "", + "mobile": "", + "proposals": [], + "id": "210996" + } +} \ No newline at end of file diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index a815cb339e253..19df78bd6c210 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -9113,7 +9113,11 @@ importers: specifier: ^3.0.1 version: 3.0.3 - components/offorte: {} + components/offorte: + dependencies: + '@pipedream/platform': + specifier: ^3.1.0 + version: 3.1.0 components/oksign: {} @@ -44140,7 +44144,7 @@ snapshots: jest-util: 29.7.0 natural-compare: 1.4.0 pretty-format: 29.7.0 - semver: 7.7.1 + semver: 7.7.2 transitivePeerDependencies: - supports-color