From ddd569d3fb24b553d3ce4c4d7525a716b9675d15 Mon Sep 17 00:00:00 2001 From: Jorge Cortes Date: Fri, 20 Sep 2024 17:45:10 -0500 Subject: [PATCH 1/2] Simla: new action and source components --- .../create-customer/create-customer.mjs | 115 ++++++++++ .../actions/create-order/create-order.mjs | 195 ++++++++++++++++ components/simla_com/common/constants.mjs | 29 +++ components/simla_com/common/utils.mjs | 107 +++++++++ components/simla_com/package.json | 7 +- components/simla_com/simla_com.app.mjs | 213 +++++++++++++++++- .../simla_com/sources/common/polling.mjs | 120 ++++++++++ .../sources/new-customer/new-customer.mjs | 41 ++++ .../simla_com/sources/new-order/new-order.mjs | 41 ++++ .../updated-customer/updated-customer.mjs | 44 ++++ pnpm-lock.yaml | 7 +- 11 files changed, 911 insertions(+), 8 deletions(-) create mode 100644 components/simla_com/actions/create-customer/create-customer.mjs create mode 100644 components/simla_com/actions/create-order/create-order.mjs create mode 100644 components/simla_com/common/constants.mjs create mode 100644 components/simla_com/common/utils.mjs create mode 100644 components/simla_com/sources/common/polling.mjs create mode 100644 components/simla_com/sources/new-customer/new-customer.mjs create mode 100644 components/simla_com/sources/new-order/new-order.mjs create mode 100644 components/simla_com/sources/updated-customer/updated-customer.mjs diff --git a/components/simla_com/actions/create-customer/create-customer.mjs b/components/simla_com/actions/create-customer/create-customer.mjs new file mode 100644 index 0000000000000..d67ac9ae5c421 --- /dev/null +++ b/components/simla_com/actions/create-customer/create-customer.mjs @@ -0,0 +1,115 @@ +import app from "../../simla_com.app.mjs"; + +export default { + key: "simla_com-create-customer", + name: "Create Customer", + description: "Creates a new customer profile. [See the documentation](https://docs.simla.com/Developers/API/APIVersions/APIv5#post--api-v5-customers-create).", + version: "0.0.1", + type: "action", + props: { + app, + firstName: { + type: "string", + label: "First Name", + description: "The name of the customer.", + }, + lastName: { + type: "string", + label: "Last Name", + description: "The last name of the customer.", + optional: true, + }, + phones: { + type: "string[]", + label: "Phone Numbers", + description: "The phone numbers of the customer.", + optional: true, + }, + email: { + type: "string", + label: "Email", + description: "The email address of the customer.", + optional: true, + }, + postalCode: { + type: "string", + label: "Postal Code", + description: "The postal code of the customer.", + optional: true, + }, + countryIso: { + optional: true, + propDefinition: [ + app, + "countryIso", + ], + }, + region: { + type: "string", + label: "Region", + description: "The region of the customer.", + optional: true, + }, + city: { + type: "string", + label: "City", + description: "The city of the customer.", + optional: true, + }, + street: { + type: "string", + label: "Street", + description: "The street of the customer.", + optional: true, + }, + }, + methods: { + createCustomer(args = {}) { + return this.app.post({ + path: "/customers/create", + ...args, + }); + }, + }, + async run({ $ }) { + const { + createCustomer, + firstName, + lastName, + phones, + email, + postalCode, + countryIso, + region, + city, + street, + } = this; + + const response = await createCustomer({ + $, + data: { + customer: JSON.stringify({ + firstName, + lastName, + email, + address: { + index: postalCode, + countryIso, + region, + city, + street, + }, + ...(phones?.length && { + phones: phones.map((number) => ({ + number, + })), + }), + }), + }, + }); + + $.export("$summary", `Successfully created customer with ID \`${response.id}\`.`); + + return response; + }, +}; diff --git a/components/simla_com/actions/create-order/create-order.mjs b/components/simla_com/actions/create-order/create-order.mjs new file mode 100644 index 0000000000000..b1e0d688d6f75 --- /dev/null +++ b/components/simla_com/actions/create-order/create-order.mjs @@ -0,0 +1,195 @@ +import app from "../../simla_com.app.mjs"; +import utils from "../../common/utils.mjs"; + +export default { + key: "simla_com-create-order", + name: "Create Order", + description: "Creates a new order with customer and order details. [See the documentation](https://docs.simla.com/Developers/API/APIVersions/APIv5#post--api-v5-orders-create).", + version: "0.0.1", + type: "action", + props: { + app, + site: { + propDefinition: [ + app, + "site", + ], + }, + customerType: { + propDefinition: [ + app, + "customerType", + ], + }, + customerId: { + propDefinition: [ + app, + "customerId", + ({ customerType }) => ({ + customerType, + }), + ], + }, + countryIso: { + propDefinition: [ + app, + "countryIso", + ], + }, + orderType: { + propDefinition: [ + app, + "orderType", + ], + }, + deliveryCost: { + type: "string", + label: "Delivery Cost", + description: "The cost of delivery.", + }, + deliveryNetCost: { + type: "string", + label: "Delivery Net Cost", + description: "The net cost of delivery.", + }, + numberOfItems: { + type: "integer", + label: "Number Of Items", + description: "The number of items to be ordered.", + default: 1, + reloadProps: true, + }, + }, + methods: { + itemsPropsMapper(prefix) { + const { + [`${prefix}initialPrice`]: initialPrice, + [`${prefix}quantity`]: quantity, + [`${prefix}comment`]: comment, + [`${prefix}purchasePrice`]: purchasePrice, + [`${prefix}productName`]: productName, + [`${prefix}discountManualAmount`]: discountManualAmount, + [`${prefix}discountManualPercent`]: discountManualPercent, + } = this; + + return { + initialPrice, + quantity, + comment, + purchasePrice, + productName, + discountManualAmount, + discountManualPercent, + }; + }, + getItemsPropDefinitions({ + prefix, + label, + } = {}) { + return { + [`${prefix}initialPrice`]: { + type: "string", + label: `${label} - Initial Price`, + description: "The initial price of the item.", + optional: true, + }, + [`${prefix}quantity`]: { + type: "string", + label: `${label} - Quantity`, + description: "The quantity of the item.", + optional: true, + }, + [`${prefix}comment`]: { + type: "string", + label: `${label} - Comment`, + description: "The comment for the item.", + optional: true, + }, + [`${prefix}purchasePrice`]: { + type: "string", + label: `${label} - Purchase Price`, + description: "The purchase price of the item.", + optional: true, + }, + [`${prefix}productName`]: { + type: "string", + label: `${label} - Product Name`, + description: "The name of the product.", + optional: true, + }, + [`${prefix}discountManualAmount`]: { + type: "string", + label: `${label} - Discount Manual Amount`, + description: "The manual discount amount for the item.", + optional: true, + }, + [`${prefix}discountManualPercent`]: { + type: "string", + label: `${label} - Discount Manual Percent`, + description: "The manual discount percent for the item.", + optional: true, + }, + }; + }, + createOrder(args = {}) { + return this.app.post({ + path: "/orders/create", + ...args, + }); + }, + }, + async additionalProps() { + const { + numberOfItems, + getItemsPropDefinitions, + } = this; + + return utils.getAdditionalProps({ + numberOfFields: numberOfItems, + fieldName: "item", + getPropDefinitions: getItemsPropDefinitions, + }); + }, + async run({ $ }) { + const { + numberOfItems, + itemsPropsMapper, + createOrder, + countryIso, + orderType, + site, + customerType, + customerId, + deliveryCost, + deliveryNetCost, + } = this; + + const response = await createOrder({ + $, + data: { + site, + customer: JSON.stringify({ + customerType, + customerId, + }), + order: JSON.stringify({ + countryIso, + orderType, + customerType, + customerId, + delivery: { + cost: deliveryCost, + netCost: deliveryNetCost, + }, + items: utils.getFieldsProps({ + numberOfFields: numberOfItems, + fieldName: "item", + propsMapper: itemsPropsMapper, + }), + }), + }, + }); + $.export("$summary", `Successfully created order with ID \`${response.id}\`.`); + return response; + }, +}; diff --git a/components/simla_com/common/constants.mjs b/components/simla_com/common/constants.mjs new file mode 100644 index 0000000000000..01c27eabff9d9 --- /dev/null +++ b/components/simla_com/common/constants.mjs @@ -0,0 +1,29 @@ +const SUBDOMAIN_PLACEHOLDER = "{subdomain}"; +const VERSION_PLACEHOLDER = "{version}"; +const BASE_URL = `https://${SUBDOMAIN_PLACEHOLDER}.simla.com/api/${VERSION_PLACEHOLDER}`; +const IS_FIRST_RUN = "isFirstRun"; +const LAST_DATE_AT = "lastDateAt"; +const DEFAULT_LIMIT = 20; +const DEFAULT_MAX = 200; + +const CUSTOMER_TYPE = { + CUSTOMER: { + label: "Customer", + value: "customer", + }, + CORPORATE: { + label: "Corporate Customer", + value: "customer_corporate", + }, +}; + +export default { + SUBDOMAIN_PLACEHOLDER, + VERSION_PLACEHOLDER, + BASE_URL, + IS_FIRST_RUN, + CUSTOMER_TYPE, + LAST_DATE_AT, + DEFAULT_LIMIT, + DEFAULT_MAX, +}; diff --git a/components/simla_com/common/utils.mjs b/components/simla_com/common/utils.mjs new file mode 100644 index 0000000000000..aced76b9a7d22 --- /dev/null +++ b/components/simla_com/common/utils.mjs @@ -0,0 +1,107 @@ +import constants from "./constants.mjs"; + +function getNestedProperty(obj, propertyString) { + const properties = propertyString.split("."); + return properties.reduce((prev, curr) => prev?.[curr], obj); +} + +async function iterate(iterations) { + const items = []; + for await (const item of iterations) { + items.push(item); + } + return items; +} + +function toPascalCase(str) { + return str.replace(/(\w)(\w*)/g, (_, group1, group2) => + group1.toUpperCase() + group2.toLowerCase()); +} + +function getMetadataProp({ + index, fieldName, prefix, label, +} = {}) { + const fieldIdx = index + 1; + const key = `${fieldName}${fieldIdx}`; + return { + prefix: prefix + ? `${prefix}${key}${constants.SEP}` + : `${key}${constants.SEP}`, + label: label + ? `${label} - ${toPascalCase(fieldName)} ${fieldIdx}` + : `${toPascalCase(fieldName)} ${fieldIdx}`, + }; +} + +function getFieldProps({ + index, fieldName, prefix, + propsMapper = function propsMapper(prefix) { + const { [`${prefix}name`]: name } = this; + return { + name, + }; + }, +} = {}) { + const { prefix: metaPrefix } = getMetadataProp({ + index, + fieldName, + prefix, + }); + return propsMapper(metaPrefix); +} + +function getFieldsProps({ + numberOfFields, fieldName, propsMapper, prefix, +} = {}) { + return Array.from({ + length: numberOfFields, + }).map((_, index) => getFieldProps({ + index, + fieldName, + prefix, + propsMapper, + })); +} + +function getAdditionalProps({ + numberOfFields, fieldName, prefix, label, + getPropDefinitions = async ({ + prefix, label, + }) => ({ + [`${prefix}name`]: { + type: "string", + label, + description: "The name of the field.", + optional: true, + }, + }), +} = {}) { + return Array.from({ + length: numberOfFields, + }).reduce(async (reduction, _, index) => { + const { + prefix: metaPrefix, + label: metaLabel, + } = getMetadataProp({ + index, + fieldName, + prefix, + label, + }); + + return { + ...await reduction, + ...await getPropDefinitions({ + prefix: metaPrefix, + label: metaLabel, + }), + }; + }, {}); +} + +export default { + getNestedProperty, + iterate, + getFieldsProps, + getAdditionalProps, +}; diff --git a/components/simla_com/package.json b/components/simla_com/package.json index 509338b0e3a34..3eeec870d5d10 100644 --- a/components/simla_com/package.json +++ b/components/simla_com/package.json @@ -1,6 +1,6 @@ { "name": "@pipedream/simla_com", - "version": "0.0.1", + "version": "0.1.0", "description": "Pipedream Simla.com Components", "main": "simla_com.app.mjs", "keywords": [ @@ -11,5 +11,8 @@ "author": "Pipedream (https://pipedream.com/)", "publishConfig": { "access": "public" + }, + "dependencies": { + "@pipedream/platform": "3.0.1" } -} \ No newline at end of file +} diff --git a/components/simla_com/simla_com.app.mjs b/components/simla_com/simla_com.app.mjs index a470d7d7f4ffc..47dd69a43cac9 100644 --- a/components/simla_com/simla_com.app.mjs +++ b/components/simla_com/simla_com.app.mjs @@ -1,11 +1,216 @@ +import { axios } from "@pipedream/platform"; +import constants from "./common/constants.mjs"; +import utils from "./common/utils.mjs"; + export default { type: "app", app: "simla_com", - propDefinitions: {}, + propDefinitions: { + countryIso: { + type: "string", + label: "Country ISO", + description: "The ISO code of the customer's country (ISO 3166-1 alpha-2).", + async options() { + const { countriesIso } = await this.listCountries(); + return countriesIso; + }, + }, + orderType: { + type: "string", + label: "Order Type", + description: "The type of the order.", + async options() { + const { orderTypes } = await this.listOrderTypes(); + return Object.values(orderTypes) + .map(({ + code: value, name: label, + }) => ({ + label, + value, + })); + }, + }, + site: { + type: "string", + label: "Site", + description: "The site of the order.", + async options() { + const { sites } = await this.listSites(); + return Object.values(sites) + .map(({ + id: value, name: label, + }) => ({ + label, + value, + })); + }, + }, + customerType: { + type: "string", + label: "Customer Type", + description: "The type of the customer.", + options: Object.values(constants.CUSTOMER_TYPE), + }, + customerId: { + type: "string", + label: "Customer ID", + description: "The unique identifier for the customer.", + async options({ + page, customerType, params, + }) { + const isCustomer = customerType === constants.CUSTOMER_TYPE.CUSTOMER.value; + const args = { + params: { + ...params, + page: page + 1, + }, + }; + const fieldName = isCustomer + ? "customers" + : "customersCorporate"; + const { [fieldName]: customers } = + isCustomer + ? await this.listCustomers(args) + : await this.listCorporateCustomers(args); + return customers.map(({ + id: value, firstName, lastName, site, + }) => ({ + label: isCustomer + ? [ + firstName, + lastName, + ].join(" ") + : site, + value, + })); + }, + }, + }, methods: { - // this.$auth contains connected account data - authKeys() { - console.log(Object.keys(this.$auth)); + getUrl(path) { + const { + subdomain, + version, + } = this.$auth; + const baseUrl = constants.BASE_URL + .replace(constants.SUBDOMAIN_PLACEHOLDER, subdomain) + .replace(constants.VERSION_PLACEHOLDER, version); + return `${baseUrl}${path}`; + }, + getHeaders(headers) { + return { + ...headers, + "X-API-KEY": this.$auth.api_key, + }; + }, + _makeRequest({ + $ = this, path, headers, ...args + } = {}) { + return axios($, { + ...args, + url: this.getUrl(path), + headers: this.getHeaders(headers), + }); + }, + post(args = {}) { + return this._makeRequest({ + method: "POST", + ...args, + }); + }, + listCountries(args = {}) { + return this._makeRequest({ + path: "/reference/countries", + ...args, + }); + }, + listOrderTypes(args = {}) { + return this._makeRequest({ + path: "/reference/order-types", + ...args, + }); + }, + listSites(args = {}) { + return this._makeRequest({ + path: "/reference/sites", + ...args, + }); + }, + listCustomers(args = {}) { + return this._makeRequest({ + path: "/customers", + ...args, + }); + }, + listCorporateCustomers(args = {}) { + return this._makeRequest({ + path: "/customers-corporate", + ...args, + }); + }, + listCustomerChangeHistory(args = {}) { + return this._makeRequest({ + path: "/customers/history", + ...args, + }); + }, + listOrders(args = {}) { + return this._makeRequest({ + path: "/orders", + ...args, + }); + }, + async *getIterations({ + resourcesFn, resourcesFnArgs, resourceName, + lastDateAt, dateField, + max = constants.DEFAULT_MAX, + }) { + let page = 1; + let resourcesCount = 0; + + while (true) { + const response = + await resourcesFn({ + ...resourcesFnArgs, + params: { + ...resourcesFnArgs?.params, + page, + }, + }); + + const nextResources = utils.getNestedProperty(response, resourceName); + + if (!nextResources?.length) { + console.log("No more resources found"); + return; + } + + for (const resource of nextResources) { + const isDateGreater = + lastDateAt + && Date.parse(resource[dateField]) >= Date.parse(lastDateAt); + + if (!lastDateAt || isDateGreater) { + yield resource; + resourcesCount += 1; + } + + if (resourcesCount >= max) { + console.log("Reached max resources"); + return; + } + } + + if (nextResources.length < constants.DEFAULT_LIMIT) { + console.log("No next page found"); + return; + } + + page += 1; + } + }, + paginate(args = {}) { + return utils.iterate(this.getIterations(args)); }, }, }; diff --git a/components/simla_com/sources/common/polling.mjs b/components/simla_com/sources/common/polling.mjs new file mode 100644 index 0000000000000..d56c7d764f974 --- /dev/null +++ b/components/simla_com/sources/common/polling.mjs @@ -0,0 +1,120 @@ +import { + ConfigurationError, + DEFAULT_POLLING_SOURCE_TIMER_INTERVAL, +} from "@pipedream/platform"; +import app from "../../simla_com.app.mjs"; +import constants from "../../common/constants.mjs"; + +export default { + props: { + app, + db: "$.service.db", + timer: { + type: "$.interface.timer", + label: "Polling Schedule", + description: "How often to poll the API", + default: { + intervalSeconds: DEFAULT_POLLING_SOURCE_TIMER_INTERVAL, + }, + }, + }, + hooks: { + deploy() { + this.setIsFirstRun(true); + }, + }, + methods: { + isDescendingOrder() { + return true; + }, + generateMeta() { + throw new ConfigurationError("generateMeta is not implemented"); + }, + setIsFirstRun(value) { + this.db.set(constants.IS_FIRST_RUN, value); + }, + getIsFirstRun() { + return this.db.get(constants.IS_FIRST_RUN); + }, + setLastDateAt(value) { + this.db.set(constants.LAST_DATE_AT, value); + }, + getLastDateAt() { + return this.db.get(constants.LAST_DATE_AT); + }, + getDateField() { + throw new ConfigurationError("getDateField is not implemented"); + }, + sortFn() { + return; + }, + isResourceRelevant() { + return true; + }, + getResourceName() { + throw new ConfigurationError("getResourceName is not implemented"); + }, + getResourcesFn() { + throw new ConfigurationError("getResourcesFn is not implemented"); + }, + getResourcesFnArgs() { + throw new ConfigurationError("getResourcesFnArgs is not implemented"); + }, + processResource(resource) { + const meta = this.generateMeta(resource); + this.$emit(resource, meta); + }, + }, + async run() { + const { + app, + getDateField, + getLastDateAt, + getResourcesFn, + getResourcesFnArgs, + getResourceName, + processResource, + getIsFirstRun, + setIsFirstRun, + setLastDateAt, + isDescendingOrder, + } = this; + + const isFirstRun = getIsFirstRun(); + const dateField = getDateField(); + const lastDateAt = getLastDateAt(); + const isDescending = isDescendingOrder(); + + const otherArgs = isFirstRun + ? { + max: constants.DEFAULT_LIMIT, + } + : { + dateField, + lastDateAt, + }; + + const resources = await app.paginate({ + resourcesFn: getResourcesFn(), + resourcesFnArgs: getResourcesFnArgs(), + resourceName: getResourceName(), + ...otherArgs, + }); + + const orderedResources = isDescending + ? resources + : Array.from(resources).reverse(); + orderedResources.forEach(processResource); + + if (resources.length) { + const latestResource = orderedResources[0]; + if (latestResource) { + setLastDateAt(latestResource[dateField]); + } + } + + if (isFirstRun) { + setIsFirstRun(false); + } + }, +}; diff --git a/components/simla_com/sources/new-customer/new-customer.mjs b/components/simla_com/sources/new-customer/new-customer.mjs new file mode 100644 index 0000000000000..5c6941b64998b --- /dev/null +++ b/components/simla_com/sources/new-customer/new-customer.mjs @@ -0,0 +1,41 @@ +import common from "../common/polling.mjs"; +import constants from "../../common/constants.mjs"; + +export default { + ...common, + key: "simla_com-new-customer", + name: "New Customer", + description: "Emit new event when a new customer is created. [See the documentation](https://docs.simla.com/Developers/API/APIVersions/APIv5#get--api-v5-customers).", + version: "0.0.1", + type: "source", + dedupe: "unique", + methods: { + ...common.methods, + getDateField() { + return "createdAt"; + }, + getResourceName() { + return "customers"; + }, + getResourcesFn() { + return this.app.listCustomers; + }, + getResourcesFnArgs() { + return { + params: { + limit: constants.DEFAULT_LIMIT, + filter: { + dateFrom: this.getLastDateAt(), + }, + }, + }; + }, + generateMeta(resource) { + return { + id: resource.id, + summary: `New Customer: ${resource.firstName || resource.site}`, + ts: Date.parse(resource.createdAt), + }; + }, + }, +}; diff --git a/components/simla_com/sources/new-order/new-order.mjs b/components/simla_com/sources/new-order/new-order.mjs new file mode 100644 index 0000000000000..a26ea29a17710 --- /dev/null +++ b/components/simla_com/sources/new-order/new-order.mjs @@ -0,0 +1,41 @@ +import common from "../common/polling.mjs"; +import constants from "../../common/constants.mjs"; + +export default { + ...common, + key: "simla_com-new-order", + name: "New Order", + description: "Emit new event when an order is created. [See the documentation](https://docs.simla.com/Developers/API/APIVersions/APIv5#get--api-v5-orders).", + version: "0.0.1", + type: "source", + dedupe: "unique", + methods: { + ...common.methods, + getDateField() { + return "createdAt"; + }, + getResourceName() { + return "orders"; + }, + getResourcesFn() { + return this.app.listOrders; + }, + getResourcesFnArgs() { + return { + params: { + limit: constants.DEFAULT_LIMIT, + filter: { + createdAtFrom: this.getLastDateAt(), + }, + }, + }; + }, + generateMeta(resource) { + return { + id: resource.id, + summary: `New Order: ${resource.id}`, + ts: Date.parse(resource.createdAt), + }; + }, + }, +}; diff --git a/components/simla_com/sources/updated-customer/updated-customer.mjs b/components/simla_com/sources/updated-customer/updated-customer.mjs new file mode 100644 index 0000000000000..da2ad005cc7bd --- /dev/null +++ b/components/simla_com/sources/updated-customer/updated-customer.mjs @@ -0,0 +1,44 @@ +import common from "../common/polling.mjs"; +import constants from "../../common/constants.mjs"; + +export default { + ...common, + key: "simla_com-updated-customer", + name: "Updated Customer", + description: "Emit new event when a customer is updated. [See the documentation](https://docs.simla.com/Developers/API/APIVersions/APIv5#get--api-v5-customers).", + version: "0.0.1", + type: "source", + dedupe: "unique", + methods: { + ...common.methods, + isDescendingOrder() { + return false; + }, + getDateField() { + return "createdAt"; + }, + getResourceName() { + return "history"; + }, + getResourcesFn() { + return this.app.listCustomerChangeHistory; + }, + getResourcesFnArgs() { + return { + params: { + limit: constants.DEFAULT_LIMIT, + filter: { + startDate: this.getLastDateAt(), + }, + }, + }; + }, + generateMeta(resource) { + return { + id: resource.id, + summary: `Updated Customer: ${resource.customer?.id}`, + ts: Date.parse(resource.createdAt), + }; + }, + }, +}; diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 64e0e710fe76d..a9d77d2d6523d 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -8929,7 +8929,10 @@ importers: '@pipedream/platform': 1.6.2 components/simla_com: - specifiers: {} + specifiers: + '@pipedream/platform': 3.0.1 + dependencies: + '@pipedream/platform': 3.0.1 components/simple_analytics: specifiers: {} @@ -17584,7 +17587,7 @@ packages: /@pipedream/platform/3.0.1: resolution: {integrity: sha512-xja1ZHUR/DpOQZZJY39daml8q1ZMzg8wKYwYbyxVPs7MiMqneHM7Bz+Lgj/QrjbNissIKsRSGXmkXbT+Y10L0w==} dependencies: - axios: 1.7.7 + axios: 1.7.5 fp-ts: 2.16.9 io-ts: 2.2.21_fp-ts@2.16.9 querystring: 0.2.1 From ec4c8d444d3a84a8d8e0d2a04052c2c475c256e8 Mon Sep 17 00:00:00 2001 From: Leo Vu Date: Mon, 23 Sep 2024 09:00:32 +0700 Subject: [PATCH 2/2] Improve source summary --- components/simla_com/sources/new-customer/new-customer.mjs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/simla_com/sources/new-customer/new-customer.mjs b/components/simla_com/sources/new-customer/new-customer.mjs index 5c6941b64998b..300d17ee1feda 100644 --- a/components/simla_com/sources/new-customer/new-customer.mjs +++ b/components/simla_com/sources/new-customer/new-customer.mjs @@ -33,7 +33,7 @@ export default { generateMeta(resource) { return { id: resource.id, - summary: `New Customer: ${resource.firstName || resource.site}`, + summary: `New Customer: ${resource.id}`, ts: Date.parse(resource.createdAt), }; },