diff --git a/components/add_to_calendar_pro/add_to_calendar_pro.app.mjs b/components/add_to_calendar_pro/add_to_calendar_pro.app.mjs index f1adfd7f2a2ac..98b59c7cbe899 100644 --- a/components/add_to_calendar_pro/add_to_calendar_pro.app.mjs +++ b/components/add_to_calendar_pro/add_to_calendar_pro.app.mjs @@ -8,4 +8,4 @@ export default { console.log(Object.keys(this.$auth)); }, }, -}; \ No newline at end of file +}; diff --git a/components/arpoone/arpoone.app.mjs b/components/arpoone/arpoone.app.mjs index 03485c698d662..256b3c3bae150 100644 --- a/components/arpoone/arpoone.app.mjs +++ b/components/arpoone/arpoone.app.mjs @@ -8,4 +8,4 @@ export default { console.log(Object.keys(this.$auth)); }, }, -}; \ No newline at end of file +}; diff --git a/components/commonninja/commonninja.app.mjs b/components/commonninja/commonninja.app.mjs index 28f98e685ab1b..7acef33d1d9f9 100644 --- a/components/commonninja/commonninja.app.mjs +++ b/components/commonninja/commonninja.app.mjs @@ -8,4 +8,4 @@ export default { console.log(Object.keys(this.$auth)); }, }, -}; \ No newline at end of file +}; diff --git a/components/openai_passthrough/openai_passthrough.app.mjs b/components/openai_passthrough/openai_passthrough.app.mjs index 724fad102b789..1f002ec290115 100644 --- a/components/openai_passthrough/openai_passthrough.app.mjs +++ b/components/openai_passthrough/openai_passthrough.app.mjs @@ -8,4 +8,4 @@ export default { console.log(Object.keys(this.$auth)); }, }, -}; \ No newline at end of file +}; diff --git a/components/pembee/pembee.app.mjs b/components/pembee/pembee.app.mjs index ff158c5c93fa4..c08741d426b24 100644 --- a/components/pembee/pembee.app.mjs +++ b/components/pembee/pembee.app.mjs @@ -8,4 +8,4 @@ export default { console.log(Object.keys(this.$auth)); }, }, -}; \ No newline at end of file +}; diff --git a/components/phonely/phonely.app.mjs b/components/phonely/phonely.app.mjs index d7ce6f4251c7b..cc965f9283561 100644 --- a/components/phonely/phonely.app.mjs +++ b/components/phonely/phonely.app.mjs @@ -8,4 +8,4 @@ export default { console.log(Object.keys(this.$auth)); }, }, -}; \ No newline at end of file +}; diff --git a/components/picqer/actions/add-order-comment/add-order-comment.mjs b/components/picqer/actions/add-order-comment/add-order-comment.mjs new file mode 100644 index 0000000000000..574d7f759c81f --- /dev/null +++ b/components/picqer/actions/add-order-comment/add-order-comment.mjs @@ -0,0 +1,50 @@ +import picqer from "../../picqer.app.mjs"; + +export default { + key: "picqer-add-order-comment", + name: "Add Comment To Order", + description: "Add a comment to an order in Picqer. [See the documentation](https://picqer.com/en/api/comments#adding-comments-to-an-order)", + version: "0.0.1", + type: "action", + props: { + picqer, + orderId: { + propDefinition: [ + picqer, + "orderId", + ], + }, + body: { + propDefinition: [ + picqer, + "commentBody", + ], + }, + showAtRelated: { + propDefinition: [ + picqer, + "showAtRelated", + ], + }, + isVisibleFulfillment: { + propDefinition: [ + picqer, + "isVisibleFulfillment", + ], + }, + }, + async run({ $ }) { + const response = await this.picqer.addOrderComment({ + $, + orderId: this.orderId, + data: { + body: this.body, + show_at_related: this.showAtRelated, + is_visible_fulfilment: this.isVisibleFulfillment, + }, + }); + + $.export("$summary", `Successfully added comment to order ${this.orderId}`); + return response; + }, +}; diff --git a/components/picqer/actions/add-return-comment/add-return-comment.mjs b/components/picqer/actions/add-return-comment/add-return-comment.mjs new file mode 100644 index 0000000000000..b8df5e64f94bb --- /dev/null +++ b/components/picqer/actions/add-return-comment/add-return-comment.mjs @@ -0,0 +1,50 @@ +import picqer from "../../picqer.app.mjs"; + +export default { + key: "picqer-add-return-comment", + name: "Add Comment To Return", + description: "Add a comment to a return in Picqer. [See the documentation](https://picqer.com/en/api/comments#add-a-comment-to-an-return)", + version: "0.0.1", + type: "action", + props: { + picqer, + returnId: { + propDefinition: [ + picqer, + "returnId", + ], + }, + body: { + propDefinition: [ + picqer, + "commentBody", + ], + }, + showAtRelated: { + propDefinition: [ + picqer, + "showAtRelated", + ], + }, + isVisibleFulfillment: { + propDefinition: [ + picqer, + "isVisibleFulfillment", + ], + }, + }, + async run({ $ }) { + const response = await this.picqer.addReturnComment({ + $, + returnId: this.returnId, + data: { + body: this.body, + show_at_related: this.showAtRelated, + is_visible_fulfilment: this.isVisibleFulfillment, + }, + }); + + $.export("$summary", `Successfully added comment to return ${this.returnId}`); + return response; + }, +}; diff --git a/components/picqer/actions/create-order/create-order.mjs b/components/picqer/actions/create-order/create-order.mjs new file mode 100644 index 0000000000000..1515a21b2ae1f --- /dev/null +++ b/components/picqer/actions/create-order/create-order.mjs @@ -0,0 +1,364 @@ +import { ConfigurationError } from "@pipedream/platform"; +import { LANGUAGE_OPTIONS } from "../../common/constants.mjs"; +import { parseObject } from "../../common/utils.mjs"; +import picqer from "../../picqer.app.mjs"; + +export default { + key: "picqer-create-order", + name: "Create Picqer Order", + description: "Create a new order in Picqer. [See the documentation](https://picqer.com/en/api/orders)", + version: "0.0.1", + type: "action", + props: { + picqer, + customerId: { + propDefinition: [ + picqer, + "customerId", + ], + reloadProps: true, + optional: true, + }, + templateId: { + propDefinition: [ + picqer, + "templateId", + ], + optional: true, + }, + shippingProviderId: { + propDefinition: [ + picqer, + "shippingProviderId", + ], + optional: true, + }, + deliveryName: { + propDefinition: [ + picqer, + "deliveryName", + ], + hidden: true, + }, + deliveryContactName: { + propDefinition: [ + picqer, + "deliveryContactName", + ], + optional: true, + hidden: true, + }, + deliveryAddress: { + propDefinition: [ + picqer, + "deliveryAddress", + ], + optional: true, + hidden: true, + }, + deliveryAddress2: { + propDefinition: [ + picqer, + "deliveryAddress2", + ], + optional: true, + hidden: true, + }, + deliveryZipcode: { + propDefinition: [ + picqer, + "deliveryZipcode", + ], + optional: true, + hidden: true, + }, + deliveryCity: { + propDefinition: [ + picqer, + "deliveryCity", + ], + optional: true, + hidden: true, + }, + deliveryRegion: { + propDefinition: [ + picqer, + "deliveryRegion", + ], + optional: true, + hidden: true, + }, + deliveryCountry: { + propDefinition: [ + picqer, + "deliveryCountry", + ], + hidden: true, + }, + invoiceName: { + propDefinition: [ + picqer, + "invoiceName", + ], + optional: true, + hidden: true, + }, + invoiceContactName: { + propDefinition: [ + picqer, + "invoiceContactName", + ], + optional: true, + hidden: true, + }, + invoiceAddress: { + propDefinition: [ + picqer, + "invoiceAddress", + ], + optional: true, + hidden: true, + }, + invoiceAddress2: { + propDefinition: [ + picqer, + "invoiceAddress2", + ], + optional: true, + hidden: true, + }, + invoiceZipcode: { + propDefinition: [ + picqer, + "invoiceZipcode", + ], + optional: true, + hidden: true, + }, + invoiceCity: { + propDefinition: [ + picqer, + "invoiceCity", + ], + optional: true, + hidden: true, + }, + invoiceRegion: { + propDefinition: [ + picqer, + "invoiceRegion", + ], + optional: true, + hidden: true, + }, + invoiceCountry: { + propDefinition: [ + picqer, + "invoiceCountry", + ], + description: "Country of invoice address (needs to be ISO 3166 2-char code).", + hidden: true, + }, + telephone: { + propDefinition: [ + picqer, + "telephone", + ], + optional: true, + }, + emailAddress: { + propDefinition: [ + picqer, + "emailAddress", + ], + optional: true, + }, + reference: { + propDefinition: [ + picqer, + "reference", + ], + optional: true, + }, + customerRemarks: { + propDefinition: [ + picqer, + "customerRemarks", + ], + optional: true, + }, + partialDelivery: { + propDefinition: [ + picqer, + "partialDelivery", + ], + optional: true, + }, + discount: { + propDefinition: [ + picqer, + "discount", + ], + optional: true, + }, + invoiced: { + propDefinition: [ + picqer, + "invoiced", + ], + optional: true, + }, + preferredDeliveryDate: { + propDefinition: [ + picqer, + "preferredDeliveryDate", + ], + optional: true, + }, + language: { + propDefinition: [ + picqer, + "language", + ], + options: LANGUAGE_OPTIONS, + optional: true, + }, + products: { + type: "string[]", + label: "Products", + description: "List of objects of products to add to the order. **Format: [{\"idproduct\": 123, \"productcode\": \"ABC123\", \"name\": \"Product Name\", \"remarks\": \"Product remarks\", \"amount\": 100, \"idvatgroup\": 123}]**", + optional: true, + }, + }, + async additionalProps(fixedProps) { + const props = {}; + const hasCustomerId = !!this.customerId; + fixedProps.deliveryName.hidden = hasCustomerId; + fixedProps.deliveryContactName.hidden = hasCustomerId; + fixedProps.deliveryAddress.hidden = hasCustomerId; + fixedProps.deliveryAddress2.hidden = hasCustomerId; + fixedProps.deliveryZipcode.hidden = hasCustomerId; + fixedProps.deliveryCity.hidden = hasCustomerId; + fixedProps.deliveryRegion.hidden = hasCustomerId; + fixedProps.deliveryCountry.hidden = hasCustomerId; + fixedProps.invoiceName.hidden = hasCustomerId; + fixedProps.invoiceContactName.hidden = hasCustomerId; + fixedProps.invoiceAddress.hidden = hasCustomerId; + fixedProps.invoiceAddress2.hidden = hasCustomerId; + fixedProps.invoiceZipcode.hidden = hasCustomerId; + fixedProps.invoiceCity.hidden = hasCustomerId; + fixedProps.invoiceRegion.hidden = hasCustomerId; + fixedProps.invoiceCountry.hidden = hasCustomerId; + + if (this.customerId) { + const orderFields = await this.picqer.listOrderFields(); + + for (const field of orderFields) { + const propData = { + type: `string${field.type === "multicheckbox" + ? "[]" + : ""}`, + label: field.title, + description: `Order field: ${field.title}`, + optional: !field.required, + }; + + if (field.values.length) { + propData.options = field.values; + } + + props[`id${field.idorderfield}`] = propData; + } + } + return props; + }, + async run({ $ }) { + const { + picqer, + customerId, + templateId, + shippingProviderId, + deliveryName, + deliveryContactName, + deliveryAddress, + deliveryAddress2, + deliveryZipcode, + deliveryCity, + deliveryRegion, + deliveryCountry, + invoiceName, + invoiceContactName, + invoiceAddress, + invoiceAddress2, + invoiceZipcode, + invoiceCity, + invoiceRegion, + invoiceCountry, + telephone, + emailAddress, + reference, + customerRemarks, + partialDelivery, + discount, + invoiced, + products, + preferredDeliveryDate, + language, + ...otherFields + } = this; + + if (!customerId && !deliveryName) { + throw new ConfigurationError("Delivery Name is required if **Customer Id** is not provided"); + } + if (!customerId && !deliveryCountry) { + throw new ConfigurationError("Delivery Country is required if **Customer Id** is not provided"); + } + + const response = await picqer.createOrder({ + $, + data: { + idcustomer: customerId, + idtemplate: templateId, + idshippingprovider: shippingProviderId, + deliveryname: deliveryName, + deliverycontactname: deliveryContactName, + deliveryaddress: deliveryAddress, + deliveryaddress2: deliveryAddress2, + deliveryzipcode: deliveryZipcode, + deliverycity: deliveryCity, + deliveryregion: deliveryRegion, + deliverycountry: deliveryCountry, + invoicename: invoiceName, + invoicecontactname: invoiceContactName, + invoiceaddress: invoiceAddress, + invoiceaddress2: invoiceAddress2, + invoicezipcode: invoiceZipcode, + invoicecity: invoiceCity, + invoiceregion: invoiceRegion, + invoicecountry: invoiceCountry, + telephone, + emailaddress: emailAddress, + reference, + customerremarks: customerRemarks, + partialdelivery: partialDelivery, + discount: discount && parseFloat(discount), + invoiced, + preferreddeliverydate: preferredDeliveryDate, + language, + products: parseObject(products), + orderfields: Object.entries(otherFields)?.map(([ + key, + value, + ]) => ({ + idorderfield: parseInt(key.replace("id", "")), + value: Array.isArray(value) + ? value.join(";") + : value, + })), + }, + }); + + $.export("$summary", `Order created successfully with ID ${response.idorder}`); + return response; + }, +}; diff --git a/components/picqer/actions/get-customer/get-customer.mjs b/components/picqer/actions/get-customer/get-customer.mjs new file mode 100644 index 0000000000000..60da7823c5248 --- /dev/null +++ b/components/picqer/actions/get-customer/get-customer.mjs @@ -0,0 +1,27 @@ +import picqer from "../../picqer.app.mjs"; + +export default { + key: "picqer-get-customer", + name: "Get Customer", + description: "Get a customer in Picqer. [See the documentation](https://picqer.com/en/api/customers#get-single-customer)", + version: "0.0.1", + type: "action", + props: { + picqer, + customerId: { + propDefinition: [ + picqer, + "customerId", + ], + }, + }, + async run({ $ }) { + const response = await this.picqer.getCustomer({ + $, + customerId: this.customerId, + }); + + $.export("$summary", `Successfully retrieved customer ${this.customerId}`); + return response; + }, +}; diff --git a/components/picqer/actions/get-order/get-order.mjs b/components/picqer/actions/get-order/get-order.mjs new file mode 100644 index 0000000000000..3f1d03d2c22b5 --- /dev/null +++ b/components/picqer/actions/get-order/get-order.mjs @@ -0,0 +1,27 @@ +import picqer from "../../picqer.app.mjs"; + +export default { + key: "picqer-get-order", + name: "Get Picqer Order", + description: "Get an order in Picqer. [See the documentation](https://picqer.com/en/api/orders#get-single-order)", + version: "0.0.1", + type: "action", + props: { + picqer, + orderId: { + propDefinition: [ + picqer, + "orderId", + ], + }, + }, + async run({ $ }) { + const response = await this.picqer.getOrder({ + $, + orderId: this.orderId, + }); + + $.export("$summary", `Successfully retrieved order ${this.orderId}`); + return response; + }, +}; diff --git a/components/picqer/actions/get-picklist/get-picklist.mjs b/components/picqer/actions/get-picklist/get-picklist.mjs new file mode 100644 index 0000000000000..5ddb4ce78028a --- /dev/null +++ b/components/picqer/actions/get-picklist/get-picklist.mjs @@ -0,0 +1,27 @@ +import picqer from "../../picqer.app.mjs"; + +export default { + key: "picqer-get-picklist", + name: "Get Picklist", + description: "Get a picklist in Picqer. [See the documentation](https://picqer.com/en/api/picklists#h-get-single-picklist)", + version: "0.0.1", + type: "action", + props: { + picqer, + picklistId: { + propDefinition: [ + picqer, + "picklistId", + ], + }, + }, + async run({ $ }) { + const response = await this.picqer.getPicklist({ + $, + picklistId: this.picklistId, + }); + + $.export("$summary", `Successfully retrieved picklist ${this.picklistId}`); + return response; + }, +}; diff --git a/components/picqer/actions/get-status-per-order-line/get-status-per-order-line.mjs b/components/picqer/actions/get-status-per-order-line/get-status-per-order-line.mjs new file mode 100644 index 0000000000000..bc27e8556cb3a --- /dev/null +++ b/components/picqer/actions/get-status-per-order-line/get-status-per-order-line.mjs @@ -0,0 +1,28 @@ +import picqer from "../../picqer.app.mjs"; + +export default { + key: "picqer-get-status-per-order-line", + name: "Get Status Per Order Line", + description: "Get the status per order line in Picqer. [See the documentation](https://picqer.com/en/api/orders#get-status-per-order-line)", + version: "0.0.1", + type: "action", + props: { + picqer, + orderId: { + propDefinition: [ + picqer, + "orderId", + ], + description: "Get the status per order line for this order.", + }, + }, + async run({ $ }) { + const response = await this.picqer.getStatusPerOrderLine({ + $, + orderId: this.orderId, + }); + + $.export("$summary", `Successfully retrieved status per order line for order ${this.orderId}`); + return response; + }, +}; diff --git a/components/picqer/actions/search-orders/search-orders.mjs b/components/picqer/actions/search-orders/search-orders.mjs new file mode 100644 index 0000000000000..244891c7498d0 --- /dev/null +++ b/components/picqer/actions/search-orders/search-orders.mjs @@ -0,0 +1,107 @@ +import { STATUS_OPTIONS } from "../../common/constants.mjs"; +import picqer from "../../picqer.app.mjs"; + +export default { + key: "picqer-search-orders", + name: "Search Picqer Orders", + description: "Search for orders in Picqer. [See the documentation](https://picqer.com/en/api/orders#get-all-orders)", + version: "0.0.1", + type: "action", + props: { + picqer, + search: { + type: "string", + label: "Search", + description: "Search through the fields orderid, reference, customer name and customer contact name.", + optional: true, + }, + sinceId: { + type: "string", + label: "Since ID", + description: "Get the orders with a later idorder than given.", + optional: true, + }, + beforeId: { + type: "string", + label: "Before ID", + description: "Get the orders with a smaller idorder than given.", + optional: true, + }, + sinceDate: { + type: "string", + label: "Since Date", + description: "Get the orders that are added after this date and time. **Format: YYYY-MM-DD HH:MM:SS**", + optional: true, + }, + untilDate: { + type: "string", + label: "Until Date", + description: "Get the orders that are added before this date and time. **Format: YYYY-MM-DD HH:MM:SS**", + optional: true, + }, + status: { + type: "string", + label: "Status", + description: "Get the orders that have this status.", + options: STATUS_OPTIONS, + optional: true, + }, + reference: { + type: "string", + label: "Reference", + description: "Get the orders that have this value as reference.", + optional: true, + }, + emailAddress: { + type: "string", + label: "Email Address", + description: "Get the orders that have this value as email address.", + optional: true, + }, + customerId: { + propDefinition: [ + picqer, + "customerId", + ], + description: "Get all orders for this customer.", + optional: true, + }, + warehouseId: { + propDefinition: [ + picqer, + "warehouseId", + ], + description: "Get the orders that can be delivered from this warehouse.", + optional: true, + }, + fulfillmentCustomerId: { + propDefinition: [ + picqer, + "fulfillmentCustomerId", + ], + description: "Get the orders for this fulfilment.", + optional: true, + }, + }, + async run({ $ }) { + const response = await this.picqer.searchOrders({ + $, + params: { + search: this.search, + sinceid: this.sinceId, + beforeid: this.beforeId, + sincedate: this.sinceDate, + untildate: this.untilDate, + status: this.status, + reference: this.reference, + emailaddress: this.emailAddress, + idcustomer: this.customerId, + idwarehouse: this.warehouseId, + idfulfilment_customer: this.fulfillmentCustomerId, + }, + }); + + $.export("$summary", `Orders found: ${response.length}`); + return response; + }, +}; diff --git a/components/picqer/actions/update-order/update-order.mjs b/components/picqer/actions/update-order/update-order.mjs new file mode 100644 index 0000000000000..4857c6f9f13d6 --- /dev/null +++ b/components/picqer/actions/update-order/update-order.mjs @@ -0,0 +1,356 @@ +import picqer from "../../picqer.app.mjs"; + +export default { + key: "picqer-update-order", + name: "Update Picqer Order", + description: "Update an order in Picqer. [See the documentation](https://picqer.com/en/api/orders#update)", + version: "0.0.1", + type: "action", + props: { + picqer, + orderId: { + propDefinition: [ + picqer, + "orderId", + ], + }, + customerId: { + propDefinition: [ + picqer, + "customerId", + ], + reloadProps: true, + optional: true, + }, + templateId: { + propDefinition: [ + picqer, + "templateId", + ], + optional: true, + }, + deliveryName: { + propDefinition: [ + picqer, + "deliveryName", + ], + description: "Name of delivery address.", + optional: true, + hidden: true, + }, + deliveryContactName: { + propDefinition: [ + picqer, + "deliveryContactName", + ], + optional: true, + hidden: true, + }, + deliveryAddress: { + propDefinition: [ + picqer, + "deliveryAddress", + ], + optional: true, + hidden: true, + }, + deliveryAddress2: { + propDefinition: [ + picqer, + "deliveryAddress2", + ], + optional: true, + hidden: true, + }, + deliveryZipcode: { + propDefinition: [ + picqer, + "deliveryZipcode", + ], + optional: true, + hidden: true, + }, + deliveryCity: { + propDefinition: [ + picqer, + "deliveryCity", + ], + optional: true, + hidden: true, + }, + deliveryRegion: { + propDefinition: [ + picqer, + "deliveryRegion", + ], + optional: true, + hidden: true, + }, + deliveryCountry: { + propDefinition: [ + picqer, + "deliveryCountry", + ], + description: "Country of delivery address (needs to be ISO 3166 2-char code).", + optional: true, + hidden: true, + }, + invoiceName: { + propDefinition: [ + picqer, + "invoiceName", + ], + description: "Name of invoice address.", + optional: true, + hidden: true, + }, + invoiceContactName: { + propDefinition: [ + picqer, + "invoiceContactName", + ], + optional: true, + hidden: true, + }, + invoiceAddress: { + propDefinition: [ + picqer, + "invoiceAddress", + ], + optional: true, + hidden: true, + }, + invoiceAddress2: { + propDefinition: [ + picqer, + "invoiceAddress2", + ], + optional: true, + hidden: true, + }, + invoiceZipcode: { + propDefinition: [ + picqer, + "invoiceZipcode", + ], + optional: true, + hidden: true, + }, + invoiceCity: { + propDefinition: [ + picqer, + "invoiceCity", + ], + optional: true, + hidden: true, + }, + invoiceRegion: { + propDefinition: [ + picqer, + "invoiceRegion", + ], + optional: true, + hidden: true, + }, + invoiceCountry: { + propDefinition: [ + picqer, + "invoiceCountry", + ], + optional: true, + hidden: true, + }, + telephone: { + propDefinition: [ + picqer, + "telephone", + ], + optional: true, + }, + emailAddress: { + propDefinition: [ + picqer, + "emailAddress", + ], + optional: true, + }, + discount: { + propDefinition: [ + picqer, + "discount", + ], + optional: true, + }, + preferredDeliveryDate: { + propDefinition: [ + picqer, + "preferredDeliveryDate", + ], + optional: true, + }, + customerRemarks: { + propDefinition: [ + picqer, + "customerRemarks", + ], + optional: true, + }, + reference: { + propDefinition: [ + picqer, + "reference", + ], + optional: true, + }, + invoiced: { + propDefinition: [ + picqer, + "invoiced", + ], + optional: true, + }, + shippingProviderId: { + propDefinition: [ + picqer, + "shippingProviderId", + ], + optional: true, + }, + partialDelivery: { + propDefinition: [ + picqer, + "partialDelivery", + ], + optional: true, + }, + language: { + propDefinition: [ + picqer, + "language", + ], + optional: true, + }, + }, + async additionalProps(fixedProps) { + const props = {}; + const hasCustomerId = !!this.customerId; + fixedProps.deliveryName.hidden = hasCustomerId; + fixedProps.deliveryContactName.hidden = hasCustomerId; + fixedProps.deliveryAddress.hidden = hasCustomerId; + fixedProps.deliveryAddress2.hidden = hasCustomerId; + fixedProps.deliveryZipcode.hidden = hasCustomerId; + fixedProps.deliveryCity.hidden = hasCustomerId; + fixedProps.deliveryRegion.hidden = hasCustomerId; + fixedProps.deliveryCountry.hidden = hasCustomerId; + fixedProps.invoiceName.hidden = hasCustomerId; + fixedProps.invoiceContactName.hidden = hasCustomerId; + fixedProps.invoiceAddress.hidden = hasCustomerId; + fixedProps.invoiceAddress2.hidden = hasCustomerId; + fixedProps.invoiceZipcode.hidden = hasCustomerId; + fixedProps.invoiceCity.hidden = hasCustomerId; + fixedProps.invoiceRegion.hidden = hasCustomerId; + fixedProps.invoiceCountry.hidden = hasCustomerId; + + if (this.customerId) { + const orderFields = await this.picqer.listOrderFields(); + for (const field of orderFields) { + const propData = { + type: `string${field.type === "multicheckbox" + ? "[]" + : ""}`, + label: field.title, + description: `Order field: ${field.title}`, + }; + + if (field.values.length) { + propData.options = field.values; + } + + props[field.idorderfield] = propData; + } + } + return props; + }, + async run({ $ }) { + const { + picqer, + orderId, + customerId, + templateId, + shippingProviderId, + deliveryName, + deliveryContactName, + deliveryAddress, + deliveryAddress2, + deliveryZipcode, + deliveryCity, + deliveryRegion, + deliveryCountry, + invoiceName, + invoiceContactName, + invoiceAddress, + invoiceAddress2, + invoiceZipcode, + invoiceCity, + invoiceRegion, + invoiceCountry, + telephone, + emailAddress, + reference, + customerRemarks, + partialDelivery, + discount, + invoiced, + preferredDeliveryDate, + language, + ...otherFields + } = this; + + const response = await picqer.updateOrder({ + $, + orderId, + data: { + idcustomer: customerId, + idtemplate: templateId, + idshippingprovider: shippingProviderId, + deliveryname: deliveryName, + deliverycontactname: deliveryContactName, + deliveryaddress: deliveryAddress, + deliveryaddress2: deliveryAddress2, + deliveryzipcode: deliveryZipcode, + deliverycity: deliveryCity, + deliveryregion: deliveryRegion, + deliverycountry: deliveryCountry, + invoicename: invoiceName, + invoicecontactname: invoiceContactName, + invoiceaddress: invoiceAddress, + invoiceaddress2: invoiceAddress2, + invoicezipcode: invoiceZipcode, + invoicecity: invoiceCity, + invoiceregion: invoiceRegion, + invoicecountry: invoiceCountry, + telephone, + emailaddress: emailAddress, + reference, + customerremarks: customerRemarks, + partialdelivery: partialDelivery, + discount: discount && parseFloat(discount), + invoiced, + preferreddeliverydate: preferredDeliveryDate, + language, + orderfields: Object.entries(otherFields)?.map(([ + key, + value, + ]) => ({ + idorderfield: parseInt(key), + value: Array.isArray(value) + ? value.join(";") + : value, + })), + }, + }); + + $.export("$summary", `Order updated successfully with ID ${orderId}`); + return response; + }, +}; diff --git a/components/picqer/common/constants.mjs b/components/picqer/common/constants.mjs new file mode 100644 index 0000000000000..dad2dbb57f71d --- /dev/null +++ b/components/picqer/common/constants.mjs @@ -0,0 +1,230 @@ +export const LIMIT = 100; + +export const LANGUAGE_OPTIONS = [ + { + label: "English", + value: "en", + }, + { + label: "Dutch", + value: "nl", + }, +]; + +export const STATUS_OPTIONS = [ + { + label: "Concept", + value: "concept", + }, + { + label: "Expected", + value: "expected", + }, + { + label: "Processing", + value: "processing", + }, + { + label: "Paused", + value: "paused", + }, + { + label: "Completed", + value: "completed", + }, + { + label: "Cancelled", + value: "cancelled", + }, +]; + +export const EVENT_OPTIONS = [ + { + label: "New Comment Created", + value: "comments.created", + }, + { + label: "New Movement", + value: "movements.moved", + }, + { + label: "New Order Created", + value: "orders.created", + }, + { + label: "Order Allocated", + value: "orders.allocated", + }, + { + label: "Order Closed", + value: "orders.closed", + }, + { + label: "Order Paused", + value: "orders.paused", + }, + { + label: "Order Resumed", + value: "orders.resumed", + }, + { + label: "Order Status Changed", + value: "orders.status_changed", + }, + { + label: "Order Completed", + value: "orders.completed", + }, + { + label: "New Order Note Created", + value: "orders.notes.created", + }, + { + label: "New Picklist Created", + value: "picklists.created", + }, + { + label: "Picklist Changed", + value: "picklists.changed", + }, + { + label: "Picklist Paused", + value: "picklists.paused", + }, + { + label: "Picklist Resumed", + value: "picklists.resumed", + }, + { + label: "Picklist Closed", + value: "picklists.closed", + }, + { + label: "Picklist Cancelled", + value: "picklists.cancelled", + }, + { + label: "Picklist Snoozed", + value: "picklists.snoozed", + }, + { + label: "Picklist Unsnoozed", + value: "picklists.unsnoozed", + }, + { + label: "New Picklist Shipment Created", + value: "picklists.shipments.created", + }, + { + label: "Picklist Shipment Cancelled", + value: "picklists.shipments.cancelled", + }, + { + label: "New Picklist Batch Created", + value: "picklist_batches.created", + }, + { + label: "Picklist Batch Changed", + value: "picklist_batches.changed", + }, + { + label: "Picklist Batch Completed", + value: "picklist_batches.completed", + }, + { + label: "New Product Created", + value: "products.created", + }, + { + label: "Product Changed", + value: "products.changed", + }, + { + label: "Product Free Stock Changed", + value: "products.free_stock_changed", + }, + { + label: "Product Stock Changed", + value: "products.stock_changed", + }, + { + label: "Product Assembled Stock Changed", + value: "products.assembled_stock_changed", + }, + { + label: "Product Stock On Location Changed", + value: "products.stock_on_location_changed", + }, + { + label: "Product Parts Changed", + value: "products.parts.changed", + }, + { + label: "New Purchase Order Created", + value: "purchase_orders.created", + }, + { + label: "Purchase Order Changed", + value: "purchase_orders.changed", + }, + { + label: "Purchase Order Purchased", + value: "purchase_orders.purchased", + }, + { + label: "New Receipt Created", + value: "receipts.created", + }, + { + label: "Receipt Completed", + value: "receipts.completed", + }, + { + label: "Receipt Product Received", + value: "receipts.product_received", + }, + { + label: "Receipt Product Reverted", + value: "receipts.product_reverted", + }, + { + label: "New Return Created", + value: "returns.created", + }, + { + label: "Return Changed", + value: "returns.changed", + }, + { + label: "Return Status Changed", + value: "returns.status_changed", + }, + { + label: "Return Products Received", + value: "returns.products_received", + }, + { + label: "Location Stock Counts Completed", + value: "location_stock_counts.completed", + }, + { + label: "New Task Created", + value: "tasks.created", + }, + { + label: "Task Changed", + value: "tasks.changed", + }, + { + label: "Task Deleted", + value: "tasks.deleted", + }, + { + label: "Task Completed", + value: "tasks.completed", + }, + { + label: "Task Uncompleted", + value: "tasks.uncompleted", + }, +]; diff --git a/components/picqer/common/utils.mjs b/components/picqer/common/utils.mjs new file mode 100644 index 0000000000000..dcc9cc61f6f41 --- /dev/null +++ b/components/picqer/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/picqer/package.json b/components/picqer/package.json index 68967efd5ca2c..afec885e938a8 100644 --- a/components/picqer/package.json +++ b/components/picqer/package.json @@ -1,6 +1,6 @@ { "name": "@pipedream/picqer", - "version": "0.0.1", + "version": "0.1.0", "description": "Pipedream Picqer Components", "main": "picqer.app.mjs", "keywords": [ @@ -11,5 +11,9 @@ "author": "Pipedream (https://pipedream.com/)", "publishConfig": { "access": "public" + }, + "dependencies": { + "@pipedream/platform": "^3.1.0", + "crypto-js": "^4.2.0" } -} \ No newline at end of file +} diff --git a/components/picqer/picqer.app.mjs b/components/picqer/picqer.app.mjs index 930696c76057f..8193ece2eae68 100644 --- a/components/picqer/picqer.app.mjs +++ b/components/picqer/picqer.app.mjs @@ -1,11 +1,454 @@ +import { axios } from "@pipedream/platform"; +import { + LANGUAGE_OPTIONS, + LIMIT, +} from "./common/constants.mjs"; + export default { type: "app", app: "picqer", - propDefinitions: {}, + propDefinitions: { + orderId: { + type: "string", + label: "Order ID", + description: "The order id for searching orders.", + async options({ page }) { + const data = await this.searchOrders({ + params: { + offset: page * LIMIT, + }, + }); + + return data.map(({ + idorder: value, invoicename: label, + }) => ({ + label, + value, + })); + }, + }, + customerId: { + type: "string", + label: "Customer ID", + description: "The customer id for creating a new order.", + async options({ page }) { + const data = await this.listCustomers({ + params: { + offset: page * LIMIT, + }, + }); + + return data.map(({ + idcustomer: value, name: label, + }) => ({ + label, + value, + })); + }, + }, + templateId: { + type: "string", + label: "Template Id", + description: "The template id for creating a new order.", + async options({ page }) { + const data = await this.listTemplates({ + params: { + offset: page * LIMIT, + }, + }); + + return data.map(({ + idtemplate: value, name: label, + }) => ({ + label, + value, + })); + }, + }, + shippingProviderId: { + type: "string", + label: "Shipping Provider Id", + description: "The shipping provider id for creating a new order.", + async options({ page }) { + const data = await this.listShippingProviders({ + params: { + offset: page * LIMIT, + }, + }); + return data.map(({ + idshippingprovider: value, name: label, + }) => ({ + label, + value, + })); + }, + }, + warehouseId: { + type: "string", + label: "Warehouse ID", + description: "Warehouses that can be used to fulfil this order.", + async options({ page }) { + const warehouses = await this.listWarehouses({ + params: { + offset: page * LIMIT, + }, + }); + return warehouses.map(({ + idwarehouse: value, name: label, + }) => ({ + label, + value, + })); + }, + }, + fulfillmentCustomerId: { + type: "string", + label: "Fulfillment Customer ID", + description: "Fulfillment customer for this order.", + async options({ page }) { + const fulfillmentCustomers = await this.listFulfillmentCustomers({ + params: { + offset: page * LIMIT, + }, + }); + return fulfillmentCustomers.map(({ + idcustomer: value, name: label, + }) => ({ + label, + value, + })); + }, + }, + returnId: { + type: "string", + label: "Return ID", + description: "The return id for searching returns.", + async options({ page }) { + const data = await this.searchReturns({ + params: { + offset: page * LIMIT, + }, + }); + + return data.map(({ + idreturn: value, returnid, name, + }) => ({ + label: `${returnid} - ${name}`, + value, + })); + }, + }, + picklistId: { + type: "string", + label: "Picklist ID", + description: "The picklist id for searching picklists.", + async options({ page }) { + const data = await this.listPicklists({ + params: { + offset: page * LIMIT, + }, + }); + return data.map(({ + idpicklist: value, picklistid, deliveryname, + }) => ({ + label: `${picklistid} - ${deliveryname}`, + value, + })); + }, + }, + deliveryName: { + type: "string", + label: "Delivery Name", + description: "Name of delivery address. Required if **Customer Id** is not provided.", + }, + deliveryContactName: { + type: "string", + label: "Delivery Contact Name", + description: "Contact name of delivery address.", + }, + deliveryAddress: { + type: "string", + label: "Delivery Address", + description: "Address line of delivery address.", + }, + deliveryAddress2: { + type: "string", + label: "Delivery Address 2", + description: "Second address line. Not accepted by all shipping providers.", + }, + deliveryZipcode: { + type: "string", + label: "Delivery Zipcode", + description: "ZIP code of delivery address.", + }, + deliveryCity: { + type: "string", + label: "Delivery City", + description: "City of delivery address.", + }, + deliveryRegion: { + type: "string", + label: "Delivery Region", + description: "Region, province or state of delivery address.", + }, + deliveryCountry: { + type: "string", + label: "Delivery Country", + description: "Country of delivery address (needs to be ISO 3166 2-char code). Required if **Customer Id** is not provided.", + }, + invoiceName: { + type: "string", + label: "Invoice Name", + description: "Name of invoice address. Required if **Customer Id** is not provided.", + }, + invoiceContactName: { + type: "string", + label: "Invoice Contact Name", + description: "Contact name of invoice address", + }, + invoiceAddress: { + type: "string", + label: "Invoice Address", + description: "Address line of invoice address", + }, + invoiceAddress2: { + type: "string", + label: "Invoice Address 2", + description: "Second address line. Not accepted by all shipping providers.", + }, + invoiceZipcode: { + type: "string", + label: "Invoice Zipcode", + description: "ZIP code of invoice address", + }, + invoiceCity: { + type: "string", + label: "Invoice City", + description: "City of invoice address", + }, + invoiceRegion: { + type: "string", + label: "Invoice Region", + description: "Region, province or state of invoice address", + }, + invoiceCountry: { + type: "string", + label: "Invoice Country", + description: "Country of invoice address (needs to be ISO 3166 2-char code). Required if **Customer Id** is not provided.", + }, + telephone: { + type: "string", + label: "Telephone", + description: "Telephone number of the customer.", + }, + emailAddress: { + type: "string", + label: "Email Address", + description: "Email address of the customer", + }, + discount: { + type: "string", + label: "Discount", + description: "Discount percentage of order", + }, + preferredDeliveryDate: { + type: "string", + label: "Preferred Delivery Date", + description: "Customer supplied preferred delivery date, in format **yyyy-mm-dd**.", + }, + customerRemarks: { + type: "string", + label: "Customer Remarks", + description: "Remarks from the customer, will be printed on picking and packing list", + }, + reference: { + type: "string", + label: "Reference", + description: "Reference for customer, will be printed on invoice and picking list", + }, + invoiced: { + type: "boolean", + label: "Invoiced", + description: "If this order is already invoiced, set this to true. This will make sure Picqer will not invoice this order", + }, + partialDelivery: { + type: "boolean", + label: "Partial Delivery", + description: "If Picqer AutoSplit is enabled, order can be split over multiple picklists over multiple warehouses. If disabled, it will wait for all products to be available", + }, + language: { + type: "string", + label: "Language", + description: "Language of the order", + options: LANGUAGE_OPTIONS, + }, + commentBody: { + type: "string", + label: "Comment Body", + description: "The body of the comment.", + }, + showAtRelated: { + type: "boolean", + label: "Show At Related", + description: "Whether the comment is visible on related resources. For example: comments added to orders can be shown when retrieving comments for a picklist of that order.", + }, + isVisibleFulfillment: { + type: "boolean", + label: "Visible In Fulfillment", + description: "Only for Picqer Fulfilment: Whether the comment is visible for the fulfilment customer the resource belongs to.", + }, + }, methods: { - // this.$auth contains connected account data - authKeys() { - console.log(Object.keys(this.$auth)); + _baseUrl() { + return `https://${this.$auth.subdomain}.picqer.com/api/v1`; + }, + _auth() { + return { + username: `${this.$auth.api_key}`, + password: "", + }; + }, + _makeRequest({ + $ = this, path, ...opts + }) { + return axios($, { + url: this._baseUrl() + path, + auth: this._auth(), + ...opts, + }); + }, + createOrder(opts = {}) { + return this._makeRequest({ + method: "POST", + path: "/orders", + ...opts, + }); + }, + updateOrder({ + orderId, ...opts + }) { + return this._makeRequest({ + method: "PUT", + path: `/orders/${orderId}`, + ...opts, + }); + }, + getOrder({ + orderId, ...opts + }) { + return this._makeRequest({ + path: `/orders/${orderId}`, + ...opts, + }); + }, + getCustomer({ + customerId, ...opts + }) { + return this._makeRequest({ + path: `/customers/${customerId}`, + ...opts, + }); + }, + listCustomers(opts = {}) { + return this._makeRequest({ + path: "/customers", + ...opts, + }); + }, + listOrderFields(opts = {}) { + return this._makeRequest({ + path: "/orderfields", + ...opts, + }); + }, + listTemplates(opts = {}) { + return this._makeRequest({ + path: "/templates", + ...opts, + }); + }, + listShippingProviders(opts = {}) { + return this._makeRequest({ + path: "/shippingproviders", + ...opts, + }); + }, + searchOrders(opts = {}) { + return this._makeRequest({ + path: "/orders", + ...opts, + }); + }, + listWarehouses(opts = {}) { + return this._makeRequest({ + path: "/warehouses", + ...opts, + }); + }, + listFulfillmentCustomers(opts = {}) { + return this._makeRequest({ + path: "/fulfilment/customers", + ...opts, + }); + }, + getStatusPerOrderLine({ + orderId, ...opts + }) { + return this._makeRequest({ + path: `/orders/${orderId}/productstatus`, + ...opts, + }); + }, + addOrderComment({ + orderId, ...opts + }) { + return this._makeRequest({ + method: "POST", + path: `/orders/${orderId}/comments`, + ...opts, + }); + }, + addReturnComment({ + returnId, ...opts + }) { + return this._makeRequest({ + method: "POST", + path: `/returns/${returnId}/comments`, + ...opts, + }); + }, + searchReturns(opts = {}) { + return this._makeRequest({ + path: "/returns", + ...opts, + }); + }, + listPicklists(opts = {}) { + return this._makeRequest({ + path: "/picklists", + ...opts, + }); + }, + getPicklist({ + picklistId, ...opts + }) { + return this._makeRequest({ + path: `/picklists/${picklistId}`, + ...opts, + }); + }, + createHook(opts = {}) { + return this._makeRequest({ + method: "POST", + path: "/hooks", + ...opts, + }); + }, + deleteHook(hookId) { + return this._makeRequest({ + method: "DELETE", + path: `/hooks/${hookId}`, + }); }, }, }; diff --git a/components/picqer/sources/common/base.mjs b/components/picqer/sources/common/base.mjs new file mode 100644 index 0000000000000..1c8c58bcce806 --- /dev/null +++ b/components/picqer/sources/common/base.mjs @@ -0,0 +1,84 @@ +import CryptoJS from "crypto-js"; +import { EVENT_OPTIONS } from "../../common/constants.mjs"; +import picqer from "../../picqer.app.mjs"; + +export default { + props: { + picqer, + db: "$.service.db", + http: { + type: "$.interface.http", + customResponse: true, + }, + warehouseId: { + propDefinition: [ + picqer, + "warehouseId", + ], + }, + event: { + type: "string", + label: "Event", + description: "The event to emit.", + options: EVENT_OPTIONS, + }, + name: { + type: "string", + label: "Name", + description: "Your own reference for this hook.", + }, + secret: { + type: "string", + label: "Secret", + description: "If you provide a secret key with your webhook, we will use it to sign every request so you can check the sender.", + optional: true, + secret: true, + }, + }, + hooks: { + async activate() { + const response = await this.picqer.createHook({ + data: { + event: this.event, + address: this.http.endpoint, + secret: this.secret, + name: this.name, + }, + }); + this.db.set("webhookId", response.idhook); + }, + async deactivate() { + const webhookId = this.db.get("webhookId"); + await this.picqer.deleteHook(webhookId); + }, + }, + async run(event) { + const { body } = event; + const signature = event?.headers["x-picqer-signature"]; + if (signature) { + const hash = CryptoJS.HmacSHA256(event.bodyRaw, this.secret); + const hashBase64 = CryptoJS.enc.Base64.stringify(hash); + + if (hashBase64 !== signature) { + this.http.respond({ + status: 401, + body: "Unauthorized", + }); + return; + } + } + + this.http.respond({ + status: 200, + body: "Success", + }); + + const ts = Date.parse(body.event_triggered_at); + + this.$emit(body, { + id: `${body.idhook}-${ts}`, + summary: this.getSummary(body), + ts, + }); + }, +}; diff --git a/components/picqer/sources/new-event-instant/new-event-instant.mjs b/components/picqer/sources/new-event-instant/new-event-instant.mjs new file mode 100644 index 0000000000000..5a9c2e5b54b39 --- /dev/null +++ b/components/picqer/sources/new-event-instant/new-event-instant.mjs @@ -0,0 +1,20 @@ +import { EVENT_OPTIONS } from "../../common/constants.mjs"; +import common from "../common/base.mjs"; +import sampleEmit from "./test-event.mjs"; + +export default { + ...common, + key: "picqer-new-event-instant", + name: "New Event Instant", + description: "Emit new event when Picqer sends a webhook matched with selected event. [See the documentation](https://picqer.com/en/api/webhooks)", + version: "0.0.1", + type: "source", + dedupe: "unique", + methods: { + getSummary(body) { + const event = EVENT_OPTIONS.find((e) => e.value === body.event); + return event.label; + }, + }, + sampleEmit, +}; diff --git a/components/picqer/sources/new-event-instant/test-event.mjs b/components/picqer/sources/new-event-instant/test-event.mjs new file mode 100644 index 0000000000000..ccc328ef55a4c --- /dev/null +++ b/components/picqer/sources/new-event-instant/test-event.mjs @@ -0,0 +1,43 @@ +export default { + "idhook":228, + "name":"Stock change notifications", + "event":"products.free_stock_changed", + "event_triggered_at":"2018-12-01 02:09:12", + "data": { + "idproduct":138, + "idvatgroup":18, + "idsupplier":null, + "productcode": "6531-RB-7-9", + "name": "Hyperkewl Evaporative Cooling Vest Ultra Blue 7-9yr", + "price": 54.46, + "fixedstockprice": 0, + "productcode_supplier": "", + "deliverytime": null, + "description": "", + "barcode": "857825001442", + "type": "normal", + "unlimitedstock": false, + "weight": 200, + "minimum_purchase_quantity": 0, + "purchase_in_quantities_of": 0, + "hs_code": null, + "country_of_origin": null, + "active": true, + "tags": {}, + "productfields": [], + "images": [ + "/files/2/cb594f30-25d0-43a6-88f2-d93e193ea316/original.jpg" + ], + "stock": [ + { + "idwarehouse":18, + "stock":35, + "reserved":0, + "reservedbackorders":0, + "reservedpicklists":0, + "freestock":35, + "freepickablestock":35 + } + ] + } +} \ No newline at end of file diff --git a/components/postmaster/postmaster.app.mjs b/components/postmaster/postmaster.app.mjs index 40c14b726ac99..f8d79c8e6651b 100644 --- a/components/postmaster/postmaster.app.mjs +++ b/components/postmaster/postmaster.app.mjs @@ -8,4 +8,4 @@ export default { console.log(Object.keys(this.$auth)); }, }, -}; \ No newline at end of file +}; diff --git a/components/test_apps_for_switching_appslug_025/test_apps_for_switching_appslug_025.app.mjs b/components/test_apps_for_switching_appslug_025/test_apps_for_switching_appslug_025.app.mjs index 70259540dcced..c6b9f43f01c6f 100644 --- a/components/test_apps_for_switching_appslug_025/test_apps_for_switching_appslug_025.app.mjs +++ b/components/test_apps_for_switching_appslug_025/test_apps_for_switching_appslug_025.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 ce75a1502ea96..1f3f85f02b8ef 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -2850,8 +2850,7 @@ importers: components/common_paper: {} - components/commonninja: - specifiers: {} + components/commonninja: {} components/commpeak: dependencies: @@ -9307,8 +9306,7 @@ importers: specifier: ^17.0.45 version: 17.0.45 - components/openai_passthrough: - specifiers: {} + components/openai_passthrough: {} components/opencage: dependencies: @@ -9907,8 +9905,7 @@ importers: specifier: ^1.5.1 version: 1.6.6 - components/phonely: - specifiers: {} + components/phonely: {} components/php_point_of_sale: dependencies: @@ -9934,7 +9931,14 @@ importers: specifier: ^1.2.1 version: 1.6.6 - components/picqer: {} + components/picqer: + dependencies: + '@pipedream/platform': + specifier: ^3.1.0 + version: 3.1.0 + crypto-js: + specifier: ^4.2.0 + version: 4.2.0 components/pidj: dependencies: @@ -13421,8 +13425,7 @@ importers: components/test_apps_for_switching_appslug_009: {} - components/test_apps_for_switching_appslug_025: - specifiers: {} + components/test_apps_for_switching_appslug_025: {} components/testlocally: dependencies: