docs: update b2b recipe (#11213)
This commit is contained in:
@@ -1,14 +1,19 @@
|
||||
import { AcademicCapSolid, UsersSolid } from "@medusajs/icons"
|
||||
import { BetaBadge } from "docs-ui"
|
||||
|
||||
export const metadata = {
|
||||
title: `B2B Recipe`,
|
||||
}
|
||||
|
||||
# {metadata.title} <BetaBadge text="Soon" tooltipText="This recipe is a work in progress." />
|
||||
# {metadata.title}
|
||||
|
||||
This recipe provides the general steps to implement a B2B store with Medusa.
|
||||
|
||||
<Note title="Tip">
|
||||
|
||||
Medusa has a ready-to-use B2B starter that you install and use in [this GitHub repository](https://github.com/medusajs/b2b-starter-medusa).
|
||||
|
||||
</Note>
|
||||
|
||||
## Overview
|
||||
|
||||
In a B2B store, you provide different types of customers with relevant pricing, products, shopping experience, and more.
|
||||
@@ -29,26 +34,12 @@ Use sales channels to set product availability per channel. In this case, create
|
||||
|
||||
You can create a sales channel through the Medusa Admin or Admin REST APIs.
|
||||
|
||||
{/* TODO add links */}
|
||||
|
||||
<CardList items={[
|
||||
{
|
||||
href: "#",
|
||||
title: "Option 1: Use Medusa Admin",
|
||||
text: "Create the sales channel using the Medusa Admin.",
|
||||
icon: UsersSolid,
|
||||
badge: {
|
||||
variant: "blue",
|
||||
children: "Guide Soon"
|
||||
}
|
||||
},
|
||||
{
|
||||
href: "!api!/admin#sales-channels_postsaleschannels",
|
||||
title: "Option 2: Using the REST APIs",
|
||||
text: "Create the sales channel using the REST APIs.",
|
||||
icon: AcademicCapSolid,
|
||||
},
|
||||
]} />
|
||||
<Card
|
||||
href="!api!/admin#sales-channels_postsaleschannels"
|
||||
title="Create Sales Channel"
|
||||
text="Create the sales channel using the REST APIs."
|
||||
icon={AcademicCapSolid}
|
||||
/>
|
||||
|
||||
---
|
||||
|
||||
@@ -63,51 +54,23 @@ Then, all products retrieved belong to the associated sales channel(s).
|
||||
|
||||
You can create a publishable API key through the Medusa Admin or the Admin REST APIs, then associate it with the B2B sales channel. Later, you'll use this key when developing your B2B storefront.
|
||||
|
||||
{/* TODO add links */}
|
||||
|
||||
### Create Key
|
||||
|
||||
<CardList items={[
|
||||
{
|
||||
href: "#",
|
||||
title: "Option 1: Use Medusa Admin",
|
||||
text: "Create the publishable API key using the Medusa Admin.",
|
||||
icon: UsersSolid,
|
||||
badge: {
|
||||
variant: "blue",
|
||||
children: "Guide Soon"
|
||||
}
|
||||
},
|
||||
{
|
||||
href: "!api!/admin#api-keys_postapikeys",
|
||||
title: "Option 2: Using the REST APIs",
|
||||
text: "Create the publishable API key using the REST APIs.",
|
||||
icon: AcademicCapSolid,
|
||||
},
|
||||
]} />
|
||||
<Card
|
||||
href="!api!/admin#api-keys_postapikeys"
|
||||
title="Create Publishable API Key"
|
||||
text="Create the publishable API key using the REST APIs."
|
||||
icon={AcademicCapSolid}
|
||||
/>
|
||||
|
||||
### Associate Key with Sales Channel
|
||||
|
||||
{/* TODO add links */}
|
||||
|
||||
<CardList items={[
|
||||
{
|
||||
href: "#",
|
||||
title: "Option 1: Use Medusa Admin",
|
||||
text: "Associate the publishable API key with the B2B sales channel using the Medusa Admin.",
|
||||
icon: UsersSolid,
|
||||
badge: {
|
||||
variant: "blue",
|
||||
children: "Guide Soon"
|
||||
}
|
||||
},
|
||||
{
|
||||
href: "#",
|
||||
title: "Option 2: Using the REST APIs",
|
||||
text: "Associate the publishable API key with the B2B sales channel using the REST APIs.",
|
||||
icon: AcademicCapSolid,
|
||||
},
|
||||
]} />
|
||||
<Card
|
||||
href="!api!/admin#api-keys_postapikeysidsaleschannels"
|
||||
title="Create Publishable API Key"
|
||||
text="Create the publishable API key using the REST APIs."
|
||||
icon={AcademicCapSolid}
|
||||
/>
|
||||
|
||||
---
|
||||
|
||||
@@ -117,49 +80,21 @@ You can create new products or add existing ones to the B2B sales channel using
|
||||
|
||||
### Create Products
|
||||
|
||||
{/* TODO add links */}
|
||||
|
||||
<CardList items={[
|
||||
{
|
||||
href: "#",
|
||||
title: "Using Medusa Admin",
|
||||
text: "Create products using the Medusa Admin.",
|
||||
icon: UsersSolid,
|
||||
badge: {
|
||||
variant: "blue",
|
||||
children: "Guide Soon"
|
||||
}
|
||||
},
|
||||
{
|
||||
href: "!api!/admin#products_postproducts",
|
||||
title: "Using REST APIs",
|
||||
text: "Create products using the REST APIs.",
|
||||
icon: AcademicCapSolid,
|
||||
},
|
||||
]} />
|
||||
<Card
|
||||
href="!api!/admin#products_postproducts"
|
||||
title="Create Products"
|
||||
text="Create products using the REST APIs."
|
||||
icon={AcademicCapSolid}
|
||||
/>
|
||||
|
||||
### Add Products to Sales Channel
|
||||
|
||||
{/* TODO add links */}
|
||||
|
||||
<CardList items={[
|
||||
{
|
||||
href: "#",
|
||||
title: "Using Medusa Admin",
|
||||
text: "Add the products to the B2B sales channel using the Medusa Admin.",
|
||||
icon: UsersSolid,
|
||||
badge: {
|
||||
variant: "blue",
|
||||
children: "Guide Soon"
|
||||
}
|
||||
},
|
||||
{
|
||||
href: "!api!/admin#sales-channels_postsaleschannelsidproductsbatchadd",
|
||||
title: "Using REST APIs",
|
||||
text: "Add the products to the B2B sales channel using the REST APIs.",
|
||||
icon: AcademicCapSolid,
|
||||
},
|
||||
]} />
|
||||
<Card
|
||||
href="!api!/admin#sales-channels_postsaleschannelsidproductsbatchadd"
|
||||
title="Add to Sales Channel"
|
||||
text="Add the products to the B2B sales channel using the REST APIs."
|
||||
icon={AcademicCapSolid}
|
||||
/>
|
||||
|
||||
---
|
||||
|
||||
@@ -169,7 +104,7 @@ Use customer groups to organize your customers into different groups. Then, you
|
||||
|
||||
This is useful in B2B sales, as you often negotiate special prices with each customer or company.
|
||||
|
||||
You can create a B2B module that adds necessary data models to represent a B2B company. Then, you link that company to a customer group. Any customer belonging to that group also belongs to the company, meaning they're a B2B customer.
|
||||
You can create a B2B module that adds necessary data models to represent a B2B company. Then, you link that company to a customer group, which is defined in the Customer Module. Any customer belonging to that group also belongs to the company, meaning they're a B2B customer.
|
||||
|
||||
<CardList items={[
|
||||
{
|
||||
@@ -186,302 +121,13 @@ You can create a B2B module that adds necessary data models to represent a B2B c
|
||||
},
|
||||
]} />
|
||||
|
||||
{/* <Card
|
||||
href="!docs!/learn/fundamentals/modules/module-relationships"
|
||||
title="Create Module Relationships"
|
||||
text="Learn how to create a relationship between modules."
|
||||
<Card
|
||||
href="!docs!/learn/fundamentals/module-links"
|
||||
title="Create Module Links"
|
||||
text="Learn how to create links between modules."
|
||||
icon={AcademicCapSolid}
|
||||
className="mt-1"
|
||||
/> */}
|
||||
|
||||
{/* <Details summaryContent="Example">
|
||||
In this section, you'll create a B2B module that has a `Company` data model. The `Company` data model has a relationship to the `CustomerGroup` data model of the Customer Module.
|
||||
|
||||
Start by creating the `src/modules/b2b` directory.
|
||||
|
||||
Then, create the file `src/modules/b2b/models/company.ts` with the following content:
|
||||
|
||||
```ts title="src/modules/b2b/models/company.ts" highlights={[["8", "", "The property will be used to create a relationship to customer groups."]]}
|
||||
import { model } from "@medusajs/framework/utils"
|
||||
|
||||
const Company = model.define("company", {
|
||||
id: model.id().primaryKey(),
|
||||
name: model.text(),
|
||||
city: model.text(),
|
||||
country_code: model.text(),
|
||||
customer_group_id: model.text().nullable(),
|
||||
})
|
||||
|
||||
export default Company
|
||||
```
|
||||
|
||||
This creates a `Company` data model with some relevant properties. Most importantly, it has a `customer_group_id` property. It'll later be used when creating the relationship to the `CustomerGroup` data model in the Customer Module.
|
||||
|
||||
Next, create the migration in the file `src/modules/b2b/migrations/Migration20240516081502.ts` with the following content:
|
||||
|
||||
```ts title="src/modules/b2b/migrations/Migration20240516081502.ts"
|
||||
import { Migration } from "@mikro-orm/migrations"
|
||||
|
||||
export class Migration20240516081502 extends Migration {
|
||||
|
||||
async up(): Promise<void> {
|
||||
this.addSql("create table if not exists \"company\" (\"id\" text not null, \"name\" text not null, \"city\" text not null, \"country_code\" text not null, \"customer_group_id\" text not null, constraint \"company_pkey\" primary key (\"id\"));")
|
||||
}
|
||||
|
||||
async down(): Promise<void> {
|
||||
this.addSql("drop table if exists \"company\" cascade;")
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
You'll run the migration to reflect the data model in the database after finishing the module definition.
|
||||
|
||||
Then, create the module's main service at `src/modules/b2b/service.ts` with the following content:
|
||||
|
||||
```ts title="src/modules/b2b/service.ts"
|
||||
import { MedusaService } from "@medusajs/framework/utils"
|
||||
import Company from "./models/company"
|
||||
|
||||
class B2bModuleService extends MedusaService({
|
||||
Company,
|
||||
}){
|
||||
// TODO add custom methods
|
||||
}
|
||||
|
||||
export default B2bModuleService
|
||||
```
|
||||
|
||||
This creates a `B2bModuleService` that extends the service factory, which generates data-management functionalities for the `Company` data model.
|
||||
|
||||
Next, create the module definition at `src/modules/b2b/index.ts` with the following content:
|
||||
|
||||
```ts title="src/modules/b2b/index.ts"
|
||||
import B2bModuleService from "./service"
|
||||
import { Module } from "@medusajs/framework/utils"
|
||||
|
||||
export default Module("b2b", {
|
||||
service: B2bModuleService,
|
||||
})
|
||||
```
|
||||
|
||||
Finally, add the module to the `modules` object in `medusa-config.js`:
|
||||
|
||||
```js title="medusa-config.js"
|
||||
module.exports = defineConfig({
|
||||
// ...
|
||||
modules: {
|
||||
b2bModuleService: {
|
||||
resolve: "./modules/b2b",
|
||||
definition: {
|
||||
isQueryable: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
})
|
||||
```
|
||||
|
||||
You can now run migrations with the following commands:
|
||||
|
||||
```bash npm2yarn
|
||||
npx medusa db:migrate
|
||||
```
|
||||
|
||||
### Add Create Company API Route
|
||||
|
||||
To test out using the B2B Module, you'll add an API route to create a company.
|
||||
|
||||
Start by creating the file `src/types/b2b/index.ts` with some helper types:
|
||||
|
||||
```ts title="src/types/b2b/index.ts"
|
||||
import { CustomerGroupDTO } from "@medusajs/framework/types"
|
||||
|
||||
export type CompanyDTO = {
|
||||
id: string
|
||||
name: string
|
||||
city: string
|
||||
country_code: string
|
||||
customer_group_id?: string
|
||||
customer_group?: CustomerGroupDTO
|
||||
}
|
||||
|
||||
export type CreateCompanyDTO = {
|
||||
name: string
|
||||
city: string
|
||||
country_code: string
|
||||
customer_group_id?: string
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
Then, create the file `src/workflows/create-company.ts` with the following content:
|
||||
|
||||
export const workflowHighlights = [
|
||||
["23", "tryToCreateCustomerGroupStep", "This step creates the customer group if its data is passed in the `customer_group` property."],
|
||||
["36", "createCustomerGroupsWorkflow", "Use the `createCustomerGroupsWorkflow` defined by Medusa to create the customer group."],
|
||||
["44", "", "Set the ID of the new customer group in the `customer_group_id` property so that it's added to the created company."],
|
||||
["54", "createCompanyStep", "This step creates the company."],
|
||||
]
|
||||
|
||||
```ts title="src/workflows/create-company.ts" highlights={workflowHighlights} collapsibleLines="1-12" expandButtonLabel="Show Imports"
|
||||
import {
|
||||
StepResponse,
|
||||
createStep,
|
||||
createWorkflow,
|
||||
} from "@medusajs/framework/workflows-sdk"
|
||||
import {
|
||||
createCustomerGroupsWorkflow,
|
||||
} from "@medusajs/medusa/core-flows"
|
||||
import { CreateCustomerGroupDTO } from "@medusajs/framework/types"
|
||||
import { CompanyDTO, CreateCompanyDTO } from "../types/b2b"
|
||||
import B2bModuleService from "../modules/b2b/service"
|
||||
|
||||
export type CreateCompanyWorkflowInput = CreateCompanyDTO & {
|
||||
customer_group?: CreateCustomerGroupDTO
|
||||
}
|
||||
|
||||
type CreateCompanyWorkflowOutput = {
|
||||
company: CompanyDTO
|
||||
}
|
||||
|
||||
type CreateCustomerGroupStepInput = CreateCompanyWorkflowInput
|
||||
|
||||
const tryToCreateCustomerGroupStep = createStep(
|
||||
"try-to-create-customer-group-step",
|
||||
async (
|
||||
{
|
||||
customer_group,
|
||||
...company
|
||||
}: CreateCustomerGroupStepInput,
|
||||
{ container }) => {
|
||||
if (!customer_group) {
|
||||
return new StepResponse({ company })
|
||||
}
|
||||
|
||||
// create customer group
|
||||
const { result } = await createCustomerGroupsWorkflow(
|
||||
container
|
||||
).run({
|
||||
input: {
|
||||
customersData: [customer_group],
|
||||
},
|
||||
})
|
||||
|
||||
company.customer_group_id = result[0].id
|
||||
|
||||
return new StepResponse({ company })
|
||||
}
|
||||
)
|
||||
|
||||
export type CreateCompanyStep = {
|
||||
companyData: CreateCompanyDTO
|
||||
}
|
||||
|
||||
const createCompanyStep = createStep(
|
||||
"create-company-step",
|
||||
async (
|
||||
{ companyData }: CreateCompanyStep,
|
||||
{ container }) => {
|
||||
const b2bModuleService: B2bModuleService = container
|
||||
.resolve(
|
||||
"b2bModuleService"
|
||||
)
|
||||
|
||||
const company = await b2bModuleService.createCompany(
|
||||
companyData
|
||||
)
|
||||
|
||||
return new StepResponse({ company })
|
||||
}
|
||||
)
|
||||
|
||||
export const createCompanyWorkflow = createWorkflow<
|
||||
CreateCompanyWorkflowInput,
|
||||
CreateCompanyWorkflowOutput
|
||||
>(
|
||||
"create-company",
|
||||
function (input) {
|
||||
const {
|
||||
company: companyData,
|
||||
} = tryToCreateCustomerGroupStep(input)
|
||||
|
||||
const company = createCompanyStep({ companyData })
|
||||
|
||||
return company
|
||||
}
|
||||
)
|
||||
```
|
||||
|
||||
You create a workflow with two steps:
|
||||
|
||||
1. The first one tries to create a customer group if its data is provided in the `customer_group` property and sets its value in the `customer_group_id` property.
|
||||
2. The second one creates the company.
|
||||
|
||||
Finally, create the file `src/api/admin/b2b/company/route.ts` with the following content:
|
||||
|
||||
```ts title="src/api/admin/b2b/company/route.ts" collapsibleLines="1-9" expandButtonLabel="Show Imports"
|
||||
import type {
|
||||
MedusaRequest,
|
||||
MedusaResponse,
|
||||
} from "@medusajs/medusa"
|
||||
import {
|
||||
CreateCompanyWorkflowInput,
|
||||
createCompanyWorkflow,
|
||||
} from "../../../../workflows/create-company"
|
||||
|
||||
type CreateCompanyReq = CreateCompanyWorkflowInput
|
||||
|
||||
export async function POST(
|
||||
req: MedusaRequest<CreateCompanyReq>,
|
||||
res: MedusaResponse
|
||||
) {
|
||||
const { result } = await createCompanyWorkflow(req.scope)
|
||||
.run({
|
||||
input: req.body,
|
||||
})
|
||||
|
||||
res.json({
|
||||
company: result.company,
|
||||
})
|
||||
}
|
||||
```
|
||||
|
||||
The API route uses the workflow to create the company. It passes the request body as the workflow's input.
|
||||
|
||||
### Test API Route
|
||||
|
||||
To test the API route, start the Medusa application:
|
||||
|
||||
```bash npm2yarn
|
||||
npm run dev
|
||||
```
|
||||
|
||||
Next, make sure you authenticate as an admin user as explained in [this Authentication guide](!api!/admin#authentication).
|
||||
|
||||
Then, send a `POST` request to the `/admin/b2b/company` API route:
|
||||
|
||||
```bash
|
||||
curl -X POST 'localhost:9000/admin/b2b/company' \
|
||||
--header 'Content-Type: application/json' \
|
||||
--header 'Authorization: Bearer {jwt_token}' \
|
||||
--data '{
|
||||
"name": "Acme",
|
||||
"city": "London",
|
||||
"country_code": "gb",
|
||||
"customer_group": {
|
||||
"name": "B2B"
|
||||
}
|
||||
}'
|
||||
```
|
||||
|
||||
This creates a company and its associated customer group.
|
||||
|
||||
<Note title="Tip">
|
||||
|
||||
You can alternatively pass a `customer_group_id` to use an existing customer group.
|
||||
|
||||
</Note>
|
||||
|
||||
</Details> */}
|
||||
/>
|
||||
|
||||
## Add B2B Customers
|
||||
|
||||
@@ -491,49 +137,21 @@ You can do that through the Medusa Admin or Admin REST APIs.
|
||||
|
||||
### Create Customers
|
||||
|
||||
{/* TODO add links */}
|
||||
|
||||
<CardList items={[
|
||||
{
|
||||
href: "#",
|
||||
title: "Option 1: Use Medusa Admin",
|
||||
text: "Create the customers using the Medusa Admin.",
|
||||
icon: UsersSolid,
|
||||
badge: {
|
||||
variant: "blue",
|
||||
children: "Guide Soon"
|
||||
}
|
||||
},
|
||||
{
|
||||
href: "!api!/admin#customers_postcustomers",
|
||||
title: "Option 2: Using the REST APIs",
|
||||
text: "Create the customers using the REST APIs.",
|
||||
icon: AcademicCapSolid,
|
||||
},
|
||||
]} />
|
||||
<Card
|
||||
href="!api!/admin#customers_postcustomers"
|
||||
title="Create Customers"
|
||||
text="Create the customers using the REST APIs."
|
||||
icon={AcademicCapSolid}
|
||||
/>
|
||||
|
||||
### Assign Customers to Groups
|
||||
|
||||
{/* TODO add links */}
|
||||
|
||||
<CardList items={[
|
||||
{
|
||||
href: "#",
|
||||
title: "Option 1: Use Medusa Admin",
|
||||
text: "Assign the customers to the B2B customer group using the Medusa Admin.",
|
||||
icon: UsersSolid,
|
||||
badge: {
|
||||
variant: "blue",
|
||||
children: "Guide Soon"
|
||||
}
|
||||
},
|
||||
{
|
||||
href: "!api!/admin#customer-groups_postcustomergroupsidcustomersbatch",
|
||||
title: "Option 2: Using the REST APIs",
|
||||
text: "Assign the customers to the B2B customer group using the REST APIs.",
|
||||
icon: AcademicCapSolid,
|
||||
},
|
||||
]} />
|
||||
<Card
|
||||
href="!api!/admin#customer-groups_postcustomergroupsidcustomersbatch"
|
||||
title="Assign Customers to Groups"
|
||||
text="Assign the customers to the B2B customer group using the REST APIs."
|
||||
icon={AcademicCapSolid}
|
||||
/>
|
||||
|
||||
---
|
||||
|
||||
@@ -543,26 +161,12 @@ Use price lists to set different prices for each B2B customer group, among other
|
||||
|
||||
You can create a price list using the Medusa Admin or the Admin REST APIs. Make sure to set the B2B customer group as a condition.
|
||||
|
||||
{/* TODO add links */}
|
||||
|
||||
<CardList items={[
|
||||
{
|
||||
href: "#",
|
||||
title: "Using Medusa Admin",
|
||||
text: "Create the price list using the Medusa Admin.",
|
||||
icon: UsersSolid,
|
||||
badge: {
|
||||
variant: "blue",
|
||||
children: "Guide Soon"
|
||||
}
|
||||
},
|
||||
{
|
||||
href: "!api!/admin#price-lists_postpricelists",
|
||||
title: "Using REST APIs",
|
||||
text: "Create the price list using the REST APIs.",
|
||||
icon: AcademicCapSolid,
|
||||
},
|
||||
]} />
|
||||
<Card
|
||||
href="!api!/admin#price-lists_postpricelists"
|
||||
title="Create Price List"
|
||||
text="Create the price list using the REST APIs."
|
||||
icon={AcademicCapSolid}
|
||||
/>
|
||||
|
||||
---
|
||||
|
||||
@@ -594,126 +198,6 @@ The API route can check if the customer has any group with an associated company
|
||||
icon={AcademicCapSolid}
|
||||
/>
|
||||
|
||||
{/* <Details summaryContent="Example">
|
||||
|
||||
For example, create the API route `src/api/store/b2b/check-customer/route.ts` with the following content:
|
||||
|
||||
export const checkCustomerHighlights = [
|
||||
["19", "retrieveCustomer", "Retrieve the customer along with its groups."],
|
||||
["26", "listCompanies", "List the companies that have a customer group ID matching any of the customer's group IDs."],
|
||||
["31", "", "Return whether there are any companies associated with the customer's groups."]
|
||||
]
|
||||
|
||||
```ts title="src/api/store/b2b/check-customer/route.ts" highlights={checkCustomerHighlights} collapsibleLines="1-5" expandButtonLabel="Show Imports"
|
||||
import type {
|
||||
AuthenticatedMedusaRequest,
|
||||
MedusaResponse,
|
||||
} from "@medusajs/medusa"
|
||||
import { Modules } from "@medusajs/framework/utils"
|
||||
import { ICustomerModuleService } from "@medusajs/framework/types"
|
||||
import B2bModuleService from "../../../../modules/b2b/service"
|
||||
|
||||
export async function GET(
|
||||
req: AuthenticatedMedusaRequest,
|
||||
res: MedusaResponse
|
||||
) {
|
||||
const customerModuleService: ICustomerModuleService = req
|
||||
.scope.resolve(Modules.CUSTOMER)
|
||||
const b2bModuleService: B2bModuleService = req.scope.resolve(
|
||||
"b2bModuleService"
|
||||
)
|
||||
|
||||
const customer = await customerModuleService.retrieveCustomer(
|
||||
req.auth_context.actor_id,
|
||||
{
|
||||
relations: ["groups"],
|
||||
}
|
||||
)
|
||||
|
||||
const companies = await b2bModuleService.listCompanies({
|
||||
customer_group_id: customer.groups.map((group) => group.id),
|
||||
})
|
||||
|
||||
res.json({
|
||||
is_b2b: companies.length > 0,
|
||||
})
|
||||
}
|
||||
```
|
||||
|
||||
This creates a `GET` API Route at `/store/b2b/check-customer` that:
|
||||
|
||||
1. Retrieves the customer along with its groups using the Customer Module's main service.
|
||||
2. Lists the companies that have a customer group ID matching any of the customer's group IDs.
|
||||
3. Return an `is_b2b` field whose value is `true` if there are any companies associated with the customer's groups.
|
||||
|
||||
Before using the API route, create the file `src/api/middlewares.ts` with the following content:
|
||||
|
||||
```ts title="src/api/middlewares.ts"
|
||||
import {
|
||||
MiddlewaresConfig,
|
||||
authenticate,
|
||||
} from "@medusajs/medusa"
|
||||
|
||||
export const config: MiddlewaresConfig = {
|
||||
routes: [
|
||||
{
|
||||
matcher: "/store/b2b*",
|
||||
middlewares: [
|
||||
authenticate("store", ["bearer", "session"]),
|
||||
],
|
||||
},
|
||||
],
|
||||
}
|
||||
```
|
||||
|
||||
This ensures that only logged-in customers can use the API route.
|
||||
|
||||
### Test API Route
|
||||
|
||||
To test out the API route:
|
||||
|
||||
1. Start the Medusa application.
|
||||
2. Obtain an authentication JWT token for a new customer. Do that by sending a `POST` request to the `/auth/store/emailpass` API Route:
|
||||
|
||||
```bash
|
||||
curl -X POST 'http://localhost:9000/auth/store/emailpass' \
|
||||
-H 'Content-Type: application/json' \
|
||||
--data-raw '{
|
||||
"email": "test@medusajs.com",
|
||||
"password": "supersecret"
|
||||
}'
|
||||
```
|
||||
|
||||
3. Send a `POST` request to the `/store/customers` API route that registers the customer. Make sure to pass the authentication JWT token from the previous token in the header:
|
||||
|
||||
```bash
|
||||
curl -X POST 'http://localhost:9000/store/customers' \
|
||||
-H 'Content-Type: application/json' \
|
||||
-H 'Authorization: Bearer {jwt_token}' \
|
||||
--data-raw '{
|
||||
"email": "test@medusajs.com",
|
||||
"password": "supersecret"
|
||||
}'
|
||||
```
|
||||
|
||||
4. Add the customer to the B2B group as explained in a [previous section](#add-b2b-customers).
|
||||
5. Send a `GET` request to the `/store/b2b/check-customer` API route you created in this section:
|
||||
|
||||
```bash
|
||||
curl 'http://localhost:9000/store/b2b/check-customer' \
|
||||
--header 'Authorization: Bearer {jwt_token}'
|
||||
```
|
||||
|
||||
You'll receive a JSON response as the following:
|
||||
|
||||
```json
|
||||
{
|
||||
"is_b2b": true
|
||||
}
|
||||
```
|
||||
|
||||
</Details> */}
|
||||
|
||||
---
|
||||
|
||||
## Customize Admin
|
||||
@@ -726,23 +210,25 @@ The Medusa Admin plugin can be extended to add widgets, new pages, and setting p
|
||||
{
|
||||
href: "!docs!/learn/fundamentals/admin/widgets",
|
||||
title: "Create Admin Widget",
|
||||
text: "Learn how to add widgets into existing admin pages.",
|
||||
text: "Add widgets into existing admin pages.",
|
||||
icon: AcademicCapSolid,
|
||||
},
|
||||
{
|
||||
href: "!docs!/learn/fundamentals/admin/ui-routes",
|
||||
title: "Create Admin UI Routes",
|
||||
text: "Learn how to add new pages to your Medusa Admin.",
|
||||
icon: AcademicCapSolid,
|
||||
},
|
||||
{
|
||||
href: "!docs!/learn/fundamentals/admin/ui-routes#create-settings-page",
|
||||
title: "Create Admin Setting Page",
|
||||
text: "Learn how to add new page to the Medusa Admin settings.",
|
||||
text: "Add new pages to your Medusa Admin.",
|
||||
icon: AcademicCapSolid,
|
||||
},
|
||||
]} />
|
||||
|
||||
<Card
|
||||
href="!docs!/learn/fundamentals/admin/ui-routes#create-settings-page"
|
||||
title="Create Admin Setting Page"
|
||||
text="Add new page to the Medusa Admin settings."
|
||||
icon={AcademicCapSolid}
|
||||
className="mt-1"
|
||||
/>
|
||||
|
||||
---
|
||||
|
||||
## Customize Storefront
|
||||
|
||||
@@ -110,7 +110,7 @@ export const generatedEditDates = {
|
||||
"app/medusa-container-resources/page.mdx": "2025-01-06T11:19:35.623Z",
|
||||
"app/medusa-workflows-reference/page.mdx": "2025-01-20T08:21:29.962Z",
|
||||
"app/nextjs-starter/page.mdx": "2025-01-06T12:19:31.143Z",
|
||||
"app/recipes/b2b/page.mdx": "2024-10-03T13:07:44.153Z",
|
||||
"app/recipes/b2b/page.mdx": "2025-01-29T11:35:23.247Z",
|
||||
"app/recipes/commerce-automation/page.mdx": "2024-10-16T08:52:01.585Z",
|
||||
"app/recipes/digital-products/examples/standard/page.mdx": "2025-01-13T11:31:35.362Z",
|
||||
"app/recipes/digital-products/page.mdx": "2025-01-06T11:19:35.623Z",
|
||||
|
||||
Reference in New Issue
Block a user