docs: updates to use DML and other changes (#7834)

- Change existing data model guides and add new ones for DML
- Change module's docs around service factory + remove guides that are now necessary
- Hide/remove all mentions of module relationships, or label them as coming soon.
- Change all data model creation snippets to use DML
- use `property` instead of `field` when referring to a data model's properties.
- Fix all snippets in commerce module guides to use new method suffix (no more main model methods)
- Rework recipes, removing/hiding a lot of sections as a lot of recipes are incomplete with the current state of DML.


### Other changes

- Highlight fixes in some guides
- Remove feature flags guide
- Fix code block styles when there are no line numbers.

### Upcoming changes in other PRs

- Re-generate commerce module references (for the updates in the method names)
- Ensure that the data model references are generated correctly for models using DML.
- (probably at a very later point) revisit recipes
This commit is contained in:
Shahed Nasser
2024-06-26 07:55:59 +00:00
committed by GitHub
parent 62dacdda75
commit 0462cc5acf
126 changed files with 1808 additions and 14242 deletions
+90 -147
View File
@@ -8,6 +8,12 @@ export const metadata = {
This recipe provides the general steps to implement a B2B store with Medusa.
<Note type="soon" title="In Development">
This recipe is a work in progress, as some features are not ready yet in Medusa V2.
</Note>
## Overview
In a B2B store, you provide different types of customers with relevant pricing, products, shopping experience, and more.
@@ -180,6 +186,12 @@ This is useful in B2B sales, as you often negotiate special prices with each cus
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.
<Note type="soon">
Module Relationships is coming soon.
</Note>
<CardList items={[
{
href: "!docs!/basics/modules-and-services",
@@ -197,50 +209,37 @@ You can create a B2B module that adds necessary data models to represent a B2B c
},
]} />
<Card
{/* <Card
href="!docs!/advanced-development/modules/module-relationships"
title="Create Module Relationships"
text="Learn how to create a relationship between modules."
startIcon={<AcademicCapSolid />}
showLinkIcon={false}
className="mt-1"
/>
/> */}
<Details summaryContent="Example">
{/* <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={[["23", "", "Field will be used to create a relationship to customer groups."]]} collapsibleLines="1-7" expandButtonLabel="Show Imports"
import { BaseEntity } from "@medusajs/utils"
import {
Entity,
PrimaryKey,
Property,
} from "@mikro-orm/core"
```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/utils"
@Entity()
export class Company extends BaseEntity {
@PrimaryKey({ columnType: "text" })
id!: string
const Company = model.define("company", {
id: model.id(),
name: model.text(),
city: model.text(),
country_code: model.text(),
customer_group_id: model.text().nullable(),
})
@Property({ columnType: "text" })
name: string
@Property({ columnType: "text" })
city: string
@Property({ columnType: "text" })
country_code: string
@Property({ columnType: "text" })
customer_group_id?: string
}
export default Company
```
This creates a `Company` data model with some relevant fields. Most importantly, it has a `customer_group_id` field. It'll later be used when creating the relationship to the `CustomerGroup` data model in the Customer Module.
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:
@@ -261,106 +260,22 @@ You can create a B2B module that adds necessary data models to represent a B2B c
You'll run the migration to reflect the data model in the database after finishing the module definition.
Before creating the module's main service, create the file `src/types/b2b/index.ts` with some helper types:
```ts title="src/types/b2b/index.ts"
import { CustomerGroupDTO } from "@medusajs/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
}
```
You can now create the module's main service at `src/modules/b2b/service.ts` with the following content:
export const mainServiceHighlights = [
["42", "relationships", "Implement the relationship to the `CustomerGroup` data model in the Customer Module."],
["56", "create", "Implement a create method to create a company."]
]
Then, create the module's main service at `src/modules/b2b/service.ts` with the following content:
```ts title="src/modules/b2b/service.ts" highlights={mainServiceHighlights} collapsibleLines="1-6" expandButtonLabel="Show Imports"
import { ModulesSdkUtils } from "@medusajs/utils"
import { ModuleJoinerConfig, ModulesSdkTypes } from "@medusajs/types"
import { Modules } from "@medusajs/modules-sdk"
import { Company } from "./models/company"
import { CompanyDTO, CreateCompanyDTO } from "../../types/b2b"
type InjectedDependencies = {
companyService: ModulesSdkTypes.InternalModuleService<any>
```ts title="src/modules/b2b/service.ts"
import { MedusaService } from "@medusajs/utils"
import Company from "./models/company"
class B2bModuleService extends MedusaService({
Company,
}){
// TODO add custom methods
}
type AllModelsDTO = {
Company: {
dto: CompanyDTO
}
}
class B2bModuleService extends ModulesSdkUtils
.abstractModuleServiceFactory<
InjectedDependencies,
CompanyDTO,
AllModelsDTO
>(Company, []) {
companyService_: ModulesSdkTypes.InternalModuleService<Company>
constructor({ companyService }: InjectedDependencies) {
// @ts-ignore
super(...arguments)
this.companyService_ = companyService
}
__joinerConfig(): ModuleJoinerConfig {
return {
serviceName: "b2bModuleService",
alias: [
{
name: ["company"],
args: {
entity: Company.name,
},
},
],
relationships: [
{
serviceName: Modules.CUSTOMER,
alias: "customer_group",
primaryKey: "id",
foreignKey: "customer_group_id",
args: {
methodSuffix: "CustomerGroups",
},
},
],
}
}
async create(data: CreateCompanyDTO): Promise<CompanyDTO> {
const company = this.companyService_.create(data)
return company
}
}
export default B2bModuleService
```
This creates a `B2bModuleService` that extends the service factory and implements:
- The module's relationship to the `CustomerGroup` data model in the Customer Module within the `__joinerConfig` method.
- A `create` method to create a company.
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:
@@ -398,7 +313,30 @@ export const mainServiceHighlights = [
To test out using the B2B Module, you'll add an API route to create a company.
Start by creating the file `src/workflows/create-company.ts` with the following content:
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/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."],
@@ -419,7 +357,7 @@ export const workflowHighlights = [
import { CreateCustomerGroupDTO } from "@medusajs/types"
import { CompanyDTO, CreateCompanyDTO } from "../types/b2b"
import B2bModuleService from "../modules/b2b/service"
export type CreateCompanyWorkflowInput = CreateCompanyDTO & {
customer_group?: CreateCustomerGroupDTO
}
@@ -471,7 +409,7 @@ export const workflowHighlights = [
"b2bModuleService"
)
const company = await b2bModuleService.create(
const company = await b2bModuleService.createCompany(
companyData
)
@@ -498,10 +436,10 @@ export const workflowHighlights = [
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` field.
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.
Then, create the file `src/api/admin/b2b/company/route.ts` with the following content:
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 {
@@ -566,7 +504,7 @@ export const workflowHighlights = [
</Note>
</Details>
</Details> */}
## Add B2B Customers
@@ -687,18 +625,21 @@ The API route can check if the customer has any group with an associated company
showLinkIcon={false}
/>
<Details summaryContent="Example">
{/* <Details summaryContent="Example">
For example, create the API route `src/api/store/b2b/check-customer/route.ts` with the following content:
export const checkCustomerHighlights = [
["16", "retrieve", "Retrieve the customer along with its groups."],
["20", "list", "List the companies that have a customer group ID matching any of the customer's group IDs."],
["25", "", "Return whether there are any companies associated with the customer's groups."]
["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 type {
AuthenticatedMedusaRequest,
MedusaResponse,
} from "@medusajs/medusa"
import { ModuleRegistrationName } from "@medusajs/modules-sdk"
import { ICustomerModuleService } from "@medusajs/types"
import B2bModuleService from "../../../../modules/b2b/service"
@@ -713,11 +654,14 @@ export const checkCustomerHighlights = [
"b2bModuleService"
)
const customer = await customerModuleService.retrieve(req.auth.actor_id, {
relations: ["groups"],
})
const customer = await customerModuleService.retrieveCustomer(
req.auth_context.actor_id,
{
relations: ["groups"],
}
)
const companies = await b2bModuleService.list({
const companies = await b2bModuleService.listCompanies({
customer_group_id: customer.groups.map((group) => group.id),
})
@@ -736,7 +680,10 @@ export const checkCustomerHighlights = [
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"
import {
MiddlewaresConfig,
authenticate,
} from "@medusajs/medusa"
export const config: MiddlewaresConfig = {
routes: [
@@ -796,16 +743,12 @@ export const checkCustomerHighlights = [
}
```
</Details>
</Details> */}
---
## Customize Admin
<Note type="soon">
Admin customizations are coming soon!
</Note>
Based on your use case, you may need to customize the Medusa Admin to add new widgets or pages.
The Medusa Admin plugin can be extended to add widgets, new pages, and setting pages.
@@ -851,9 +794,9 @@ Use the publishable API key you associated with your B2B sales channel in the st
showLinkIcon: false
},
{
href: "!docs!/storefront-development/tips",
title: "Storefront Tips",
text: "Find tips on developing a custom storefront.",
href: "/storefront-development",
title: "Storefront Development",
text: "Find guides for your storefront development.",
startIcon: <AcademicCapSolid />,
showLinkIcon: false
},