chore(docs): added eslint to lint documentation code blocks (#2920)
* docs: added rule for code length * chore: fixes based on vale errors * changed to use eslint * fixes using eslint * added github action for documentation eslint * changed allowed max-length * fixed incorrect heading level * removed comment
This commit is contained in:
1 parent
99add15fc3
commit
d1b4b11ff6
67 files changed
+2611
-1735
No files matched your search
@@ -49,17 +49,20 @@ Batch job strategies must extend the abstract class `AbstractBatchJobStrategy` a
|
||||
|
||||
Add the following content to the file you created:
|
||||
|
||||
```tsx title=src/strategies/publish.ts
|
||||
import { AbstractBatchJobStrategy, BatchJobService } from '@medusajs/medusa'
|
||||
import { EntityManager } from 'typeorm'
|
||||
```ts title=src/strategies/publish.ts
|
||||
import {
|
||||
AbstractBatchJobStrategy,
|
||||
BatchJobService,
|
||||
} from "@medusajs/medusa"
|
||||
import { EntityManager } from "typeorm"
|
||||
|
||||
class PublishStrategy extends AbstractBatchJobStrategy {
|
||||
protected batchJobService_: BatchJobService
|
||||
processJob(batchJobId: string): Promise<void> {
|
||||
throw new Error('Method not implemented.')
|
||||
throw new Error("Method not implemented.")
|
||||
}
|
||||
buildTemplate(): Promise<string> {
|
||||
throw new Error('Method not implemented.')
|
||||
throw new Error("Method not implemented.")
|
||||
}
|
||||
protected manager_: EntityManager
|
||||
protected transactionManager_: EntityManager
|
||||
@@ -79,12 +82,12 @@ You will use the `batchType` later when you [interact with the Batch Job APIs](#
|
||||
|
||||
Following the same example, add the following properties to the `PublishStrategy` class:
|
||||
|
||||
```tsx
|
||||
```ts
|
||||
class PublishStrategy extends AbstractBatchJobStrategy {
|
||||
static identifier = 'publish-products-strategy'
|
||||
static batchType = 'publish-products'
|
||||
static identifier = "publish-products-strategy"
|
||||
static batchType = "publish-products"
|
||||
|
||||
//...
|
||||
// ...
|
||||
}
|
||||
```
|
||||
|
||||
@@ -98,10 +101,16 @@ Medusa runs this method before it creates the batch job to prepare the content o
|
||||
|
||||
Implementing this method is optional. For example:
|
||||
|
||||
```tsx
|
||||
async prepareBatchJobForProcessing(batchJob: CreateBatchJobInput, req: Express.Request): Promise<CreateBatchJobInput> {
|
||||
//make changes to the batch job's fields...
|
||||
return batchJob
|
||||
```ts
|
||||
class PublishStrategy extends AbstractBatchJobStrategy {
|
||||
// ...
|
||||
async prepareBatchJobForProcessing(
|
||||
batchJob: CreateBatchJobInput,
|
||||
req: Express.Request
|
||||
): Promise<CreateBatchJobInput> {
|
||||
// make changes to the batch job's fields...
|
||||
return batchJob
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
@@ -111,35 +120,38 @@ Medusa runs this method after it creates the batch job, but before it is confirm
|
||||
|
||||
For example, this implementation of the `preProcessBatchJob` method calculates how many draft products it will published and adds it to the `result` attribute of the batch job:
|
||||
|
||||
```tsx
|
||||
async preProcessBatchJob(batchJobId: string): Promise<void> {
|
||||
return await this.atomicPhase_(async (transactionManager) => {
|
||||
const batchJob = (await this.batchJobService_
|
||||
.withTransaction(transactionManager)
|
||||
.retrieve(batchJobId))
|
||||
|
||||
const count = await this.productService_
|
||||
.withTransaction(transactionManager)
|
||||
.count({
|
||||
status: ProductStatus.DRAFT
|
||||
});
|
||||
```ts
|
||||
class PublishStrategy extends AbstractBatchJobStrategy {
|
||||
// ...
|
||||
async preProcessBatchJob(batchJobId: string): Promise<void> {
|
||||
return await this.atomicPhase_(async (transactionManager) => {
|
||||
const batchJob = (await this.batchJobService_
|
||||
.withTransaction(transactionManager)
|
||||
.retrieve(batchJobId))
|
||||
|
||||
const count = await this.productService_
|
||||
.withTransaction(transactionManager)
|
||||
.count({
|
||||
status: ProductStatus.DRAFT,
|
||||
})
|
||||
|
||||
await this.batchJobService_
|
||||
.withTransaction(transactionManager)
|
||||
.update(batchJob, {
|
||||
result: {
|
||||
advancement_count: 0,
|
||||
count,
|
||||
stat_descriptors: [
|
||||
{
|
||||
key: 'product-publish-count',
|
||||
name: 'Number of products to publish',
|
||||
message: `${count} product(s) will be published.`
|
||||
}
|
||||
]
|
||||
}
|
||||
})
|
||||
})
|
||||
await this.batchJobService_
|
||||
.withTransaction(transactionManager)
|
||||
.update(batchJob, {
|
||||
result: {
|
||||
advancement_count: 0,
|
||||
count,
|
||||
stat_descriptors: [
|
||||
{
|
||||
key: "product-publish-count",
|
||||
name: "Number of products to publish",
|
||||
message: `${count} product(s) will be published.`,
|
||||
},
|
||||
],
|
||||
},
|
||||
})
|
||||
})
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
@@ -155,34 +167,37 @@ Medusa runs this method to process the batch job once it is confirmed.
|
||||
|
||||
For example, this implementation of the `processJob` method retrieves all draft products and changes their status to published:
|
||||
|
||||
```tsx
|
||||
async processJob(batchJobId: string): Promise<void> {
|
||||
return await this.atomicPhase_(
|
||||
async (transactionManager) => {
|
||||
const productServiceTx = this.productService_
|
||||
.withTransaction(transactionManager)
|
||||
```ts
|
||||
class PublishStrategy extends AbstractBatchJobStrategy {
|
||||
// ...
|
||||
async processJob(batchJobId: string): Promise<void> {
|
||||
return await this.atomicPhase_(
|
||||
async (transactionManager) => {
|
||||
const productServiceTx = this.productService_
|
||||
.withTransaction(transactionManager)
|
||||
|
||||
const productList = await productServiceTx
|
||||
.list({
|
||||
status: [ProductStatus.DRAFT]
|
||||
})
|
||||
|
||||
productList.forEach(async (product: Product) => {
|
||||
await productServiceTx
|
||||
.update(product.id, {
|
||||
status: ProductStatus.PUBLISHED
|
||||
const productList = await productServiceTx
|
||||
.list({
|
||||
status: [ProductStatus.DRAFT],
|
||||
})
|
||||
})
|
||||
|
||||
await this.batchJobService_
|
||||
.withTransaction(transactionManager)
|
||||
.update(batchJobId, {
|
||||
result: {
|
||||
advancement_count: productList.length
|
||||
}
|
||||
|
||||
productList.forEach(async (product: Product) => {
|
||||
await productServiceTx
|
||||
.update(product.id, {
|
||||
status: ProductStatus.PUBLISHED,
|
||||
})
|
||||
})
|
||||
}
|
||||
)
|
||||
|
||||
await this.batchJobService_
|
||||
.withTransaction(transactionManager)
|
||||
.update(batchJobId, {
|
||||
result: {
|
||||
advancement_count: productList.length,
|
||||
},
|
||||
})
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
@@ -198,9 +213,12 @@ This method can be used in cases where you provide a template file to download,
|
||||
|
||||
If not necessary to your use case, you can simply return an empty string:
|
||||
|
||||
```tsx
|
||||
async buildTemplate(): Promise<string> {
|
||||
return ''
|
||||
```ts
|
||||
class PublishStrategy extends AbstractBatchJobStrategy {
|
||||
// ...
|
||||
async buildTemplate(): Promise<string> {
|
||||
return ""
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
@@ -212,9 +230,15 @@ By default, the `AbstractBatchJobStrategy` class implements this method and retu
|
||||
|
||||
If you would like to change that behavior, you can override this method to return a different value:
|
||||
|
||||
```tsx
|
||||
protected async shouldRetryOnProcessingError(batchJob: BatchJob, err: unknown): Promise<boolean> {
|
||||
return true
|
||||
```ts
|
||||
class PublishStrategy extends AbstractBatchJobStrategy {
|
||||
// ...
|
||||
protected async shouldRetryOnProcessingError(
|
||||
batchJob: BatchJob,
|
||||
err: unknown
|
||||
): Promise<boolean> {
|
||||
return true
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
@@ -226,9 +250,16 @@ You can use this method as implemented in `AbstractBatchJobStrategy` at any poin
|
||||
|
||||
You can also override this method in your batch job strategy and change how it works:
|
||||
|
||||
```tsx
|
||||
protected async handleProcessingError<T>(batchJobId: string, err: unknown, result: T): Promise<void> {
|
||||
//different implementation...
|
||||
```ts
|
||||
class PublishStrategy extends AbstractBatchJobStrategy {
|
||||
// ...
|
||||
protected async handleProcessingError<T>(
|
||||
batchJobId: string,
|
||||
err: unknown,
|
||||
result: T
|
||||
): Promise<void> {
|
||||
// different implementation...
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
@@ -273,13 +304,13 @@ For example, this creates a batch job of the type `publish-products`:
|
||||
|
||||
```jsx
|
||||
medusa.admin.batchJobs.create({
|
||||
type: 'publish-products',
|
||||
type: "publish-products",
|
||||
context: { },
|
||||
dry_run: true
|
||||
dry_run: true,
|
||||
})
|
||||
.then(( batch_job ) => {
|
||||
console.log(batch_job.status);
|
||||
});
|
||||
console.log(batch_job.status)
|
||||
})
|
||||
```
|
||||
|
||||
</TabItem>
|
||||
@@ -287,21 +318,21 @@ medusa.admin.batchJobs.create({
|
||||
|
||||
```jsx
|
||||
fetch(`<YOUR_SERVER>/admin/batch-jobs`, {
|
||||
method: 'POST',
|
||||
credentials: 'include',
|
||||
method: "POST",
|
||||
credentials: "include",
|
||||
headers: {
|
||||
'Content-Type': 'application/json'
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
body: JSON.stringify({
|
||||
type: 'publish-products',
|
||||
type: "publish-products",
|
||||
context: { },
|
||||
dry_run: true
|
||||
})
|
||||
dry_run: true,
|
||||
}),
|
||||
})
|
||||
.then((response) => response.json())
|
||||
.then(({ batch_job }) => {
|
||||
console.log(batch_job.status);
|
||||
});
|
||||
console.log(batch_job.status)
|
||||
})
|
||||
```
|
||||
|
||||
</TabItem>
|
||||
@@ -335,8 +366,8 @@ You can retrieve the batch job afterward to get its status and view details abou
|
||||
```jsx
|
||||
medusa.admin.batchJobs.retrieve(batchJobId)
|
||||
.then(( batch_job ) => {
|
||||
console.log(batch_job.status, batch_job.result);
|
||||
});
|
||||
console.log(batch_job.status, batch_job.result)
|
||||
})
|
||||
```
|
||||
|
||||
</TabItem>
|
||||
@@ -344,12 +375,12 @@ medusa.admin.batchJobs.retrieve(batchJobId)
|
||||
|
||||
```jsx
|
||||
fetch(`<YOUR_SERVER>/admin/batch-jobs/${batchJobId}`, {
|
||||
credentials: 'include',
|
||||
credentials: "include",
|
||||
})
|
||||
.then((response) => response.json())
|
||||
.then(({ batch_job }) => {
|
||||
console.log(batch_job.status, batch_job.result);
|
||||
});
|
||||
console.log(batch_job.status, batch_job.result)
|
||||
})
|
||||
```
|
||||
|
||||
</TabItem>
|
||||
@@ -390,8 +421,8 @@ To process the batch job, send a request to [confirm the batch job](https://docs
|
||||
```jsx
|
||||
medusa.admin.batchJobs.confirm(batchJobId)
|
||||
.then(( batch_job ) => {
|
||||
console.log(batch_job.status);
|
||||
});
|
||||
console.log(batch_job.status)
|
||||
})
|
||||
```
|
||||
|
||||
</TabItem>
|
||||
@@ -399,13 +430,13 @@ medusa.admin.batchJobs.confirm(batchJobId)
|
||||
|
||||
```jsx
|
||||
fetch(`<YOUR_SERVER>/admin/batch-jobs/${batchJobId}/confirm`, {
|
||||
method: 'POST',
|
||||
credentials: 'include',
|
||||
method: "POST",
|
||||
credentials: "include",
|
||||
})
|
||||
.then((response) => response.json())
|
||||
.then(({ batch_job }) => {
|
||||
console.log(batch_job.status);
|
||||
});
|
||||
console.log(batch_job.status)
|
||||
})
|
||||
```
|
||||
|
||||
</TabItem>
|
||||
|
||||
@@ -565,7 +565,7 @@ To load resources, such as services, in endpoints, use the `req.scope.resolve` f
|
||||
For example:
|
||||
|
||||
```ts
|
||||
const logger = req.scope.resolve('logger');
|
||||
const logger = req.scope.resolve("logger")
|
||||
```
|
||||
|
||||
Please note that in endpoints some resources, such as repositories, are not available.
|
||||
@@ -577,13 +577,13 @@ In classes such as services, strategies, or subscribers, you can load resources
|
||||
For example:
|
||||
|
||||
```ts
|
||||
import { OrderService } from '@medusajs/medusa';
|
||||
import { OrderService } from "@medusajs/medusa"
|
||||
|
||||
class OrderSubscriber {
|
||||
protected orderService: OrderService;
|
||||
protected orderService: OrderService
|
||||
|
||||
constructor({ orderService }) {
|
||||
this.orderService = orderService;
|
||||
this.orderService = orderService
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
@@ -62,12 +62,13 @@ Next, in the exported function, retrieve the CORS configurations of your server
|
||||
|
||||
```ts
|
||||
export default (rootDirectory) => {
|
||||
//...
|
||||
// ...
|
||||
|
||||
const { configModule } = getConfigFile<ConfigModule>(rootDirectory, "medusa-config")
|
||||
const { configModule } =
|
||||
getConfigFile<ConfigModule>(rootDirectory, "medusa-config")
|
||||
const { projectConfig } = configModule
|
||||
|
||||
//....
|
||||
// ....
|
||||
}
|
||||
```
|
||||
|
||||
@@ -94,7 +95,7 @@ Finally, for each route you add, create an `OPTIONS` request and add `cors`
|
||||
```ts
|
||||
router.options("/admin/hello", cors(corsOptions))
|
||||
router.get("/admin/hello", cors(corsOptions), (req, res) => {
|
||||
//...
|
||||
// ...
|
||||
})
|
||||
```
|
||||
|
||||
@@ -202,20 +203,24 @@ Protected routes are routes that should be accessible by logged-in customers or
|
||||
To make a storefront route protected, first, import the `authenticate-customer` middleware:
|
||||
|
||||
```ts
|
||||
import authenticate from "@medusajs/medusa/dist/api/middlewares/authenticate-customer"
|
||||
import
|
||||
authenticate
|
||||
from "@medusajs/medusa/dist/api/middlewares/authenticate-customer"
|
||||
```
|
||||
|
||||
Then, add the middleware to your route:
|
||||
|
||||
```ts
|
||||
router.options("/store/hello", cors(corsOptions))
|
||||
router.get("/store/hello", cors(corsOptions), authenticate(), async (req, res) => {
|
||||
if (req.user) {
|
||||
//user is logged in
|
||||
//to get customer id: req.user.customer_id
|
||||
router.get("/store/hello", cors(corsOptions), authenticate(),
|
||||
async (req, res) => {
|
||||
if (req.user) {
|
||||
// user is logged in
|
||||
// to get customer id: req.user.customer_id
|
||||
}
|
||||
// ...
|
||||
}
|
||||
//...
|
||||
})
|
||||
)
|
||||
```
|
||||
|
||||
Please note that the endpoint is still accessible by all users, however, you’ll be able to access the current logged-in customer if there’s any.
|
||||
@@ -227,21 +232,25 @@ To disallow guest customers from accessing the endpoint, you can throw an error
|
||||
To make an admin route protected, first, import the `authenticate` middleware:
|
||||
|
||||
```ts
|
||||
import authenticate from "@medusajs/medusa/dist/api/middlewares/authenticate"
|
||||
import
|
||||
authenticate
|
||||
from "@medusajs/medusa/dist/api/middlewares/authenticate"
|
||||
```
|
||||
|
||||
Then, add the middleware to your route:
|
||||
|
||||
```ts
|
||||
router.options("/admin/products/count", cors(corsOptions))
|
||||
router.get("/admin/products/count", cors(corsOptions), authenticate(), async (req, res) => {
|
||||
//access current user
|
||||
const id = req.user.userId
|
||||
const userService = req.scope.resolve("userService")
|
||||
|
||||
const user = await userService.retrieve(id)
|
||||
//...
|
||||
})
|
||||
router.get("/admin/products/count", cors(corsOptions), authenticate(),
|
||||
async (req, res) => {
|
||||
// access current user
|
||||
const id = req.user.userId
|
||||
const userService = req.scope.resolve("userService")
|
||||
|
||||
const user = await userService.retrieve(id)
|
||||
// ...
|
||||
}
|
||||
)
|
||||
```
|
||||
|
||||
Now, only authenticated users can access this endpoint.
|
||||
@@ -257,15 +266,17 @@ You can retrieve any registered service in your endpoint using `req.scope.resol
|
||||
Here’s an example of an endpoint that retrieves the count of products in your store:
|
||||
|
||||
```ts
|
||||
router.get("/admin/products/count", cors(corsOptions), authenticate(), (req, res) => {
|
||||
const productService = req.scope.resolve("productService")
|
||||
router.get("/admin/products/count", cors(corsOptions), authenticate(),
|
||||
(req, res) => {
|
||||
const productService = req.scope.resolve("productService")
|
||||
|
||||
productService.count().then((count) => {
|
||||
res.json({
|
||||
count,
|
||||
productService.count().then((count) => {
|
||||
res.json({
|
||||
count,
|
||||
})
|
||||
})
|
||||
})
|
||||
})
|
||||
}
|
||||
)
|
||||
```
|
||||
|
||||
The `productService` has a `count` method that returns a Promise. This Promise resolves to the count of the products. You return a JSON of the product count.
|
||||
|
||||
@@ -6,15 +6,15 @@ In this document, you’ll learn how you can create an [Entity](overview.md).
|
||||
|
||||
To create an entity, create a TypeScript file in `src/models`. For example, here’s a `Post` entity defined in the file `src/models/post.ts`:
|
||||
|
||||
```tsx title=src/models/post.ts
|
||||
import { BeforeInsert, Column, Entity, PrimaryColumn } from "typeorm";
|
||||
import { BaseEntity} from "@medusajs/medusa";
|
||||
```ts title=src/models/post.ts
|
||||
import { BeforeInsert, Column, Entity, PrimaryColumn } from "typeorm"
|
||||
import { BaseEntity } from "@medusajs/medusa"
|
||||
import { generateEntityId } from "@medusajs/medusa/dist/utils"
|
||||
|
||||
@Entity()
|
||||
export class Post extends BaseEntity {
|
||||
@Column({type: 'varchar'})
|
||||
title: string | null;
|
||||
@Column({ type: "varchar" })
|
||||
title: string | null
|
||||
|
||||
@BeforeInsert()
|
||||
private beforeInsert(): void {
|
||||
@@ -31,12 +31,12 @@ To generate an ID for your entity that matches the IDs generated for Medusa’s
|
||||
|
||||
If you want the entity to also be soft deletable then it should extend `SoftDeletableEntity` instead:
|
||||
|
||||
```tsx
|
||||
import { SoftDeletableEntity } from "@medusajs/medusa";
|
||||
```ts
|
||||
import { SoftDeletableEntity } from "@medusajs/medusa"
|
||||
|
||||
@Entity()
|
||||
export class Post extends SoftDeletableEntity {
|
||||
//...
|
||||
// ...
|
||||
}
|
||||
```
|
||||
|
||||
@@ -52,7 +52,7 @@ You can learn more about Migrations, how to create them, and how to run them in
|
||||
|
||||
Entities data can be easily accessed and modified using Typeorm [Repositories](https://typeorm.io/working-with-repository). To create a repository, create a file in `src/repositories`. For example, here’s a repository `PostRepository` created in `src/repositories/post.ts`:
|
||||
|
||||
```tsx title=src/repositories/post.ts
|
||||
```ts title=src/repositories/post.ts
|
||||
import { EntityRepository, Repository } from "typeorm"
|
||||
|
||||
import { Post } from "../models/post"
|
||||
@@ -85,24 +85,25 @@ npm run build
|
||||
|
||||
You can access your custom entity data in the database in services or subscribers using the repository. For example, here’s a service that lists all posts:
|
||||
|
||||
```tsx
|
||||
import { TransactionBaseService } from '@medusajs/medusa';
|
||||
```ts
|
||||
import { TransactionBaseService } from "@medusajs/medusa"
|
||||
|
||||
class PostService extends TransactionBaseService {
|
||||
constructor({ postRepository, manager }) {
|
||||
super({ postRepository, manager });
|
||||
super({ postRepository, manager })
|
||||
|
||||
this.postRepository = postRepository;
|
||||
this.manager_ = manager;
|
||||
this.postRepository = postRepository
|
||||
this.manager_ = manager
|
||||
}
|
||||
|
||||
async list() {
|
||||
const postRepository = this.manager_.getCustomRepository(this.postRepository);
|
||||
return await postRepository.find();
|
||||
const postRepository = this.manager_
|
||||
.getCustomRepository(this.postRepository)
|
||||
return await postRepository.find()
|
||||
}
|
||||
}
|
||||
|
||||
export default PostService;
|
||||
export default PostService
|
||||
```
|
||||
|
||||
In the constructor, you can use dependency injection to get access to instances of services and repositories. Here, you initialize class fields `postRepository` and `manager`. The `manager` is a [Typeorm Entity Manager](https://typeorm.io/working-with-entity-manager).
|
||||
@@ -123,8 +124,8 @@ This same usage of repositories can be done in subscribers as well.
|
||||
|
||||
To delete soft-deletable entities that extend the `SoftDeletableEntity` class, you can use the repository method `softDelete` method:
|
||||
|
||||
```tsx
|
||||
await postRepository.softDelete(post.id);
|
||||
```ts
|
||||
await postRepository.softDelete(post.id)
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
@@ -51,9 +51,9 @@ For example, to enable the Tax-Inclusive Pricing beta feature, add the following
|
||||
```jsx title=medusa-config.js
|
||||
module.exports = {
|
||||
featureFlags: {
|
||||
tax_inclusive_pricing: true
|
||||
tax_inclusive_pricing: true,
|
||||
},
|
||||
//...
|
||||
// ...
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
@@ -23,23 +23,39 @@ Creating a Notification Provider is as simple as creating a TypeScript or JavaS
|
||||
For example, create the file `src/services/email-sender.ts` with the following content:
|
||||
|
||||
```ts title=src/services/email-sender.ts
|
||||
import { AbstractNotificationService } from "@medusajs/medusa";
|
||||
import { EntityManager } from "typeorm";
|
||||
import { AbstractNotificationService } from "@medusajs/medusa"
|
||||
import { EntityManager } from "typeorm"
|
||||
|
||||
class EmailSenderService extends AbstractNotificationService {
|
||||
protected manager_: EntityManager;
|
||||
protected transactionManager_: EntityManager;
|
||||
protected manager_: EntityManager
|
||||
protected transactionManager_: EntityManager
|
||||
|
||||
sendNotification(event: string, data: unknown, attachmentGenerator: unknown): Promise<{ to: string; status: string; data: Record<string, unknown>; }> {
|
||||
throw new Error("Method not implemented.");
|
||||
sendNotification(
|
||||
event: string,
|
||||
data: unknown,
|
||||
attachmentGenerator: unknown
|
||||
): Promise<{
|
||||
to: string;
|
||||
status: string;
|
||||
data: Record<string, unknown>;
|
||||
}> {
|
||||
throw new Error("Method not implemented.")
|
||||
}
|
||||
resendNotification(notification: unknown, config: unknown, attachmentGenerator: unknown): Promise<{ to: string; status: string; data: Record<string, unknown>; }> {
|
||||
throw new Error("Method not implemented.");
|
||||
resendNotification(
|
||||
notification: unknown,
|
||||
config: unknown,
|
||||
attachmentGenerator: unknown
|
||||
): Promise<{
|
||||
to: string;
|
||||
status: string;
|
||||
data: Record<string, unknown>;
|
||||
}> {
|
||||
throw new Error("Method not implemented.")
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
export default EmailSenderService;
|
||||
export default EmailSenderService
|
||||
```
|
||||
|
||||
Where `EmailSenderService` is the name of your Notification Provider Service.
|
||||
@@ -63,7 +79,10 @@ The value of this property is also used later when you want to subscribe the Not
|
||||
For example, in the class you created in the previous code snippet you can add the following property:
|
||||
|
||||
```ts
|
||||
static identifier = "email-sender";
|
||||
class EmailSenderService extends AbstractNotificationService {
|
||||
static identifier = "email-sender"
|
||||
// ...
|
||||
}
|
||||
```
|
||||
|
||||
### constructor
|
||||
@@ -83,23 +102,26 @@ You can learn more about plugins and how to create them in the [Plugins](../plug
|
||||
Continuing on with the previous example, if you want to use the [`OrderService`](../../../references/services/classes/OrderService.md) later when sending notifications, you can inject it into the constructor:
|
||||
|
||||
```ts
|
||||
import { AbstractNotificationService, OrderService } from "@medusajs/medusa";
|
||||
import {
|
||||
AbstractNotificationService,
|
||||
OrderService,
|
||||
} from "@medusajs/medusa"
|
||||
|
||||
class EmailSenderService extends AbstractNotificationService {
|
||||
protected manager_: EntityManager;
|
||||
protected transactionManager_: EntityManager;
|
||||
static identifier = "email-sender";
|
||||
protected orderService: OrderService;
|
||||
protected manager_: EntityManager
|
||||
protected transactionManager_: EntityManager
|
||||
static identifier = "email-sender"
|
||||
protected orderService: OrderService
|
||||
|
||||
constructor(container, options) {
|
||||
super(container);
|
||||
//you can access options here in case you're
|
||||
//using a plugin
|
||||
super(container)
|
||||
// you can access options here in case you're
|
||||
// using a plugin
|
||||
|
||||
this.orderService = container.orderService;
|
||||
this.orderService = container.orderService
|
||||
}
|
||||
|
||||
//...
|
||||
// ...
|
||||
}
|
||||
```
|
||||
|
||||
@@ -129,23 +151,34 @@ This method must return an object containing two properties:
|
||||
Continuing with the previous example you can have the following implementation of the `sendNotification` method:
|
||||
|
||||
```ts
|
||||
async sendNotification(event: string, data: any, attachmentGenerator: unknown): Promise<{ to: string; status: string; data: Record<string, unknown>; }> {
|
||||
if (event === 'order.placed') {
|
||||
//retrieve order
|
||||
const order = await this.orderService.retrieve(data.id);
|
||||
//TODO send email
|
||||
class EmailSenderService extends AbstractNotificationService {
|
||||
// ...
|
||||
async sendNotification(
|
||||
event: string,
|
||||
data: any,
|
||||
attachmentGenerator: unknown
|
||||
): Promise<{
|
||||
to: string;
|
||||
status: string;
|
||||
data: Record<string, unknown>;
|
||||
}> {
|
||||
if (event === "order.placed") {
|
||||
// retrieve order
|
||||
const order = await this.orderService.retrieve(data.id)
|
||||
// TODO send email
|
||||
|
||||
console.log('Notification sent');
|
||||
return {
|
||||
to: order.email,
|
||||
status: 'done',
|
||||
data: {
|
||||
//any data necessary to send the email
|
||||
//for example:
|
||||
subject: 'You placed a new order!',
|
||||
items: order.items
|
||||
console.log("Notification sent")
|
||||
return {
|
||||
to: order.email,
|
||||
status: "done",
|
||||
data: {
|
||||
// any data necessary to send the email
|
||||
// for example:
|
||||
subject: "You placed a new order!",
|
||||
items: order.items,
|
||||
},
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
@@ -180,17 +213,29 @@ Similarly to the `sendNotification` method, this method must return an object co
|
||||
Continuing with the previous example you can have the following implementation of the `resendNotification` method:
|
||||
|
||||
```ts
|
||||
async resendNotification(notification: any, config: any, attachmentGenerator: unknown): Promise<{ to: string; status: string; data: Record<string, unknown>; }> {
|
||||
//check if the receiver of the notification should be changed
|
||||
const to: string = config.to ? config.to : notification.to;
|
||||
class EmailSenderService extends AbstractNotificationService {
|
||||
// ...
|
||||
async resendNotification(
|
||||
notification: any,
|
||||
config: any,
|
||||
attachmentGenerator: unknown
|
||||
): Promise<{
|
||||
to: string;
|
||||
status: string;
|
||||
data: Record<string, unknown>;
|
||||
}> {
|
||||
// check if the receiver of the notification should be changed
|
||||
const to: string = config.to ? config.to : notification.to
|
||||
|
||||
//TODO resend the notification using the same data that is saved under notification.data
|
||||
// TODO resend the notification using the same data
|
||||
// that is saved under notification.data
|
||||
|
||||
console.log('Notification resent');
|
||||
return {
|
||||
to,
|
||||
status: 'done',
|
||||
data: notification.data //you can also make changes to the data
|
||||
console.log("Notification resent")
|
||||
return {
|
||||
to,
|
||||
status: "done",
|
||||
data: notification.data, // you can also make changes to the data
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
@@ -224,11 +269,12 @@ Following the previous example, to make sure the `email-sender` Notification Pro
|
||||
```ts title=src/subscribers/notification.js
|
||||
class NotificationSubscriber {
|
||||
constructor({ notificationService }) {
|
||||
notificationService.subscribe('order.placed', 'email-sender');
|
||||
notificationService.subscribe("order.placed", "email-sender")
|
||||
}
|
||||
// ...
|
||||
}
|
||||
|
||||
export default NotificationSubscriber;
|
||||
export default NotificationSubscriber
|
||||
```
|
||||
|
||||
This subscriber accesses the `notificationService` using dependency injection. The `notificationService` contains a `subscribe` method that accepts 2 parameters. The first one is the name of the event to subscribe to, and the second is the identifier of the Notification Provider that is subscribing to that event.
|
||||
@@ -288,5 +334,5 @@ This request returns the same notification object as the List Notifications endp
|
||||
- [Events reference](../subscribers/events-list.md)
|
||||
- [SendGrid Plugin](../../../add-plugins/sendgrid.mdx)
|
||||
- [Create a Subscriber](../subscribers/create-subscriber.md)
|
||||
- [Create a Service](../services/create-service.md).
|
||||
- [Create a Plugin](../plugins/create.md).
|
||||
- [Create a Service](../services/create-service.md)
|
||||
- [Create a Plugin](../plugins/create.md)
|
||||
@@ -50,51 +50,60 @@ The first step to create a payment provider is to create a JavaScript or TypeScr
|
||||
|
||||
For example, create the file `src/services/my-payment.ts` with the following content:
|
||||
|
||||
<!-- eslint-disable max-len -->
|
||||
|
||||
```ts title=src/services/my-payment.ts
|
||||
import { AbstractPaymentService, Cart, Data, Payment, PaymentSession, PaymentSessionStatus, TransactionBaseService } from "@medusajs/medusa"
|
||||
import { EntityManager } from "typeorm";
|
||||
import {
|
||||
AbstractPaymentService,
|
||||
Cart, Data, Payment, PaymentSession,
|
||||
PaymentSessionStatus, TransactionBaseService,
|
||||
} from "@medusajs/medusa"
|
||||
import { EntityManager } from "typeorm"
|
||||
|
||||
class MyPaymentService extends AbstractPaymentService<TransactionBaseService> {
|
||||
protected manager_: EntityManager;
|
||||
protected transactionManager_: EntityManager;
|
||||
protected manager_: EntityManager
|
||||
protected transactionManager_: EntityManager
|
||||
|
||||
getPaymentData(paymentSession: PaymentSession): Promise<Data> {
|
||||
throw new Error("Method not implemented.");
|
||||
throw new Error("Method not implemented.")
|
||||
}
|
||||
updatePaymentData(paymentSessionData: Data, data: Data): Promise<Data> {
|
||||
throw new Error("Method not implemented.");
|
||||
throw new Error("Method not implemented.")
|
||||
}
|
||||
createPayment(cart: Cart): Promise<Data> {
|
||||
throw new Error("Method not implemented.");
|
||||
throw new Error("Method not implemented.")
|
||||
}
|
||||
retrievePayment(paymentData: Data): Promise<Data> {
|
||||
throw new Error("Method not implemented.");
|
||||
throw new Error("Method not implemented.")
|
||||
}
|
||||
updatePayment(paymentSessionData: Data, cart: Cart): Promise<Data> {
|
||||
throw new Error("Method not implemented.");
|
||||
throw new Error("Method not implemented.")
|
||||
}
|
||||
authorizePayment(paymentSession: PaymentSession, context: Data): Promise<{ data: Data; status: PaymentSessionStatus; }> {
|
||||
throw new Error("Method not implemented.");
|
||||
authorizePayment(
|
||||
paymentSession: PaymentSession,
|
||||
context: Data
|
||||
): Promise<{ data: Data; status: PaymentSessionStatus; }> {
|
||||
throw new Error("Method not implemented.")
|
||||
}
|
||||
capturePayment(payment: Payment): Promise<Data> {
|
||||
throw new Error("Method not implemented.");
|
||||
throw new Error("Method not implemented.")
|
||||
}
|
||||
refundPayment(payment: Payment, refundAmount: number): Promise<Data> {
|
||||
throw new Error("Method not implemented.");
|
||||
throw new Error("Method not implemented.")
|
||||
}
|
||||
cancelPayment(payment: Payment): Promise<Data> {
|
||||
throw new Error("Method not implemented.");
|
||||
throw new Error("Method not implemented.")
|
||||
}
|
||||
deletePayment(paymentSession: PaymentSession): Promise<void> {
|
||||
throw new Error("Method not implemented.");
|
||||
throw new Error("Method not implemented.")
|
||||
}
|
||||
getStatus(data: Data): Promise<PaymentSessionStatus> {
|
||||
throw new Error("Method not implemented.");
|
||||
throw new Error("Method not implemented.")
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
export default MyPaymentService;
|
||||
export default MyPaymentService
|
||||
```
|
||||
|
||||
Where `MyPaymentService` is the name of your Payment Provider service. For example, Stripe’s Payment Provider Service is called `StripeProviderService`.
|
||||
@@ -123,10 +132,16 @@ You can also use the constructor to initialize your integration with the third-p
|
||||
|
||||
Additionally, if you’re creating your Payment Provider as an external plugin to be installed on any Medusa server and you want to access the options added for the plugin, you can access it in the constructor. The options are passed as a second parameter:
|
||||
|
||||
<!-- eslint-disable max-len -->
|
||||
|
||||
```ts
|
||||
constructor({ productService }, options) {
|
||||
super();
|
||||
//you can access options here
|
||||
class MyPaymentService extends AbstractPaymentService<TransactionBaseService> {
|
||||
// ...
|
||||
constructor({ productService }, options) {
|
||||
super()
|
||||
// you can access options here
|
||||
}
|
||||
// ...
|
||||
}
|
||||
```
|
||||
|
||||
@@ -140,15 +155,20 @@ This method must return an object that is going to be stored in the `data` field
|
||||
|
||||
An example of a minimal implementation of `createPayment` that does not interact with any third-party providers:
|
||||
|
||||
<!-- eslint-disable max-len -->
|
||||
|
||||
```ts
|
||||
import { Cart, Data } from "@medusajs/medusa"
|
||||
//...
|
||||
// ...
|
||||
|
||||
async createPayment(cart: Cart): Promise<Data> {
|
||||
return {
|
||||
id: 'test-payment',
|
||||
status: 'pending'
|
||||
};
|
||||
class MyPaymentService extends AbstractPaymentService<TransactionBaseService> {
|
||||
// ...
|
||||
async createPayment(cart: Cart): Promise<Data> {
|
||||
return {
|
||||
id: "test-payment",
|
||||
status: "pending",
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
@@ -162,12 +182,17 @@ This method must return an object containing the data from the third-party provi
|
||||
|
||||
An example of a minimal implementation of `retrievePayment` where you don’t need to interact with the third-party provider:
|
||||
|
||||
<!-- eslint-disable max-len -->
|
||||
|
||||
```ts
|
||||
import { Data } from "@medusajs/medusa"
|
||||
//...
|
||||
// ...
|
||||
|
||||
async retrievePayment(paymentData: Data): Promise<Data> {
|
||||
return {};
|
||||
class MyPaymentService extends AbstractPaymentService<TransactionBaseService> {
|
||||
// ...
|
||||
async retrievePayment(paymentData: Data): Promise<Data> {
|
||||
return {}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
@@ -189,12 +214,17 @@ This method returns a string that represents the status. The status must be one
|
||||
|
||||
An example of a minimal implementation of `getStatus` where you don’t need to interact with the third-party provider:
|
||||
|
||||
<!-- eslint-disable max-len -->
|
||||
|
||||
```ts
|
||||
import { Data, PaymentSessionStatus } from "@medusajs/medusa"
|
||||
//...
|
||||
// ...
|
||||
|
||||
async getStatus(data: Data): Promise<PaymentSessionStatus> {
|
||||
return PaymentSessionStatus.AUTHORIZED;
|
||||
class MyPaymentService extends AbstractPaymentService<TransactionBaseService> {
|
||||
// ...
|
||||
async getStatus(data: Data): Promise<PaymentSessionStatus> {
|
||||
return PaymentSessionStatus.AUTHORIZED
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
@@ -222,12 +252,17 @@ This method must return an object that will be stored in the `data` field of the
|
||||
|
||||
An example of a minimal implementation of `updatePayment` that does not need to make any updates on the third-party provider or the `data` field of the Payment Session:
|
||||
|
||||
```ts
|
||||
import { Cart, Data } from "@medusajs/medusa";
|
||||
//...
|
||||
<!-- eslint-disable max-len -->
|
||||
|
||||
async updatePayment(paymentSessionData: Data, cart: Cart): Promise<Data> {
|
||||
return paymentSessionData;
|
||||
```ts
|
||||
import { Cart, Data } from "@medusajs/medusa"
|
||||
// ...
|
||||
|
||||
class MyPaymentService extends AbstractPaymentService<TransactionBaseService> {
|
||||
// ...
|
||||
async updatePayment(paymentSessionData: Data, cart: Cart): Promise<Data> {
|
||||
return paymentSessionData
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
@@ -243,12 +278,20 @@ This method must return an object that will be stored in the `data` field of the
|
||||
|
||||
An example of a minimal implementation of `updatePaymentData` that returns the `updatedData` passed in the body of the request as-is to update the `data` field of the Payment Session.
|
||||
|
||||
```ts
|
||||
import { Data } from "@medusajs/medusa";
|
||||
//...
|
||||
<!-- eslint-disable max-len -->
|
||||
|
||||
async updatePaymentData(paymentSessionData: Data, updatedData: Data): Promise<Data> {
|
||||
return updatedData;
|
||||
```ts
|
||||
import { Data } from "@medusajs/medusa"
|
||||
// ...
|
||||
|
||||
class MyPaymentService extends AbstractPaymentService<TransactionBaseService> {
|
||||
// ...
|
||||
async updatePaymentData(
|
||||
paymentSessionData: Data,
|
||||
updatedData: Data
|
||||
): Promise<Data> {
|
||||
return updatedData
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
@@ -267,12 +310,17 @@ You can use this method to interact with the third-party provider to delete data
|
||||
|
||||
An example of a minimal implementation of `deletePayment` where no interaction with a third-party provider is required:
|
||||
|
||||
```ts
|
||||
import { PaymentSession } from "@medusajs/medusa";
|
||||
//...
|
||||
<!-- eslint-disable max-len -->
|
||||
|
||||
async deletePayment(paymentSession: PaymentSession): Promise<void> {
|
||||
return;
|
||||
```ts
|
||||
import { PaymentSession } from "@medusajs/medusa"
|
||||
// ...
|
||||
|
||||
class MyPaymentService extends AbstractPaymentService<TransactionBaseService> {
|
||||
// ...
|
||||
async deletePayment(paymentSession: PaymentSession): Promise<void> {
|
||||
return
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
@@ -305,17 +353,29 @@ You can utilize this method to interact with the third-party provider and perfor
|
||||
|
||||
An example of a minimal implementation of `authorizePayment` that doesn’t need to interact with any third-party provider:
|
||||
|
||||
```ts
|
||||
import { Data, PaymentSession, PaymentSessionStatus } from "@medusajs/medusa";
|
||||
//...
|
||||
<!-- eslint-disable max-len -->
|
||||
|
||||
async authorizePayment(paymentSession: PaymentSession, context: Data): Promise<{ data: Data; status: PaymentSessionStatus; }> {
|
||||
return {
|
||||
status: PaymentSessionStatus.AUTHORIZED,
|
||||
data: {
|
||||
id: 'test'
|
||||
```ts
|
||||
import {
|
||||
Data,
|
||||
PaymentSession,
|
||||
PaymentSessionStatus,
|
||||
} from "@medusajs/medusa"
|
||||
// ...
|
||||
|
||||
class MyPaymentService extends AbstractPaymentService<TransactionBaseService> {
|
||||
// ...
|
||||
async authorizePayment(
|
||||
paymentSession: PaymentSession,
|
||||
context: Data
|
||||
): Promise<{ data: Data; status: PaymentSessionStatus; }> {
|
||||
return {
|
||||
status: PaymentSessionStatus.AUTHORIZED,
|
||||
data: {
|
||||
id: "test",
|
||||
},
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
@@ -329,12 +389,17 @@ This method must return an object to be stored in the `data` field of the Paymen
|
||||
|
||||
An example of a minimal implementation of `getPaymentData`:
|
||||
|
||||
```ts
|
||||
import { Data, PaymentSession } from "@medusajs/medusa";
|
||||
//...
|
||||
<!-- eslint-disable max-len -->
|
||||
|
||||
async getPaymentData(paymentSession: PaymentSession): Promise<Data> {
|
||||
return paymentSession.data;
|
||||
```ts
|
||||
import { Data, PaymentSession } from "@medusajs/medusa"
|
||||
// ...
|
||||
|
||||
class MyPaymentService extends AbstractPaymentService<TransactionBaseService> {
|
||||
// ...
|
||||
async getPaymentData(paymentSession: PaymentSession): Promise<Data> {
|
||||
return paymentSession.data
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
@@ -352,14 +417,19 @@ This method must return an object that will be stored in the `data` field of the
|
||||
|
||||
An example of a minimal implementation of `capturePayment` that doesn’t need to interact with a third-party provider:
|
||||
|
||||
```ts
|
||||
import { Data, Payment } from "@medusajs/medusa";
|
||||
//...
|
||||
<!-- eslint-disable max-len -->
|
||||
|
||||
async capturePayment(payment: Payment): Promise<Data> {
|
||||
return {
|
||||
status: 'captured'
|
||||
};
|
||||
```ts
|
||||
import { Data, Payment } from "@medusajs/medusa"
|
||||
// ...
|
||||
|
||||
class MyPaymentService extends AbstractPaymentService<TransactionBaseService> {
|
||||
// ...
|
||||
async capturePayment(payment: Payment): Promise<Data> {
|
||||
return {
|
||||
status: "captured",
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
@@ -377,13 +447,21 @@ This method must return an object that is stored in the `data` field of the Paym
|
||||
|
||||
An example of a minimal implementation of `refundPayment` that doesn’t need to interact with a third-party provider:
|
||||
|
||||
```ts
|
||||
import { Data, Payment } from "@medusajs/medusa";
|
||||
//...
|
||||
<!-- eslint-disable max-len -->
|
||||
|
||||
async refundPayment(payment: Payment, refundAmount: number): Promise<Data> {
|
||||
return {
|
||||
id: 'test'
|
||||
```ts
|
||||
import { Data, Payment } from "@medusajs/medusa"
|
||||
// ...
|
||||
|
||||
class MyPaymentService extends AbstractPaymentService<TransactionBaseService> {
|
||||
// ...
|
||||
async refundPayment(
|
||||
payment: Payment,
|
||||
refundAmount: number
|
||||
): Promise<Data> {
|
||||
return {
|
||||
id: "test",
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
@@ -405,13 +483,18 @@ This method must return an object that is stored in the `data` field of the Paym
|
||||
|
||||
An example of a minimal implementation of `cancelPayment` that doesn’t need to interact with a third-party provider:
|
||||
|
||||
```ts
|
||||
import { Data, Payment } from "@medusajs/medusa";
|
||||
//...
|
||||
<!-- eslint-disable max-len -->
|
||||
|
||||
async cancelPayment(payment: Payment): Promise<Data> {
|
||||
return {
|
||||
id: 'test'
|
||||
```ts
|
||||
import { Data, Payment } from "@medusajs/medusa"
|
||||
// ...
|
||||
|
||||
class MyPaymentService extends AbstractPaymentService<TransactionBaseService> {
|
||||
// ...
|
||||
async cancelPayment(payment: Payment): Promise<Data> {
|
||||
return {
|
||||
id: "test",
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
@@ -438,26 +521,31 @@ If you’re using Medusa’s [Next.js](../../../starters/nextjs-medusa-starter.m
|
||||
|
||||
An example of the implementation of `retrieveSavedMethods` taken from Stripe’s Payment Provider:
|
||||
|
||||
<!-- eslint-disable max-len -->
|
||||
|
||||
```ts
|
||||
import { Customer, Data } from "@medusajs/medusa"
|
||||
//...
|
||||
// ...
|
||||
|
||||
/**
|
||||
* Fetches a customers saved payment methods if registered in Stripe.
|
||||
* @param {object} customer - customer to fetch saved cards for
|
||||
* @returns {Promise<Array<object>>} saved payments methods
|
||||
*/
|
||||
async retrieveSavedMethods(customer: Customer): Promise<Data[]> {
|
||||
if (customer.metadata && customer.metadata.stripe_id) {
|
||||
const methods = await this.stripe_.paymentMethods.list({
|
||||
customer: customer.metadata.stripe_id,
|
||||
type: "card",
|
||||
})
|
||||
class MyPaymentService extends AbstractPaymentService<TransactionBaseService> {
|
||||
// ...
|
||||
/**
|
||||
* Fetches a customers saved payment methods if registered in Stripe.
|
||||
* @param {object} customer - customer to fetch saved cards for
|
||||
* @return {Promise<Array<object>>} saved payments methods
|
||||
*/
|
||||
async retrieveSavedMethods(customer: Customer): Promise<Data[]> {
|
||||
if (customer.metadata && customer.metadata.stripe_id) {
|
||||
const methods = await this.stripe_.paymentMethods.list({
|
||||
customer: customer.metadata.stripe_id,
|
||||
type: "card",
|
||||
})
|
||||
|
||||
return methods.data
|
||||
return methods.data
|
||||
}
|
||||
|
||||
return Promise.resolve([])
|
||||
}
|
||||
|
||||
return Promise.resolve([])
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
@@ -212,7 +212,7 @@ To pass a plugin its configurations on a Medusa server, you have to add it to th
|
||||
|
||||
```jsx title=medusa-config.js
|
||||
const plugins = [
|
||||
//...
|
||||
// ...
|
||||
{
|
||||
resolve: `medusa-plugin-custom`,
|
||||
options: {
|
||||
@@ -225,19 +225,23 @@ const plugins = [
|
||||
Then, you can have access to your plugin configuration in the constructor of services in your plugin:
|
||||
|
||||
```jsx title=src/service/test.ts
|
||||
//In a service in your plugin
|
||||
constructor({}, options) {
|
||||
//options contains plugin configurations
|
||||
this.name = options.name
|
||||
// In a service in your plugin
|
||||
class MyService extends TransactionBaseService {
|
||||
constructor(container, options) {
|
||||
super(container)
|
||||
// options contains plugin configurations
|
||||
this.name = options.name
|
||||
}
|
||||
// ...
|
||||
}
|
||||
```
|
||||
|
||||
You can also have access to the configurations in endpoints in your plugin:
|
||||
|
||||
```jsx title=src/api/index.ts
|
||||
//in an endpoint in your plugin
|
||||
// in an endpoint in your plugin
|
||||
export default (rootDirectory, options) => {
|
||||
//options contain the plugin configurations
|
||||
// options contain the plugin configurations
|
||||
const router = Router()
|
||||
|
||||
router.get("/hello-world", (req, res) => {
|
||||
@@ -293,10 +297,10 @@ Then, add your plugin into the array of plugins in `medusa-config.js`:
|
||||
|
||||
```jsx title=medusa-config.js
|
||||
const plugins = [
|
||||
//...
|
||||
// ...
|
||||
{
|
||||
resolve: `medusa-plugin-custom`,
|
||||
//if your plugin has configurations
|
||||
// if your plugin has configurations
|
||||
options: {
|
||||
name: "My Store",
|
||||
},
|
||||
|
||||
@@ -37,6 +37,8 @@ When you create a price list, you can specify different conditions to control wh
|
||||
|
||||
In the body of your request, aside from the required fields, you can send the following fields to apply different conditions:
|
||||
|
||||
<!-- eslint-skip -->
|
||||
|
||||
```js noReport
|
||||
{
|
||||
prices: [
|
||||
@@ -70,28 +72,28 @@ For example, sending the following request creates a price list with two prices:
|
||||
import { PriceListType } from "@medusajs/medusa"
|
||||
|
||||
medusa.admin.priceLists.create({
|
||||
name: 'New Price List',
|
||||
description: 'A new price list',
|
||||
name: "New Price List",
|
||||
description: "A new price list",
|
||||
type: PriceListType.SALE,
|
||||
status: 'active',
|
||||
status: "active",
|
||||
prices: [
|
||||
{
|
||||
amount: 1000,
|
||||
variant_id,
|
||||
currency_code: 'eur',
|
||||
max_quantity: 3
|
||||
currency_code: "eur",
|
||||
max_quantity: 3,
|
||||
},
|
||||
{
|
||||
amount: 1500,
|
||||
variant_id,
|
||||
currency_code: 'eur',
|
||||
min_quantity: 4
|
||||
}
|
||||
]
|
||||
currency_code: "eur",
|
||||
min_quantity: 4,
|
||||
},
|
||||
],
|
||||
})
|
||||
.then(({ price_list }) => {
|
||||
console.log(price_list.id);
|
||||
});
|
||||
console.log(price_list.id)
|
||||
})
|
||||
```
|
||||
|
||||
</TabItem>
|
||||
@@ -99,31 +101,31 @@ medusa.admin.priceLists.create({
|
||||
|
||||
```jsx
|
||||
fetch(`<SERVER_URL>/admin/price-lists`, {
|
||||
method: 'POST',
|
||||
credentials: 'include',
|
||||
method: "POST",
|
||||
credentials: "include",
|
||||
headers: {
|
||||
'Content-Type': 'application/json'
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
body: JSON.stringify({
|
||||
name: 'New Price List',
|
||||
description: 'A new price list',
|
||||
type: 'sale',
|
||||
status: 'active',
|
||||
name: "New Price List",
|
||||
description: "A new price list",
|
||||
type: "sale",
|
||||
status: "active",
|
||||
prices: [
|
||||
{
|
||||
amount: 1000,
|
||||
variant_id,
|
||||
currency_code: 'eur',
|
||||
max_quantity: 3
|
||||
currency_code: "eur",
|
||||
max_quantity: 3,
|
||||
},
|
||||
{
|
||||
amount: 1500,
|
||||
variant_id,
|
||||
currency_code: 'eur',
|
||||
min_quantity: 4
|
||||
}
|
||||
]
|
||||
})
|
||||
currency_code: "eur",
|
||||
min_quantity: 4,
|
||||
},
|
||||
],
|
||||
}),
|
||||
})
|
||||
.then((response) => response.json())
|
||||
.then(({ price_list }) => {
|
||||
@@ -179,8 +181,8 @@ You can retrieve all of a price list’s details using the Get a Price List endp
|
||||
```jsx
|
||||
medusa.admin.priceLists.retrieve(priceListId)
|
||||
.then(({ price_list }) => {
|
||||
console.log(price_list.id);
|
||||
});
|
||||
console.log(price_list.id)
|
||||
})
|
||||
```
|
||||
|
||||
</TabItem>
|
||||
@@ -188,7 +190,7 @@ medusa.admin.priceLists.retrieve(priceListId)
|
||||
|
||||
```jsx
|
||||
fetch(`<SERVER_URL>/admin/price-lists/${priceListId}`, {
|
||||
credentials: 'include',
|
||||
credentials: "include",
|
||||
})
|
||||
.then((response) => response.json())
|
||||
.then(({ price_list }) => {
|
||||
@@ -199,7 +201,7 @@ fetch(`<SERVER_URL>/admin/price-lists/${priceListId}`, {
|
||||
</TabItem>
|
||||
<TabItem value="curl" label="cURL">
|
||||
|
||||
```jsx
|
||||
```bash
|
||||
curl -L -X GET '<SERVER_URL>/admin/price-lists/{id}' \
|
||||
-H 'Authorization: Bearer <API_TOKEN>'
|
||||
```
|
||||
@@ -220,11 +222,11 @@ For example, by sending the following request the end date of the price list wil
|
||||
|
||||
```jsx
|
||||
medusa.admin.priceLists.update(priceListId, {
|
||||
ends_at: '2022-10-11'
|
||||
ends_at: "2022-10-11",
|
||||
})
|
||||
.then(({ price_list }) => {
|
||||
console.log(price_list.id);
|
||||
});
|
||||
console.log(price_list.id)
|
||||
})
|
||||
```
|
||||
|
||||
</TabItem>
|
||||
@@ -232,14 +234,14 @@ medusa.admin.priceLists.update(priceListId, {
|
||||
|
||||
```jsx
|
||||
fetch(`<SERVER_URL>/admin/price-lists/${priceListId}`, {
|
||||
method: 'POST',
|
||||
credentials: 'include',
|
||||
method: "POST",
|
||||
credentials: "include",
|
||||
headers: {
|
||||
'Content-Type': 'application/json'
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
body: JSON.stringify({
|
||||
ends_at: '2022-10-11'
|
||||
})
|
||||
ends_at: "2022-10-11",
|
||||
}),
|
||||
})
|
||||
.then((response) => response.json())
|
||||
.then(({ price_list }) => {
|
||||
@@ -287,13 +289,13 @@ medusa.admin.priceLists.addPrices(priceListId, {
|
||||
{
|
||||
amount: 1200,
|
||||
variant_id,
|
||||
currency_code: 'eur'
|
||||
}
|
||||
]
|
||||
currency_code: "eur",
|
||||
},
|
||||
],
|
||||
})
|
||||
.then(({ price_list }) => {
|
||||
console.log(price_list.id);
|
||||
});
|
||||
console.log(price_list.id)
|
||||
})
|
||||
```
|
||||
|
||||
</TabItem>
|
||||
@@ -301,20 +303,20 @@ medusa.admin.priceLists.addPrices(priceListId, {
|
||||
|
||||
```jsx
|
||||
fetch(`<SERVER_URL>/admin/price-lists/${priceListId}/prices/batch`, {
|
||||
method: 'POST',
|
||||
credentials: 'include',
|
||||
method: "POST",
|
||||
credentials: "include",
|
||||
headers: {
|
||||
'Content-Type': 'application/json'
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
body: JSON.stringify({
|
||||
prices: [
|
||||
{
|
||||
amount: 1200,
|
||||
variant_id,
|
||||
currency_code: 'eur'
|
||||
}
|
||||
]
|
||||
})
|
||||
currency_code: "eur",
|
||||
},
|
||||
],
|
||||
}),
|
||||
})
|
||||
.then((response) => response.json())
|
||||
.then(({ price_list }) => {
|
||||
@@ -357,18 +359,23 @@ You can delete all the prices of a product’s variants using the [Delete Produc
|
||||
```jsx
|
||||
medusa.admin.priceLists.deleteProductPrices(priceListId, productId)
|
||||
.then(({ ids, object, deleted }) => {
|
||||
console.log(ids.length);
|
||||
});
|
||||
console.log(ids.length)
|
||||
})
|
||||
```
|
||||
|
||||
</TabItem>
|
||||
<TabItem value="fetch" label="Fetch API">
|
||||
|
||||
<!-- eslint-disable max-len -->
|
||||
|
||||
```jsx
|
||||
fetch(`<SERVER_URL>/admin/price-lists/${priceListId}/products/${productId}/prices`, {
|
||||
method: 'DELETE',
|
||||
credentials: 'include',
|
||||
})
|
||||
fetch(
|
||||
`<SERVER_URL>/admin/price-lists/${priceListId}/products/${productId}/prices`,
|
||||
{
|
||||
method: "DELETE",
|
||||
credentials: "include",
|
||||
}
|
||||
)
|
||||
.then((response) => response.json())
|
||||
.then(({ ids, object, deleted }) => {
|
||||
console.log(ids.length)
|
||||
@@ -398,18 +405,23 @@ You can delete all the prices of a variant using the [Delete Variant Prices](htt
|
||||
```jsx
|
||||
medusa.admin.priceLists.deleteVariantPrices(priceListId, variantId)
|
||||
.then(({ ids, object, deleted }) => {
|
||||
console.log(ids);
|
||||
});
|
||||
console.log(ids)
|
||||
})
|
||||
```
|
||||
|
||||
</TabItem>
|
||||
<TabItem value="fetch" label="Fetch API">
|
||||
|
||||
<!-- eslint-disable max-len -->
|
||||
|
||||
```jsx
|
||||
fetch(`<SERVER_URL>/admin/price-lists/${priceListId}/variants/${variantId}/prices`, {
|
||||
method: 'DELETE',
|
||||
credentials: 'include',
|
||||
})
|
||||
fetch(
|
||||
`<SERVER_URL>/admin/price-lists/${priceListId}/variants/${variantId}/prices`,
|
||||
{
|
||||
method: "DELETE",
|
||||
credentials: "include",
|
||||
}
|
||||
)
|
||||
.then((response) => response.json())
|
||||
.then(({ ids, object, deleted }) => {
|
||||
console.log(ids.length)
|
||||
@@ -419,7 +431,7 @@ fetch(`<SERVER_URL>/admin/price-lists/${priceListId}/variants/${variantId}/price
|
||||
</TabItem>
|
||||
<TabItem value="curl" label="cURL">
|
||||
|
||||
```jsx
|
||||
```bash
|
||||
curl -L -X DELETE '<SERVER_URL>/admin/price-lists/<PRICE_LIST_ID>/variants/<VARIANT_ID>/prices' \
|
||||
-H 'Authorization: Bearer <API_TOKEN>'
|
||||
```
|
||||
@@ -441,8 +453,8 @@ You can delete a price list, and subsequently all prices defined in it, using th
|
||||
```jsx
|
||||
medusa.admin.priceLists.delete(priceListId)
|
||||
.then(({ id, object, deleted }) => {
|
||||
console.log(id);
|
||||
});
|
||||
console.log(id)
|
||||
})
|
||||
```
|
||||
|
||||
</TabItem>
|
||||
@@ -450,8 +462,8 @@ medusa.admin.priceLists.delete(priceListId)
|
||||
|
||||
```jsx
|
||||
fetch(`<SERVER_URL>/admin/price-lists/${priceListId}`, {
|
||||
method: 'DELETE',
|
||||
credentials: 'include',
|
||||
method: "DELETE",
|
||||
credentials: "include",
|
||||
})
|
||||
.then((response) => response.json())
|
||||
.then(({ id, object, deleted }) => {
|
||||
@@ -462,7 +474,7 @@ fetch(`<SERVER_URL>/admin/price-lists/${priceListId}`, {
|
||||
</TabItem>
|
||||
<TabItem value="curl" label="cURL">
|
||||
|
||||
```jsx
|
||||
```bash
|
||||
curl -L -X DELETE '<SERVER_URL>/admin/price-lists/<PRICE_LIST_ID>' \
|
||||
-H 'Authorization: Bearer <API_TOKEN>'
|
||||
```
|
||||
|
||||
@@ -57,12 +57,12 @@ You can create a sales channel by sending a request to the Create a Sales Channe
|
||||
|
||||
```jsx
|
||||
medusa.admin.salesChannels.create({
|
||||
name: 'App',
|
||||
description: 'Mobile app'
|
||||
name: "App",
|
||||
description: "Mobile app",
|
||||
})
|
||||
.then(({ sales_channel }) => {
|
||||
console.log(sales_channel.id);
|
||||
});
|
||||
console.log(sales_channel.id)
|
||||
})
|
||||
```
|
||||
|
||||
</TabItem>
|
||||
@@ -70,20 +70,20 @@ medusa.admin.salesChannels.create({
|
||||
|
||||
```jsx
|
||||
fetch(`<SERVER_URL>/admin/sales-channels`, {
|
||||
method: 'POST',
|
||||
credentials: 'include',
|
||||
method: "POST",
|
||||
credentials: "include",
|
||||
headers: {
|
||||
'Content-Type': 'application/json'
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
body: JSON.stringify({
|
||||
name: 'App',
|
||||
description: 'Mobile app'
|
||||
})
|
||||
name: "App",
|
||||
description: "Mobile app",
|
||||
}),
|
||||
})
|
||||
.then((response) => response.json())
|
||||
.then(({ sales_channel }) => {
|
||||
console.log(sales_channel.id)
|
||||
});
|
||||
})
|
||||
```
|
||||
|
||||
</TabItem>
|
||||
@@ -118,8 +118,8 @@ You can list all sales channels by sending a request to the List Sales Channels
|
||||
```jsx
|
||||
medusa.admin.salesChannels.list()
|
||||
.then(({ sales_channels, limit, offset, count }) => {
|
||||
console.log(sales_channels.length);
|
||||
});
|
||||
console.log(sales_channels.length)
|
||||
})
|
||||
```
|
||||
|
||||
</TabItem>
|
||||
@@ -127,12 +127,12 @@ medusa.admin.salesChannels.list()
|
||||
|
||||
```jsx
|
||||
fetch(`<SERVER_URL>/admin/sales-channels`, {
|
||||
credentials: 'include',
|
||||
credentials: "include",
|
||||
})
|
||||
.then((response) => response.json())
|
||||
.then(({ sales_channels, limit, offset, count }) => {
|
||||
console.log(sales_channels.length)
|
||||
});
|
||||
})
|
||||
```
|
||||
|
||||
</TabItem>
|
||||
@@ -160,8 +160,8 @@ You can retrieve a sales channel’s details by its ID using the Get Sales Chann
|
||||
```jsx
|
||||
medusa.admin.salesChannels.retrieve(salesChannelId)
|
||||
.then(({ sales_channel }) => {
|
||||
console.log(sales_channel.id);
|
||||
});
|
||||
console.log(sales_channel.id)
|
||||
})
|
||||
```
|
||||
|
||||
</TabItem>
|
||||
@@ -169,12 +169,12 @@ medusa.admin.salesChannels.retrieve(salesChannelId)
|
||||
|
||||
```jsx
|
||||
fetch(`<SERVER_URL>/admin/sales-channels/${salesChannelId}`, {
|
||||
credentials: 'include',
|
||||
credentials: "include",
|
||||
})
|
||||
.then((response) => response.json())
|
||||
.then(({ sales_channels, limit, offset, count }) => {
|
||||
console.log(sales_channels.length)
|
||||
});
|
||||
})
|
||||
```
|
||||
|
||||
</TabItem>
|
||||
@@ -201,11 +201,11 @@ You can update a Sales Channel’s details and attributes by sending a request t
|
||||
|
||||
```jsx
|
||||
medusa.admin.salesChannels.update(salesChannelId, {
|
||||
is_disabled: false
|
||||
is_disabled: false,
|
||||
})
|
||||
.then(({ sales_channel }) => {
|
||||
console.log(sales_channel.id);
|
||||
});
|
||||
console.log(sales_channel.id)
|
||||
})
|
||||
```
|
||||
|
||||
</TabItem>
|
||||
@@ -213,19 +213,19 @@ medusa.admin.salesChannels.update(salesChannelId, {
|
||||
|
||||
```jsx
|
||||
fetch(`<SERVER_URL>/admin/sales-channels/${salesChannelId}`, {
|
||||
method: 'POST',
|
||||
credentials: 'include',
|
||||
method: "POST",
|
||||
credentials: "include",
|
||||
headers: {
|
||||
'Content-Type': 'application/json'
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
body: JSON.stringify({
|
||||
is_disabled: false
|
||||
})
|
||||
is_disabled: false,
|
||||
}),
|
||||
})
|
||||
.then((response) => response.json())
|
||||
.then(({ sales_channel }) => {
|
||||
console.log(sales_channel.id)
|
||||
});
|
||||
})
|
||||
```
|
||||
|
||||
</TabItem>
|
||||
@@ -261,8 +261,8 @@ You can delete a sales channel by sending a request to the Delete Sales Channel
|
||||
```jsx
|
||||
medusa.admin.salesChannels.delete(salesChannelId)
|
||||
.then(({ id, object, deleted }) => {
|
||||
console.log(id);
|
||||
});
|
||||
console.log(id)
|
||||
})
|
||||
```
|
||||
|
||||
</TabItem>
|
||||
@@ -270,13 +270,13 @@ medusa.admin.salesChannels.delete(salesChannelId)
|
||||
|
||||
```jsx
|
||||
fetch(`<SERVER_URL>/admin/sales-channels/${salesChannelId}`, {
|
||||
method: 'DELETE',
|
||||
credentials: 'include',
|
||||
method: "DELETE",
|
||||
credentials: "include",
|
||||
})
|
||||
.then((response) => response.json())
|
||||
.then(({ id, object, deleted }) => {
|
||||
console.log(id)
|
||||
});
|
||||
})
|
||||
```
|
||||
|
||||
</TabItem>
|
||||
@@ -307,37 +307,40 @@ To add a product to a sales channel, send a request to the Sales Channel’s Add
|
||||
medusa.admin.salesChannels.addProducts(salesChannelId, {
|
||||
product_ids: [
|
||||
{
|
||||
id: productId
|
||||
}
|
||||
]
|
||||
id: productId,
|
||||
},
|
||||
],
|
||||
})
|
||||
.then(({ sales_channel }) => {
|
||||
console.log(sales_channel.id);
|
||||
});
|
||||
console.log(sales_channel.id)
|
||||
})
|
||||
```
|
||||
|
||||
</TabItem>
|
||||
<TabItem value="fetch" label="Fetch API">
|
||||
|
||||
```jsx
|
||||
fetch(`<SERVER_URL>/admin/sales-channels/${salesChannelId}/products/batch`, {
|
||||
method: 'POST',
|
||||
credentials: 'include',
|
||||
headers: {
|
||||
'Content-Type': 'application/json'
|
||||
},
|
||||
body: JSON.stringify({
|
||||
product_ids: [
|
||||
{
|
||||
id: productId
|
||||
}
|
||||
]
|
||||
})
|
||||
})
|
||||
fetch(
|
||||
`<SERVER_URL>/admin/sales-channels/${salesChannelId}/products/batch`,
|
||||
{
|
||||
method: "POST",
|
||||
credentials: "include",
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
body: JSON.stringify({
|
||||
product_ids: [
|
||||
{
|
||||
id: productId,
|
||||
},
|
||||
],
|
||||
}),
|
||||
}
|
||||
)
|
||||
.then((response) => response.json())
|
||||
.then(({ sales_channel }) => {
|
||||
console.log(sales_channel.id)
|
||||
});
|
||||
})
|
||||
```
|
||||
|
||||
</TabItem>
|
||||
@@ -373,25 +376,28 @@ You can list the products available in a sales channel by sending a request to t
|
||||
```jsx
|
||||
medusa.admin.products.list({
|
||||
sales_channel_id: [
|
||||
salesChannelId
|
||||
]
|
||||
salesChannelId,
|
||||
],
|
||||
})
|
||||
.then(({ products, limit, offset, count }) => {
|
||||
console.log(products.length);
|
||||
});
|
||||
console.log(products.length)
|
||||
})
|
||||
```
|
||||
|
||||
</TabItem>
|
||||
<TabItem value="fetch" label="Fetch API">
|
||||
|
||||
```jsx
|
||||
fetch(`<SERVER_URL>/admin/products?sales_channel_id[0]=${salesChannelId}`, {
|
||||
credentials: 'include',
|
||||
})
|
||||
fetch(
|
||||
`<SERVER_URL>/admin/products?sales_channel_id[0]=${salesChannelId}`,
|
||||
{
|
||||
credentials: "include",
|
||||
}
|
||||
)
|
||||
.then((response) => response.json())
|
||||
.then(({ products, limit, offset, count }) => {
|
||||
console.log(products.length)
|
||||
});
|
||||
})
|
||||
```
|
||||
|
||||
</TabItem>
|
||||
@@ -424,43 +430,46 @@ You can delete a product from a sales channel by sending a request to the Sales
|
||||
medusa.admin.salesChannels.removeProducts(salesChannelId, {
|
||||
product_ids: [
|
||||
{
|
||||
id: productId
|
||||
}
|
||||
]
|
||||
id: productId,
|
||||
},
|
||||
],
|
||||
})
|
||||
.then(({ sales_channel }) => {
|
||||
console.log(sales_channel.id);
|
||||
});
|
||||
console.log(sales_channel.id)
|
||||
})
|
||||
```
|
||||
|
||||
</TabItem>
|
||||
<TabItem value="fetch" label="Fetch API">
|
||||
|
||||
```jsx
|
||||
fetch(`<SERVER_URL>/admin/sales-channels/${salesChannelId}/products/batch`, {
|
||||
method: 'DELETE',
|
||||
credentials: 'include',
|
||||
headers: {
|
||||
'Content-Type': 'application/json'
|
||||
},
|
||||
body: JSON.stringify({
|
||||
product_ids: [
|
||||
{
|
||||
id: productId
|
||||
}
|
||||
]
|
||||
})
|
||||
})
|
||||
fetch(
|
||||
`<SERVER_URL>/admin/sales-channels/${salesChannelId}/products/batch`,
|
||||
{
|
||||
method: "DELETE",
|
||||
credentials: "include",
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
body: JSON.stringify({
|
||||
product_ids: [
|
||||
{
|
||||
id: productId,
|
||||
},
|
||||
],
|
||||
}),
|
||||
}
|
||||
)
|
||||
.then((response) => response.json())
|
||||
.then(({ sales_channel }) => {
|
||||
console.log(sales_channel.id)
|
||||
});
|
||||
})
|
||||
```
|
||||
|
||||
</TabItem>
|
||||
<TabItem value="curl" label="cURL">
|
||||
|
||||
```jsx
|
||||
```bash
|
||||
curl -L -X DELETE '<SERVER_URL>/admin/sales-channels/<SALES_CHANNEL_ID>/products/batch' \
|
||||
-H 'Authorization: Bearer <API_TOKEN>' \
|
||||
-H 'Content-Type: application/json' \
|
||||
@@ -492,14 +501,14 @@ You can filter orders by a specific sales channel by sending a request to the Li
|
||||
```jsx
|
||||
medusa.admin.orders.list({
|
||||
sales_channel_id: [
|
||||
salesChannelId
|
||||
salesChannelId,
|
||||
],
|
||||
limit: 50,
|
||||
offset: 0
|
||||
offset: 0,
|
||||
})
|
||||
.then(({ orders, limit, offset, count }) => {
|
||||
console.log(orders.length);
|
||||
});
|
||||
console.log(orders.length)
|
||||
})
|
||||
```
|
||||
|
||||
</TabItem>
|
||||
@@ -507,18 +516,18 @@ medusa.admin.orders.list({
|
||||
|
||||
```jsx
|
||||
fetch(`<SERVER_URL>/admin/orders?sales_channel_id[0]=${salesChannelId}`, {
|
||||
credentials: 'include',
|
||||
credentials: "include",
|
||||
})
|
||||
.then((response) => response.json())
|
||||
.then(({ orders, limit, offset, count }) => {
|
||||
console.log(orders.length)
|
||||
});
|
||||
})
|
||||
```
|
||||
|
||||
</TabItem>
|
||||
<TabItem value="curl" label="cURL">
|
||||
|
||||
```jsx
|
||||
```bash
|
||||
curl -L -X GET '<SERVER_URL>/admin/orders?sales_channel_id[0]=<SALES_CHANNEL_ID>' \
|
||||
-H 'Authorization: Bearer <API_TOKEN>'
|
||||
```
|
||||
|
||||
@@ -38,23 +38,25 @@ To create a scheduled job, add the following code in the file you created, which
|
||||
|
||||
```ts title=src/loaders/publish.ts
|
||||
const publishJob = async (container, options) => {
|
||||
const jobSchedulerService = container.resolve("jobSchedulerService");
|
||||
jobSchedulerService.create("publish-products", {}, "0 0 * * *", async () => {
|
||||
//job to execute
|
||||
const productService = container.resolve("productService");
|
||||
const draftProducts = await productService.list({
|
||||
status: 'draft'
|
||||
});
|
||||
const jobSchedulerService = container.resolve("jobSchedulerService")
|
||||
jobSchedulerService.create("publish-products", {}, "0 0 * * *",
|
||||
async () => {
|
||||
// job to execute
|
||||
const productService = container.resolve("productService")
|
||||
const draftProducts = await productService.list({
|
||||
status: "draft",
|
||||
})
|
||||
|
||||
for (const product of draftProducts) {
|
||||
await productService.update(product.id, {
|
||||
status: 'published'
|
||||
});
|
||||
for (const product of draftProducts) {
|
||||
await productService.update(product.id, {
|
||||
status: "published",
|
||||
})
|
||||
}
|
||||
}
|
||||
})
|
||||
)
|
||||
}
|
||||
|
||||
export default publishJob;
|
||||
export default publishJob
|
||||
```
|
||||
|
||||
:::info
|
||||
@@ -87,12 +89,12 @@ For example:
|
||||
```ts
|
||||
jobSchedulerService.create("publish-products", {
|
||||
data: {
|
||||
productId
|
||||
}
|
||||
productId,
|
||||
},
|
||||
}, "0 0 * * *", async (job) => {
|
||||
console.log(job.data); // {productId: 'prod_124...'}
|
||||
//...
|
||||
});
|
||||
console.log(job.data) // {productId: 'prod_124...'}
|
||||
// ...
|
||||
})
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
@@ -9,12 +9,12 @@ To create a service, create a TypeScript or JavaScript file in `src/services` to
|
||||
For example, if you want to create a service `helloService`, create the file `hello.ts` in `src/services` with the following content:
|
||||
|
||||
```ts title=/src/services/hello.ts
|
||||
import { TransactionBaseService } from '@medusajs/medusa';
|
||||
import { EntityManager } from 'typeorm';
|
||||
import { TransactionBaseService } from "@medusajs/medusa"
|
||||
import { EntityManager } from "typeorm"
|
||||
|
||||
class HelloService extends TransactionBaseService {
|
||||
protected manager_: EntityManager;
|
||||
protected transactionManager_: EntityManager;
|
||||
protected manager_: EntityManager
|
||||
protected transactionManager_: EntityManager
|
||||
getMessage() {
|
||||
return `Welcome to My Store!`
|
||||
}
|
||||
@@ -32,19 +32,25 @@ As the service extends the `TransactionBaseService` class, all services in Medus
|
||||
So, if you want your service to use another service, simply add it as part of your constructor’s dependencies and set it to a field inside your service’s class:
|
||||
|
||||
```ts
|
||||
private productService: ProductService;
|
||||
class HelloService extends TransactionBaseService {
|
||||
private productService: ProductService
|
||||
|
||||
constructor(container) {
|
||||
super(container);
|
||||
this.productService = container.productService;
|
||||
constructor(container) {
|
||||
super(container)
|
||||
this.productService = container.productService
|
||||
}
|
||||
// ...
|
||||
}
|
||||
```
|
||||
|
||||
Then, you can use that service anywhere in your custom service:
|
||||
|
||||
```ts
|
||||
async getProductCount() {
|
||||
return await this.productService.count();
|
||||
class HelloService extends TransactionBaseService {
|
||||
// ...
|
||||
async getProductCount() {
|
||||
return await this.productService.count()
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
@@ -69,9 +75,12 @@ npm run build
|
||||
To use your custom service in another custom service, you can have easy access to it in the dependencies injected to the constructor of your service:
|
||||
|
||||
```ts
|
||||
constructor(container) {
|
||||
super(container);
|
||||
this.helloService = container.helloService;
|
||||
class MyService extends TransactionBaseService {
|
||||
constructor(container) {
|
||||
super(container)
|
||||
this.helloService = container.helloService
|
||||
}
|
||||
// ...
|
||||
}
|
||||
```
|
||||
|
||||
@@ -92,8 +101,11 @@ res.json({
|
||||
To use your custom service in a subscriber, you can have easy access to it in the subscriber’s dependencies injected to the constructor of your subscriber:
|
||||
|
||||
```ts
|
||||
constructor({ helloService, eventBusService }) {
|
||||
this.helloService = helloService;
|
||||
class MySubscriber {
|
||||
constructor({ helloService, eventBusService }) {
|
||||
this.helloService = helloService
|
||||
}
|
||||
// ...
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
@@ -32,7 +32,7 @@ class MyFulfillmentService extends FulfillmentService {
|
||||
|
||||
}
|
||||
|
||||
export default MyFulfillmentService;
|
||||
export default MyFulfillmentService
|
||||
```
|
||||
|
||||
Fulfillment provider services must extend the `FulfillmentService` class imported from `medusa-interfaces`.
|
||||
@@ -55,10 +55,10 @@ The value of this property will also be used to reference the fulfillment provid
|
||||
import { FulfillmentService } from "medusa-interfaces"
|
||||
|
||||
class MyFulfillmentService extends FulfillmentService {
|
||||
static identifier = 'my-fulfillment';
|
||||
static identifier = "my-fulfillment"
|
||||
}
|
||||
|
||||
export default MyFulfillmentService;
|
||||
export default MyFulfillmentService
|
||||
```
|
||||
|
||||
### constructor
|
||||
@@ -72,9 +72,12 @@ Additionally, if you’re creating your fulfillment provider as an external plug
|
||||
For example:
|
||||
|
||||
```ts
|
||||
constructor({ productService }, options) {
|
||||
super();
|
||||
//you can access options here
|
||||
class MyFulfillmentService extends FulfillmentService {
|
||||
// ...
|
||||
constructor(container, options) {
|
||||
super(container)
|
||||
// you can access options here
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
@@ -89,15 +92,18 @@ These fulfillment options are defined in the `getFulfillmentOptions` method. Thi
|
||||
For example:
|
||||
|
||||
```ts
|
||||
async getFulfillmentOptions () {
|
||||
return [
|
||||
{
|
||||
id: 'my-fulfillment'
|
||||
},
|
||||
{
|
||||
id: 'my-fulfillment-dynamic'
|
||||
}
|
||||
];
|
||||
class MyFulfillmentService extends FulfillmentService {
|
||||
// ...
|
||||
async getFulfillmentOptions() {
|
||||
return [
|
||||
{
|
||||
id: "my-fulfillment",
|
||||
},
|
||||
{
|
||||
id: "my-fulfillment-dynamic",
|
||||
},
|
||||
]
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
@@ -116,8 +122,11 @@ This method returns a boolean. If the result is false, an error is thrown and th
|
||||
For example, you can use this method to ensure that the `id` in the `data` object is correct:
|
||||
|
||||
```ts
|
||||
async validateOption (data) {
|
||||
return data.id == 'my-fulfillment';
|
||||
class MyFulfillmentService extends FulfillmentService {
|
||||
// ...
|
||||
async validateOption(data) {
|
||||
return data.id == "my-fulfillment"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
@@ -144,13 +153,16 @@ If everything is valid, this method must return a value that will be stored in t
|
||||
For example:
|
||||
|
||||
```ts
|
||||
async validateFulfillmentData(optionData, data, cart) {
|
||||
if (data.id !== "my-fulfillment") {
|
||||
throw new Error("invalid data");
|
||||
}
|
||||
class MyFulfillmentService extends FulfillmentService {
|
||||
// ...
|
||||
async validateFulfillmentData(optionData, data, cart) {
|
||||
if (data.id !== "my-fulfillment") {
|
||||
throw new Error("invalid data")
|
||||
}
|
||||
|
||||
return {
|
||||
...data
|
||||
return {
|
||||
...data,
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
@@ -173,14 +185,17 @@ You can use the `data` property in the shipping method (first parameter) to acce
|
||||
Here is a basic implementation of `createFulfillment` for a fulfillment provider that does not interact with any third-party provider to create the fulfillment:
|
||||
|
||||
```ts
|
||||
createFulfillment(
|
||||
methodData,
|
||||
fulfillmentItems,
|
||||
fromOrder,
|
||||
fulfillment
|
||||
) {
|
||||
// No data is being sent anywhere
|
||||
return Promise.resolve({})
|
||||
class MyFulfillmentService extends FulfillmentService {
|
||||
// ...
|
||||
createFulfillment(
|
||||
methodData,
|
||||
fulfillmentItems,
|
||||
fromOrder,
|
||||
fulfillment
|
||||
) {
|
||||
// No data is being sent anywhere
|
||||
return Promise.resolve({})
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
@@ -206,8 +221,11 @@ This method receives as a parameter the `data` object sent with the request that
|
||||
For example:
|
||||
|
||||
```ts
|
||||
canCalculate(data) {
|
||||
return data.id === 'my-fulfillment-dynamic';
|
||||
class MyFulfillmentService extends FulfillmentService {
|
||||
// ...
|
||||
canCalculate(data) {
|
||||
return data.id === "my-fulfillment-dynamic"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
@@ -224,16 +242,22 @@ This method receives three parameters:
|
||||
If your fulfillment provider does not provide any dynamically calculated rates you can keep the function empty:
|
||||
|
||||
```ts
|
||||
calculatePrice() {
|
||||
|
||||
class MyFulfillmentService extends FulfillmentService {
|
||||
// ...
|
||||
calculatePrice() {
|
||||
// leave empty
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Otherwise, you can use it to calculate the price with a custom logic. For example:
|
||||
|
||||
```ts
|
||||
calculatePrice (optionData, data, cart) {
|
||||
return cart.items.length * 1000;
|
||||
class MyFulfillmentService extends FulfillmentService {
|
||||
// ...
|
||||
calculatePrice(optionData, data, cart) {
|
||||
return cart.items.length * 1000
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
@@ -250,8 +274,11 @@ It receives the return created as a parameter. The value it returns is set to th
|
||||
This is the basic implementation of the method for a fulfillment provider that does not contact with a third-party provider to fulfill the return:
|
||||
|
||||
```ts
|
||||
createReturn(returnOrder) {
|
||||
return Promise.resolve({})
|
||||
class MyFulfillmentService extends FulfillmentService {
|
||||
// ...
|
||||
createReturn(returnOrder) {
|
||||
return Promise.resolve({})
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
@@ -266,8 +293,11 @@ This method receives the fulfillment being cancelled as a parameter.
|
||||
This is the basic implementation of the method for a fulfillment provider that does not interact with a third-party provider to cancel the fulfillment:
|
||||
|
||||
```ts
|
||||
cancelFulfillment(fulfillment) {
|
||||
return Promise.resolve({})
|
||||
class MyFulfillmentService extends FulfillmentService {
|
||||
// ...
|
||||
cancelFulfillment(fulfillment) {
|
||||
return Promise.resolve({})
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
@@ -18,20 +18,20 @@ After creating the file under `src/subscribers`, in the constructor of your subs
|
||||
|
||||
The `eventBusService.subscribe` method receives the name of the event as a first parameter and as a second parameter a method in your subscriber that will handle this event.
|
||||
|
||||
For example, here is the `OrderNotifierSubscriber` class created in `src/subscribers/orderNotifier.js`:
|
||||
For example, here is the `OrderNotifierSubscriber` class created in `src/subscribers/orderNotifier.ts`:
|
||||
|
||||
```ts title=src/subscribers/orderNotifier.js
|
||||
```ts title=src/subscribers/orderNotifier.ts
|
||||
class OrderNotifierSubscriber {
|
||||
constructor({ eventBusService }) {
|
||||
eventBusService.subscribe("order.placed", this.handleOrder);
|
||||
eventBusService.subscribe("order.placed", this.handleOrder)
|
||||
}
|
||||
|
||||
handleOrder = async (data) => {
|
||||
console.log("New Order: " + data.id)
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
export default OrderNotifierSubscriber;
|
||||
export default OrderNotifierSubscriber
|
||||
```
|
||||
|
||||
This subscriber registers the method `handleOrder` as one of the handlers of the `order.placed` event. The method `handleOrder` will be executed every time an order is placed. It receives the order ID in the `data` parameter. You can then use the order’s details to perform any kind of task you need.
|
||||
@@ -51,19 +51,25 @@ You can access any service through the dependencies injected to your subscriber
|
||||
For example:
|
||||
|
||||
```ts
|
||||
constructor({ productService, eventBusService }) {
|
||||
this.productService = productService;
|
||||
class OrderNotifierSubscriber {
|
||||
constructor({ productService, eventBusService }) {
|
||||
this.productService = productService
|
||||
|
||||
eventBusService.subscribe("order.placed", this.handleOrder);
|
||||
eventBusService.subscribe("order.placed", this.handleOrder)
|
||||
}
|
||||
// ...
|
||||
}
|
||||
```
|
||||
|
||||
You can then use `this.productService` anywhere in your subscriber’s methods. For example:
|
||||
|
||||
```ts
|
||||
handleOrder = async (data) => {
|
||||
//...
|
||||
const product = this.productService.list()
|
||||
class OrderNotifierSubscriber {
|
||||
// ...
|
||||
handleOrder = async (data) => {
|
||||
// ...
|
||||
const product = this.productService.list()
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
@@ -51,7 +51,7 @@ Object of the following format:
|
||||
|
||||
```js noReport noCopy
|
||||
{
|
||||
id //string ID of batch job
|
||||
id // string ID of batch job
|
||||
}
|
||||
```
|
||||
|
||||
@@ -72,7 +72,7 @@ Object of the following format:
|
||||
|
||||
```js noReport noCopy
|
||||
{
|
||||
id //string ID of batch job
|
||||
id // string ID of batch job
|
||||
}
|
||||
```
|
||||
|
||||
@@ -93,7 +93,7 @@ Object of the following format:
|
||||
|
||||
```js noReport noCopy
|
||||
{
|
||||
id //string ID of batch job
|
||||
id // string ID of batch job
|
||||
}
|
||||
```
|
||||
|
||||
@@ -116,7 +116,7 @@ Object of the following format:
|
||||
|
||||
```js noReport noCopy
|
||||
{
|
||||
id //string ID of batch job
|
||||
id // string ID of batch job
|
||||
}
|
||||
```
|
||||
|
||||
@@ -139,7 +139,7 @@ Object of the following format:
|
||||
|
||||
```js noReport noCopy
|
||||
{
|
||||
id //string ID of batch job
|
||||
id // string ID of batch job
|
||||
}
|
||||
```
|
||||
|
||||
@@ -160,7 +160,7 @@ Object of the following format:
|
||||
|
||||
```js noReport noCopy
|
||||
{
|
||||
id //string ID of batch job
|
||||
id // string ID of batch job
|
||||
}
|
||||
```
|
||||
|
||||
@@ -181,7 +181,7 @@ Object of the following format:
|
||||
|
||||
```js noReport noCopy
|
||||
{
|
||||
id //string ID of batch job
|
||||
id // string ID of batch job
|
||||
}
|
||||
```
|
||||
|
||||
@@ -202,7 +202,7 @@ Object of the following format:
|
||||
|
||||
```js noReport noCopy
|
||||
{
|
||||
id //string ID of batch job
|
||||
id // string ID of batch job
|
||||
}
|
||||
```
|
||||
|
||||
@@ -262,7 +262,7 @@ Object of the following format:
|
||||
|
||||
```js noReport noCopy
|
||||
{
|
||||
id //string ID of cart
|
||||
id // string ID of cart
|
||||
}
|
||||
```
|
||||
|
||||
@@ -329,8 +329,8 @@ Object of the following format:
|
||||
|
||||
```js noReport noCopy
|
||||
{
|
||||
id, //string ID of claim
|
||||
no_notification //boolean indicating whether a notification should be sent or not
|
||||
id, // string ID of claim
|
||||
no_notification // boolean indicating whether a notification should be sent
|
||||
}
|
||||
```
|
||||
|
||||
@@ -354,8 +354,8 @@ Object of the following format:
|
||||
|
||||
```js noReport noCopy
|
||||
{
|
||||
id, //string ID of claim
|
||||
no_notification //boolean indicating whether a notification should be sent or not
|
||||
id, // string ID of claim
|
||||
no_notification // boolean indicating whether a notification should be sent
|
||||
}
|
||||
```
|
||||
|
||||
@@ -379,8 +379,8 @@ Object of the following format:
|
||||
|
||||
```js noReport noCopy
|
||||
{
|
||||
id, //string ID of claim
|
||||
no_notification //boolean indicating whether a notification should be sent or not
|
||||
id, // string ID of claim
|
||||
no_notification // boolean indicating whether a notification should be sent
|
||||
}
|
||||
```
|
||||
|
||||
@@ -404,9 +404,9 @@ Object of the following format:
|
||||
|
||||
```js noReport noCopy
|
||||
{
|
||||
id, //string ID of claim
|
||||
fulfillment_id, //string ID of the fulfillment created
|
||||
no_notification //boolean indicating whether a notification should be sent or not
|
||||
id, // string ID of claim
|
||||
fulfillment_id, // string ID of the fulfillment created
|
||||
no_notification // boolean indicating whether a notification should be sent
|
||||
}
|
||||
```
|
||||
|
||||
@@ -430,9 +430,9 @@ Object of the following format:
|
||||
|
||||
```js noReport noCopy
|
||||
{
|
||||
id, //string ID of claim
|
||||
fulfillment_id, //string ID of the fulfillment created
|
||||
no_notification //boolean indicating whether a notification should be sent or not
|
||||
id, // string ID of claim
|
||||
fulfillment_id, // string ID of the fulfillment created
|
||||
no_notification // boolean indicating whether a notification should be sent
|
||||
}
|
||||
```
|
||||
|
||||
@@ -456,8 +456,8 @@ Object of the following format:
|
||||
|
||||
```js noReport noCopy
|
||||
{
|
||||
id, //string ID of claim
|
||||
no_notification //boolean indicating whether a notification should be sent or not
|
||||
id, // string ID of claim
|
||||
no_notification // boolean indicating whether a notification should be sent
|
||||
}
|
||||
```
|
||||
|
||||
@@ -505,7 +505,7 @@ Object of the following format:
|
||||
|
||||
```js noReport noCopy
|
||||
{
|
||||
id //string ID of claim item
|
||||
id // string ID of claim item
|
||||
}
|
||||
```
|
||||
|
||||
@@ -529,7 +529,7 @@ Object of the following format:
|
||||
|
||||
```js noReport noCopy
|
||||
{
|
||||
id //string ID of claim item
|
||||
id // string ID of claim item
|
||||
}
|
||||
```
|
||||
|
||||
@@ -553,7 +553,7 @@ Object of the following format:
|
||||
|
||||
```js noReport noCopy
|
||||
{
|
||||
id //string ID of claim item
|
||||
id // string ID of claim item
|
||||
}
|
||||
```
|
||||
|
||||
@@ -601,7 +601,7 @@ Object of the following format:
|
||||
|
||||
```js noReport noCopy
|
||||
{
|
||||
code //string 3 character ISO code of the updated currency.
|
||||
code // string 3 character ISO code of the updated currency.
|
||||
}
|
||||
```
|
||||
|
||||
@@ -685,11 +685,11 @@ Object of the following format:
|
||||
|
||||
```js noReport noCopy
|
||||
{
|
||||
id, //string ID of customer
|
||||
email, //string email of the customer
|
||||
first_name, //string first name of the customer
|
||||
last_name, //string last name of the customer
|
||||
token //string reset password token
|
||||
id, // string ID of customer
|
||||
email, // string email of the customer
|
||||
first_name, // string first name of the customer
|
||||
last_name, // string last name of the customer
|
||||
token // string reset password token
|
||||
}
|
||||
```
|
||||
|
||||
@@ -737,7 +737,7 @@ Object of the following format:
|
||||
|
||||
```js noReport noCopy
|
||||
{
|
||||
id //string ID of draft order
|
||||
id // string ID of draft order
|
||||
}
|
||||
```
|
||||
|
||||
@@ -761,7 +761,7 @@ Object of the following format:
|
||||
|
||||
```js noReport noCopy
|
||||
{
|
||||
id //string ID of draft order
|
||||
id // string ID of draft order
|
||||
}
|
||||
```
|
||||
|
||||
@@ -858,9 +858,9 @@ Object of the following format:
|
||||
|
||||
```js noReport noCopy
|
||||
{
|
||||
id //string ID of invite
|
||||
token, //string token generated to validate the invited user
|
||||
user_email //string email of invited user
|
||||
id // string ID of invite
|
||||
token, // string token generated to validate the invited user
|
||||
user_email // string email of invited user
|
||||
}
|
||||
```
|
||||
|
||||
@@ -907,7 +907,7 @@ Object of the following format:
|
||||
|
||||
```js noReport noCopy
|
||||
{
|
||||
id //string ID of note
|
||||
id // string ID of note
|
||||
}
|
||||
```
|
||||
|
||||
@@ -931,7 +931,7 @@ Object of the following format:
|
||||
|
||||
```js noReport noCopy
|
||||
{
|
||||
id //string ID of note
|
||||
id // string ID of note
|
||||
}
|
||||
```
|
||||
|
||||
@@ -955,7 +955,7 @@ Object of the following format:
|
||||
|
||||
```js noReport noCopy
|
||||
{
|
||||
id //string ID of note
|
||||
id // string ID of note
|
||||
}
|
||||
```
|
||||
|
||||
@@ -1070,8 +1070,8 @@ Object of the following format:
|
||||
|
||||
```js noReport noCopy
|
||||
{
|
||||
id, //string ID of order
|
||||
no_notification //boolean indicating whether a notification should be sent or not
|
||||
id, // string ID of order
|
||||
no_notification // boolean indicating whether a notification should be sent
|
||||
}
|
||||
```
|
||||
|
||||
@@ -1095,8 +1095,8 @@ Object of the following format:
|
||||
|
||||
```js noReport noCopy
|
||||
{
|
||||
id, //string ID of order
|
||||
no_notification //(optional) boolean indicating whether a notification should be sent or not
|
||||
id, // string ID of order
|
||||
no_notification // (optional) boolean indicating whether a notification should be sent
|
||||
}
|
||||
```
|
||||
|
||||
@@ -1120,8 +1120,8 @@ Object of the following format:
|
||||
|
||||
```js noReport noCopy
|
||||
{
|
||||
id, //string ID of order
|
||||
no_notification //boolean indicating whether a notification should be sent or not
|
||||
id, // string ID of order
|
||||
no_notification // boolean indicating whether a notification should be sent
|
||||
}
|
||||
```
|
||||
|
||||
@@ -1145,8 +1145,8 @@ Object of the following format:
|
||||
|
||||
```js noReport noCopy
|
||||
{
|
||||
id, //string ID of order
|
||||
no_notification //boolean indicating whether a notification should be sent or not
|
||||
id, // string ID of order
|
||||
no_notification // boolean indicating whether a notification should be sent
|
||||
}
|
||||
```
|
||||
|
||||
@@ -1194,7 +1194,7 @@ Object of the following format:
|
||||
|
||||
```js noReport noCopy
|
||||
{
|
||||
id //string ID of order
|
||||
id // string ID of order
|
||||
}
|
||||
```
|
||||
|
||||
@@ -1218,8 +1218,8 @@ Object of the following format:
|
||||
|
||||
```js noReport noCopy
|
||||
{
|
||||
id, //string ID of order
|
||||
no_notification //boolean indicating whether a notification should be sent or not
|
||||
id, // string ID of order
|
||||
no_notification // boolean indicating whether a notification should be sent
|
||||
}
|
||||
```
|
||||
|
||||
@@ -1243,10 +1243,10 @@ Object of the following format:
|
||||
|
||||
```js noReport noCopy
|
||||
{
|
||||
id, //string ID of order
|
||||
payment_id, //string ID of Payment
|
||||
error, //string error message
|
||||
no_notification //boolean indicating whether a notification should be sent or not
|
||||
id, // string ID of order
|
||||
payment_id, // string ID of Payment
|
||||
error, // string error message
|
||||
no_notification // boolean indicating whether a notification should be sent
|
||||
}
|
||||
```
|
||||
|
||||
@@ -1270,9 +1270,9 @@ Object of the following format:
|
||||
|
||||
```js noReport noCopy
|
||||
{
|
||||
id, //string ID of order
|
||||
fulfillment_id, //string ID of fulfillment
|
||||
no_notification //boolean indicating whether a notification should be sent or not
|
||||
id, // string ID of order
|
||||
fulfillment_id, // string ID of fulfillment
|
||||
no_notification // boolean indicating whether a notification should be sent
|
||||
}
|
||||
```
|
||||
|
||||
@@ -1296,9 +1296,9 @@ Object of the following format:
|
||||
|
||||
```js noReport noCopy
|
||||
{
|
||||
id, //string ID of order
|
||||
fulfillment_id, //string ID of fulfillment
|
||||
no_notification //boolean indicating whether a notification should be sent or not
|
||||
id, // string ID of order
|
||||
fulfillment_id, // string ID of fulfillment
|
||||
no_notification // boolean indicating whether a notification should be sent
|
||||
}
|
||||
```
|
||||
|
||||
@@ -1322,9 +1322,9 @@ Object of the following format:
|
||||
|
||||
```js noReport noCopy
|
||||
{
|
||||
id, //string ID of order
|
||||
fulfillment_id, //string ID of fulfillment
|
||||
no_notification //boolean indicating whether a notification should be sent or not
|
||||
id, // string ID of order
|
||||
fulfillment_id, // string ID of fulfillment
|
||||
no_notification // boolean indicating whether a notification should be sent
|
||||
}
|
||||
```
|
||||
|
||||
@@ -1348,9 +1348,9 @@ Object of the following format:
|
||||
|
||||
```js noReport noCopy
|
||||
{
|
||||
id, //string ID of order
|
||||
return_id, //string ID of return
|
||||
no_notification //(optional) boolean indicating whether a notification should be sent or not
|
||||
id, // string ID of order
|
||||
return_id, // string ID of return
|
||||
no_notification // (optional) boolean indicating whether a notification should be sent
|
||||
}
|
||||
```
|
||||
|
||||
@@ -1374,9 +1374,9 @@ Object of the following format:
|
||||
|
||||
```js noReport noCopy
|
||||
{
|
||||
id, //string ID of order
|
||||
return_id, //string ID of return
|
||||
no_notification //boolean indicating whether a notification should be sent or not
|
||||
id, // string ID of order
|
||||
return_id, // string ID of return
|
||||
no_notification // boolean indicating whether a notification should be sent
|
||||
}
|
||||
```
|
||||
|
||||
@@ -1400,9 +1400,9 @@ Object of the following format:
|
||||
|
||||
```js noReport noCopy
|
||||
{
|
||||
id, //string ID of order
|
||||
return_id, //string ID of return
|
||||
no_notification //boolean indicating whether a notification should be sent or not
|
||||
id, // string ID of order
|
||||
return_id, // string ID of return
|
||||
no_notification // boolean indicating whether a notification should be sent
|
||||
}
|
||||
```
|
||||
|
||||
@@ -1426,9 +1426,9 @@ Object of the following format:
|
||||
|
||||
```js noReport noCopy
|
||||
{
|
||||
id, //string ID of order
|
||||
refund_id, //string ID of refund
|
||||
no_notification //boolean indicating whether a notification should be sent or not
|
||||
id, // string ID of order
|
||||
refund_id, // string ID of refund
|
||||
no_notification // boolean indicating whether a notification should be sent
|
||||
}
|
||||
```
|
||||
|
||||
@@ -1631,7 +1631,7 @@ Object of the following format:
|
||||
|
||||
```js noReport noCopy
|
||||
{
|
||||
id //string ID of order edit
|
||||
id // string ID of order edit
|
||||
}
|
||||
```
|
||||
|
||||
@@ -1712,7 +1712,7 @@ Triggered when an order edit item change is created.
|
||||
|
||||
```js noReport noCopy
|
||||
{
|
||||
id //string ID of item change
|
||||
id // string ID of item change
|
||||
}
|
||||
```
|
||||
|
||||
@@ -1734,7 +1734,7 @@ Triggered when an order edit item change is deleted.
|
||||
|
||||
```js noReport noCopy
|
||||
{
|
||||
id //string ID of item change
|
||||
id // string ID of item change
|
||||
}
|
||||
```
|
||||
|
||||
@@ -2027,7 +2027,7 @@ Object of the following format:
|
||||
|
||||
```js noReport noCopy
|
||||
{
|
||||
id //string ID of product
|
||||
id // string ID of product
|
||||
}
|
||||
```
|
||||
|
||||
@@ -2053,8 +2053,8 @@ In one case, when the `/admin/products/{id}` endpoint is used to update the prod
|
||||
|
||||
```js noReport noCopy
|
||||
{
|
||||
id, //id of product
|
||||
fields //an array of field names that were updated
|
||||
id, // id of product
|
||||
fields // an array of field names that were updated
|
||||
}
|
||||
```
|
||||
|
||||
@@ -2078,7 +2078,7 @@ Object of the following format:
|
||||
|
||||
```js noReport noCopy
|
||||
{
|
||||
id //string ID of product
|
||||
id // string ID of product
|
||||
}
|
||||
```
|
||||
|
||||
@@ -2126,8 +2126,8 @@ Object of the following format:
|
||||
|
||||
```js noReport noCopy
|
||||
{
|
||||
id, //string ID of variant
|
||||
product_id //string ID of product
|
||||
id, // string ID of variant
|
||||
product_id // string ID of product
|
||||
}
|
||||
```
|
||||
|
||||
@@ -2151,9 +2151,9 @@ Object of the following format:
|
||||
|
||||
```js noReport noCopy
|
||||
{
|
||||
id, //string ID of variant
|
||||
product_id, //string ID of product
|
||||
fields //array of names of updated fields
|
||||
id, // string ID of variant
|
||||
product_id, // string ID of product
|
||||
fields // array of names of updated fields
|
||||
}
|
||||
```
|
||||
|
||||
@@ -2177,9 +2177,9 @@ Object of the following format:
|
||||
|
||||
```js noReport noCopy
|
||||
{
|
||||
id, //string ID of variant
|
||||
product_id, //string ID of product
|
||||
metadata //object of the `metadata` field of the variant
|
||||
id, // string ID of variant
|
||||
product_id, // string ID of product
|
||||
metadata // object of the `metadata` field of the variant
|
||||
}
|
||||
```
|
||||
|
||||
@@ -2239,7 +2239,7 @@ Object of the following format:
|
||||
|
||||
```js noReport noCopy
|
||||
{
|
||||
id //string ID of publishable API key
|
||||
id // string ID of publishable API key
|
||||
}
|
||||
```
|
||||
|
||||
@@ -2263,7 +2263,7 @@ Object of the following format:
|
||||
|
||||
```js noReport noCopy
|
||||
{
|
||||
id //string ID of publishable API key
|
||||
id // string ID of publishable API key
|
||||
}
|
||||
```
|
||||
|
||||
@@ -2311,7 +2311,7 @@ Object of the following format:
|
||||
|
||||
```js noReport noCopy
|
||||
{
|
||||
id //string ID of region
|
||||
id // string ID of region
|
||||
}
|
||||
```
|
||||
|
||||
@@ -2335,8 +2335,8 @@ Object of the following format:
|
||||
|
||||
```js noReport noCopy
|
||||
{
|
||||
id, //string ID of region
|
||||
fields //array of names of updated fields
|
||||
id, // string ID of region
|
||||
fields // array of names of updated fields
|
||||
}
|
||||
```
|
||||
|
||||
@@ -2360,7 +2360,7 @@ Object of the following format:
|
||||
|
||||
```js noReport noCopy
|
||||
{
|
||||
id //string ID of region
|
||||
id // string ID of region
|
||||
}
|
||||
```
|
||||
|
||||
@@ -2418,7 +2418,7 @@ Object of the following format:
|
||||
|
||||
```js noReport noCopy
|
||||
{
|
||||
id //string ID of sales channel
|
||||
id // string ID of sales channel
|
||||
}
|
||||
```
|
||||
|
||||
@@ -2466,7 +2466,7 @@ Object of the following format:
|
||||
|
||||
```js noReport noCopy
|
||||
{
|
||||
id //string ID of sales channel
|
||||
id // string ID of sales channel
|
||||
}
|
||||
```
|
||||
|
||||
@@ -2513,8 +2513,8 @@ Object of the following format:
|
||||
|
||||
```js noReport noCopy
|
||||
{
|
||||
id, //string ID of swap
|
||||
no_notification //boolean indicating whether a notification should be sent or not
|
||||
id, // string ID of swap
|
||||
no_notification // boolean indicating whether a notification should be sent
|
||||
}
|
||||
```
|
||||
|
||||
@@ -2538,9 +2538,9 @@ Object of the following format:
|
||||
|
||||
```js noReport noCopy
|
||||
{
|
||||
id, //string ID of swap
|
||||
order_id, //string ID of order
|
||||
no_notification //boolean indicating whether a notification should be sent or not
|
||||
id, // string ID of swap
|
||||
order_id, // string ID of order
|
||||
no_notification // boolean indicating whether a notification should be sent
|
||||
}
|
||||
```
|
||||
|
||||
@@ -2564,9 +2564,9 @@ Object of the following format:
|
||||
|
||||
```js noReport noCopy
|
||||
{
|
||||
id, //string ID of swap
|
||||
fulfillment_id, //string ID of fulfillment
|
||||
no_notification //boolean indicating whether a notification should be sent or not
|
||||
id, // string ID of swap
|
||||
fulfillment_id, // string ID of fulfillment
|
||||
no_notification // boolean indicating whether a notification should be sent
|
||||
}
|
||||
```
|
||||
|
||||
@@ -2590,9 +2590,9 @@ Object of the following format:
|
||||
|
||||
```js noReport noCopy
|
||||
{
|
||||
id, //string ID of swap
|
||||
fulfillment_id, //string ID of fulfillment
|
||||
no_notification //boolean indicating whether a notification should be sent or not
|
||||
id, // string ID of swap
|
||||
fulfillment_id, // string ID of fulfillment
|
||||
no_notification // boolean indicating whether a notification should be sent
|
||||
}
|
||||
```
|
||||
|
||||
@@ -2616,8 +2616,8 @@ Object of the following format:
|
||||
|
||||
```js noReport noCopy
|
||||
{
|
||||
id, //string ID of swap
|
||||
no_notification //boolean indicating whether a notification should be sent or not
|
||||
id, // string ID of swap
|
||||
no_notification // boolean indicating whether a notification should be sent
|
||||
}
|
||||
```
|
||||
|
||||
@@ -2641,8 +2641,8 @@ Object of the following format:
|
||||
|
||||
```js noReport noCopy
|
||||
{
|
||||
id, //string ID of swap
|
||||
no_notification //boolean indicating whether a notification should be sent or not
|
||||
id, // string ID of swap
|
||||
no_notification // boolean indicating whether a notification should be sent
|
||||
}
|
||||
```
|
||||
|
||||
@@ -2666,8 +2666,8 @@ Object of the following format:
|
||||
|
||||
```js noReport noCopy
|
||||
{
|
||||
id, //string ID of swap
|
||||
no_notification //boolean indicating whether a notification should be sent or not
|
||||
id, // string ID of swap
|
||||
no_notification // boolean indicating whether a notification should be sent
|
||||
}
|
||||
```
|
||||
|
||||
@@ -2691,8 +2691,8 @@ Object of the following format:
|
||||
|
||||
```js noReport noCopy
|
||||
{
|
||||
id, //string ID of swap
|
||||
no_notification //boolean indicating whether a notification should be sent or not
|
||||
id, // string ID of swap
|
||||
no_notification // boolean indicating whether a notification should be sent
|
||||
}
|
||||
```
|
||||
|
||||
@@ -2716,8 +2716,8 @@ Object of the following format:
|
||||
|
||||
```js noReport noCopy
|
||||
{
|
||||
id, //string ID of swap
|
||||
no_notification //boolean indicating whether a notification should be sent or not
|
||||
id, // string ID of swap
|
||||
no_notification // boolean indicating whether a notification should be sent
|
||||
}
|
||||
```
|
||||
|
||||
@@ -2816,7 +2816,7 @@ Object of the following format:
|
||||
|
||||
```js noReport noCopy
|
||||
{
|
||||
id //string ID of user
|
||||
id // string ID of user
|
||||
}
|
||||
```
|
||||
|
||||
@@ -2840,7 +2840,7 @@ Object of the following format:
|
||||
|
||||
```js noReport noCopy
|
||||
{
|
||||
id //string ID of user
|
||||
id // string ID of user
|
||||
}
|
||||
```
|
||||
|
||||
@@ -2864,8 +2864,8 @@ Object of the following format:
|
||||
|
||||
```js noReport noCopy
|
||||
{
|
||||
email, //string email of user requesting to reset their password
|
||||
token //token create to reset the password
|
||||
email, // string email of user requesting to reset their password
|
||||
token // token create to reset the password
|
||||
}
|
||||
```
|
||||
|
||||
@@ -2889,7 +2889,7 @@ Object of the following format:
|
||||
|
||||
```js noReport noCopy
|
||||
{
|
||||
id //string ID of user
|
||||
id // string ID of user
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
@@ -126,7 +126,9 @@ Where `amount` is the amount of the variant’s price in the price list, `taxRat
|
||||
|
||||
Here is an example of these fields when tax inclusivity is enabled for both the currency and the price list:
|
||||
|
||||
```jsx noReport
|
||||
<!-- eslint-skip -->
|
||||
|
||||
```js noReport
|
||||
{
|
||||
original_price: 110,
|
||||
calculated_price: 100,
|
||||
|
||||
@@ -29,7 +29,7 @@ You can, however, force calculating the taxes of the cart by passing in the thir
|
||||
For example:
|
||||
|
||||
```jsx
|
||||
cartService.retrieve('cart_01G8Z...', { }, { force_taxes: true });
|
||||
cartService.retrieve("cart_01G8Z...", { }, { force_taxes: true })
|
||||
```
|
||||
|
||||
:::tip
|
||||
@@ -45,20 +45,20 @@ Another way you can use the `CartService` to calculate taxes is using the method
|
||||
```jsx
|
||||
|
||||
export default () => {
|
||||
//...
|
||||
// ...
|
||||
|
||||
router.get("/store/line-taxes", async (req, res) => {
|
||||
//example of retrieving cart
|
||||
const cartService = req.scope.resolve("cartService");
|
||||
// example of retrieving cart
|
||||
const cartService = req.scope.resolve("cartService")
|
||||
const cart = await cartService.retrieve(cart_id)
|
||||
|
||||
//...
|
||||
//retrieve taxes of line items
|
||||
// ...
|
||||
// retrieve taxes of line items
|
||||
const data = await decorateTotals(cart, {
|
||||
force_taxes: true
|
||||
force_taxes: true,
|
||||
})
|
||||
|
||||
return res.status(200).json({ cart: data });
|
||||
return res.status(200).json({ cart: data })
|
||||
})
|
||||
}
|
||||
```
|
||||
@@ -72,7 +72,7 @@ You can calculate and retrieve taxes of line items using the `getLineItemTotals`
|
||||
```jsx
|
||||
const itemTotals = await totalsService
|
||||
.getLineItemTotals(item, cart, {
|
||||
include_tax: true
|
||||
include_tax: true,
|
||||
})
|
||||
```
|
||||
|
||||
|
||||
@@ -35,28 +35,29 @@ If you use a `.env` file to load environment variables on your server, you need
|
||||
You can add the following code snippet at the top of the file which uses the [dotenv](https://www.npmjs.com/package/dotenv) package to load the environment variables based on the current Node environment:
|
||||
|
||||
```jsx
|
||||
const dotenv = require('dotenv')
|
||||
const dotenv = require("dotenv")
|
||||
|
||||
let ENV_FILE_NAME = '';
|
||||
let ENV_FILE_NAME = ""
|
||||
switch (process.env.NODE_ENV) {
|
||||
case 'production':
|
||||
ENV_FILE_NAME = '.env.production';
|
||||
break;
|
||||
case 'staging':
|
||||
ENV_FILE_NAME = '.env.staging';
|
||||
break;
|
||||
case 'test':
|
||||
ENV_FILE_NAME = '.env.test';
|
||||
break;
|
||||
case 'development':
|
||||
case "production":
|
||||
ENV_FILE_NAME = ".env.production"
|
||||
break
|
||||
case "staging":
|
||||
ENV_FILE_NAME = ".env.staging"
|
||||
break
|
||||
case "test":
|
||||
ENV_FILE_NAME = ".env.test"
|
||||
break
|
||||
case "development":
|
||||
default:
|
||||
ENV_FILE_NAME = '.env';
|
||||
break;
|
||||
ENV_FILE_NAME = ".env"
|
||||
break
|
||||
}
|
||||
|
||||
try {
|
||||
dotenv.config({ path: process.cwd() + '/' + ENV_FILE_NAME });
|
||||
dotenv.config({ path: process.cwd() + "/" + ENV_FILE_NAME })
|
||||
} catch (e) {
|
||||
// handle error
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
@@ -31,19 +31,19 @@ Instead of using `customerService.retrieveByEmail`, you should now use the metho
|
||||
The `customerService.retrieveRegisteredByEmail` method allows you to retrieve a registered customer by email:
|
||||
|
||||
```ts
|
||||
customerService.retrieveRegisteredByEmail("example@gmail.com");
|
||||
customerService.retrieveRegisteredByEmail("example@gmail.com")
|
||||
```
|
||||
|
||||
On the other hand, the `retrieveUnregisteredByEmail` method allows to retrieve guest customers by email:
|
||||
|
||||
```jsx
|
||||
customerService.retrieveUnregisteredByEmail("example@gmail.com");
|
||||
customerService.retrieveUnregisteredByEmail("example@gmail.com")
|
||||
```
|
||||
|
||||
To retrieve a customer by email regardless of whether they are registered or not, you can use the `customerService.list` method instead:
|
||||
|
||||
```ts
|
||||
customerService.list({
|
||||
email: "example@gmail.com"
|
||||
email: "example@gmail.com",
|
||||
})
|
||||
```
|
||||
@@ -56,13 +56,13 @@ In your loader file that creates a cron job, replace the use of `eventBus` to `j
|
||||
|
||||
```ts
|
||||
const myJob = async (container, options) => {
|
||||
const jobSchedulerService = container.resolve("jobSchedulerService");
|
||||
const jobSchedulerService = container.resolve("jobSchedulerService")
|
||||
jobSchedulerService.create("my-job", {}, "0 0 * * *", async () => {
|
||||
//...
|
||||
});
|
||||
// ...
|
||||
})
|
||||
}
|
||||
|
||||
export default myJob;
|
||||
export default myJob
|
||||
```
|
||||
|
||||
You can learn more in the [How to Create a Scheduled Job](../scheduled-jobs/create.md) documentation.
|
||||
@@ -73,15 +73,26 @@ This version of Medusa introduces a change in how payment providers are implemen
|
||||
|
||||
Although this change is currently backwards compatible, it is recommended to change the signature of these methods to the following:
|
||||
|
||||
<!-- eslint-disable max-len -->
|
||||
|
||||
```ts
|
||||
import { PaymentContext, PaymentSessionResponse } from '@medusajs/medusa'
|
||||
import { PaymentContext, PaymentSessionResponse } from "@medusajs/medusa"
|
||||
// ...
|
||||
|
||||
async createPayment(context: PaymentContext): Promise<PaymentSessionResponse> {
|
||||
//...
|
||||
}
|
||||
class MyPaymentService extends AbstractPaymentService<TransactionBaseService> {
|
||||
// ...
|
||||
async createPayment(
|
||||
context: PaymentContext
|
||||
): Promise<PaymentSessionResponse> {
|
||||
// ...
|
||||
}
|
||||
|
||||
async updatePayment(paymentSessionData: PaymentSessionData, context: PaymentContext): Promise<PaymentSessionResponse> {
|
||||
//...
|
||||
async updatePayment(
|
||||
paymentSessionData: PaymentSessionData,
|
||||
context: PaymentContext
|
||||
): Promise<PaymentSessionResponse> {
|
||||
// ...
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
Reference in new issue
Block a user