diff --git a/components/americommerce/actions/change-order-status/change-order-status.mjs b/components/americommerce/actions/change-order-status/change-order-status.mjs new file mode 100644 index 0000000000000..23acbf3b93314 --- /dev/null +++ b/components/americommerce/actions/change-order-status/change-order-status.mjs @@ -0,0 +1,132 @@ +import app from "../../americommerce.app.mjs"; + +export default { + key: "americommerce-change-order-status", + name: "Change Order Status", + description: "Changes the status of an existing order. [See the documentation](https://developers.cart.com/docs/rest-api/6898d9f254dfb-update-an-order-status).", + version: "0.0.1", + type: "action", + props: { + app, + orderStatusId: { + optional: false, + propDefinition: [ + app, + "orderStatusId", + ], + }, + name: { + type: "string", + label: "Name", + description: "The name of the order status.", + optional: true, + }, + isOpen: { + type: "boolean", + label: "Is Open", + description: "Indicates whether the order status is open.", + optional: true, + }, + isDeclined: { + type: "boolean", + label: "Is Declined", + description: "Indicates whether the order status is declined.", + optional: true, + }, + isCancelled: { + type: "boolean", + label: "Is Cancelled", + description: "Indicates whether the order status is cancelled.", + optional: true, + }, + isShipped: { + type: "boolean", + label: "Is Shipped", + description: "Indicates whether the order status is shipped.", + optional: true, + }, + color: { + type: "string", + label: "Color", + description: "The color of the order status.", + optional: true, + }, + emailTemplateId: { + propDefinition: [ + app, + "emailTemplateId", + ], + }, + isFullyRefunded: { + type: "boolean", + label: "Is Fully Refunded", + description: "Indicates whether the order status is fully refunded.", + optional: true, + }, + isPartiallyRefunded: { + type: "boolean", + label: "Is Partially Refunded", + description: "Indicates whether the order status is partially refunded.", + optional: true, + }, + isQuoteStatus: { + type: "boolean", + label: "Is Quote Status", + description: "Indicates whether the order status is a quote status.", + optional: true, + }, + isPartiallyShipped: { + type: "boolean", + label: "Is Partially Shipped", + description: "Indicates whether the order status is partially shipped.", + optional: true, + }, + }, + methods: { + changeOrderStatus({ + orderStatusId, ...args + } = {}) { + return this.app.put({ + path: `/order_statuses/${orderStatusId}`, + ...args, + }); + }, + }, + async run({ $ }) { + const { + changeOrderStatus, + orderStatusId, + name, + isOpen, + isDeclined, + isCancelled, + isShipped, + color, + emailTemplateId, + isFullyRefunded, + isPartiallyRefunded, + isQuoteStatus, + isPartiallyShipped, + } = this; + + const response = await changeOrderStatus({ + $, + orderStatusId, + data: { + name, + is_open: isOpen, + is_declined: isDeclined, + is_cancelled: isCancelled, + is_shipped: isShipped, + color, + email_template_id: emailTemplateId, + is_fully_refunded: isFullyRefunded, + is_partially_refunded: isPartiallyRefunded, + is_quote_status: isQuoteStatus, + is_partially_shipped: isPartiallyShipped, + }, + }); + $.export("$summary", `Successfully changed the order status with ID \`${response.id}\`.`); + return response; + }, +}; diff --git a/components/americommerce/actions/create-update-order/create-update-order.mjs b/components/americommerce/actions/create-update-order/create-update-order.mjs new file mode 100644 index 0000000000000..461773224d914 --- /dev/null +++ b/components/americommerce/actions/create-update-order/create-update-order.mjs @@ -0,0 +1,431 @@ +import { ConfigurationError } from "@pipedream/platform"; +import app from "../../americommerce.app.mjs"; + +export default { + key: "americommerce-create-update-order", + name: "Create Or Update Order", + description: "Creates a new order or updates an existing one. [See the documentation here](https://developers.cart.com/docs/rest-api/3f2ab73188031-create-an-order) and [here](https://developers.cart.com/docs/rest-api/e2649bb3adba9-update-an-order).", + version: "0.0.1", + type: "action", + props: { + app, + orderId: { + propDefinition: [ + app, + "orderId", + ], + }, + customerId: { + optional: true, + propDefinition: [ + app, + "customerId", + ], + }, + orderStatusId: { + propDefinition: [ + app, + "orderStatusId", + ], + }, + orderShippingAddressId: { + label: "Order Shipping Address ID", + description: "The ID of the order's shipping address.", + propDefinition: [ + app, + "orderAddressId", + ], + }, + orderBillingAddressId: { + label: "Order Billing Address ID", + description: "The ID of the order's billing address.", + propDefinition: [ + app, + "orderAddressId", + ], + }, + customerTypeId: { + propDefinition: [ + app, + "customerTypeId", + ], + }, + specialInstructions: { + type: "string", + label: "Special Instructions", + description: "Special instructions for the order.", + optional: true, + }, + subtotal: { + type: "string", + label: "Subtotal", + description: "The subtotal of the order.", + optional: true, + }, + taxTotal: { + type: "string", + label: "Tax Total", + description: "The total tax for the order or tax added to the order.", + optional: true, + }, + shippingTotal: { + type: "string", + label: "Shipping Total", + description: "The total shipping cost for the order or shipping added to the order.", + optional: true, + }, + discountTotal: { + type: "string", + label: "Discount Total", + description: "The total discount for the order.", + optional: true, + }, + grandTotal: { + type: "string", + label: "Grand Total", + description: "The grand total of the order.", + optional: true, + }, + costTotal: { + type: "string", + label: "Cost Total", + description: "The total cost of the order.", + optional: true, + }, + selectedShippingMethod: { + label: "Selected Shipping Method", + description: "The selected shipping method for the order.", + propDefinition: [ + app, + "shippingMethodId", + () => ({ + mapper: ({ + shipping_method_id: value, + shipping_method: label, + }) => ({ + label, + value: String(value), + }), + }), + ], + }, + referrer: { + type: "string", + label: "Referrer", + description: "The referrer for the order.", + optional: true, + }, + adminComments: { + type: "string", + label: "Admin Comments", + description: "Comments from the admin about the order.", + optional: true, + }, + source: { + type: "string", + label: "Source", + description: "The source of the order.", + optional: true, + }, + searchPhrase: { + type: "string", + label: "Search Phrase", + description: "The search phrase for the order.", + optional: true, + }, + storeId: { + propDefinition: [ + app, + "storeId", + ], + }, + isPpc: { + type: "boolean", + label: "Is PPC", + description: "Whether the order is a PPC order.", + optional: true, + }, + ppcKeyword: { + type: "string", + label: "PPC Keyword", + description: "The PPC keyword for the order.", + optional: true, + }, + handlingTotal: { + type: "string", + label: "Handling Total", + description: "The handling total for the order.", + optional: true, + }, + isPaymentOrderOnly: { + type: "boolean", + label: "Is Payment Order Only", + description: "Whether the order is a payment order only.", + optional: true, + }, + selectedShippingProviderService: { + type: "string", + label: "Selected Shipping Provider Service", + description: "The selected shipping provider service for the order.", + optional: true, + }, + additionalFees: { + type: "string", + label: "Additional Fees", + description: "Additional fees for the order.", + optional: true, + }, + adcodeId: { + propDefinition: [ + app, + "adcodeId", + ], + }, + isGift: { + type: "boolean", + label: "Is Gift", + description: "Whether the order is a gift.", + optional: true, + }, + giftMessage: { + type: "string", + label: "Gift Message", + description: "The gift message for the order.", + optional: true, + }, + publicComments: { + type: "string", + label: "Public Comments", + description: "Public comments about the order.", + optional: true, + }, + instructions: { + type: "string", + label: "Instructions", + description: "Instructions for the order.", + optional: true, + }, + sourceGroup: { + type: "string", + label: "Source Group", + description: "The source group for the order.", + optional: true, + }, + fromSubscriptionId: { + label: "From Subscription ID", + description: "The ID of the subscription.", + propDefinition: [ + app, + "subscriptionId", + ], + }, + discountedShippingTotal: { + type: "string", + label: "Discounted Shipping Total", + description: "The discounted shipping total for the order.", + optional: true, + }, + orderNumber: { + type: "string", + label: "Order Number", + description: "The order number.", + optional: true, + }, + couponCode: { + type: "string", + label: "Coupon Code", + description: "The coupon code for the order.", + optional: true, + }, + orderType: { + type: "string", + label: "Order Type", + description: "The type of order.", + optional: true, + }, + expires: { + type: "boolean", + label: "Expires", + description: "Whether the order expires.", + optional: true, + }, + campaignCode: { + type: "string", + label: "Campaign Code", + description: "The campaign code for the order.", + optional: true, + }, + rewardPointsCredited: { + type: "boolean", + label: "Reward Points Credited", + description: "Whether the reward points are credited.", + optional: true, + }, + channel: { + type: "string", + label: "Channel", + description: "The channel for the order.", + optional: true, + options: [ + "Online", + "InStore", + "Chat", + "Phone", + "Email", + ], + }, + device: { + type: "string", + label: "Device", + description: "The device for the order.", + optional: true, + }, + dueDate: { + type: "string", + label: "Due Date", + description: "The due date for the order. Eg. `2021-05-14`", + optional: true, + }, + }, + methods: { + createOrder(args = {}) { + return this.app.post({ + path: "/orders", + ...args, + }); + }, + updateOrder({ + orderId, ...args + } = {}) { + return this.app.put({ + path: `/orders/${orderId}`, + ...args, + }); + }, + }, + async run({ $ }) { + const { + createOrder, + updateOrder, + orderId, + customerId, + orderStatusId, + orderShippingAddressId, + orderBillingAddressId, + customerTypeId, + specialInstructions, + subtotal, + taxTotal, + shippingTotal, + discountTotal, + grandTotal, + costTotal, + selectedShippingMethod, + referrer, + adminComments, + source, + searchPhrase, + storeId, + isPpc, + ppcKeyword, + handlingTotal, + isPaymentOrderOnly, + selectedShippingProviderService, + additionalFees, + adcodeId, + isGift, + giftMessage, + publicComments, + instructions, + sourceGroup, + fromSubscriptionId, + discountedShippingTotal, + orderNumber, + couponCode, + orderType, + expires, + campaignCode, + rewardPointsCredited, + channel, + device, + dueDate, + } = this; + + const isCreate = !orderId; + + if ( + isCreate + && ( + !customerId + || !orderStatusId + || !orderShippingAddressId + || !orderBillingAddressId + || !taxTotal + || !shippingTotal + ) + ) { + throw new ConfigurationError("The **Customer ID**, **Order Status ID**, **Order Shipping Address ID**, **Order Billing Address ID**, **Tax Total**, and **Shipping Total** are required to create a new order."); + } + + const data = { + customer_id: customerId, + order_status_id: orderStatusId, + order_shipping_address_id: orderShippingAddressId, + order_billing_address_id: orderBillingAddressId, + customer_type_id: customerTypeId, + special_instructions: specialInstructions, + subtotal, + tax_total: taxTotal, + shipping_total: shippingTotal, + discount_total: discountTotal, + grand_total: grandTotal, + cost_total: costTotal, + selected_shipping_method: selectedShippingMethod, + referrer, + admin_comments: adminComments, + source, + search_phrase: searchPhrase, + store_id: storeId, + is_ppc: isPpc, + ppc_keyword: ppcKeyword, + handling_total: handlingTotal, + is_payment_order_only: isPaymentOrderOnly, + selected_shipping_provider_service: selectedShippingProviderService, + additional_fees: additionalFees, + adcode_id: adcodeId, + is_gift: isGift, + gift_message: giftMessage, + public_comments: publicComments, + instructions, + source_group: sourceGroup, + from_subscription_id: fromSubscriptionId, + discounted_shipping_total: discountedShippingTotal, + order_number: orderNumber, + coupon_code: couponCode, + order_type: orderType, + expires, + campaign_code: campaignCode, + reward_points_credited: rewardPointsCredited, + channel, + device, + due_date: dueDate, + }; + + if (isCreate) { + const response = await createOrder({ + $, + data, + }); + $.export("$summary", `Successfully created the order with ID \`${response.id}\`.`); + return response; + } + + const response = await updateOrder({ + $, + orderId, + data, + }); + $.export("$summary", `Successfully updated the order with ID \`${response.id}\`.`); + return response; + }, +}; diff --git a/components/americommerce/actions/update-customer/update-customer.mjs b/components/americommerce/actions/update-customer/update-customer.mjs new file mode 100644 index 0000000000000..9157ccab10b85 --- /dev/null +++ b/components/americommerce/actions/update-customer/update-customer.mjs @@ -0,0 +1,252 @@ +import app from "../../americommerce.app.mjs"; + +export default { + key: "americommerce-update-customer", + name: "Update Customer", + description: "Updates the details of a registered customer. [See the documentation](https://developers.cart.com/docs/rest-api/5da2f1ddbe199-update-a-customer).", + version: "0.0.1", + type: "action", + props: { + app, + customerId: { + propDefinition: [ + app, + "customerId", + ], + }, + customerNumber: { + type: "string", + label: "Customer Number", + description: "The customer number for the customer.", + optional: true, + }, + lastName: { + type: "string", + label: "Last Name", + description: "The last name of the customer.", + optional: true, + }, + firstName: { + type: "string", + label: "First Name", + description: "The first name of the customer.", + optional: true, + }, + email: { + type: "string", + label: "Email", + description: "The email address of the customer.", + optional: true, + }, + phoneNumber: { + type: "string", + label: "Phone Number", + description: "The phone number of the customer.", + optional: true, + }, + adcodeId: { + propDefinition: [ + app, + "adcodeId", + ], + }, + customerTypeId: { + propDefinition: [ + app, + "customerTypeId", + ], + }, + isNoTaxCustomer: { + type: "boolean", + label: "Is No Tax Customer", + description: "Whether the customer is a no-tax customer.", + optional: true, + }, + comments: { + type: "string", + label: "Comments", + description: "Comments about the customer.", + optional: true, + }, + storeId: { + propDefinition: [ + app, + "storeId", + ], + }, + source: { + type: "string", + label: "Source", + description: "The source of the customer.", + optional: true, + }, + searchString: { + type: "string", + label: "Search String", + description: "The search string for the customer.", + optional: true, + }, + noAccount: { + type: "boolean", + label: "No Account", + description: "Indicates whether the customer does not have an account.", + optional: true, + }, + alternatePhoneNumber: { + type: "string", + label: "Alternate Phone Number", + description: "The alternate phone number for the customer.", + optional: true, + }, + isAffiliateCustomer: { + type: "boolean", + label: "Is Affiliate Customer", + description: "Whether the customer is an affiliate customer.", + optional: true, + }, + username: { + type: "string", + label: "Username", + description: "The username for the customer.", + optional: true, + }, + isContactInformationOnly: { + type: "boolean", + label: "Is Contact Information Only", + description: "Whether the customer is contact information only.", + optional: true, + }, + taxExemptionNumber: { + type: "string", + label: "Tax Exemption Number", + description: "The tax exemption number for the customer.", + optional: true, + }, + company: { + type: "string", + label: "Company", + description: "The company for the customer.", + optional: true, + }, + taxRate: { + type: "string", + label: "Tax Rate", + description: "The tax rate for the customer.", + optional: true, + }, + lockDefaultAddress: { + type: "boolean", + label: "Lock Default Address", + description: "Whether the default address is locked.", + optional: true, + }, + paymentNetTerm: { + type: "integer", + label: "Payment Net Term", + description: "The payment net term for the customer.", + optional: true, + }, + creditLimit: { + type: "string", + label: "Credit Limit", + description: "The credit limit for the customer.", + optional: true, + }, + isInactive: { + type: "boolean", + label: "Is Inactive", + description: "Whether the customer is inactive.", + optional: true, + }, + useSharedCreditLimit: { + type: "boolean", + label: "Use Shared Credit Limit", + description: "Whether the shared credit limit is used.", + optional: true, + }, + overrideSharedCreditLimit: { + type: "boolean", + label: "Override Shared Credit Limit", + description: "Whether the shared credit limit is overridden.", + optional: true, + }, + }, + methods: { + updateCustomer({ + customerId, ...args + } = {}) { + return this.app.put({ + path: `/customers/${customerId}`, + ...args, + }); + }, + }, + async run({ $ }) { + const { + updateCustomer, + customerId, + customerNumber, + lastName, + firstName, + email, + phoneNumber, + adcodeId, + customerTypeId, + isNoTaxCustomer, + comments, + storeId, + source, + searchString, + noAccount, + alternatePhoneNumber, + isAffiliateCustomer, + username, + isContactInformationOnly, + taxExemptionNumber, + company, + taxRate, + lockDefaultAddress, + paymentNetTerm, + creditLimit, + isInactive, + useSharedCreditLimit, + overrideSharedCreditLimit, + } = this; + + const response = await updateCustomer({ + $, + customerId, + data: { + customer_number: customerNumber, + last_name: lastName, + first_name: firstName, + email, + phone_number: phoneNumber, + adcode_id: adcodeId, + customer_type_id: customerTypeId, + is_no_tax_customer: isNoTaxCustomer, + comments, + store_id: storeId, + source, + search_string: searchString, + no_account: noAccount, + alternate_phone_number: alternatePhoneNumber, + is_affiliate_customer: isAffiliateCustomer, + username, + is_contact_information_only: isContactInformationOnly, + tax_exemption_number: taxExemptionNumber, + company, + tax_rate: taxRate, + lock_default_address: lockDefaultAddress, + payment_net_term: paymentNetTerm, + credit_limit: creditLimit, + is_inactive: isInactive, + use_shared_credit_limit: useSharedCreditLimit, + override_shared_credit_limit: overrideSharedCreditLimit, + }, + }); + + $.export("$summary", `Successfully updated customer with ID \`${response.id}\`.`); + return response; + }, +}; diff --git a/components/americommerce/americommerce.app.mjs b/components/americommerce/americommerce.app.mjs index ad8d07fa72b62..b10102186aeb9 100644 --- a/components/americommerce/americommerce.app.mjs +++ b/components/americommerce/americommerce.app.mjs @@ -1,11 +1,253 @@ +import { axios } from "@pipedream/platform"; +import constants from "./common/constants.mjs"; + export default { type: "app", app: "americommerce", - propDefinitions: {}, + propDefinitions: { + customerId: { + type: "string", + label: "Customer ID", + description: "The unique identifier for the customer. This ID is optional.", + async options({ filter = () => true }) { + const { customers } = await this.getCustomers(); + return customers + .filter(filter) + .map(({ + first_name: firstName, last_name: lastName, id: value, + }) => ({ + label: [ + firstName, + lastName, + ].filter(Boolean).join(" "), + value, + })); + }, + }, + adcodeId: { + type: "string", + label: "Adcode ID", + description: "The adcode ID for the customer.", + optional: true, + async options() { + const { adcodes } = await this.getAdCodes(); + return adcodes.map(({ + name: label, id: value, + }) => ({ + label, + value: String(value), + })); + }, + }, + customerTypeId: { + type: "string", + label: "Customer Type ID", + description: "The customer type ID for the customer.", + optional: true, + async options() { + const { customer_types: customerTypes } = await this.getCustomerTypes(); + return customerTypes.map(({ + name: label, id: value, + }) => ({ + label, + value: String(value), + })); + }, + }, + storeId: { + type: "string", + label: "Store ID", + description: "The ID of the store.", + optional: true, + async options() { + const { stores } = await this.getStores(); + return stores.map(({ + name: label, id: value, + }) => ({ + label, + value: String(value), + })); + }, + }, + orderId: { + type: "string", + label: "Order ID", + description: "The unique identifier for the order. Required for updating or changing the status of an order.", + optional: true, + async options() { + const { orders } = await this.getOrders(); + return orders.map(({ + id, order_number: orderNumber, + }) => ({ + label: `Order #${orderNumber}`, + value: String(id), + })); + }, + }, + orderStatusId: { + type: "string", + label: "Order Status ID", + description: "The ID of the order status.", + optional: true, + async options() { + const { order_statuses: orderStatuses } = await this.getOrderStatuses(); + return orderStatuses.map(({ + name: label, id: value, + }) => ({ + label, + value: String(value), + })); + }, + }, + orderAddressId: { + type: "string", + label: "Order Address ID", + description: "The ID of the order's address.", + optional: true, + async options() { + const { addresses } = await this.getOrderAddresses(); + return addresses.map(({ + id, address_line_1: label, + }) => ({ + label, + value: String(id), + })); + }, + }, + shippingMethodId: { + type: "string", + label: "Shipping Method ID", + description: "The ID of the shipping method.", + optional: true, + async options({ mapper = ({ id }) => String(id) }) { + const { shipments } = await this.getOrderShipments(); + return shipments.map(mapper); + }, + }, + subscriptionId: { + type: "string", + label: "Subscription ID", + description: "The ID of the subscription.", + optional: true, + async options() { + const { subscriptions } = await this.getSubscriptions(); + return subscriptions.map(({ id }) => String(id)); + }, + }, + emailTemplateId: { + type: "string", + label: "Email Template ID", + description: "The ID of the email template.", + optional: true, + async options() { + const { email_templates: emailTemplates } = await this.getEmailTemplates(); + return emailTemplates.map(({ + type: label, id: value, + }) => ({ + label, + value: String(value), + })); + }, + }, + }, methods: { - // this.$auth contains connected account data - authKeys() { - console.log(Object.keys(this.$auth)); + getUrl(path) { + const baseUrl = constants.BASE_URL + .replace(constants.SUBDOMAIN_PLACEHOLDER, this.$auth.subdomain); + return `${baseUrl}${constants.VERSION_PATH}${path}`; + }, + getHeaders(headers) { + return { + ...headers, + "X-AC-Auth-Token": this.$auth.api_token, + }; + }, + _makeRequest({ + $ = this, path, headers, ...args + } = {}) { + return axios($, { + ...args, + url: this.getUrl(path), + headers: this.getHeaders(headers), + }); + }, + post(args = {}) { + return this._makeRequest({ + ...args, + method: "POST", + }); + }, + put(args = {}) { + return this._makeRequest({ + ...args, + method: "PUT", + }); + }, + delete(args = {}) { + return this._makeRequest({ + ...args, + method: "DELETE", + }); + }, + getCustomers(args = {}) { + return this._makeRequest({ + ...args, + path: "/customers", + }); + }, + getAdCodes(args = {}) { + return this._makeRequest({ + ...args, + path: "/adcodes", + }); + }, + getCustomerTypes(args = {}) { + return this._makeRequest({ + ...args, + path: "/customer_types", + }); + }, + getStores(args = {}) { + return this._makeRequest({ + ...args, + path: "/stores", + }); + }, + getOrders(args = {}) { + return this._makeRequest({ + ...args, + path: "/orders", + }); + }, + getOrderStatuses(args = {}) { + return this._makeRequest({ + ...args, + path: "/order_statuses", + }); + }, + getOrderAddresses(args = {}) { + return this._makeRequest({ + ...args, + path: "/order_addresses", + }); + }, + getOrderShipments(args = {}) { + return this._makeRequest({ + ...args, + path: "/order_shipments", + }); + }, + getSubscriptions(args = {}) { + return this._makeRequest({ + ...args, + path: "/subscriptions", + }); + }, + getEmailTemplates(args = {}) { + return this._makeRequest({ + ...args, + path: "/email_templates", + }); }, }, -}; \ No newline at end of file +}; diff --git a/components/americommerce/common/constants.mjs b/components/americommerce/common/constants.mjs new file mode 100644 index 0000000000000..c00ef6f39b068 --- /dev/null +++ b/components/americommerce/common/constants.mjs @@ -0,0 +1,11 @@ +const SUBDOMAIN_PLACEHOLDER = "{subdomain}"; +const BASE_URL = `https://${SUBDOMAIN_PLACEHOLDER}.americommerce.com`; +const VERSION_PATH = "/api/v1"; +const WEBHOOK_ID = "webhookId"; + +export default { + SUBDOMAIN_PLACEHOLDER, + BASE_URL, + VERSION_PATH, + WEBHOOK_ID, +}; diff --git a/components/americommerce/package.json b/components/americommerce/package.json index 16ec5c0c702b2..ed22f1a8a124a 100644 --- a/components/americommerce/package.json +++ b/components/americommerce/package.json @@ -1,6 +1,6 @@ { "name": "@pipedream/americommerce", - "version": "0.0.1", + "version": "0.1.0", "description": "Pipedream AmeriCommerce Components", "main": "americommerce.app.mjs", "keywords": [ @@ -11,5 +11,8 @@ "author": "Pipedream (https://pipedream.com/)", "publishConfig": { "access": "public" + }, + "dependencies": { + "@pipedream/platform": "3.0.3" } -} \ No newline at end of file +} diff --git a/components/americommerce/sources/common/events.mjs b/components/americommerce/sources/common/events.mjs new file mode 100644 index 0000000000000..f56051158ea2f --- /dev/null +++ b/components/americommerce/sources/common/events.mjs @@ -0,0 +1,32 @@ +export default { + AUTHORIZING_PAYMENT: "AuthorizingPayment", + CAPTURING_PAYMENT: "CapturingPayment", + CUSTOMER_CREATED: "CustomerCreated", + CUSTOMER_EMAIL_UPDATED: "CustomerEmailUpdated", + CUSTOMER_UPDATED: "CustomerUpdated", + CUSTOMER_REGISTERED: "CustomerRegistered", + GET_DISCOUNT: "GetDiscount", + GET_PRICE: "GetPrice", + GET_PRODUCT_STATUS: "GetProductStatus", + GET_TAX: "GetTax", + NEW_ORDER: "NewOrder", + NEW_QUOTE: "NewQuote", + NEW_VALID_ORDER: "NewValidOrder", + ORDER_APPROVED: "OrderApproved", + ORDER_CANCELED: "OrderCanceled", + ORDER_DECLINED: "OrderDeclined", + ORDER_PLACED: "OrderPlaced", + ORDER_SHIPPED: "OrderShipped", + ORDER_STATUS_CHANGED: "OrderStatusChanged", + ORDER_UPDATED: "OrderUpdated", + PAYMENT_PROCESSED: "PaymentProcessed", + PRODUCT_CREATED: "ProductCreated", + PRODUCT_STATUS_CHANGED: "ProductStatusChanged", + PRODUCT_UPDATED: "ProductUpdated", + QUOTE_STATUS_CHANGED: "QuoteStatusChanged", + QUOTE_UPDATED: "QuoteUpdated", + VALIDATE_CART: "ValidateCart", + VALIDATE_CHECKOUT: "ValidateCheckout", + VALIDATE_CUSTOMER: "ValidateCustomer", + VALIDATE_PRODUCT: "ValidateProduct", +}; diff --git a/components/americommerce/sources/common/webhook.mjs b/components/americommerce/sources/common/webhook.mjs new file mode 100644 index 0000000000000..1eb548fc8dc00 --- /dev/null +++ b/components/americommerce/sources/common/webhook.mjs @@ -0,0 +1,90 @@ +import { ConfigurationError } from "@pipedream/platform"; +import app from "../../americommerce.app.mjs"; +import constants from "../../common/constants.mjs"; + +export default { + props: { + app, + db: "$.service.db", + http: { + type: "$.interface.http", + customResponse: true, + }, + storeId: { + optional: false, + propDefinition: [ + app, + "storeId", + ], + }, + }, + hooks: { + async activate() { + const { + createWebhook, + setWebhookId, + http: { endpoint: url }, + getEventType, + storeId, + } = this; + const response = + await createWebhook({ + data: { + url, + event_type: getEventType(), + store_id: storeId, + }, + }); + + setWebhookId(response.id); + }, + async deactivate() { + const webhookId = this.getWebhookId(); + if (webhookId) { + await this.deleteWebhook({ + webhookId, + }); + } + }, + }, + methods: { + generateMeta() { + throw new ConfigurationError("generateMeta is not implemented"); + }, + setWebhookId(value) { + this.db.set(constants.WEBHOOK_ID, value); + }, + getWebhookId() { + return this.db.get(constants.WEBHOOK_ID); + }, + getEventType() { + throw new ConfigurationError("getEventType is not implemented"); + }, + processResource(resource) { + this.$emit(resource, this.generateMeta(resource)); + }, + createWebhook(args = {}) { + return this.app.post({ + debug: true, + path: "/webhooks", + ...args, + }); + }, + deleteWebhook({ + webhookId, ...args + } = {}) { + return this.app.delete({ + debug: true, + path: `/webhooks/${webhookId}`, + ...args, + }); + }, + }, + async run({ body }) { + this.http.respond({ + status: 200, + }); + + this.processResource(body); + }, +}; diff --git a/components/americommerce/sources/new-customer-instant/new-customer-instant.mjs b/components/americommerce/sources/new-customer-instant/new-customer-instant.mjs new file mode 100644 index 0000000000000..93def75236dc7 --- /dev/null +++ b/components/americommerce/sources/new-customer-instant/new-customer-instant.mjs @@ -0,0 +1,28 @@ +import common from "../common/webhook.mjs"; +import events from "../common/events.mjs"; +import sampleEmit from "./test-event.mjs"; + +export default { + ...common, + key: "americommerce-new-customer-instant", + name: "New Customer Created (Instant)", + description: "Emit new event when a customer is created in your Americommerce store. [See the documentation](https://developers.cart.com/docs/rest-api/ZG9jOjM1MDU4Nw-webhooks#subscribing-to-a-webhook).", + version: "0.0.1", + type: "source", + dedupe: "unique", + methods: { + ...common.methods, + getEventType() { + return events.CUSTOMER_CREATED; + }, + generateMeta(resource) { + const { customer } = resource; + return { + id: customer.id, + summary: `New Customer: ${customer.first_name}`, + ts: Date.parse(customer.created_at), + }; + }, + }, + sampleEmit, +}; diff --git a/components/americommerce/sources/new-customer-instant/test-event.mjs b/components/americommerce/sources/new-customer-instant/test-event.mjs new file mode 100644 index 0000000000000..4e9d27c46ea19 --- /dev/null +++ b/components/americommerce/sources/new-customer-instant/test-event.mjs @@ -0,0 +1,48 @@ +export default { + "customer": { + "id": 0, + "customer_number": "string", + "last_name": "string", + "first_name": "string", + "email": "string", + "phone_number": "string", + "registered_at": "string", + "last_visit_at": "string", + "adcode": "string", + "adcode_id": 0, + "affiliate_id": 0, + "customer_type_id": 0, + "is_no_tax_customer": true, + "comments": "string", + "store_id": 0, + "source": "string", + "search_string": "string", + "no_account": true, + "sales_person": "string", + "alternate_phone_number": "string", + "is_affiliate_customer": true, + "updated_at": "string", + "created_at": "string", + "username": "string", + "is_contact_information_only": true, + "tax_exemption_number": "string", + "company": "string", + "source_group": "string", + "sales_person_user_id": 0, + "store_payment_methods_enabled": [ + "string" + ], + "tax_rate": 0, + "lock_default_address": true, + "reward_tier_id": 0, + "payment_net_term": 0, + "credit_limit": 0, + "is_inactive": true, + "use_shared_credit_limit": true, + "override_shared_credit_limit": true, + "customer_payment_methods_availability": [ + {} + ], + "default_payment_type_name": "string" + } +}; diff --git a/components/americommerce/sources/new-product-instant/new-product-instant.mjs b/components/americommerce/sources/new-product-instant/new-product-instant.mjs new file mode 100644 index 0000000000000..149892507386c --- /dev/null +++ b/components/americommerce/sources/new-product-instant/new-product-instant.mjs @@ -0,0 +1,28 @@ +import common from "../common/webhook.mjs"; +import events from "../common/events.mjs"; +import sampleEmit from "./test-event.mjs"; + +export default { + ...common, + key: "americommerce-new-product-instant", + name: "New Product Instant", + description: "Emit new event when a product is added to your Americommerce store. [See the documentation](https://developers.cart.com/docs/rest-api/ZG9jOjM1MDU4Nw-webhooks#subscribing-to-a-webhook).", + version: "0.0.1", + type: "source", + dedupe: "unique", + methods: { + ...common.methods, + getEventType() { + return events.PRODUCT_CREATED; + }, + generateMeta(resource) { + const { product } = resource; + return { + id: product.id, + summary: `New Product: ${product.id}`, + ts: Date.parse(product.created_at), + }; + }, + }, + sampleEmit, +}; diff --git a/components/americommerce/sources/new-product-instant/test-event.mjs b/components/americommerce/sources/new-product-instant/test-event.mjs new file mode 100644 index 0000000000000..fcb3539767e5c --- /dev/null +++ b/components/americommerce/sources/new-product-instant/test-event.mjs @@ -0,0 +1,169 @@ +export default { + "product": { + "id": 0, + "item_number": "string", + "manufacturer_id": 0, + "manufacturer_part_number": "string", + "primary_category_id": 0, + "product_status_id": 0, + "item_name": "string", + "bullets": "string", + "short_description": "string", + "long_description_2": "string", + "long_description_3": "string", + "long_description_4": "string", + "long_description_5": "string", + "height": "string", + "length": "string", + "width": "string", + "size_unit": "string", + "weight": 0, + "weight_unit": "string", + "cost": 0, + "price": 0, + "retail": 0, + "minimum_quantity": 0, + "maximum_quantity": 0, + "is_spotlight_item": 0, + "quantity_on_hand": 0, + "keywords": "string", + "is_non_taxable": 0, + "is_shipped_individually": 0, + "is_hidden": 0, + "sort_order": 0, + "e_product_type": "string", + "e_product_url": "string", + "e_product_password": "string", + "e_product_verification_link_expiration": 0, + "e_product_email": "string", + "e_product_allow_multiple_deliveries": 0, + "warehouse_id": 0, + "call_for_shipping": 0, + "quickbooks_item_id": "string", + "call_for_pricing": 0, + "rate_adjustment_type": "string", + "meta_description": "string", + "page_title": "string", + "use_tabs": true, + "related_name": "string", + "override_theme_use_tabs": true, + "long_description_tab_name_1": "string", + "long_description_tab_name_2": "string", + "long_description_tab_name_3": "string", + "long_description_tab_name_4": "string", + "long_description_tab_name_5": "string", + "long_description_1": "string", + "is_non_shipping_item": true, + "e_product_delivery_action": "string", + "use_variant_inventory": true, + "is_featured_item": true, + "long_description_external_url_1": "string", + "long_description_external_url_2": "string", + "long_description_external_url_3": "string", + "long_description_external_url_4": "string", + "long_description_external_url_5": "string", + "bullets_external_url": "string", + "custom_flag_1": true, + "custom_flag_2": true, + "custom_flag_3": true, + "custom_flag_4": true, + "custom_flag_5": true, + "created_at": "string", + "updated_at": "string", + "url_rewrite": "string", + "is_kit": true, + "is_child_product": true, + "is_non_inventory": true, + "is_discontinued": true, + "eta_date": "string", + "quantity_on_order": 0, + "available_region_id": 0, + "call_for_shipping_on_whole_order": true, + "break_out_shipping": true, + "shipping_classification_code": "string", + "exclude_parent_from_display": true, + "drop_ship": true, + "no_price_mask": "string", + "starting_quantity": 0, + "tax_code": "string", + "use_map_pricing": true, + "last_item_number": "string", + "has_visible_variants": true, + "product_rating_dimension_group_override_id": 0, + "average_review_rating": 0, + "review_count": 0, + "exclude_children_from_display": true, + "use_pricing_from_parent": true, + "low_stock_warning_threshold": 0, + "enable_low_stock_warning": true, + "do_not_discount": true, + "head_tags": "string", + "handling_fee": 0, + "custom_upsell_url": "string", + "e_product_serial_number_file_path": "string", + "hide_variant_surcharges": true, + "quantity_increment": 0, + "gtin": "string", + "add_to_cart_message": "string", + "is_subscription_product": true, + "subscription_frequency": 0, + "subscription_frequency_type": "string", + "e_product_generic_username": "string", + "e_product_generic_password": "string", + "shipping_override": 0, + "insurance_cost": 0, + "exclude_from_commissions": true, + "days_until_reorder_allowed": 0, + "force_separate_order": true, + "approval_required": true, + "in_stock_notification_email_template_id": 0, + "inelligible_for_purchase_by_points": true, + "earns_points": true, + "additional_points_earned": 0, + "allowed_variable_subscription_types": "string", + "profile_id": 0, + "is_linked_product": true, + "master_product_id": 0, + "do_not_send_review_request": true, + "pack_slip_sort_order": 0, + "is_enable_variants_on_parent": true, + "is_hide_children_on_parent": true, + "cart_product_id": null, + "enabled_configurator": "string", + "material_code": "string", + "product_line_code": "string", + "ext_update_date": "string", + "additional_attributes": "string", + "shipper_hq_shipping_groups": "string", + "shipper_hq_dimensional_rule_groups": "string", + "shipper_hq_packing_boxes": "string", + "freight_class": "string", + "hs_code": "string", + "coo": "string", + "hts": "string", + "is_exempt_from_min_order_amount": true, + "category_list": "string", + "variants": [ + { + "id": 0, + "product_id": 0, + "variant_group_id": 0, + "description": "string", + "price_adjustment": 0, + "price_adjustment_type": "string", + "sort_order": 0, + "item_number_extension": "string", + "item_number_sort_order": 0, + "is_hidden": true, + "weight": 0, + "weight_type": "string", + "updated_at": "string", + "created_at": "string", + "is_default_selection": true, + "swatch_file": "string", + "swatch_thumbnail": "string", + "swatch_thumbnail_color": "string" + } + ] + } +}; diff --git a/components/americommerce/sources/new-valid-order-instant/new-valid-order-instant.mjs b/components/americommerce/sources/new-valid-order-instant/new-valid-order-instant.mjs new file mode 100644 index 0000000000000..188f3d0d110d7 --- /dev/null +++ b/components/americommerce/sources/new-valid-order-instant/new-valid-order-instant.mjs @@ -0,0 +1,28 @@ +import common from "../common/webhook.mjs"; +import events from "../common/events.mjs"; +import sampleEmit from "./test-event.mjs"; + +export default { + ...common, + key: "americommerce-new-valid-order-instant", + name: "New Valid Order (Instant)", + description: "Emit new event when a new valid order (not declined or cancelled) is created in your Americommerce store. [See the documentation](https://developers.cart.com/docs/rest-api/ZG9jOjM1MDU4Nw-webhooks#subscribing-to-a-webhook).", + version: "0.0.1", + type: "source", + dedupe: "unique", + methods: { + ...common.methods, + getEventType() { + return events.NEW_VALID_ORDER; + }, + generateMeta(resource) { + const { order } = resource; + return { + id: order.id, + summary: `New Valid Order: ${order.id}`, + ts: Date.parse(order.created_at), + }; + }, + }, + sampleEmit, +}; diff --git a/components/americommerce/sources/new-valid-order-instant/test-event.mjs b/components/americommerce/sources/new-valid-order-instant/test-event.mjs new file mode 100644 index 0000000000000..3cfbadc1a063e --- /dev/null +++ b/components/americommerce/sources/new-valid-order-instant/test-event.mjs @@ -0,0 +1,65 @@ +export default { + "order": { + "id": 0, + "customer_id": 0, + "customer_type_id": 0, + "adcode": "string", + "ordered_at": "string", + "order_status_id": 0, + "special_instructions": "string", + "subtotal": 0, + "tax_total": 0, + "shipping_total": 0, + "discount_total": 0, + "grand_total": 0, + "cost_total": 0, + "selected_shipping_method": "string", + "ip_address": "string", + "exported_to_accounting_system": 0, + "referrer": "string", + "order_shipping_address_id": 0, + "order_billing_address_id": 0, + "admin_comments": "string", + "source": "string", + "search_phrase": "string", + "is_ppc": true, + "ppc_keyword": "string", + "store_id": 0, + "session_id": 0, + "handling_total": 0, + "is_payment_order_only": true, + "selected_shipping_provider_service": "string", + "additional_fees": 0, + "adcode_id": 0, + "updated_at": "string", + "created_at": "string", + "is_gift": true, + "gift_message": "string", + "public_comments": "string", + "instructions": "string", + "source_group": "string", + "from_subscription_id": 0, + "previous_order_status_id": 0, + "order_status_last_changed_at": "string", + "discounted_shipping_total": 0, + "order_number": "string", + "coupon_code": "string", + "order_type": "string", + "expires_at": "string", + "expires": true, + "from_quote_id": 0, + "campaign_code": "string", + "reward_points_credited": true, + "sales_agent_user_id": 0, + "channel": "string", + "device": "string", + "manufacturer_invoice_number": "string", + "manufacturer_invoice_amount": 0, + "manufacturer_invoice_paid": true, + "due_date": "string", + "delivery_tax": 0, + "location_id": 0, + "entered_by": "string", + "entered_by_type": "string" + } +}; diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index fa0a44c2d4641..c6a752a0303bd 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -567,7 +567,10 @@ importers: specifiers: {} components/americommerce: - specifiers: {} + specifiers: + '@pipedream/platform': 3.0.3 + dependencies: + '@pipedream/platform': 3.0.3 components/amilia: specifiers: