docs: add details on updating a cart's customer (#10226)

Should be merged after releasing v2.0.5

Closes DX-1096
This commit is contained in:
Shahed Nasser
2024-11-25 11:56:35 +00:00
committed by GitHub
parent 01b0a84898
commit ae1c607f4e
12 changed files with 110 additions and 65 deletions
@@ -233,7 +233,7 @@ export const GET = async (
const b = req.validatedQuery.b as number const b = req.validatedQuery.b as number
res.json({ res.json({
sum: a + b sum: a + b,
}) })
} }
``` ```
@@ -149,7 +149,7 @@ class HelloModuleService {
data: { data: {
id: "123", id: "123",
// other data payload // other data payload
} },
}) })
} }
} }
@@ -167,7 +167,7 @@ export const depsHighlight = [
] ]
```ts title="medusa-config.ts" highlights={depsHighlight} ```ts title="medusa-config.ts" highlights={depsHighlight}
import { Modules } from '@medusajs/framework/utils' import { Modules } from "@medusajs/framework/utils"
module.exports = defineConfig({ module.exports = defineConfig({
// ... // ...
@@ -175,10 +175,10 @@ module.exports = defineConfig({
{ {
resolve: "./src/modules/hello", resolve: "./src/modules/hello",
dependencies: [ dependencies: [
Modules.EVENT_BUS Modules.EVENT_BUS,
] ],
} },
] ],
}) })
``` ```
@@ -150,7 +150,7 @@ const { data: productCustoms } = await query.graph({
take: 5, take: 5,
skip: 0, skip: 0,
}, },
}); })
``` ```
In the object passed to the `graph` method: In the object passed to the `graph` method:
@@ -318,9 +318,9 @@ export default defineMiddlewares({
defaults: [ defaults: [
"id", "id",
"name", "name",
"products.*" "products.*",
], ],
isList: true isList: true,
} }
), ),
], ],
@@ -371,7 +371,7 @@ export const GET = async (
const { data: myCustoms } = await query.graph({ const { data: myCustoms } = await query.graph({
entity: "my_custom", entity: "my_custom",
...req.remoteQueryConfig ...req.remoteQueryConfig,
}) })
res.json({ my_customs: myCustoms }) res.json({ my_customs: myCustoms })
@@ -106,7 +106,7 @@ const myWorkflow = createWorkflow(
const today = new Date() const today = new Date()
return new WorkflowResponse({ return new WorkflowResponse({
today today,
}) })
}) })
@@ -117,7 +117,7 @@ const myWorkflow = createWorkflow(
const today = transform({}, () => new Date()) const today = transform({}, () => new Date())
return new WorkflowResponse({ return new WorkflowResponse({
today today,
}) })
}) })
``` ```
@@ -16,7 +16,7 @@ Each workflow step must have a unique ID, which is the ID passed as a first para
```ts ```ts
const useQueryGraphStep = createStep( const useQueryGraphStep = createStep(
"use-query-graph", "use-query-graph"
// ... // ...
) )
``` ```
@@ -29,13 +29,13 @@ const helloWorkflow = createWorkflow(
() => { () => {
const { data: products } = useQueryGraphStep({ const { data: products } = useQueryGraphStep({
entity: "product", entity: "product",
fields: ["id"] fields: ["id"],
}) })
// ERROR OCCURS HERE: A STEP HAS THE SAME ID AS ANOTHER IN THE WORKFLOW // ERROR OCCURS HERE: A STEP HAS THE SAME ID AS ANOTHER IN THE WORKFLOW
const { data: customers } = useQueryGraphStep({ const { data: customers } = useQueryGraphStep({
entity: "customer", entity: "customer",
fields: ["id"] fields: ["id"],
}) })
} }
) )
@@ -63,13 +63,13 @@ const helloWorkflow = createWorkflow(
() => { () => {
const { data: products } = useQueryGraphStep({ const { data: products } = useQueryGraphStep({
entity: "product", entity: "product",
fields: ["id"] fields: ["id"],
}) })
// ✓ No error occurs, the step has a different ID. // ✓ No error occurs, the step has a different ID.
const { data: customers } = useQueryGraphStep({ const { data: customers } = useQueryGraphStep({
entity: "customer", entity: "customer",
fields: ["id"] fields: ["id"],
}).config({ name: "fetch-customers" }) }).config({ name: "fetch-customers" })
} }
) )
@@ -54,8 +54,8 @@ export default async function orderPlacedHandler({
await sendOrderConfirmationWorkflow(container) await sendOrderConfirmationWorkflow(container)
.run({ .run({
input: { input: {
id: data.id id: data.id,
} },
}) })
} }
+12 -12
View File
@@ -133,8 +133,8 @@ export const loaderHighlights = [
```ts title="src/modules/mongo/loaders/connection.ts" highlights={loaderHighlights} ```ts title="src/modules/mongo/loaders/connection.ts" highlights={loaderHighlights}
import { LoaderOptions } from "@medusajs/framework/types" import { LoaderOptions } from "@medusajs/framework/types"
import { ContainerRegistrationKeys } from "@medusajs/framework/utils"; import { ContainerRegistrationKeys } from "@medusajs/framework/utils"
import { asValue } from "awilix"; import { asValue } from "awilix"
import { MongoClient } from "mongodb" import { MongoClient } from "mongodb"
type ModuleOptions = { type ModuleOptions = {
@@ -144,7 +144,7 @@ type ModuleOptions = {
export default async function mongoConnectionLoader({ export default async function mongoConnectionLoader({
container, container,
options options,
}: LoaderOptions<ModuleOptions>) { }: LoaderOptions<ModuleOptions>) {
if (!options.connection_url) { if (!options.connection_url) {
throw new Error(`[MONGO MDOULE]: connection_url option is required.`) throw new Error(`[MONGO MDOULE]: connection_url option is required.`)
@@ -187,10 +187,10 @@ module.exports = defineConfig({
resolve: "./src/modules/mongo", resolve: "./src/modules/mongo",
options: { options: {
connection_url: process.env.MONGO_CONNECTION_URL, connection_url: process.env.MONGO_CONNECTION_URL,
db_name: process.env.MONGO_DB_NAME db_name: process.env.MONGO_DB_NAME,
} },
} },
] ],
}) })
``` ```
@@ -239,11 +239,11 @@ export default class MongoModuleService {
const moviesCol = this.mongoClient_.collection("movie") const moviesCol = this.mongoClient_.collection("movie")
const insertedMovie = await moviesCol.insertOne({ const insertedMovie = await moviesCol.insertOne({
title title,
}) })
const movie = await moviesCol.findOne({ const movie = await moviesCol.findOne({
_id: insertedMovie.insertedId _id: insertedMovie.insertedId,
}) })
return movie return movie
@@ -254,8 +254,8 @@ export default class MongoModuleService {
await moviesCol.deleteOne({ await moviesCol.deleteOne({
_id: { _id: {
equals: id equals: id,
} },
}) })
} }
} }
@@ -274,7 +274,7 @@ export const MONGO_MODULE = "mongo"
export default Module(MONGO_MODULE, { export default Module(MONGO_MODULE, {
service: MongoModuleService, service: MongoModuleService,
loaders: [mongoConnectionLoader] loaders: [mongoConnectionLoader],
}) })
``` ```
@@ -26,8 +26,8 @@ export const highlights = [
] ]
```ts highlights={highlights} ```ts highlights={highlights}
import { MedusaRequest, MedusaResponse } from "@medusajs/framework"; import { MedusaRequest, MedusaResponse } from "@medusajs/framework"
import { ContainerRegistrationKeys } from "@medusajs/framework/utils"; import { ContainerRegistrationKeys } from "@medusajs/framework/utils"
export async function GET( export async function GET(
req: MedusaRequest, req: MedusaRequest,
@@ -41,12 +41,12 @@ export async function GET(
entity: "product", entity: "product",
fields: ["*"], fields: ["*"],
filters: { filters: {
id: "prod_123" id: "prod_123",
} },
}) })
res.json({ res.json({
products products,
}) })
} }
``` ```
@@ -84,7 +84,7 @@ export const subscriberHighlights = [
```ts highlights={subscriberHighlights} ```ts highlights={subscriberHighlights}
import { SubscriberArgs, type SubscriberConfig } from "@medusajs/framework" import { SubscriberArgs, type SubscriberConfig } from "@medusajs/framework"
import { ContainerRegistrationKeys } from "@medusajs/framework/utils"; import { ContainerRegistrationKeys } from "@medusajs/framework/utils"
export default async function productCreateHandler({ export default async function productCreateHandler({
event: { data }, event: { data },
@@ -96,8 +96,8 @@ export default async function productCreateHandler({
entity: "product", entity: "product",
fields: ["*"], fields: ["*"],
filters: { filters: {
id: data.id id: data.id,
} },
}) })
console.log(`You created a product with the title ${products[0].title}`) console.log(`You created a product with the title ${products[0].title}`)
@@ -119,7 +119,7 @@ export const scheduledJobHighlights = [
```ts highlights={scheduledJobHighlights} ```ts highlights={scheduledJobHighlights}
import { MedusaContainer } from "@medusajs/framework/types" import { MedusaContainer } from "@medusajs/framework/types"
import { ContainerRegistrationKeys } from "@medusajs/framework/utils"; import { ContainerRegistrationKeys } from "@medusajs/framework/utils"
export default async function myCustomJob( export default async function myCustomJob(
container: MedusaContainer container: MedusaContainer
@@ -130,8 +130,8 @@ export default async function myCustomJob(
entity: "product", entity: "product",
fields: ["*"], fields: ["*"],
filters: { filters: {
id: "prod_123" id: "prod_123",
} },
}) })
console.log( console.log(
@@ -160,7 +160,7 @@ import {
createStep, createStep,
StepResponse, StepResponse,
} from "@medusajs/framework/workflows-sdk" } from "@medusajs/framework/workflows-sdk"
import { ContainerRegistrationKeys } from "@medusajs/framework/utils"; import { ContainerRegistrationKeys } from "@medusajs/framework/utils"
const step1 = createStep("step-1", async (_, { container }) => { const step1 = createStep("step-1", async (_, { container }) => {
const query = container.resolve(ContainerRegistrationKeys.QUERY) const query = container.resolve(ContainerRegistrationKeys.QUERY)
@@ -169,8 +169,8 @@ const step1 = createStep("step-1", async (_, { container }) => {
entity: "product", entity: "product",
fields: ["*"], fields: ["*"],
filters: { filters: {
id: "prod_123" id: "prod_123",
} },
}) })
return new StepResponse(products) return new StepResponse(products)
+18 -18
View File
@@ -37,7 +37,7 @@ import { model } from "@medusajs/framework/utils"
const Post = model.define("post", { const Post = model.define("post", {
id: model.id().primaryKey(), id: model.id().primaryKey(),
title: model.text() title: model.text(),
}) })
export default Post export default Post
@@ -143,8 +143,8 @@ module.exports = defineConfig({
}, },
modules: [ modules: [
{ {
resolve: "./src/modules/blog" resolve: "./src/modules/blog",
} },
], ],
}) })
``` ```
@@ -168,16 +168,16 @@ npx medusa db:generate blog
The `db:generate` command of the Medusa CLI accepts one or more module names to generate the migration for. It will create a migration file for the Blog Module in the directory `src/modules/blog/migrations` similar to the following: The `db:generate` command of the Medusa CLI accepts one or more module names to generate the migration for. It will create a migration file for the Blog Module in the directory `src/modules/blog/migrations` similar to the following:
```ts ```ts
import { Migration } from '@mikro-orm/migrations'; import { Migration } from "@mikro-orm/migrations"
export class Migration20241121103722 extends Migration { export class Migration20241121103722 extends Migration {
async up(): Promise<void> { async up(): Promise<void> {
this.addSql('create table if not exists "post" ("id" text not null, "title" text not null, "created_at" timestamptz not null default now(), "updated_at" timestamptz not null default now(), "deleted_at" timestamptz null, constraint "post_pkey" primary key ("id"));'); this.addSql("create table if not exists \"post\" (\"id\" text not null, \"title\" text not null, \"created_at\" timestamptz not null default now(), \"updated_at\" timestamptz not null default now(), \"deleted_at\" timestamptz null, constraint \"post_pkey\" primary key (\"id\"));")
} }
async down(): Promise<void> { async down(): Promise<void> {
this.addSql('drop table if exists "post" cascade;'); this.addSql("drop table if exists \"post\" cascade;")
} }
} }
@@ -226,10 +226,10 @@ import {
createStep, createStep,
createWorkflow, createWorkflow,
StepResponse, StepResponse,
WorkflowResponse WorkflowResponse,
} from "@medusajs/framework/workflows-sdk"; } from "@medusajs/framework/workflows-sdk"
import { BLOG_MODULE } from "../modules/blog"; import { BLOG_MODULE } from "../modules/blog"
import BlogModuleService from "../modules/blog/service"; import BlogModuleService from "../modules/blog/service"
type CreatePostWorkflowInput = { type CreatePostWorkflowInput = {
title: string title: string
@@ -241,7 +241,7 @@ const createPostStep = createStep(
const blogModuleService: BlogModuleService = container.resolve(BLOG_MODULE) const blogModuleService: BlogModuleService = container.resolve(BLOG_MODULE)
const post = await blogModuleService.createPosts({ const post = await blogModuleService.createPosts({
title title,
}) })
return new StepResponse(post, post) return new StepResponse(post, post)
@@ -272,11 +272,11 @@ You'll now execute that workflow in an API route to expose the feature of creati
```ts ```ts
import type { import type {
MedusaRequest, MedusaRequest,
MedusaResponse MedusaResponse,
} from "@medusajs/framework/http"; } from "@medusajs/framework/http"
import { import {
createPostWorkflow createPostWorkflow,
} from "../../../workflows/create-post"; } from "../../../workflows/create-post"
export async function POST( export async function POST(
req: MedusaRequest, req: MedusaRequest,
@@ -285,12 +285,12 @@ export async function POST(
const { result: post } = await createPostWorkflow(req.scope) const { result: post } = await createPostWorkflow(req.scope)
.run({ .run({
input: { input: {
title: "My Post" title: "My Post",
} },
}) })
res.json({ res.json({
post post,
}) })
} }
``` ```
@@ -159,7 +159,7 @@ module.exports = defineConfig({
}, },
}, },
}, },
] ],
}) })
``` ```
@@ -118,3 +118,5 @@ This is necessary, as only products matching the cart's sales channel(s) can be
## Associate Customer with Cart ## Associate Customer with Cart
When the cart is created for a logged-in customer, it's automatically associated with that customer. When the cart is created for a logged-in customer, it's automatically associated with that customer.
However, if the cart is created for a guest customer, then the customer logs in, then you have to set the cart's customer as explained in [this guide](../update/page.mdx#set-carts-customer).
@@ -46,3 +46,46 @@ fetch(`http://localhost:9000/store/carts/${cartId}`, {
``` ```
The Update Cart API route accepts a `region_id` request body parameter, whose value is the new region to associate with the cart. The Update Cart API route accepts a `region_id` request body parameter, whose value is the new region to associate with the cart.
---
## Set Cart's Customer
You might need to change the cart's customer in two cases:
- You created the cart for the customer as a guest, then they logged-in, so you want to associate the cart with them as a registered customer.
- You're transfering the cart from one customer to another, which is useful in company setups, such as when implementing B2B commerce applicatons.
To set or change the cart's customer, send an authenticated `POST` request to the Set Cart's Customer API route:
<Note>
This API route is only available after [Medusa v2.0.5](https://github.com/medusajs/medusa/releases/tag/v2.0.5).
</Note>
```ts
fetch(`http://localhost:9000/store/carts/${cartId}/customer`, {
credentials: "include",
method: "POST",
headers: {
"Content-Type": "application/json",
},
})
.then((res) => res.json())
.then(({ cart }) => {
// use cart...
console.log(cart)
})
```
To send an authenticated request, either use `credentials: include` if the customer is already authenticated with a cookie session, or pass the Authorization Bearer token in the request's header.
<Note title="Tip">
Learn more about authenticating customers in [this guide](../../customers/login/page.mdx).
</Note>
The cart is now associated with the logged-in customer.