@pipedream/sendcloud
Version:
Pipedream Sendcloud Components
929 lines (895 loc) • 26.5 kB
JavaScript
import { axios } from "@pipedream/platform";
import constants from "./common/constants.mjs";
export default {
type: "app",
app: "sendcloud",
propDefinitions: {
parcelId: {
type: "string",
label: "Parcel ID",
description: "The unique identifier of the parcel",
async options({ prevContext }) {
const params = {};
if (prevContext?.cursor) params.cursor = prevContext.cursor;
const {
parcels: resources, next,
} = await this.listParcels({
params,
});
return {
context: {
cursor: next,
},
options: resources.map(({
id, name,
}) => ({
value: id,
label: name,
})),
};
},
},
name: {
type: "string",
label: "Name",
description: "Name of the recipient",
},
address: {
type: "string",
label: "Address",
description: "Address of the recipient",
},
city: {
type: "string",
label: "City",
description: "City of the recipient",
optional: true,
},
houseNumber: {
type: "string",
label: "House Number",
description: "House number of the recipient",
},
postalCode: {
type: "string",
label: "Postal Code",
description: "Zip code of the recipient",
},
country: {
type: "string",
label: "country",
description: "Country of the recipient",
options: constants.COUNTRIES,
},
integrationId: {
type: "string",
label: "Integration ID",
description: "The ID of the integration",
async options() {
const integrations = await this.listIntegrations();
return integrations.map(({
id: value, shop_name: label,
}) => ({
value,
label,
}));
},
},
currency: {
type: "string",
label: "Currency",
description: "ISO 4217 currency code",
options: [
"EUR",
"USD",
"GBP",
],
},
senderAddress: {
type: "string",
label: "Sender Address ID",
description: "Specify a sender address ID to display proper allowed_shipping_methods.",
async options() {
const { sender_addresses: senderAddresses } = await this.listSenderAddresses({
params: {
page_size: 100,
},
});
return senderAddresses.map(({
id: value, contact_name: name, email,
}) => ({
value,
label: `${name} (${email})`,
}));
},
},
companyName: {
type: "string",
label: "Company Name",
description: "The company name of the shipment.",
},
createdAt: {
type: "string",
label: "Created At",
description: "Timestamp when the shipment was created in the shop system. Example: `2022-05-07T15:08:12.152000Z`",
},
customsInvoiceNr: {
type: "string",
label: "Customs Invoice Number",
description: "Commercial invoice number",
},
customsShipmentType: {
type: "string",
label: "Customs Shipment Type",
description: "The type of shipment for customs purposes.",
options: [
{
value: "0",
label: "Gift",
},
{
value: "1",
label: "Documents",
},
{
value: "2",
label: "Commercial Goods",
},
{
value: "3",
label: "Commercial Sample",
},
{
value: "4",
label: "Returned Goods",
},
],
},
email: {
type: "string",
label: "Email",
description: "The email of the recipient.",
},
externalOrderId: {
type: "string",
label: "External Order ID",
description: "External order ID assigned by the shop system",
},
externalShipmentId: {
type: "string",
label: "External Shipment ID",
description: "External shipment ID assigned by the shop system",
},
orderNumber: {
type: "string",
label: "Order Number",
description: "Unique order number generated manually or by the shop system",
},
orderStatusId: {
type: "string",
label: "Order Status ID",
description: "Custom internal shop status ID",
},
orderStatusMessage: {
type: "string",
label: "Order Status Message",
description: "User-defined human readable status",
},
parcelItems: {
type: "string[]",
label: "Parcel Items",
description: `Array of JSON objects describing each item in the parcel. Each item must include the following fields:
- \`description\` (string, required): Description of the product. Example: \`Bag\`
- \`hs_code\` (string): Harmonized System Code (<= 12 chars). Example: \`01013000\`
- \`origin_country\` (string | null): ISO 3166-1 alpha-2 country code where the product was produced. Example: \`NL\`
- \`product_id\` (string): Internal product ID. Example: \`1458734634\`
- \`properties\` (object): Key-value pairs with additional product properties (e.g., \`{ "color": "Black" }\`)
- \`quantity\` (integer, required): Number of units (>= 1). Example: \`2\`
- \`sku\` (string): Internal stock keeping unit. Example: \`WW-DR-GR-XS-001\`
- \`value\` (string, required): Price per item as a decimal string. Example: \`19.99\`
- \`weight\` (string | null): Weight per item as a decimal string. Example: \`0.5\`
- \`mid_code\` (string | null): Manufacturer's Identification code. Example: \`NLOZR92MEL\`
- \`material_content\` (string | null): Description of materials. Example: \`100% Cotton\`
- \`intended_use\` (string | null): Intended use of the contents. Example: \`Personal use\`
Example item JSON:
\`\`\`json
{
"description": "Bag",
"hs_code": "01013000",
"origin_country": "NL",
"product_id": "1458734634",
"properties": { "color": "Black" },
"quantity": 2,
"sku": "WW-DR-GR-XS-001",
"value": "19.99",
"weight": "0.5",
"mid_code": "NLOZR92MEL",
"material_content": "100% Cotton",
"intended_use": "Personal use"
}
\`\`\`
Provide each array element as a JSON object string in the UI, or programmatically as an array of objects.`,
},
paymentStatusId: {
type: "string",
label: "Payment Status ID",
description: "Custom internal payment status ID",
},
paymentStatusMessage: {
type: "string",
label: "Payment Status Message",
description: "User-defined payment status",
},
shippingMethodCheckoutName: {
type: "string",
label: "Shipping Method Checkout Name",
description: "Human readable shipping method name",
},
telephone: {
type: "string",
label: "Telephone",
description: "The telephone number of the recipient.",
},
toPostNumber: {
type: "string",
label: "To Post Number",
description: "The post number of the recipient.",
},
servicePointId: {
type: "integer",
label: "Service Point",
description: "The service point ID of the recipient.",
async options({ country }) {
const servicePoints = await this.listServicePoints({
params: {
country,
},
});
return servicePoints.map(({
id: value, name,
}) => ({
value,
label: name,
}));
},
},
toState: {
type: "string",
label: "To State",
description: "The state of the recipient.",
},
totalOrderValue: {
type: "string",
label: "Total Order Value",
description: "Total price of the order (decimal string)",
optional: true,
},
updatedAt: {
type: "string",
label: "Updated At",
description: "Timestamp when the shipment was updated in the shop system. Example: `2022-05-07T15:08:12.152000Z`",
},
weight: {
type: "string",
label: "Weight",
description: "Total weight of the order (decimal string)",
optional: true,
},
checkoutPayload: {
type: "object",
label: "Checkout Payload",
description: `Object capturing checkout selections made by the end-consumer.
Required keys:
- \`sender_address_id\` (integer): The sender address ID associated with the order.
- \`shipping_product\` (object): The shipping product chosen at checkout. Must include:
- \`code\` (string)
- \`name\` (string)
- \`selected_functionalities\` (array): Functionalities selected for this product.
- \`delivery_method_type\` (string): One of "standard_delivery", "nominated_day_delivery", or "same_day_delivery".
- \`delivery_method_data\` (object):
- \`delivery_date\` (string, date-time): Delivery date required by the end-consumer.
- \`formatted_delivery_date\` (string): Human-readable date (e.g., "February 21, 2012").
- \`parcel_handover_date\` (string, date-time): Date the parcel must be handed to the carrier.
Example:
\`\`\`json
{
"sender_address_id": 12345,
"shipping_product": {
"code": "pd-pickup",
"name": "Pickup Point",
"selected_functionalities": ["signature", "age_check"]
},
"delivery_method_type": "nominated_day_delivery",
"delivery_method_data": {
"delivery_date": "2025-02-20T09:00:00Z",
"formatted_delivery_date": "February 20, 2025",
"parcel_handover_date": "2025-02-19T18:00:00Z"
}
}
\`\`\``,
optional: true,
},
customDetails: {
type: "object",
label: "Costs & Tax Details",
description: `Optional object to provide order-level costs and tax numbers.
- \`discount_granted\` (object): Discount granted on the total order
- \`value\` (string | null): Decimal amount (e.g., "3.99"), pattern: [\\d]+(\\.[\\d]+)?
- \`currency\` (string | null): ISO 4217 code (e.g., "EUR")
- \`insurance_costs\` (object): Amount the order is insured for
- \`value\` (string | null): Decimal amount (e.g., "3.99"), pattern: [\\d]+(\\.[\\d]+)?
- \`currency\` (string | null): ISO 4217 code (e.g., "EUR")
- \`freight_costs\` (object): Shipping cost of the order
- \`value\` (string | null): Decimal amount (e.g., "3.99"), pattern: [\\d]+(\\.[\\d]+)?
- \`currency\` (string | null): ISO 4217 code (e.g., "EUR")
- \`other_costs\` (object): Any other costs (e.g., wrapping costs)
- \`value\` (string | null): Decimal amount (e.g., "3.99"), pattern: [\\d]+(\\.[\\d]+)?
- \`currency\` (string | null): ISO 4217 code (e.g., "EUR")
- \`tax_numbers\` (object | null): Tax info about sender, receiver, and importer of records
- \`sender\` (array of Tax Number): Each has { name (string|null), country_code (string|null), value (string|null) }
- \`receiver\` (array of Tax Number): Same structure as sender
- \`importer_of_records\` (array of Tax Number): Same structure as sender
Example:
\`\`\`json
{
"discount_granted": { "value": "3.99", "currency": "EUR" },
"insurance_costs": { "value": "2.50", "currency": "EUR" },
"freight_costs": { "value": "5.00", "currency": "EUR" },
"other_costs": { "value": null, "currency": null },
"tax_numbers": {
"sender": [{ "name": "VAT", "country_code": "NL", "value": "NL987654321B02" }],
"receiver": [],
"importer_of_records": []
}
}
\`\`\``,
optional: true,
},
latitude: {
type: "string",
label: "Latitude",
description: "Reference latitude for distance calculation.",
optional: true,
},
longitude: {
type: "string",
label: "Longitude",
description: "Reference longitude for distance calculation.",
optional: true,
},
neLatitude: {
type: "string",
label: "NE Latitude",
description: "Latitude of the northeast corner of the bounding box.",
optional: true,
},
neLongitude: {
type: "string",
label: "NE Longitude",
description: "Longitude of the northeast corner of the bounding box.",
optional: true,
},
swLatitude: {
type: "string",
label: "SW Latitude",
description: "Latitude of the southwest corner of the bounding box.",
optional: true,
},
swLongitude: {
type: "string",
label: "SW Longitude",
description: "Longitude of the southwest corner of the bounding box.",
optional: true,
},
accessToken: {
type: "string",
label: "Access Token",
description: "JWT containing user 'id' or 'iid' (integration ID), or a public API key.",
optional: true,
},
returnId: {
type: "string",
label: "Return ID",
description: "The unique identifier of the return",
async options({
fromDate, toDate,
}) {
if (!fromDate || !toDate) {
return [];
}
const { data } = await this.listReturns({
params: {
from_date: fromDate,
to_date: toDate,
},
});
return data.map(({
reason: {
id: value,
description: label,
},
}) => ({
value,
label,
}));
},
},
addressSetup: {
type: "object",
label: "From Address",
description: `Required fields:
- \`name\` (string): Name associated with the address. Example: \`John Doe\`
- \`address_line_1\` (string): First line of the address. Example: \`Stadhuisplein\`
- \`postal_code\` (string): Zip code. Example: \`1013 AB\`
- \`city\` (string): City. Example: \`Eindhoven\`
- \`country_code\` (string): ISO 3166-1 alpha-2 code. Example: \`NL\`
Optional fields:
- \`company_name\` (string): Company name. Example: \`Sendcloud\`
- \`house_number\` (string): House number. Example: \`50\`
- \`address_line_2\` (string): Additional info. Example: \`Apartment 17B\`
- \`po_box\` (string | null): PO box code
- \`state_province_code\` (string): ISO 3166-2 code. Example: \`IT-RM\`
- \`email\` (string): Email. Example: \`johndoe@gmail.com\`
- \`phone_number\` (string): Phone number. Example: \`+319881729999\`
Example:
\`\`\`json
{
"name": "John Doe",
"address_line_1": "Stadhuisplein",
"postal_code": "1013 AB",
"city": "Eindhoven",
"country_code": "NL"
}
\`\`\`
`,
},
shipWith: {
type: "object",
label: "Ship With",
description: `Shipping specifications chosen for the return.
Fields:
- type (string): How the carrier/method is selected. One of \`shipping_option_code\` or \`shipping_product_code\` (default is \`shipping_product_code\`).
- \`shipping_option_code\` (string): Required if type = \`shipping_option_code\`. Example: \`dpd:return/return\`
- \`shipping_product_code\` (string): Required if type = \`shipping_product_code\`. Example: \`dpd:return/return\`
- \`functionalities\` (object): Shipping functionalities. Provide only when type = \`shipping_product_code\`.
- \`contract\` (integer): Contract ID to ship the return with.
- \`dimensions\` (object):
- \`length\` (number, >= 0)
- \`width\` (number, >= 0)
- \`height\` (number, >= 0)
- \`unit\` (string): One of \`cm\`, \`mm\`, \`m\`, \`yd\`, \`ft\`, \`in\`
- \`weight\` (object):
- \`value\` (number, > 0)
- \`unit\` (string): One of \`kg\`, \`g\`, \`lbs\`, \`oz\`
Example:
\`\`\`json
{
"type": "shipping_option_code",
"shipping_option_code": "dpd:return/return",
"contract": 1234,
"dimensions": { "length": 15, "width": 20.5, "height": 37, "unit": "mm" },
"weight": { "value": 14.5, "unit": "g" }
}
\`\`\``,
},
dimensionsLength: {
type: "integer",
label: "Dimensions Length",
description: "Length in the specified unit.",
optional: true,
},
dimensionsWidth: {
type: "integer",
label: "Dimensions Width",
description: "Width in the specified unit.",
optional: true,
},
dimensionsHeight: {
type: "integer",
label: "Dimensions Height",
description: "Height in the specified unit.",
optional: true,
},
dimensionsUnit: {
type: "string",
label: "Dimensions Unit",
description: "Unit of the dimensions.",
options: [
"cm",
"mm",
"m",
"yd",
"ft",
"in",
],
optional: true,
},
weightValue: {
type: "integer",
label: "Weight Value",
description: "Weight value in the specified unit.",
},
weightUnit: {
type: "string",
label: "Weight Unit",
description: "Unit of the weight.",
options: [
"kg",
"g",
"lbs",
"oz",
],
},
brandDomain: {
type: "string",
label: "Brand Domain",
description: "Domain of the brand configured for your return portal (e.g., `my-shop`).",
async options({
mapper = ({
id: value,
name: label,
}) => ({
value,
label,
}),
}) {
const { brands } = await this.listBrands();
return brands.map(mapper);
},
},
shippingMethodId: {
type: "string",
label: "Shipping Method ID",
description: "The unique identifier of the shipping method",
async options() {
const { shipping_methods: data } = await this.listShippingMethods();
return data.map(({
id: value,
name: label,
}) => ({
value,
label,
}));
},
},
fromDate: {
type: "string",
label: "From Date",
description: "Excludes all returns before this datetime. Example: `2022-04-06 00:00:00`",
},
toDate: {
type: "string",
label: "To Date",
description: "Excludes all returns after this datetime. Example: `2022-04-07 00:00:00`",
},
},
methods: {
getMockUrl(path, versionPath = constants.VERSION_PATH.MOCK_V2) {
return `${constants.MOCK_BASE_URL}${versionPath}${path}`;
},
getUrl(path, versionPath = constants.VERSION_PATH.V2, baseUrl = constants.BASE_URL) {
return `${baseUrl}${versionPath}${path}`;
},
getAuth(auth) {
const {
public_key: username,
secret_key: password,
} = this.$auth;
return {
...auth,
username,
password,
};
},
getHeaders(headers) {
const {
username,
password,
} = this.getAuth();
const token = Buffer.from(`${username}:${password}`).toString("base64");
return {
...headers,
Authorization: `Basic ${token}`,
};
},
_makeRequest({
$ = this,
path, auth, headers, versionPath,
mockPath, mockVersionPath,
baseUrl, hasHeadersAuth = false,
...otherOpts
} = {}) {
return axios($, {
...otherOpts,
headers,
url: constants.USE_MOCK
? this.getMockUrl(mockPath, mockVersionPath)
: this.getUrl(path, versionPath, baseUrl),
...(hasHeadersAuth
? {
headers: this.getHeaders(headers),
}
: {
auth: this.getAuth(auth),
}
),
});
},
post(args = {}) {
return this._makeRequest({
method: "POST",
...args,
});
},
put(args = {}) {
return this._makeRequest({
method: "PUT",
...args,
});
},
createParcel(args = {}) {
return this.post({
path: "/parcels",
...args,
});
},
updateParcel({
id, ...args
}) {
return this.put({
path: `/parcels/${id}`,
...args,
});
},
listParcels(args = {}) {
return this._makeRequest({
path: "/parcels",
mockPath: "/299107074/parcels",
...args,
});
},
getParcel({
parcelId, ...args
} = {}) {
return this._makeRequest({
path: `/parcels/${parcelId}`,
mockPath: `/299107074/parcels/${parcelId}`,
...args,
});
},
listIntegrations(args = {}) {
return this._makeRequest({
path: "/integrations",
mockPath: "/299107069/integrations",
...args,
});
},
listIntegrationShipments({
integrationId, ...args
} = {}) {
return this._makeRequest({
path: `/integrations/${integrationId}/shipments`,
mockPath: `/299107069/integrations/${integrationId}/shipments`,
...args,
});
},
upsertIntegrationShipment({
integrationId, ...args
} = {}) {
return this.post({
path: `/integrations/${integrationId}/shipments`,
mockPath: `/299107069/integrations/${integrationId}/shipments`,
...args,
});
},
listParcelDocuments({
type, ...args
} = {}) {
return this._makeRequest({
versionPath: constants.VERSION_PATH.V3,
mockVersionPath: constants.VERSION_PATH.MOCK_V3,
path: `/parcel-documents/${type}`,
mockPath: `/299107072/parcel-documents/${type}`,
hasHeadersAuth: true,
paramsSerializer: (params) => {
return Object.entries(params)
.map(([
key,
value,
]) => {
if (Array.isArray(value)) {
return value.map((id) => `${key}=${id}`).join("&");
}
return `${key}=${value}`;
})
.join("&");
},
...args,
});
},
getLabel({
parcelId, ...args
} = {}) {
return this._makeRequest({
path: `/labels/${parcelId}`,
mockPath: `/299107071/labels/${parcelId}`,
...args,
});
},
bulkPDFLabelPrinting(args = {}) {
return this.post({
path: "/labels",
mockPath: "/299107071/labels",
...args,
});
},
listServicePoints(args = {}) {
return this._makeRequest({
hasHeadersAuth: true,
baseUrl: constants.SERVICE_POINTS_BASE_URL,
path: "/service-points",
mockPath: "/299107080/service-points",
...args,
});
},
getServicePoint({
servicePointId, ...args
} = {}) {
return this._makeRequest({
hasHeadersAuth: true,
baseUrl: constants.SERVICE_POINTS_BASE_URL,
path: `/service-points/${servicePointId}`,
mockPath: `/299107080/service-points/${servicePointId}`,
...args,
});
},
listServicePointCarriers(args = {}) {
return this._makeRequest({
hasHeadersAuth: true,
baseUrl: constants.SERVICE_POINTS_BASE_URL,
path: "/carriers",
mockPath: "/299107080/carriers",
...args,
});
},
listSenderAddresses(args = {}) {
return this._makeRequest({
path: "/user/addresses/sender",
mockPath: "/299107079/user/addresses/sender",
...args,
});
},
getSenderAddress({
senderAddressId, ...args
} = {}) {
return this._makeRequest({
path: `/user/addresses/sender/${senderAddressId}`,
mockPath: `/299107079/user/addresses/sender/${senderAddressId}`,
...args,
});
},
listParcelStatuses(args = {}) {
return this._makeRequest({
versionPath: constants.VERSION_PATH.V3,
mockVersionPath: constants.VERSION_PATH.MOCK_V3,
path: "/parcels/statuses",
mockPath: "/299107073/parcels/statuses",
...args,
});
},
listReturns(args = {}) {
return this._makeRequest({
versionPath: constants.VERSION_PATH.V3,
mockVersionPath: constants.VERSION_PATH.MOCK_V3,
path: "/returns",
mockPath: "/299107077/returns",
...args,
});
},
getReturn({
returnId, ...args
} = {}) {
return this._makeRequest({
versionPath: constants.VERSION_PATH.V3,
mockVersionPath: constants.VERSION_PATH.MOCK_V3,
path: `/returns/${returnId}`,
mockPath: `/299107077/returns/${returnId}`,
...args,
});
},
createReturn(args = {}) {
return this.post({
versionPath: constants.VERSION_PATH.V3,
mockVersionPath: constants.VERSION_PATH.MOCK_V3,
path: "/returns",
mockPath: "/299107077/returns",
...args,
});
},
validateReturn(args = {}) {
return this.post({
versionPath: constants.VERSION_PATH.V3,
mockVersionPath: constants.VERSION_PATH.MOCK_V3,
path: "/returns/validate",
mockPath: "/299107077/returns/validate",
...args,
});
},
getReturnPortalSettings({
brandDomain, ...args
} = {}) {
return this._makeRequest({
path: `/brand/${brandDomain}/return-portal`,
mockPath: `/299107078/brand/${brandDomain}/return-portal`,
...args,
});
},
getCurrentUser(args = {}) {
return this._makeRequest({
versionPath: constants.VERSION_PATH.V3,
mockVersionPath: constants.VERSION_PATH.MOCK_V3,
path: "/user/auth/metadata",
mockPath: "/979441214/user/auth/metadata",
...args,
});
},
listShippingMethods(args = {}) {
return this._makeRequest({
path: "/shipping_methods",
mockPath: "/299107081/shipping_methods",
...args,
});
},
getShippingMethod({
shippingMethodId, ...args
} = {}) {
return this._makeRequest({
path: `/shipping_methods/${shippingMethodId}`,
mockPath: `/299107081/shipping_methods/${shippingMethodId}`,
...args,
});
},
listBrands(args = {}) {
return this._makeRequest({
path: "/brands",
mockPath: "/299107066/brands",
...args,
});
},
async paginate({
requester,
requesterArgs = {},
resultsKey,
maxRequests = 3,
} = {}) {
const results = [];
let requests = 0;
let cursor;
do {
const response = await requester({
...requesterArgs,
params: {
...(requesterArgs.params || {}),
cursor,
},
});
const items = resultsKey
? response[resultsKey]
: response;
if (Array.isArray(items)) {
results.push(...items);
}
const next = response?.next;
if (next) {
const url = new URL(next);
cursor = url.searchParams.get("cursor");
}
if (typeof maxRequests === "number" && requests >= maxRequests) {
break;
}
requests++;
} while (cursor);
return results;
},
},
};