docs: document InferTypeOf (#9321)
- Add documentation on how to use InferTypeOf - Use InferTypeOf in recipes and examples
This commit is contained in:
1 parent
c5bf22f3f4
commit
b3a204e974
12 files changed
+170
-112
No files matched your search
@@ -0,0 +1,42 @@
|
|||||||
|
export const metadata = {
|
||||||
|
title: `${pageNumber} Infer Type of Data Model`,
|
||||||
|
}
|
||||||
|
|
||||||
|
# {metadata.title}
|
||||||
|
|
||||||
|
In this chapter, you'll learn how to infer the type of a data model.
|
||||||
|
|
||||||
|
## How to Infer Type of Data Model?
|
||||||
|
|
||||||
|
Consider you have a `MyCustom` data model. You can't reference this data model in a type, such as a workflow input or service method output types, since it's a variable.
|
||||||
|
|
||||||
|
Instead, Medusa provides an `InferTypeOf` utility imported from `@medusajs/types` that transforms your data model to a type.
|
||||||
|
|
||||||
|
For example:
|
||||||
|
|
||||||
|
```ts
|
||||||
|
import { InferTypeOf } from "@medusajs/types"
|
||||||
|
import { MyCustom } from "../models/my-custom" // relative path to the model
|
||||||
|
|
||||||
|
export type MyCustom = InferTypeOf<typeof MyCustom>
|
||||||
|
```
|
||||||
|
|
||||||
|
The `InferTypeOf` utility accepts as a type argument the type of the data model.
|
||||||
|
|
||||||
|
Since the `MyCustom` data model is a variable, use the `typeof` operator to pass the data model as a type argument to `InferTypeOf`.
|
||||||
|
|
||||||
|
You can now use the `MyCustom` type to reference a data model in other types, such as in workflow inputs or service method outputs:
|
||||||
|
|
||||||
|
```ts title="Example Service"
|
||||||
|
// other imports...
|
||||||
|
import { InferTypeOf } from "@medusajs/types"
|
||||||
|
import { MyCustom } from "../models/my-custom"
|
||||||
|
|
||||||
|
type MyCustom = InferTypeOf<typeof MyCustom>
|
||||||
|
|
||||||
|
class HelloModuleService extends MedusaService({ MyCustom }) {
|
||||||
|
async doSomething(): Promise<MyCustom> {
|
||||||
|
// ...
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
@@ -21,8 +21,8 @@ It’s registered in the Medusa container under the `ContainerRegistrationKeys.R
|
|||||||
For example, consider the following step:
|
For example, consider the following step:
|
||||||
|
|
||||||
export const stepHighlights = [
|
export const stepHighlights = [
|
||||||
["14", "resolve", "Resolve the remote link."],
|
["19", "resolve", "Resolve the remote link."],
|
||||||
["18", "create", "Create a link between two records."]
|
["23", "create", "Create a link between two records."]
|
||||||
]
|
]
|
||||||
|
|
||||||
```ts highlights={stepHighlights} collapsibleLines="1-10" expandButtonLabel="Show Imports"
|
```ts highlights={stepHighlights} collapsibleLines="1-10" expandButtonLabel="Show Imports"
|
||||||
@@ -36,9 +36,14 @@ import {
|
|||||||
} from "@medusajs/utils"
|
} from "@medusajs/utils"
|
||||||
import { BRAND_MODULE } from "../../modules/brand"
|
import { BRAND_MODULE } from "../../modules/brand"
|
||||||
|
|
||||||
|
type LinkProductToBrandStepInput = {
|
||||||
|
productId: string
|
||||||
|
brandId: string
|
||||||
|
}
|
||||||
|
|
||||||
export const linkProductToBrandStep = createStep(
|
export const linkProductToBrandStep = createStep(
|
||||||
"link-product-to-brand",
|
"link-product-to-brand",
|
||||||
async ({ productId, brandId }, { container }) => {
|
async ({ productId, brandId }: LinkProductToBrandStepInput, { container }) => {
|
||||||
const remoteLink = container.resolve(
|
const remoteLink = container.resolve(
|
||||||
ContainerRegistrationKeys.REMOTE_LINK
|
ContainerRegistrationKeys.REMOTE_LINK
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -66,20 +66,22 @@ The step returns the retrieved brands.
|
|||||||
Next, create the step that creates new brands in Medusa in the file `src/workflows/sync-brands-from-system/steps/create-brands.ts`:
|
Next, create the step that creates new brands in Medusa in the file `src/workflows/sync-brands-from-system/steps/create-brands.ts`:
|
||||||
|
|
||||||
export const createBrandsHighlights = [
|
export const createBrandsHighlights = [
|
||||||
["19", "createBrands", "Create the brands in Medusa"],
|
["21", "createBrands", "Create the brands in Medusa"],
|
||||||
["28", "deleteBrands", "Delete the brands from Medusa"]
|
["30", "deleteBrands", "Delete the brands from Medusa"]
|
||||||
]
|
]
|
||||||
|
|
||||||
```ts title="src/workflows/sync-brands-from-system/steps/create-brands.ts" highlights={createBrandsHighlights} collapsibleLines="1-7" expandButtonLabel="Show Imports"
|
```ts title="src/workflows/sync-brands-from-system/steps/create-brands.ts" highlights={createBrandsHighlights} collapsibleLines="1-9" expandButtonLabel="Show Imports"
|
||||||
import {
|
import {
|
||||||
createStep,
|
createStep,
|
||||||
StepResponse,
|
StepResponse,
|
||||||
} from "@medusajs/workflows-sdk"
|
} from "@medusajs/workflows-sdk"
|
||||||
|
import { InferTypeOf } from "@medusajs/types"
|
||||||
import BrandModuleService from "../../../modules/brand/service"
|
import BrandModuleService from "../../../modules/brand/service"
|
||||||
import { BRAND_MODULE } from "../../../modules/brand"
|
import { BRAND_MODULE } from "../../../modules/brand"
|
||||||
|
import { Brand } from "../../../modules/brand/models/brand"
|
||||||
|
|
||||||
type CreateBrandsInput = {
|
type CreateBrandsInput = {
|
||||||
brands: Record<string, string>[]
|
brands: InferTypeOf<typeof Brand>[]
|
||||||
}
|
}
|
||||||
|
|
||||||
export const createBrandsStep = createStep(
|
export const createBrandsStep = createStep(
|
||||||
@@ -105,6 +107,12 @@ export const createBrandsStep = createStep(
|
|||||||
|
|
||||||
This step receives the brands to create as input.
|
This step receives the brands to create as input.
|
||||||
|
|
||||||
|
<Note title="Tip">
|
||||||
|
|
||||||
|
Since a data model is a variable, use the `InferTypeOf` utility imported from `@medusajs/types` to infer its type.
|
||||||
|
|
||||||
|
</Note>
|
||||||
|
|
||||||
In the step, you resolve the Brand Module's main service and uses its `createBrands` method to create the brands.
|
In the step, you resolve the Brand Module's main service and uses its `createBrands` method to create the brands.
|
||||||
|
|
||||||
You return the created brands and pass their IDs to the compensation function, which deletes the brands if an error occurs.
|
You return the created brands and pass their IDs to the compensation function, which deletes the brands if an error occurs.
|
||||||
@@ -114,21 +122,23 @@ You return the created brands and pass their IDs to the compensation function, w
|
|||||||
To create the step that updates existing brands in Medusa, create the file `src/workflows/sync-brands-from-system/steps/update-brands.ts` with the following content:
|
To create the step that updates existing brands in Medusa, create the file `src/workflows/sync-brands-from-system/steps/update-brands.ts` with the following content:
|
||||||
|
|
||||||
export const updateBrandsHighlights = [
|
export const updateBrandsHighlights = [
|
||||||
["19", "prevUpdatedBrands", "Retrieve the data of the brands before the update."],
|
["21", "prevUpdatedBrands", "Retrieve the data of the brands before the update."],
|
||||||
["23", "updateBrands", "Update the brands in Medusa."],
|
["25", "updateBrands", "Update the brands in Medusa."],
|
||||||
["32", "updateBrands", "Revert the update by reverting the brands' to before the update."]
|
["34", "updateBrands", "Revert the update by reverting the brands' to before the update."]
|
||||||
]
|
]
|
||||||
|
|
||||||
```ts title="src/workflows/sync-brands-from-system/steps/update-brands.ts" highlights={updateBrandsHighlights} collapsibleLines="1-7" expandButtonLabel="Show Imports"
|
```ts title="src/workflows/sync-brands-from-system/steps/update-brands.ts" highlights={updateBrandsHighlights} collapsibleLines="1-9" expandButtonLabel="Show Imports"
|
||||||
import {
|
import {
|
||||||
createStep,
|
createStep,
|
||||||
StepResponse,
|
StepResponse,
|
||||||
} from "@medusajs/workflows-sdk"
|
} from "@medusajs/workflows-sdk"
|
||||||
|
import { InferTypeOf } from "@medusajs/types"
|
||||||
import BrandModuleService from "../../../modules/brand/service"
|
import BrandModuleService from "../../../modules/brand/service"
|
||||||
import { BRAND_MODULE } from "../../../modules/brand"
|
import { BRAND_MODULE } from "../../../modules/brand"
|
||||||
|
import { Brand } from "../../../modules/brand/models/brand"
|
||||||
|
|
||||||
type UpdateBrandsInput = {
|
type UpdateBrandsInput = {
|
||||||
brands: Record<string, string>[]
|
brands: InferTypeOf<typeof Brand>[]
|
||||||
}
|
}
|
||||||
|
|
||||||
export const updateBrandsStep = createStep(
|
export const updateBrandsStep = createStep(
|
||||||
@@ -172,9 +182,11 @@ import {
|
|||||||
WorkflowResponse,
|
WorkflowResponse,
|
||||||
transform,
|
transform,
|
||||||
} from "@medusajs/workflows-sdk"
|
} from "@medusajs/workflows-sdk"
|
||||||
|
import { InferTypeOf } from "@medusajs/types"
|
||||||
import { retrieveBrandsFromSystemStep } from "./steps/retrieve-brands-from-system"
|
import { retrieveBrandsFromSystemStep } from "./steps/retrieve-brands-from-system"
|
||||||
import { createBrandsStep } from "./steps/create-brands"
|
import { createBrandsStep } from "./steps/create-brands"
|
||||||
import { updateBrandsStep } from "./steps/update-brands"
|
import { updateBrandsStep } from "./steps/update-brands"
|
||||||
|
import { Brand } from "../../modules/brand/models/brand"
|
||||||
|
|
||||||
export const syncBrandsFromSystemWorkflow = createWorkflow(
|
export const syncBrandsFromSystemWorkflow = createWorkflow(
|
||||||
"sync-brands-from-system",
|
"sync-brands-from-system",
|
||||||
@@ -204,8 +216,8 @@ const { toCreate, toUpdate } = transform(
|
|||||||
brands,
|
brands,
|
||||||
},
|
},
|
||||||
(data) => {
|
(data) => {
|
||||||
const toCreate: Record<string, string>[] = []
|
const toCreate: InferTypeOf<typeof Brand>[] = []
|
||||||
const toUpdate: Record<string, string>[] = []
|
const toUpdate: InferTypeOf<typeof Brand>[] = []
|
||||||
|
|
||||||
data.brands.forEach((brand) => {
|
data.brands.forEach((brand) => {
|
||||||
if (brand.external_id) {
|
if (brand.external_id) {
|
||||||
|
|||||||
@@ -80,13 +80,17 @@ If the service integrating the third-party system was a main service, it receive
|
|||||||
Next, add the following methods to simulate sending requests to the third-party system:
|
Next, add the following methods to simulate sending requests to the third-party system:
|
||||||
|
|
||||||
export const methodsHighlights = [
|
export const methodsHighlights = [
|
||||||
["6", "sendRequest", "Since the third-party system isn't real, this method only logs a message."],
|
["10", "sendRequest", "Since the third-party system isn't real, this method only logs a message."],
|
||||||
["15", "createBrand", "A method that creates a brand in the third-party system."],
|
["19", "createBrand", "A method that creates a brand in the third-party system."],
|
||||||
["19", "deleteBrand", "A method that deletes a brand in the third-party system."],
|
["23", "deleteBrand", "A method that deletes a brand in the third-party system."],
|
||||||
["23", "retrieveBrands", "A method that retrieves a brand from a third-party system."]
|
["27", "retrieveBrands", "A method that retrieves a brand from a third-party system."]
|
||||||
]
|
]
|
||||||
|
|
||||||
```ts title="src/modules/brand/services/client.ts" highlights={methodsHighlights}
|
```ts title="src/modules/brand/services/client.ts" highlights={methodsHighlights}
|
||||||
|
// other imports...
|
||||||
|
import { InferTypeOf } from "@medusajs/types"
|
||||||
|
import { Brand } from "../models/brand"
|
||||||
|
|
||||||
export class BrandClient {
|
export class BrandClient {
|
||||||
// ...
|
// ...
|
||||||
|
|
||||||
@@ -101,7 +105,7 @@ export class BrandClient {
|
|||||||
}`)
|
}`)
|
||||||
}
|
}
|
||||||
|
|
||||||
async createBrand(brand: Record<string, any>) {
|
async createBrand(brand: InferTypeOf<typeof Brand>) {
|
||||||
await this.sendRequest("/brands", "POST", brand)
|
await this.sendRequest("/brands", "POST", brand)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -121,7 +125,7 @@ The `sendRequest` method is a dummy method to simulate sending a request to a th
|
|||||||
|
|
||||||
You also add three methods that use the `sendRequest` method:
|
You also add three methods that use the `sendRequest` method:
|
||||||
|
|
||||||
- `createBrand` that creates a brand in the third-party system.
|
- `createBrand` that creates a brand in the third-party system. To reference a brand's type, you use the `InferTypeOf` utility imported from `@medusajs/types`. This transforms a data model, which is a variable, to its equivalent type.
|
||||||
- `deleteBrand` that deletes the brand in the third-party system.
|
- `deleteBrand` that deletes the brand in the third-party system.
|
||||||
- `retrieveBrands` to retrieve a brand from the third-party system.
|
- `retrieveBrands` to retrieve a brand from the third-party system.
|
||||||
|
|
||||||
|
|||||||
@@ -87,7 +87,7 @@ export const generatedEditDates = {
|
|||||||
"app/customization/custom-features/api-route/page.mdx": "2024-09-12T12:42:34.201Z",
|
"app/customization/custom-features/api-route/page.mdx": "2024-09-12T12:42:34.201Z",
|
||||||
"app/customization/custom-features/module/page.mdx": "2024-09-12T12:39:37.928Z",
|
"app/customization/custom-features/module/page.mdx": "2024-09-12T12:39:37.928Z",
|
||||||
"app/customization/custom-features/workflow/page.mdx": "2024-09-12T12:40:39.582Z",
|
"app/customization/custom-features/workflow/page.mdx": "2024-09-12T12:40:39.582Z",
|
||||||
"app/customization/extend-models/create-links/page.mdx": "2024-09-12T12:42:55.602Z",
|
"app/customization/extend-models/create-links/page.mdx": "2024-09-26T08:31:08.177Z",
|
||||||
"app/customization/extend-models/extend-create-product/page.mdx": "2024-09-12T12:43:57.702Z",
|
"app/customization/extend-models/extend-create-product/page.mdx": "2024-09-12T12:43:57.702Z",
|
||||||
"app/customization/custom-features/page.mdx": "2024-09-12T11:18:13.271Z",
|
"app/customization/custom-features/page.mdx": "2024-09-12T11:18:13.271Z",
|
||||||
"app/customization/customize-admin/page.mdx": "2024-09-12T12:25:29.853Z",
|
"app/customization/customize-admin/page.mdx": "2024-09-12T12:25:29.853Z",
|
||||||
@@ -96,14 +96,15 @@ export const generatedEditDates = {
|
|||||||
"app/customization/extend-models/define-link/page.mdx": "2024-09-12T12:38:53.230Z",
|
"app/customization/extend-models/define-link/page.mdx": "2024-09-12T12:38:53.230Z",
|
||||||
"app/customization/extend-models/page.mdx": "2024-09-12T12:38:57.394Z",
|
"app/customization/extend-models/page.mdx": "2024-09-12T12:38:57.394Z",
|
||||||
"app/customization/extend-models/query-linked-records/page.mdx": "2024-09-12T12:44:41.089Z",
|
"app/customization/extend-models/query-linked-records/page.mdx": "2024-09-12T12:44:41.089Z",
|
||||||
"app/customization/integrate-systems/handle-event/page.mdx": "2024-09-12T12:39:07.978Z",
|
"app/customization/integrate-systems/handle-event/page.mdx": "2024-09-26T08:34:57.278Z",
|
||||||
"app/customization/integrate-systems/page.mdx": "2024-09-12T12:33:29.827Z",
|
"app/customization/integrate-systems/page.mdx": "2024-09-12T12:33:29.827Z",
|
||||||
"app/customization/integrate-systems/schedule-task/page.mdx": "2024-09-12T12:46:17.591Z",
|
"app/customization/integrate-systems/schedule-task/page.mdx": "2024-09-26T08:40:26.509Z",
|
||||||
"app/customization/integrate-systems/service/page.mdx": "2024-09-12T12:39:12.831Z",
|
"app/customization/integrate-systems/service/page.mdx": "2024-09-26T08:34:30.313Z",
|
||||||
"app/customization/next-steps/page.mdx": "2024-09-12T10:50:04.873Z",
|
"app/customization/next-steps/page.mdx": "2024-09-12T10:50:04.873Z",
|
||||||
"app/customization/page.mdx": "2024-09-12T11:16:18.504Z",
|
"app/customization/page.mdx": "2024-09-12T11:16:18.504Z",
|
||||||
"app/more-resources/cheatsheet/page.mdx": "2024-07-11T16:11:26.480Z",
|
"app/more-resources/cheatsheet/page.mdx": "2024-07-11T16:11:26.480Z",
|
||||||
"app/more-resources/examples/page.mdx": "2024-09-19T10:30:30.398Z",
|
"app/more-resources/examples/page.mdx": "2024-09-19T10:30:30.398Z",
|
||||||
"app/architecture/architectural-modules/page.mdx": "2024-09-23T12:51:04.520Z",
|
"app/architecture/architectural-modules/page.mdx": "2024-09-23T12:51:04.520Z",
|
||||||
"app/architecture/overview/page.mdx": "2024-09-23T12:55:01.339Z"
|
"app/architecture/overview/page.mdx": "2024-09-23T12:55:01.339Z",
|
||||||
|
"app/advanced-development/data-models/infer-type/page.mdx": "2024-09-26T08:28:13.041Z"
|
||||||
}
|
}
|
||||||
@@ -310,6 +310,11 @@ export const sidebar = numberSidebarItems(
|
|||||||
path: "/advanced-development/data-models",
|
path: "/advanced-development/data-models",
|
||||||
title: "Data Models",
|
title: "Data Models",
|
||||||
children: [
|
children: [
|
||||||
|
{
|
||||||
|
type: "link",
|
||||||
|
path: "/advanced-development/data-models/infer-type",
|
||||||
|
title: "Infer Type",
|
||||||
|
},
|
||||||
{
|
{
|
||||||
type: "link",
|
type: "link",
|
||||||
path: "/advanced-development/data-models/property-types",
|
path: "/advanced-development/data-models/property-types",
|
||||||
|
|||||||
@@ -58,7 +58,7 @@ const { data: products } = await query.graph({
|
|||||||
region_id: "region_123",
|
region_id: "region_123",
|
||||||
currency_code: "usd",
|
currency_code: "usd",
|
||||||
}),
|
}),
|
||||||
}
|
},
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
```
|
```
|
||||||
|
|||||||
@@ -1575,12 +1575,13 @@ You’ll only implement the `3.a` step of the workflow.
|
|||||||
Create the file `src/workflows/create-digital-product-order/steps/create-digital-product-order.ts` with the following content:
|
Create the file `src/workflows/create-digital-product-order/steps/create-digital-product-order.ts` with the following content:
|
||||||
|
|
||||||
export const createDpoHighlights = [
|
export const createDpoHighlights = [
|
||||||
|
["18", "InferTypeOf", "Infer the type of the `DigitalProduct` data model since it's a variable."],
|
||||||
["33", "createDigitalProductOrders", "Create the digital product order."],
|
["33", "createDigitalProductOrders", "Create the digital product order."],
|
||||||
["41", "digital_product_order", "Pass the created digital product order to the compensation function."],
|
["41", "digital_product_order", "Pass the created digital product order to the compensation function."],
|
||||||
["48", "deleteDigitalProductOrders", "Delete the digital product order if an error occurs in the workflow."]
|
["48", "deleteDigitalProductOrders", "Delete the digital product order if an error occurs in the workflow."]
|
||||||
]
|
]
|
||||||
|
|
||||||
```ts title="src/workflows/create-digital-product-order/steps/create-digital-product-order.ts" highlights={createDpoHighlights} collapsibleLines="1-15" expandMoreLabel="Show Imports"
|
```ts title="src/workflows/create-digital-product-order/steps/create-digital-product-order.ts" highlights={createDpoHighlights} collapsibleLines="1-14" expandMoreLabel="Show Imports"
|
||||||
import {
|
import {
|
||||||
createStep,
|
createStep,
|
||||||
StepResponse,
|
StepResponse,
|
||||||
@@ -1588,18 +1589,17 @@ import {
|
|||||||
import {
|
import {
|
||||||
OrderLineItemDTO,
|
OrderLineItemDTO,
|
||||||
ProductVariantDTO,
|
ProductVariantDTO,
|
||||||
|
InferTypeOf,
|
||||||
} from "@medusajs/types"
|
} from "@medusajs/types"
|
||||||
import {
|
import { OrderStatus } from "../../../modules/digital-product/types"
|
||||||
DigitalProductData,
|
|
||||||
OrderStatus,
|
|
||||||
} from "../../../modules/digital-product/types"
|
|
||||||
import DigitalProductModuleService from "../../../modules/digital-product/service"
|
import DigitalProductModuleService from "../../../modules/digital-product/service"
|
||||||
import { DIGITAL_PRODUCT_MODULE } from "../../../modules/digital-product"
|
import { DIGITAL_PRODUCT_MODULE } from "../../../modules/digital-product"
|
||||||
|
import DigitalProduct from "../../../modules/digital-product/models/digital-product"
|
||||||
|
|
||||||
type StepInput = {
|
type StepInput = {
|
||||||
items: (OrderLineItemDTO & {
|
items: (OrderLineItemDTO & {
|
||||||
variant: ProductVariantDTO & {
|
variant: ProductVariantDTO & {
|
||||||
digital_product: DigitalProductData
|
digital_product: InferTypeOf<typeof DigitalProduct>
|
||||||
}
|
}
|
||||||
})[]
|
})[]
|
||||||
}
|
}
|
||||||
@@ -1833,20 +1833,21 @@ So, you only need to implement the second step.
|
|||||||
Before creating the step, add to `src/modules/digital-product/types/index.ts` the following:
|
Before creating the step, add to `src/modules/digital-product/types/index.ts` the following:
|
||||||
|
|
||||||
```ts
|
```ts
|
||||||
import { OrderDTO } from "@medusajs/types"
|
import { OrderDTO, InferTypeOf } from "@medusajs/types"
|
||||||
|
import DigitalProductOrder from "../models/digital-product-order"
|
||||||
|
|
||||||
// ...
|
// ...
|
||||||
|
|
||||||
export type DigitalProductOrderData = {
|
export type DigitalProductOrder =
|
||||||
id: string
|
InferTypeOf<typeof DigitalProductOrder> & {
|
||||||
status: OrderStatus
|
order?: OrderDTO
|
||||||
products?: DigitalProductData[]
|
}
|
||||||
order?: OrderDTO
|
|
||||||
}
|
|
||||||
```
|
```
|
||||||
|
|
||||||
This adds a type for a digital product order, which you'll use next.
|
This adds a type for a digital product order, which you'll use next.
|
||||||
|
|
||||||
|
You use the `InferTypeOf` utility to infer the type of the `DigitalProductOrder` data model, and add to it the optional `order` property, which is the linked order.
|
||||||
|
|
||||||
### Create sendDigitalOrderNotificationStep
|
### Create sendDigitalOrderNotificationStep
|
||||||
|
|
||||||
To create the step, create the file `src/workflows/fulfill-digital-order/steps/send-digital-order-notification.ts` with the following content:
|
To create the step, create the file `src/workflows/fulfill-digital-order/steps/send-digital-order-notification.ts` with the following content:
|
||||||
@@ -1854,23 +1855,23 @@ To create the step, create the file `src/workflows/fulfill-digital-order/steps/s
|
|||||||
```ts title="src/workflows/fulfill-digital-order/steps/send-digital-order-notification.ts" collapsibleLines="1-11" expandMoreLabel="Show Imports"
|
```ts title="src/workflows/fulfill-digital-order/steps/send-digital-order-notification.ts" collapsibleLines="1-11" expandMoreLabel="Show Imports"
|
||||||
import {
|
import {
|
||||||
createStep,
|
createStep,
|
||||||
StepResponse
|
StepResponse,
|
||||||
} from "@medusajs/workflows-sdk"
|
} from "@medusajs/workflows-sdk"
|
||||||
import {
|
import {
|
||||||
INotificationModuleService,
|
INotificationModuleService,
|
||||||
IFileModuleService
|
IFileModuleService,
|
||||||
} from "@medusajs/types"
|
} from "@medusajs/types"
|
||||||
import { ModuleRegistrationName } from "@medusajs/utils"
|
import { ModuleRegistrationName } from "@medusajs/utils"
|
||||||
import { DigitalProductOrderData, MediaType } from "../../../modules/digital-product/types"
|
import { DigitalProductOrder, MediaType } from "../../../modules/digital-product/types"
|
||||||
|
|
||||||
type SendDigitalOrderNotificationStepInput = {
|
type SendDigitalOrderNotificationStepInput = {
|
||||||
digital_product_order: DigitalProductOrderData
|
digital_product_order: DigitalProductOrder
|
||||||
}
|
}
|
||||||
|
|
||||||
export const sendDigitalOrderNotificationStep = createStep(
|
export const sendDigitalOrderNotificationStep = createStep(
|
||||||
"send-digital-order-notification",
|
"send-digital-order-notification",
|
||||||
async ({
|
async ({
|
||||||
digital_product_order: digitalProductOrder
|
digital_product_order: digitalProductOrder,
|
||||||
}: SendDigitalOrderNotificationStepInput,
|
}: SendDigitalOrderNotificationStepInput,
|
||||||
{ container }) => {
|
{ container }) => {
|
||||||
const notificationModuleService: INotificationModuleService = container
|
const notificationModuleService: INotificationModuleService = container
|
||||||
@@ -1907,7 +1908,7 @@ const notificationData = await Promise.all(
|
|||||||
|
|
||||||
return {
|
return {
|
||||||
name: product.name,
|
name: product.name,
|
||||||
medias
|
medias,
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
)
|
)
|
||||||
@@ -1925,8 +1926,8 @@ const notification = await notificationModuleService.createNotifications({
|
|||||||
template: "digital-order-template",
|
template: "digital-order-template",
|
||||||
channel: "email",
|
channel: "email",
|
||||||
data: {
|
data: {
|
||||||
products: notificationData
|
products: notificationData,
|
||||||
}
|
},
|
||||||
})
|
})
|
||||||
|
|
||||||
return new StepResponse(notification)
|
return new StepResponse(notification)
|
||||||
@@ -1946,10 +1947,10 @@ export const fulfillWorkflowHighlights = [
|
|||||||
```ts title="src/workflows/fulfill-digital-order/index.ts" highlights={fulfillWorkflowHighlights} collapsibleLines="1-10" expandMoreLabel="Show Imports"
|
```ts title="src/workflows/fulfill-digital-order/index.ts" highlights={fulfillWorkflowHighlights} collapsibleLines="1-10" expandMoreLabel="Show Imports"
|
||||||
import {
|
import {
|
||||||
createWorkflow,
|
createWorkflow,
|
||||||
WorkflowResponse
|
WorkflowResponse,
|
||||||
} from "@medusajs/workflows-sdk"
|
} from "@medusajs/workflows-sdk"
|
||||||
import {
|
import {
|
||||||
useRemoteQueryStep
|
useRemoteQueryStep,
|
||||||
} from "@medusajs/core-flows"
|
} from "@medusajs/core-flows"
|
||||||
import { sendDigitalOrderNotificationStep } from "./steps/send-digital-order-notification"
|
import { sendDigitalOrderNotificationStep } from "./steps/send-digital-order-notification"
|
||||||
|
|
||||||
@@ -1966,7 +1967,7 @@ export const fulfillDigitalOrderWorkflow = createWorkflow(
|
|||||||
"*",
|
"*",
|
||||||
"products.*",
|
"products.*",
|
||||||
"products.medias.*",
|
"products.medias.*",
|
||||||
"order.*"
|
"order.*",
|
||||||
],
|
],
|
||||||
variables: {
|
variables: {
|
||||||
filters: {
|
filters: {
|
||||||
@@ -1974,11 +1975,11 @@ export const fulfillDigitalOrderWorkflow = createWorkflow(
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
list: false,
|
list: false,
|
||||||
throw_if_key_not_found: true
|
throw_if_key_not_found: true,
|
||||||
})
|
})
|
||||||
|
|
||||||
sendDigitalOrderNotificationStep({
|
sendDigitalOrderNotificationStep({
|
||||||
digital_product_order: digitalProductOrder
|
digital_product_order: digitalProductOrder,
|
||||||
})
|
})
|
||||||
|
|
||||||
return new WorkflowResponse(
|
return new WorkflowResponse(
|
||||||
@@ -2021,7 +2022,7 @@ module.exports = defineConfig({
|
|||||||
],
|
],
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
}
|
},
|
||||||
})
|
})
|
||||||
|
|
||||||
```
|
```
|
||||||
@@ -2040,7 +2041,7 @@ import type {
|
|||||||
SubscriberConfig,
|
SubscriberConfig,
|
||||||
} from "@medusajs/medusa"
|
} from "@medusajs/medusa"
|
||||||
import {
|
import {
|
||||||
fulfillDigitalOrderWorkflow
|
fulfillDigitalOrderWorkflow,
|
||||||
} from "../workflows/fulfill-digital-order"
|
} from "../workflows/fulfill-digital-order"
|
||||||
|
|
||||||
async function digitalProductOrderCreatedHandler({
|
async function digitalProductOrderCreatedHandler({
|
||||||
@@ -2049,8 +2050,8 @@ async function digitalProductOrderCreatedHandler({
|
|||||||
}: SubscriberArgs<{ id: string }>) {
|
}: SubscriberArgs<{ id: string }>) {
|
||||||
await fulfillDigitalOrderWorkflow(container).run({
|
await fulfillDigitalOrderWorkflow(container).run({
|
||||||
input: {
|
input: {
|
||||||
id: data.id
|
id: data.id,
|
||||||
}
|
},
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -435,17 +435,13 @@ Before implementing the functionalities, you’ll create type files in the Resta
|
|||||||
Create the file `src/modules/restaurant/types/index.ts` with the following content:
|
Create the file `src/modules/restaurant/types/index.ts` with the following content:
|
||||||
|
|
||||||
```ts title="src/modules/restaurant/types/index.ts"
|
```ts title="src/modules/restaurant/types/index.ts"
|
||||||
|
import { InferTypeOf } from "@medusajs/types"
|
||||||
import RestaurantModuleService from "../service"
|
import RestaurantModuleService from "../service"
|
||||||
|
import { Restaurant } from "../models/restaurant"
|
||||||
|
|
||||||
export interface CreateRestaurant {
|
export type CreateRestaurant = Omit<
|
||||||
name: string;
|
InferTypeOf<typeof Restaurant>, "id" | "admins"
|
||||||
handle: string;
|
>
|
||||||
address: string;
|
|
||||||
phone: string;
|
|
||||||
email: string;
|
|
||||||
image_url?: string;
|
|
||||||
is_open?: boolean;
|
|
||||||
}
|
|
||||||
|
|
||||||
declare module "@medusajs/types" {
|
declare module "@medusajs/types" {
|
||||||
export interface ModuleImplementations {
|
export interface ModuleImplementations {
|
||||||
@@ -456,6 +452,12 @@ declare module "@medusajs/types" {
|
|||||||
|
|
||||||
This adds a type used for inputs in creating a restaurant. It also adds a type for `restaurantModuleService` in `ModuleImplementations` so that when you resolve it from the Medusa container, it has the correct typing.
|
This adds a type used for inputs in creating a restaurant. It also adds a type for `restaurantModuleService` in `ModuleImplementations` so that when you resolve it from the Medusa container, it has the correct typing.
|
||||||
|
|
||||||
|
<Note title="Tip">
|
||||||
|
|
||||||
|
Since the `Restaurant` data model is a variable, use the `InferTypeOf` utility imported from `@medusajs/types` to infer its type.
|
||||||
|
|
||||||
|
</Note>
|
||||||
|
|
||||||
### Create Workflow
|
### Create Workflow
|
||||||
|
|
||||||
To implement the functionality of creating a restaurant, create a workflow and execute it in the API route.
|
To implement the functionality of creating a restaurant, create a workflow and execute it in the API route.
|
||||||
@@ -630,7 +632,7 @@ In the file `src/api/restaurants/route.ts` add the following API route:
|
|||||||
import { MedusaRequest, MedusaResponse } from "@medusajs/medusa"
|
import { MedusaRequest, MedusaResponse } from "@medusajs/medusa"
|
||||||
import {
|
import {
|
||||||
ContainerRegistrationKeys,
|
ContainerRegistrationKeys,
|
||||||
QueryContext
|
QueryContext,
|
||||||
} from "@medusajs/utils"
|
} from "@medusajs/utils"
|
||||||
|
|
||||||
// ...
|
// ...
|
||||||
@@ -662,7 +664,7 @@ export async function GET(req: MedusaRequest, res: MedusaResponse) {
|
|||||||
variants: {
|
variants: {
|
||||||
calculated_price: QueryContext({
|
calculated_price: QueryContext({
|
||||||
currency_code,
|
currency_code,
|
||||||
})
|
}),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@@ -2259,40 +2261,26 @@ Before implementing the necessary functionalities, add the following types to `s
|
|||||||
|
|
||||||
```ts title="src/modules/delivery/types/index.ts"
|
```ts title="src/modules/delivery/types/index.ts"
|
||||||
// other imports...
|
// other imports...
|
||||||
import {
|
import { InferTypeOf } from "@medusajs/types"
|
||||||
CartLineItemDTO,
|
import { Delivery } from "../models/delivery"
|
||||||
OrderLineItemDTO,
|
|
||||||
CartDTO,
|
|
||||||
OrderDTO,
|
|
||||||
} from "@medusajs/types"
|
|
||||||
|
|
||||||
// ...
|
// ...
|
||||||
|
|
||||||
export interface Delivery {
|
export type Delivery = InferTypeOf<typeof Delivery>
|
||||||
id: string;
|
|
||||||
transaction_id: string;
|
|
||||||
driver_id?: string;
|
|
||||||
delivered_at?: Date;
|
|
||||||
delivery_status: DeliveryStatus;
|
|
||||||
created_at: Date;
|
|
||||||
updated_at: Date;
|
|
||||||
eta?: Date;
|
|
||||||
items: DeliveryItem[];
|
|
||||||
cart?: CartDTO;
|
|
||||||
order?: OrderDTO;
|
|
||||||
}
|
|
||||||
|
|
||||||
export type DeliveryItem = (CartLineItemDTO | OrderLineItemDTO) & {
|
export type UpdateDelivery = Partial<Delivery> & {
|
||||||
quantity: number;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface UpdateDelivery extends Partial<Delivery> {
|
|
||||||
id: string;
|
id: string;
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
These types are useful in the upcoming implementation steps.
|
These types are useful in the upcoming implementation steps.
|
||||||
|
|
||||||
|
<Note title="Tip">
|
||||||
|
|
||||||
|
Since the `Delivery` data model is a variable, use the `InferTypeOf` utility imported from `@medusajs/types` to infer its type.
|
||||||
|
|
||||||
|
</Note>
|
||||||
|
|
||||||
### Create Workflow
|
### Create Workflow
|
||||||
|
|
||||||
As the API route should update the delivery’s status, you’ll create a new workflow to implement that functionality.
|
As the API route should update the delivery’s status, you’ll create a new workflow to implement that functionality.
|
||||||
|
|||||||
@@ -862,11 +862,11 @@ This step groups the items by the vendor associated with the product into an obj
|
|||||||
Next, create the fourth step in the file `src/workflows/marketplace/create-vendor-orders/steps/create-vendor-orders.ts`:
|
Next, create the fourth step in the file `src/workflows/marketplace/create-vendor-orders/steps/create-vendor-orders.ts`:
|
||||||
|
|
||||||
export const vendorOrder1Highlights = [
|
export const vendorOrder1Highlights = [
|
||||||
["41", "linkDefs", "An array of links to be created."],
|
["42", "linkDefs", "An array of links to be created."],
|
||||||
["58", "created_orders", "Pass the created orders to the compensation function."]
|
["59", "created_orders", "Pass the created orders to the compensation function."]
|
||||||
]
|
]
|
||||||
|
|
||||||
```ts title="src/workflows/marketplace/create-vendor-orders/steps/create-vendor-orders.ts" highlights={vendorOrder1Highlights} collapsibleLines="1-18" expandMoreLabel="Show Imports"
|
```ts title="src/workflows/marketplace/create-vendor-orders/steps/create-vendor-orders.ts" highlights={vendorOrder1Highlights} collapsibleLines="1-19" expandMoreLabel="Show Imports"
|
||||||
import {
|
import {
|
||||||
createStep,
|
createStep,
|
||||||
StepResponse,
|
StepResponse,
|
||||||
@@ -874,7 +874,8 @@ import {
|
|||||||
import {
|
import {
|
||||||
CartLineItemDTO,
|
CartLineItemDTO,
|
||||||
OrderDTO,
|
OrderDTO,
|
||||||
LinkDefinition
|
LinkDefinition,
|
||||||
|
InferTypeOf,
|
||||||
} from "@medusajs/types"
|
} from "@medusajs/types"
|
||||||
import { Modules } from "@medusajs/utils"
|
import { Modules } from "@medusajs/utils"
|
||||||
import {
|
import {
|
||||||
@@ -883,10 +884,10 @@ import {
|
|||||||
} from "@medusajs/core-flows"
|
} from "@medusajs/core-flows"
|
||||||
import MarketplaceModuleService from "../../../../modules/marketplace/service"
|
import MarketplaceModuleService from "../../../../modules/marketplace/service"
|
||||||
import { MARKETPLACE_MODULE } from "../../../../modules/marketplace"
|
import { MARKETPLACE_MODULE } from "../../../../modules/marketplace"
|
||||||
import { VendorData } from "../../../../modules/marketplace/types"
|
import Vendor from "../../../../modules/marketplace/models/vendor"
|
||||||
|
|
||||||
export type VendorOrder = (OrderDTO & {
|
export type VendorOrder = (OrderDTO & {
|
||||||
vendor: VendorData
|
vendor: InferTypeOf<typeof Vendor>
|
||||||
})
|
})
|
||||||
|
|
||||||
type StepInput = {
|
type StepInput = {
|
||||||
|
|||||||
@@ -363,6 +363,9 @@ The `getExpirationDate` method accepts a subscription’s date, interval, and pe
|
|||||||
Before overriding the `createSubscriptions` method, add the following types to `src/modules/subscription/types/index.ts`:
|
Before overriding the `createSubscriptions` method, add the following types to `src/modules/subscription/types/index.ts`:
|
||||||
|
|
||||||
```ts title="src/modules/subscription/types/index.ts"
|
```ts title="src/modules/subscription/types/index.ts"
|
||||||
|
import { InferTypeOf } from "@medusajs/types"
|
||||||
|
import Subscription from "../models/subscription"
|
||||||
|
|
||||||
// ...
|
// ...
|
||||||
|
|
||||||
export type CreateSubscriptionData = {
|
export type CreateSubscriptionData = {
|
||||||
@@ -373,19 +376,15 @@ export type CreateSubscriptionData = {
|
|||||||
metadata?: Record<string, unknown>
|
metadata?: Record<string, unknown>
|
||||||
}
|
}
|
||||||
|
|
||||||
export type SubscriptionData = {
|
export type SubscriptionData = InferTypeOf<typeof Subscription>
|
||||||
id: string
|
|
||||||
status: SubscriptionStatus
|
|
||||||
interval: SubscriptionInterval
|
|
||||||
subscription_date: Date
|
|
||||||
last_order_date: Date
|
|
||||||
next_order_date: Date | null
|
|
||||||
expiration_date: Date
|
|
||||||
metadata: Record<string, unknown> | null
|
|
||||||
}
|
|
||||||
|
|
||||||
```
|
```
|
||||||
|
|
||||||
|
<Note title="Tip">
|
||||||
|
|
||||||
|
Since the `Subscription` data model is a variable, use the `InferTypeOf` utility imported from `@medusajs/types` to infer its type.
|
||||||
|
|
||||||
|
</Note>
|
||||||
|
|
||||||
Then, in `src/modules/subscription/service.ts`, add the following to override the `createSubscriptions` method:
|
Then, in `src/modules/subscription/service.ts`, add the following to override the `createSubscriptions` method:
|
||||||
|
|
||||||
```ts title="src/modules/subscription/service.ts"
|
```ts title="src/modules/subscription/service.ts"
|
||||||
|
|||||||
@@ -141,18 +141,18 @@ export const generatedEditDates = {
|
|||||||
"app/nextjs-starter/page.mdx": "2024-07-01T10:21:19+03:00",
|
"app/nextjs-starter/page.mdx": "2024-07-01T10:21:19+03:00",
|
||||||
"app/recipes/b2b/page.mdx": "2024-08-29T09:23:12.736Z",
|
"app/recipes/b2b/page.mdx": "2024-08-29T09:23:12.736Z",
|
||||||
"app/recipes/commerce-automation/page.mdx": "2024-08-05T07:24:27+00:00",
|
"app/recipes/commerce-automation/page.mdx": "2024-08-05T07:24:27+00:00",
|
||||||
"app/recipes/digital-products/examples/standard/page.mdx": "2024-09-17T14:30:02.190Z",
|
"app/recipes/digital-products/examples/standard/page.mdx": "2024-09-26T09:00:12.671Z",
|
||||||
"app/recipes/digital-products/page.mdx": "2024-08-02T13:02:06+00:00",
|
"app/recipes/digital-products/page.mdx": "2024-08-02T13:02:06+00:00",
|
||||||
"app/recipes/ecommerce/page.mdx": "2024-06-09T15:18:43+02:00",
|
"app/recipes/ecommerce/page.mdx": "2024-06-09T15:18:43+02:00",
|
||||||
"app/recipes/integrate-ecommerce-stack/page.mdx": "2024-08-05T07:24:27+00:00",
|
"app/recipes/integrate-ecommerce-stack/page.mdx": "2024-08-05T07:24:27+00:00",
|
||||||
"app/recipes/marketplace/examples/vendors/page.mdx": "2024-09-02T14:06:37.189Z",
|
"app/recipes/marketplace/examples/vendors/page.mdx": "2024-09-26T09:06:11.833Z",
|
||||||
"app/recipes/marketplace/page.mdx": "2024-07-11T15:56:41+00:00",
|
"app/recipes/marketplace/page.mdx": "2024-07-11T15:56:41+00:00",
|
||||||
"app/recipes/multi-region-store/page.mdx": "2024-07-01T10:21:19+03:00",
|
"app/recipes/multi-region-store/page.mdx": "2024-07-01T10:21:19+03:00",
|
||||||
"app/recipes/omnichannel/page.mdx": "2024-06-09T15:18:43+02:00",
|
"app/recipes/omnichannel/page.mdx": "2024-06-09T15:18:43+02:00",
|
||||||
"app/recipes/oms/page.mdx": "2024-07-01T10:21:19+03:00",
|
"app/recipes/oms/page.mdx": "2024-07-01T10:21:19+03:00",
|
||||||
"app/recipes/personalized-products/page.mdx": "2024-09-11T10:53:03.936Z",
|
"app/recipes/personalized-products/page.mdx": "2024-09-11T10:53:03.936Z",
|
||||||
"app/recipes/pos/page.mdx": "2024-07-04T17:26:03+03:00",
|
"app/recipes/pos/page.mdx": "2024-07-04T17:26:03+03:00",
|
||||||
"app/recipes/subscriptions/examples/standard/page.mdx": "2024-09-11T10:16:35.673Z",
|
"app/recipes/subscriptions/examples/standard/page.mdx": "2024-09-26T10:19:57.044Z",
|
||||||
"app/recipes/subscriptions/page.mdx": "2024-08-02T12:40:26+03:00",
|
"app/recipes/subscriptions/page.mdx": "2024-08-02T12:40:26+03:00",
|
||||||
"app/recipes/page.mdx": "2024-07-11T15:56:41+00:00",
|
"app/recipes/page.mdx": "2024-07-11T15:56:41+00:00",
|
||||||
"app/service-factory-reference/methods/create/page.mdx": "2024-07-31T17:01:33+03:00",
|
"app/service-factory-reference/methods/create/page.mdx": "2024-07-31T17:01:33+03:00",
|
||||||
@@ -643,7 +643,7 @@ export const generatedEditDates = {
|
|||||||
"app/medusa-cli/commands/start/page.mdx": "2024-08-28T10:44:19.952Z",
|
"app/medusa-cli/commands/start/page.mdx": "2024-08-28T10:44:19.952Z",
|
||||||
"app/medusa-cli/commands/telemtry/page.mdx": "2024-08-28T11:25:08.553Z",
|
"app/medusa-cli/commands/telemtry/page.mdx": "2024-08-28T11:25:08.553Z",
|
||||||
"app/medusa-cli/commands/user/page.mdx": "2024-08-28T10:44:52.489Z",
|
"app/medusa-cli/commands/user/page.mdx": "2024-08-28T10:44:52.489Z",
|
||||||
"app/recipes/marketplace/examples/restaurant-delivery/page.mdx": "2024-09-11T13:29:33.305Z",
|
"app/recipes/marketplace/examples/restaurant-delivery/page.mdx": "2024-09-26T10:12:17.661Z",
|
||||||
"references/types/HttpTypes/interfaces/types.HttpTypes.AdminCreateCustomerGroup/page.mdx": "2024-08-30T00:11:02.074Z",
|
"references/types/HttpTypes/interfaces/types.HttpTypes.AdminCreateCustomerGroup/page.mdx": "2024-08-30T00:11:02.074Z",
|
||||||
"references/types/HttpTypes/interfaces/types.HttpTypes.AdminCreateReservation/page.mdx": "2024-08-30T00:11:02.342Z",
|
"references/types/HttpTypes/interfaces/types.HttpTypes.AdminCreateReservation/page.mdx": "2024-08-30T00:11:02.342Z",
|
||||||
"references/types/HttpTypes/interfaces/types.HttpTypes.AdminCustomerGroup/page.mdx": "2024-08-30T00:11:02.070Z",
|
"references/types/HttpTypes/interfaces/types.HttpTypes.AdminCustomerGroup/page.mdx": "2024-08-30T00:11:02.070Z",
|
||||||
|
|||||||
Reference in new issue
Block a user