diff --git a/components/braintree/actions/create-customer/create-customer.mjs b/components/braintree/actions/create-customer/create-customer.mjs new file mode 100644 index 0000000000000..3c5d6ab130783 --- /dev/null +++ b/components/braintree/actions/create-customer/create-customer.mjs @@ -0,0 +1,83 @@ +import braintree from "../../braintree.app.mjs"; +import mutations from "../../common/mutations.mjs"; + +export default { + key: "braintree-create-customer", + name: "Create Customer", + description: "Create a new customer in Braintree. [See the documentation](https://developer.paypal.com/braintree/graphql/guides/customers/#create)", + version: "0.0.1", + annotations: { + destructiveHint: false, + openWorldHint: true, + readOnlyHint: false, + }, + type: "action", + props: { + braintree, + firstName: { + type: "string", + label: "First Name", + description: "First name of the customer", + optional: true, + }, + lastName: { + type: "string", + label: "Last Name", + description: "Last name of the customer", + optional: true, + }, + company: { + type: "string", + label: "Company", + description: "Company name of the customer", + optional: true, + }, + email: { + type: "string", + label: "Email", + description: "Email of the customer", + optional: true, + }, + phoneNumber: { + type: "string", + label: "Phone Number", + description: "Phone number of the customer", + optional: true, + }, + fax: { + type: "string", + label: "Fax", + description: "Fax number of the customer", + optional: true, + }, + website: { + type: "string", + label: "Website", + description: "Website of the customer", + optional: true, + }, + }, + async run({ $ }) { + const response = await this.braintree.makeGraphQLRequest({ + $, + data: { + query: mutations.createCustomer, + variables: { + input: { + customer: { + firstName: this.firstName, + lastName: this.lastName, + company: this.company, + email: this.email, + phoneNumber: this.phoneNumber, + fax: this.fax, + website: this.website, + }, + }, + }, + }, + }); + $.export("$summary", `Customer successfully created with ID ${response.data.createCustomer.customer.id}`); + return response; + }, +}; diff --git a/components/braintree/braintree.app.mjs b/components/braintree/braintree.app.mjs index cbf7bb2ef0d60..3d289886c09fa 100644 --- a/components/braintree/braintree.app.mjs +++ b/components/braintree/braintree.app.mjs @@ -1,11 +1,32 @@ +import { + axios, ConfigurationError, +} from "@pipedream/platform"; + export default { type: "app", app: "braintree", propDefinitions: {}, methods: { - // this.$auth contains connected account data - authKeys() { - console.log(Object.keys(this.$auth)); + async makeGraphQLRequest({ + $ = this, ...opts + }) { + const response = await axios($, { + method: "post", + url: `https://${this.$auth.environment}.braintree-api.com/graphql`, + headers: { + "Braintree-Version": "2019-01-01", + "Content-Type": "application/json", + }, + auth: { + username: this.$auth.public_key, + password: this.$auth.private_key, + }, + ...opts, + }); + if (response.errors) { + throw new ConfigurationError(response.errors[0].message); + } + return response; }, }, }; diff --git a/components/braintree/common/mutations.mjs b/components/braintree/common/mutations.mjs new file mode 100644 index 0000000000000..c0056e8868a59 --- /dev/null +++ b/components/braintree/common/mutations.mjs @@ -0,0 +1,21 @@ +const createCustomer = ` + mutation createCustomer($input: CreateCustomerInput!) { + createCustomer(input: $input) { + customer { + id + firstName + lastName + company + email + phoneNumber + fax + website + createdAt + } + } + } +`; + +export default { + createCustomer, +}; diff --git a/components/braintree/common/queries.mjs b/components/braintree/common/queries.mjs new file mode 100644 index 0000000000000..145a23004f931 --- /dev/null +++ b/components/braintree/common/queries.mjs @@ -0,0 +1,69 @@ +const searchCustomers = ` + query Search($input: CustomerSearchInput!) { + search { + customers(input: $input) { + edges { + node { + id + firstName + lastName + company + email + phoneNumber + fax + website + createdAt + customFields { + name + value + } + } + } + } + } + } +`; + +const searchTransactions = ` + query ($input: TransactionSearchInput!) { + search { + transactions(input: $input) { + edges { + node { + id + status + amount { + value + currencyCode + } + paymentMethod { + id + } + orderId + merchantId + merchantName + customFields { + name + value + } + channel + customer { + id + } + lineItems { + name + quantity + totalAmount + } + createdAt + } + } + } + } + } +`; + +export default { + searchCustomers, + searchTransactions, +}; diff --git a/components/braintree/package.json b/components/braintree/package.json index dffbfe28a9c34..8fd082fa474cb 100644 --- a/components/braintree/package.json +++ b/components/braintree/package.json @@ -1,6 +1,6 @@ { "name": "@pipedream/braintree", - "version": "0.0.3", + "version": "0.1.0", "description": "Pipedream Braintree Components", "main": "braintree.app.mjs", "keywords": [ @@ -11,5 +11,8 @@ "author": "Pipedream (https://pipedream.com/)", "publishConfig": { "access": "public" + }, + "dependencies": { + "@pipedream/platform": "^3.1.1" } } diff --git a/components/braintree/sources/common/base-polling.mjs b/components/braintree/sources/common/base-polling.mjs new file mode 100644 index 0000000000000..228af1dcbf22d --- /dev/null +++ b/components/braintree/sources/common/base-polling.mjs @@ -0,0 +1,63 @@ +import braintree from "../../braintree.app.mjs"; +import { + DEFAULT_POLLING_SOURCE_TIMER_INTERVAL, ConfigurationError, +} from "@pipedream/platform"; + +export default { + props: { + braintree, + db: "$.service.db", + timer: { + type: "$.interface.timer", + default: { + intervalSeconds: DEFAULT_POLLING_SOURCE_TIMER_INTERVAL, + }, + }, + }, + methods: { + _yesterday() { + const now = new Date(); + const yesterday = new Date(now); + yesterday.setDate(now.getDate() - 1); + return yesterday.toISOString(); + }, + _getLastCreatedAt() { + return this.db.get("createdAt") || this._yesterday(); + }, + _setLastCreatedAt(lastCreatedAt) { + this.db.set("createdAt", lastCreatedAt); + }, + emitEvent(result) { + const meta = this.generateMeta(result); + this.$emit(result, meta); + }, + generateMeta(result) { + return { + id: result.id, + summary: this.getSummary(result), + ts: Date.parse(result.createdAt), + }; + }, + getResults() { + throw new ConfigurationError("getResults is not implemented"); + }, + getSummary() { + throw new ConfigurationError("getSummary is not implemented"); + }, + }, + async run() { + const lastCreatedAt = this._getLastCreatedAt(); + let maxCreatedAt = lastCreatedAt; + + const results = await this.getResults(lastCreatedAt); + for (const result of results) { + const createdAt = result.createdAt; + this.emitEvent(result); + if (Date.parse(createdAt) > Date.parse(maxCreatedAt)) { + maxCreatedAt = createdAt; + } + } + + this._setLastCreatedAt(maxCreatedAt); + }, +}; diff --git a/components/braintree/sources/new-customer-created/new-customer-created.mjs b/components/braintree/sources/new-customer-created/new-customer-created.mjs new file mode 100644 index 0000000000000..5cd9e04bc3b41 --- /dev/null +++ b/components/braintree/sources/new-customer-created/new-customer-created.mjs @@ -0,0 +1,35 @@ +import base from "../common/base-polling.mjs"; +import queries from "../../common/queries.mjs"; + +export default { + ...base, + key: "braintree-new-customer-created", + name: "New Customer Created", + description: "Emit new event when a new customer is created.", + version: "0.0.1", + type: "source", + dedupe: "unique", + methods: { + ...base.methods, + async getResults(lastCreatedAt) { + const { braintree } = this; + const response = await braintree.makeGraphQLRequest({ + data: { + query: queries.searchCustomers, + variables: { + input: { + createdAt: { + greaterThanOrEqualTo: lastCreatedAt, + }, + }, + }, + }, + }); + const edges = response?.data?.search?.customers?.edges ?? []; + return edges.map((edge) => edge.node); + }, + getSummary(result) { + return `New Customer Created: ${result.id}`; + }, + }, +}; diff --git a/components/braintree/sources/new-transaction-created/new-transaction-created.mjs b/components/braintree/sources/new-transaction-created/new-transaction-created.mjs new file mode 100644 index 0000000000000..f53497e4f9738 --- /dev/null +++ b/components/braintree/sources/new-transaction-created/new-transaction-created.mjs @@ -0,0 +1,35 @@ +import common from "../common/base-polling.mjs"; +import queries from "../../common/queries.mjs"; + +export default { + ...common, + key: "braintree-new-transaction-created", + name: "New Transaction Created", + description: "Emit new event when a new transaction is created.", + version: "0.0.1", + type: "source", + dedupe: "unique", + methods: { + ...common.methods, + async getResults(lastCreatedAt) { + const { braintree } = this; + const response = await braintree.makeGraphQLRequest({ + data: { + query: queries.searchTransactions, + variables: { + input: { + createdAt: { + greaterThanOrEqualTo: lastCreatedAt, + }, + }, + }, + }, + }); + const edges = response?.data?.search?.transactions?.edges ?? []; + return edges.map((edge) => edge.node); + }, + getSummary(result) { + return `New Transaction Created: ${result.id}`; + }, + }, +}; diff --git a/components/upsales/upsales.app.mjs b/components/upsales/upsales.app.mjs index 25742c2e6da57..a25cb38c3794c 100644 --- a/components/upsales/upsales.app.mjs +++ b/components/upsales/upsales.app.mjs @@ -8,4 +8,4 @@ export default { console.log(Object.keys(this.$auth)); }, }, -}; \ No newline at end of file +}; diff --git a/components/xero_payroll/xero_payroll.app.mjs b/components/xero_payroll/xero_payroll.app.mjs index 43ded58f0da08..6636a5fb991fb 100644 --- a/components/xero_payroll/xero_payroll.app.mjs +++ b/components/xero_payroll/xero_payroll.app.mjs @@ -8,4 +8,4 @@ export default { console.log(Object.keys(this.$auth)); }, }, -}; \ No newline at end of file +}; diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 5c38d6e1bf2ca..6076b3eab9316 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -2052,7 +2052,11 @@ importers: components/brainshop: {} - components/braintree: {} + components/braintree: + dependencies: + '@pipedream/platform': + specifier: ^3.1.1 + version: 3.1.1 components/brand_dev: {}