docs: small fix to abandoned cart guide (#12029)
This commit is contained in:
1 parent
3fa19ae4f1
commit
da52501518
4 files changed
+13826
-13822
No files matched your search
+13772
-13770
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
|
|||||||

|

|
||||||
|
|
||||||
```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: "* * * * *",
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
Reference in new issue
Block a user