docs: small fix to abandoned cart guide (#12029)

This commit is contained in:
Shahed Nasser authored and GitHub committed 2025-03-28 14:56:41 +02:00
1 parent 3fa19ae4f1
commit da52501518
4 files changed
+13826 -13822

No files matched your search

File diff suppressed because it is too large. Load diff
@@ -242,14 +242,16 @@ export const sendAbandonedNotificationsStep = createStep(
channel: "email", channel: "email",
template: process.env.ABANDONED_CART_TEMPLATE_ID || "", template: process.env.ABANDONED_CART_TEMPLATE_ID || "",
data: { data: {
first_name: cart.customer.first_name, customer: {
last_name: cart.customer.last_name, first_name: cart.customer?.first_name || cart.shipping_address?.first_name,
last_name: cart.customer?.last_name || cart.shipping_address?.last_name,
},
cart_id: cart.id, cart_id: cart.id,
items: cart.items?.map((item) => ({ items: cart.items?.map((item) => ({
name: item.title, product_title: item.title,
quantity: item.quantity, quantity: item.quantity,
price: item.unit_price, unit_price: item.unit_price,
image: item.thumbnail, thumbnail: item.thumbnail,
})), })),
}, },
})) }))
@@ -273,7 +273,7 @@ export default class MagentoModuleService {
} }
this.accessToken = { this.accessToken = {
token: token.replaceAll('"', ""), token: token.replaceAll("\"", ""),
expiresAt: new Date(Date.now() + 4 * 60 * 60 * 1000), // 4 hours in milliseconds expiresAt: new Date(Date.now() + 4 * 60 * 60 * 1000), // 4 hours in milliseconds
} }
} }
@@ -448,8 +448,8 @@ const { items: products, ...pagination }: MagentoPaginatedResponse<MagentoProduc
"Authorization": `Bearer ${this.accessToken.token}`, "Authorization": `Bearer ${this.accessToken.token}`,
}, },
} }
).then(res => res.json()) ).then((res) => res.json())
.catch(err => { .catch((err) => {
console.log(err) console.log(err)
throw new MedusaError( throw new MedusaError(
MedusaError.Types.INVALID_DATA, MedusaError.Types.INVALID_DATA,
@@ -475,10 +475,10 @@ await promiseAll(
{ {
headers: { headers: {
"Authorization": `Bearer ${this.accessToken.token}`, "Authorization": `Bearer ${this.accessToken.token}`,
},
} }
} ).then((res) => res.json())
).then(res => res.json()) .catch((err) => {
.catch(err => {
throw new MedusaError( throw new MedusaError(
MedusaError.Types.INVALID_DATA, MedusaError.Types.INVALID_DATA,
`Failed to get product children from Magento: ${err.message}` `Failed to get product children from Magento: ${err.message}`
@@ -488,7 +488,7 @@ await promiseAll(
product.media_gallery_entries = product.media_gallery_entries.map( product.media_gallery_entries = product.media_gallery_entries.map(
(entry) => ({ (entry) => ({
...entry, ...entry,
file: `${this.options.migrationOptions?.imageBaseUrl}${entry.file}` file: `${this.options.migrationOptions?.imageBaseUrl}${entry.file}`,
} }
)) ))
@@ -513,7 +513,7 @@ Add the new method `getAttributes` to the `MagentoModuleService` class:
export default class MagentoModuleService { export default class MagentoModuleService {
// ... // ...
async getAttributes({ async getAttributes({
ids ids,
}: { }: {
ids: string[] ids: string[]
}): Promise<MagentoAttribute[]> { }): Promise<MagentoAttribute[]> {
@@ -538,7 +538,7 @@ export default class MagentoModuleService {
) )
const { const {
items: attributes items: attributes,
}: MagentoPaginatedResponse<MagentoAttribute> = await fetch( }: MagentoPaginatedResponse<MagentoAttribute> = await fetch(
`${this.options.baseUrl}/rest/${this.options.storeCode}/V1/products/attributes?${searchQuery}`, `${this.options.baseUrl}/rest/${this.options.storeCode}/V1/products/attributes?${searchQuery}`,
{ {
@@ -546,8 +546,8 @@ export default class MagentoModuleService {
"Authorization": `Bearer ${this.accessToken.token}`, "Authorization": `Bearer ${this.accessToken.token}`,
}, },
} }
).then(res => res.json()) ).then((res) => res.json())
.catch(err => { .catch((err) => {
throw new MedusaError( throw new MedusaError(
MedusaError.Types.INVALID_DATA, MedusaError.Types.INVALID_DATA,
`Failed to get attributes from Magento: ${err.message}` `Failed to get attributes from Magento: ${err.message}`
@@ -621,7 +621,7 @@ module.exports = defineConfig({
password: process.env.MAGENTO_PASSWORD, password: process.env.MAGENTO_PASSWORD,
migrationOptions: { migrationOptions: {
imageBaseUrl: process.env.MAGENTO_IMAGE_BASE_URL, imageBaseUrl: process.env.MAGENTO_IMAGE_BASE_URL,
} },
}, },
}, },
], ],
@@ -733,9 +733,9 @@ In your plugin, create the file `src/workflows/steps/get-magento-products.ts` wi
![Diagram showcasing the get-magento-products file to create](https://res.cloudinary.com/dza7lstvk/image/upload/v1739349590/Medusa%20Resources/magento-5_ueb4wn.jpg) ![Diagram showcasing the get-magento-products file to create](https://res.cloudinary.com/dza7lstvk/image/upload/v1739349590/Medusa%20Resources/magento-5_ueb4wn.jpg)
```ts title="src/workflows/steps/get-magento-products.ts" ```ts title="src/workflows/steps/get-magento-products.ts"
import { createStep, StepResponse } from "@medusajs/framework/workflows-sdk"; import { createStep, StepResponse } from "@medusajs/framework/workflows-sdk"
import { MAGENTO_MODULE } from "../../modules/magento"; import { MAGENTO_MODULE } from "../../modules/magento"
import MagentoModuleService from "../../modules/magento/service"; import MagentoModuleService from "../../modules/magento/service"
type GetMagentoProductsInput = { type GetMagentoProductsInput = {
currentPage: number currentPage: number
@@ -750,7 +750,7 @@ export const getMagentoProductsStep = createStep(
const response = await magentoModuleService.getProducts({ const response = await magentoModuleService.getProducts({
currentPage, currentPage,
pageSize pageSize,
}) })
return new StepResponse(response) return new StepResponse(response)
@@ -779,15 +779,15 @@ In your plugin, create the file `src/workflows/migrate-products-from-magento.ts`
```ts title="src/workflows/migrate-products-from-magento.ts" ```ts title="src/workflows/migrate-products-from-magento.ts"
import { import {
createWorkflow, transform, WorkflowResponse createWorkflow, transform, WorkflowResponse,
} from "@medusajs/framework/workflows-sdk" } from "@medusajs/framework/workflows-sdk"
import { import {
CreateProductWorkflowInputDTO, UpsertProductDTO CreateProductWorkflowInputDTO, UpsertProductDTO,
} from "@medusajs/framework/types" } from "@medusajs/framework/types"
import { import {
createProductsWorkflow, createProductsWorkflow,
updateProductsWorkflow, updateProductsWorkflow,
useQueryGraphStep useQueryGraphStep,
} from "@medusajs/medusa/core-flows" } from "@medusajs/medusa/core-flows"
import { getMagentoProductsStep } from "./steps/get-magento-products" import { getMagentoProductsStep } from "./steps/get-magento-products"
@@ -803,7 +803,7 @@ export const migrateProductsFromMagentoWorkflow = createWorkflow(
{ {
name: migrateProductsFromMagentoWorkflowId, name: migrateProductsFromMagentoWorkflowId,
retentionTime: 10000, retentionTime: 10000,
store: true store: true,
}, },
(input: MigrateProductsFromMagentoWorkflowInput) => { (input: MigrateProductsFromMagentoWorkflowInput) => {
const { pagination, products, attributes } = getMagentoProductsStep( const { pagination, products, attributes } = getMagentoProductsStep(
@@ -831,8 +831,8 @@ const { data: stores } = useQueryGraphStep({
fields: ["supported_currencies.*", "default_sales_channel_id"], fields: ["supported_currencies.*", "default_sales_channel_id"],
pagination: { pagination: {
take: 1, take: 1,
skip: 0 skip: 0,
} },
}) })
const { data: shippingProfiles } = useQueryGraphStep({ const { data: shippingProfiles } = useQueryGraphStep({
@@ -840,8 +840,8 @@ const { data: shippingProfiles } = useQueryGraphStep({
fields: ["id"], fields: ["id"],
pagination: { pagination: {
take: 1, take: 1,
skip: 0 skip: 0,
} },
}).config({ name: "get-shipping-profiles" }) }).config({ name: "get-shipping-profiles" })
// TODO retrieve existing products // TODO retrieve existing products
@@ -855,7 +855,7 @@ Next, you'll retrieve products that were previously migrated from Magento to det
```ts title="src/workflows/migrate-products-from-magento.ts" ```ts title="src/workflows/migrate-products-from-magento.ts"
const externalIdFilters = transform({ const externalIdFilters = transform({
products products,
}, (data) => { }, (data) => {
return data.products.map((product) => product.id.toString()) return data.products.map((product) => product.id.toString())
}) })
@@ -864,8 +864,8 @@ const { data: existingProducts } = useQueryGraphStep({
entity: "product", entity: "product",
fields: ["id", "external_id", "variants.id", "variants.metadata"], fields: ["id", "external_id", "variants.id", "variants.metadata"],
filters: { filters: {
external_id: externalIdFilters external_id: externalIdFilters,
} },
}).config({ name: "get-existing-products" }) }).config({ name: "get-existing-products" })
// TODO prepare products to create or update // TODO prepare products to create or update
@@ -914,13 +914,13 @@ export const prepareHighlights = [
```ts title="src/workflows/migrate-products-from-magento.ts" highlights={prepareHighlights} ```ts title="src/workflows/migrate-products-from-magento.ts" highlights={prepareHighlights}
const { const {
productsToCreate, productsToCreate,
productsToUpdate productsToUpdate,
} = transform({ } = transform({
products, products,
attributes, attributes,
stores, stores,
shippingProfiles, shippingProfiles,
existingProducts existingProducts,
}, (data) => { }, (data) => {
const productsToCreate = new Map<string, CreateProductWorkflowInputDTO>() const productsToCreate = new Map<string, CreateProductWorkflowInputDTO>()
const productsToUpdate = new Map<string, UpsertProductDTO>() const productsToUpdate = new Map<string, UpsertProductDTO>()
@@ -940,7 +940,7 @@ const {
(entry) => entry.types.includes("thumbnail") (entry) => entry.types.includes("thumbnail")
)?.file, )?.file,
sales_channels: [{ sales_channels: [{
id: data.stores[0].default_sales_channel_id id: data.stores[0].default_sales_channel_id,
}], }],
shipping_profile_id: data.shippingProfiles[0].id, shipping_profile_id: data.shippingProfiles[0].id,
} }
@@ -956,7 +956,7 @@ const {
title: option.label, title: option.label,
values: attribute?.options.filter((opt) => { values: attribute?.options.filter((opt) => {
return option.values.find((v) => v.value_index === parseInt(opt.value)) return option.values.find((v) => v.value_index === parseInt(opt.value))
}).map((opt) => opt.label) || [] }).map((opt) => opt.label) || [],
} }
}) || [] }) || []
@@ -982,13 +982,13 @@ const {
prices: data.stores[0].supported_currencies.map(({ currency_code }) => { prices: data.stores[0].supported_currencies.map(({ currency_code }) => {
return { return {
amount: child.price, amount: child.price,
currency_code currency_code,
} }
}), }),
metadata: { metadata: {
external_id: variantExternalId external_id: variantExternalId,
}, },
id: existingVariant?.id id: existingVariant?.id,
} }
}) })
@@ -996,8 +996,8 @@ const {
return { return {
url: entry.file, url: entry.file,
metadata: { metadata: {
external_id: entry.id.toString() external_id: entry.id.toString(),
} },
} }
}) })
@@ -1010,7 +1010,7 @@ const {
return { return {
productsToCreate: Array.from(productsToCreate.values()), productsToCreate: Array.from(productsToCreate.values()),
productsToUpdate: Array.from(productsToUpdate.values()) productsToUpdate: Array.from(productsToUpdate.values()),
} }
}) })
@@ -1034,14 +1034,14 @@ The last steps of the workflow is to create and update the products. Replace the
```ts title="src/workflows/migrate-products-from-magento.ts" ```ts title="src/workflows/migrate-products-from-magento.ts"
createProductsWorkflow.runAsStep({ createProductsWorkflow.runAsStep({
input: { input: {
products: productsToCreate products: productsToCreate,
} },
}) })
updateProductsWorkflow.runAsStep({ updateProductsWorkflow.runAsStep({
input: { input: {
products: productsToUpdate products: productsToUpdate,
} },
}) })
return new WorkflowResponse(pagination) return new WorkflowResponse(pagination)
@@ -1089,12 +1089,12 @@ export default async function migrateMagentoJob(
currentPage++ currentPage++
const { const {
result: pagination result: pagination,
} = await migrateProductsFromMagentoWorkflow(container).run({ } = await migrateProductsFromMagentoWorkflow(container).run({
input: { input: {
currentPage, currentPage,
pageSize pageSize,
} },
}) })
totalCount = pagination.total_count totalCount = pagination.total_count
@@ -1105,7 +1105,7 @@ export default async function migrateMagentoJob(
export const config = { export const config = {
name: "migrate-magento-job", name: "migrate-magento-job",
schedule: "0 0 * * *" schedule: "0 0 * * *",
} }
``` ```
@@ -1125,7 +1125,7 @@ To test out this scheduled job, first, change the configuration to run the job e
```ts title="src/jobs/migrate-magento.ts" ```ts title="src/jobs/migrate-magento.ts"
export const config = { export const config = {
// ... // ...
schedule: "* * * * *" schedule: "* * * * *",
} }
``` ```
+1 -1
View File
@@ -425,7 +425,7 @@ try {
addresses, addresses,
count, count,
offset, offset,
limit limit,
} = await sdk.store.customer.listAddress() } = await sdk.store.customer.listAddress()
// no errors occurred // no errors occurred
// do something with the data // do something with the data